Практикум прикладного программирования на C# в среде VS.NET 2005

Web-службы

Разбить на страницы
Показывать лекцию целиком

Файлы к лабораторной работе Вы можете скачать здесь.

Web-службы реализуют технологию удаленной активации выполнения блока кода посредством обращения к этому коду самым простым и универсальным способом - по протоколу HTTP, который реализован практически на всех компьютерах.

Идея Web-служб предполагает, что можно создать какой-то программный продукт, держать его под своим контролем, но предлагать пользователям обращаться к нему для выполнения каких-то оригинальных действий с целью получения результата. Грубой аналогией может служить общественная прачечная, где стиральные машины сдаются в аренду клиентам, находясь под контролем владельца.

Безусловно, Web-службы относятся к приложениям категории ASP.NET, но имеют некоторую специфику. Важно помнить, что Web-службы должны выполнять определенные действия в ответ на удаленные запросы клиентов (произвести вычисления, считать данные из источника и т.д.) и ждать следующего запроса, поэтому в них недопустимо применять элементы графического интерфейса пользователя. Иными словами, Web-службы можно считать удаленными утилитами.

Заготовка приложения со стартовой формой

Применим список ListBox, в который можно добавлять сколько угодно опций вызова упражнений.

  • Выполните команду File/New/Project и заполните, в соответствии с рисунком, мастер создания проекта с именем WinApp в решении WebServiceWinApp (каталог размещения может быть любым)
  • Через панель Solution Explorer переименуйте файл Form1.cs в Start.cs, а свойству заголовка окна формы присвойте значение Text =" Lab50 - Имя студента "
  • Поместите на форму библиотечный компонент ListBox и настройте его в соответствии с таблицей свойств
  • Таблица свойств экземпляра ListBox
    Свойство Значение
    Name listBoxChoice
    Items Упражнение 1.
      Упражнение 2.
    Dock Fill
  • Через панель Properties создайте обработчик для события SelectedIndexChanged объекта listBoxChoice, который заполните так
  • Form frm;   // Объявили поле
            private void listBoxChoice_SelectedIndexChanged(object sender, EventArgs e)
            {
                // Привязали номер упражнения к индексу списка
                ListBox list = (ListBox)sender;
                string formName = "Form" + (list.SelectedIndex + 1);
        
                ///////////////////////////////////////////////////
                // Следующий код взят из лабораторной работы №47
                ///////////////////////////////////////////////////
                // Читаем коллекцию запущенных форм
                FormCollection fc = Application.OpenForms;
                bool IsRun = false;
                // Перебираем коллекцию
                foreach (Form form in fc)
                {
                    // Имя очередной запущенной формы сравниваем с закрепленным за кнопкой
                    if (form.Name == formName)
                    {
                        IsRun = true;   // Нашли, что форма запущена, поднимаем флаг
                        frm = form;     // Сохраняем ссылку на запущенную форму для фокуса
                        break;          // Выходим из цикла
                    }
                }
        
                // Если форма не запущена - запускаем
                if (!IsRun)
                {
                    switch (formName)
                    {
                        case "Form1":
                            frm = new Form1();
                            break;
                        case "Form2":
                            frm = new Form2();
                            break;
                    }
        
                    this.AddOwnedForm(frm);     // Сделать новую frm подчиненной Start
                    // frm.Owner = this;        // Алтернативный способ назначить владельца
                    frm.ShowInTaskbar = false;  // Не отображать метку окна в панели задач
                    frm.Show();                 // Показать новую форму
                }
                else
                    frm.Focus();                // Передать фокус запущенной форме        
            }

    Примененный здесь способ предотвращения одновременного запуска одного и того же упражнения мы уже использовали в предыдущих лабораторных работах.

  • Командой меню оболочки Project/Add Windows Form добавьте в проект WinApp еще две формы с именами Form1, Form2
  • Поместите на каждую форму Form1, Form2 из панели Toolbox какой-нибудь элемент управления (например, Button ) и сразу удалите его, чтобы визуальный редактор явно прописал свойство Name в файле *.Designer.cs
  • Запустите приложение и убедитесь в работоспособности механизма вызова отдельных упражнений
  • Упражнение 1. Создание простой Web-службы генерации поздравления

    Клиентами Web-службы могут быть Web-приложения и приложения рабочего стола: консольные и оконные. В данном упражнении мы в качестве клиента Web-службы создадим оконное приложение Windows Forms, представленное формой Form1. Таким образом, Form1 будет клиентом Web-службы.

    Создание оконного приложения в качестве клиента Web-службы

  • Откройте форму Form1 и поместите на нее экземпляры компонентов пользовательского интерфейса в соответствии с таблицей
  • Таблица свойств экземпляров компонентов на Form1
    Компонент Свойство Значение
    Label ( Name ) label1
      Text Введите ФИО Юбиляра:
    TextBox ( Name ) textBox1
      Text Пусто
    Button ( Name ) btnSubmit
      Text Отправить
      AutoSize True

    Интерфейс формы Упражнения 1 должен быть примерно таким

    Создание самой Web-службы

  • Выполните команду File/Add/New Web Site и заполните окно мастера создания проекта Web-службы в соответствии с рисунком
  • Мастер создаст заготовку проекта приложения Web-службы, в которой застраничный файл ( CodeBehind ) будет выглядеть так

    using System;
    using System.Web;
    using System.Web.Services;
    using System.Web.Services.Protocols;
        
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class Service : System.Web.Services.WebService
    {
        public Service () 
        {
            //Uncomment the following line if using designed components 
            //InitializeComponent(); 
        }
        
        [WebMethod]
        public string HelloWorld() 
        {
            return "Hello World";
        }
    }

    Метод HelloWorld() сгенерирован мастером автоматически точно также, как и дежурное имя службы - файл Service.cs.

  • Замените метод HelloWorld() на следующий код
  • using System;
    using System.Web;
    using System.Web.Services;
    using System.Web.Services.Protocols;
        
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class Service : System.Web.Services.WebService
    {
        public Service () 
        {
            //Uncomment the following line if using designed components 
            //InitializeComponent(); 
        }
        
        [WebMethod]
        public string Hello(string strInput) 
        {
            return "Приветствуем Вас, наш дорогой\n" + strInput;
        }
    }
  • Обязательно сохраните!!! внесенные изменения на диск, поскольку все дальнейшие действия оболочки будут опираться на сохраненный файл App_Em/Service.cs
  • Создание на клиенте класса-переходника

    Для того, чтобы связать удаленную Web-службу с оконным приложением пользователя, нужно создать специальный промежуточный proxy-класс (прокси-класс), который будет служить переходником между Web-службой и оконным приложением и организовывать всю работу по отправке запросов и получению результатов. Этот класс очень сложный для создания вручную, поэтому оболочка создает его с помощью мастера при попытке разработчика добавить к локальному приложению Web-ссылку.

  • В панели Solution Explorer выделите узел локального проекта WinApp и через контекстное меню выполните команду Add Web Reference. Появится окно мастера
  • Выберите ссылку Web services in this solution и в появишемся окне мастера выберите ссылку Service
  • После того, как станет доступной кнопка Add Reference, щелкните на ней
  • Через некоторое время мастер сгенерирует необходимую инфраструктуру для подключения к Web-службе с помощью созданного прокси-класса, которую разместит в папке Web References/localhost, и мы ее можем увидеть в Проводнике Windows Explorer

    Эту инфраструктуру обеспечивают следующие файлы

  • Reference.cs - файл, содержащий код созданного мастером прокси-класса WinApp.localhost.Service
  • Service.disco (discovery service) - XML -файл обнаружения, дающий клиенту информацию о том, что Web-служба существует)
  • Reference.map - карта Web-службы, содержащая справочную информацию о том, что делает эта служба
  • Service.wsdl (Web Services Description Language - язык описания Web-служб) - XML -описание Web-службы, необходимое различным инструментам оболочки для автоматического создания классов, интерфейсов и выполнения другой работы
  • Каталог localhost проекта WinApp в панели Solution Explorer представлен единым значком с одноименным названием

    Разработчики Web-служб обычно работают с файлами *.cs, *.asmx, *.disco, Web.config. Возможно, потребуется еще работа с файлом Global.asax, который предназначен для хранения обработчиков событий глобального уровня. Этого файла в нашем решении нет, но его всегда можно добавить, что мы сейчас и сделаем. Нужно помнить, что в отличие от файлов Web.config, которые должны быть уникальны только в отдельном каталоге, файл Global.asax в приложении должен быть единственным и находиться в корневом узле проекта.

  • В панели Solution Explorer вызовите контекстное меню для узла WebServiceApp и командой Add New Item добавьте к проекту ASP.NET файл Global.asax
  • Автоматически созданная заготовка файла Global.asax содержит несколько пустых обработчиков некоторых глобальных событий уровня всего приложения.

    Если посмотреть на проект WinApp после создания прокси-класса через панель Class View, то можно увидеть сложную конфигурацию автоматически сгенерированного оболочкой кода

  • Откройте файл Form1.cs в режиме View Designer и двойным щелчком на кнопке btnSubmit создайте для нее обработчик, который заполните так
  • private void btnSubmit_Click(object sender, EventArgs e)
            {
                if (textBox1.Text.Length == 0)
                    MessageBox.Show("Заполните текстовое поле");
                else
                {
                    this.Cursor = Cursors.WaitCursor;
                    WinApp.localhost.Service webService = new WinApp.localhost.Service();
                    string mess = webService.Hello(textBox1.Text) + " !!!";
                    this.Cursor = Cursors.Default;
                    MessageBox.Show(mess, "Сообщение от Web-службы");
                }
            }
  • В панели Solution Explorer вызовите контекстное меню для корневого узла проекта WinApp и выполните команду Set as StartUp Project (или просто щелкните курсором мыши по узлу WinApp )
  • Запустите решение и испытайте работу Web-службы
  • Вот один из вариантов полученного результата

    Создание Web-приложения в качестве клиента Web-службы

    В этом упражнении мы создадим сайт с простой главной страницей, на которой по щелчку на кнопке Submit будем получать приветствие от Web-службы.

  • Добавьте к решению командой File/Add/New Web Site новый Web-сайт с именем WebSiteApp, используя модель проекта, показанную на снимке
  • Добавьте к проекту Web-сайта ссылку на Web-службу командой контекстного меню (для узла проекта сайта WebSiteApp ) Add Web Reference
  • В появившемся окне Add Web Reference мастера щелкните на ссылке Web services in this solution, дождитесь, когда станет доступной кнопка Add Reference, и щелкните на этой кнопке
  • В результате мастер создаст папку с именем localhost, в которой разместит файлы, обеспечивающие необходимую инфраструктуру для связи с Web-службой.

  • Service.disco (discovery service) - XML -файл обнаружения, дающий клиенту информацию о том, что Web-служба существует)
  • Service.discomap - карта Web-службы, содержащая справочную информацию о том, что делает эта служба
  • Service.wsdl (Web Services Description Language - язык описания Web-служб) - XML -описание Web-службы, необходимое различным инструментам оболочки для автоматического создания классов, интерфейсов и выполнения другой работы
  • Откройте страницу Default.asp x Web-приложения WebSiteApp, переведите ее в режим редактирования Design и сформируйте интерфейс пользователя из управляющих элементов панели Toolbox согласно таблицы
  • Таблица интерфейсных элементов страницы Default.aspx
    Элемент Свойство Значение
    Label ID mess
      Text Label
    Label ID Label1
      Text Введите ФИО Юбиляра
    TextBox ID textBox1
      Text Пусто
      Width 265px
    Button ID btnSubmit
      Text Отправить
  • Добавьте в открывающий дескриптор <div> контейнера <form> атрибут style выравнивания по центру всего содержимого страницы, чтобы код декларативной части страницы стал таким
  • <%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>
        
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>Страница-клиент Web-службы приветствия</title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div style="text-align: center">
                <asp:Label ID="mess" runat="server" Text="Label"></asp:Label>
                <br />
                <asp:Label ID="Label1" runat="server" Text="Введите ФИО Юбиляра"></asp:Label>
                <br />
                <asp:TextBox ID="textBox1" runat="server" Width="265px"></asp:TextBox>
                <br />
                <asp:Button ID="btnSubmit" runat="server" Text="Отправить" />
            </div>
        </form>
    </body>
    </html>

    В соответствии с приведенным дескрипторным кодом страница Default.aspx на этапе проектирования будет иметь следующее представление

  • Двойным щелчком на кнопке btnSubmit создайте заготовку обработчика события Click и откорректируйте застраничный файл Default.aspx.cs так
  • using System;
    using System.Data;
    using System.Configuration;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
        
    public partial class _Default : System.Web.UI.Page 
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            mess.Text = string.Empty;
            mess.ForeColor = System.Drawing.Color.Red;
        }
        
        protected void btnSubmit_Click(object sender, EventArgs e)
        {
            // Создаем экземпляр класса Web-службы 
            localhost.Service webService=new localhost.Service();
        
            // Формируем сообщение, но прежде будет обращение к методу Web-службы
            if (textBox1.Text.Length != 0)
                mess.Text = "<h2>" + webService.Hello(textBox1.Text) + " !!!" + "</h2>";
            else
                mess.Text = "Заполните текстовое поле";
        }
    }
  • В панели Solution Explorer назначьте проект WebSiteApp стартовым командой Set as StartUp Project контекстного меню и запустите все решение на выполнение
  • Результат с клиентской Web-страничкой будет примерно таким

    Упражнение 2. Создание простой Web-службы калькулятора

    В данном упражнении мы создадим Web-службу и ее клиента, которые в совокупности будут имитировать работу простого калькулятора.

    Создание Web-службы калькулятора

  • Добавьте к решению новый проект Web-службы командой File/Add/New Web Site, присвоив ему имя CalcWebService
  • Откорректируйте вновь созданный файл App_Em/ Service.cs так, чтобы были реализованы 4 простых метода, как показано в листинге
  • using System;
    using System.Web;
    using System.Web.Services;
    using System.Web.Services.Protocols;
        
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class Service : System.Web.Services.WebService
    {
        // Сложить
        [WebMethod]
        public double Add(double x, double y) 
        {
            return x + y;
        }
        
        // Вычесть
        [WebMethod]
        public double Subtract(double x, double y)
        {
            return x - y;
        }
        
        // Умножить
        [WebMethod]
        public double Multiply(double x, double y)
        {
            return x * y;
        }
        
        // Разделить
        [WebMethod]
        public double Divide(double x, double y)
        {
            if (y == 0)
                throw new DivideByZeroException("Деление на ноль!");
            else
                return x / y;
        }
    }

    Создание клиента Web-службы калькулятора

    В качестве клиента Web-службы назначим форму Form2 и сформируем на ней соответствующий пользовательский интерфейс.

  • Откройте файл Form2.cs проекта WinApp в режиме View Designer и добавьте на форму компоненты пользовательского интерфейса в соответствии с таблицей, чтобы компоновка была такой
  • Таблица свойств формы Form2
    Элемент Свойство Значение
    Form Text Клиент калькулятора Web-службы
      FormBorderStyle FixedToolWindow
    Label Name lblFirst
      Text Первое число:
      TextAlign MiddleRight
    Label Name lblSecond
      Text Второе число:
      TextAlign MiddleRight
    Label Name lblResult
      Text Результат:
      TextAlign MiddleRight
    TextBox Name txtFirst
      Text пусто
    TextBox Name txtSecond
      Text пусто
    TextBox Name txtResult
      Text пусто
      ReadOnly True
      TabStop False
    Button Name btnAdd
      Text +
      Font/Bold True
      Font/Size 10
      Size 30; 30
    Button Name btnSubtract
      Text -
      Font/Name Courier New
      Font/Bold True
      Font/Size 10
      Size 30; 30
    Button Name btnMultiply
      Text *
      Font/Name Courier New
      Font/Bold True
      Font/Size 10
      Size 30; 30
    Button Name btnDivide
      Text :
      Font/Name Courier New
      Font/Bold True
      Font/Size 10
      Size 30; 30
    Button Name btnExit
      Text Выход
      AutoSize True
  • Защитите интерфейс формы Form2 от случайных изменений, выполнив команду Format/Lock Controls меню оболочки
  • Подключение Web-службы калькулятора к клиенту

  • Свяжите клиента с Web-службой, добавив к проекту WinApp необходимую инфраструктуру командой Add Web Reference и щелкнув на ссылке Web services in this solution. После этого нужно выбрать Web-службу, представленную проектом CalcWebService, и щелкнуть по соответствующей гиперссылке Service
  • После выбора сервиса CalcWebService кнопка Add Reference станет доступной и щелчок на ней заставит оболочку добавить к проекту WinApp еще одну инфраструктуру для вызова сервиса калькулятора. Созданные файлы будут помещены в папке Web References/localhost1 проекта WinApp
  • Выделите на Form2.cs[Design] одновременно все 4 кнопки операций калькулятора и создайте для них заготовку btnClick() общего обработчика события Click, которую заполните следующим кодом
  • using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
        
    namespace WinApp
    {
        public partial class Form2 : Form
        {
            public Form2()
            {
                InitializeComponent();
            }
        
            // Создаем объект Web-службы 
            WinApp.localhost1.Service calcWebService = 
                new WinApp.localhost1.Service();
        
            double numResult;
          
            private void btnClick(object sender, EventArgs e)
            {
                double numFirst, numSecond;
                // Копируем текстовые поля в локальные переменные
                string strFirst = string.Copy(txtFirst.Text);
                string strSecond = string.Copy(txtSecond.Text);
        
                // Замена в строке точки символом запятой
                // для корректного преобразования в число
                int pos = strFirst.IndexOf('.');
                if (pos != -1)
                {
                    strFirst = strFirst.Substring(0, pos)
                        + ','
                        + strFirst.Substring(pos + 1);
                }
                pos = strSecond.IndexOf('.');
                if (pos != -1)
                {
                    strSecond = strSecond.Substring(0, pos)
                        + ','
                        + strSecond.Substring(pos + 1);
                }
        
                // Преобразуем текст в число для выполнения операций
                if (txtFirst.Text.Length > 0)
                    numFirst = Convert.ToDouble(strFirst);
                else
                    numFirst = 0.0D;
                if (txtSecond.Text.Length > 0)
                    numSecond = Convert.ToDouble(strSecond);
                else
                    numSecond = 0.0D;
        
                // Выполняем нужную операцию
                Button btn = (Button)sender;// Явное приведение типов для распознавания кнопок
                switch (btn.Name)// Переключатель
                {
                    case "btnAdd":// Операция сложения
                        numResult = calcWebService.Add(numFirst, numSecond);
                        break;
                    case "btnSubtract":// Операция вычитания
                        numResult = calcWebService.Subtract(numFirst, numSecond);
                        break;
                    case "btnMultiply":// Операция умножения
                        numResult = calcWebService.Multiply(numFirst, numSecond);
                        break;
                    case "btnDivide":// Операция деления
                        // Корректность деления проверяется Web-службой 
                        numResult = calcWebService.Divide(numFirst, numSecond);
                        break;
                }
        
                // Печатаем результат
                txtResult.Text = Convert.ToString(numResult);
            }
        }
    }

    Здесь мы прежде всего скопировали значения полей ввода в промежуточные текстовые переменные, используя статический метод System.String.Copy() класса String (псевдоним string ). Затем мы проверяем наличие символа "точки" в этих переменных и при обнаружении производим замену на символ "запятая" с полным формированием новой строки. Мы не можем заменить символ "на месте" в существующей строке, обратившись к нему как элементу массива, поскольку индексная форма адресации в строках существует только для чтения.

    Но мы можем, сформировав новую строку справа от знака присваивания, присвоить результат вновь той же самой ссылке, которая фактически будет адресоваться к новой области памяти, а старая строка, как брошенный фрагмент памяти, будет оставлена для сборщика мусора. Операция замены точки на запятую выполняется для того, чтобы корректно преобразовать текстовое значение поля ввода в числовое, иначе генерируется исключение.

  • Создайте обработчик для кнопки btnExit и заполните его кодом завершения работы клиента Web-службы простого калькулятора
  • private void btnExit_Click(object sender, EventArgs e)
            {
                this.Close();
            }

    Теперь нужно защитить поля ввода от всех символов, кроме цифр, одного знака минус и одной точки. Стрелки и клавиша Del в текстовых полях функционируют, но работу клавиши Backspace нужно учесть явно.

  • Объявите в конце класса Form2 логическое поле isNumeric для отфильтровывания нецифровых символов, которые пользователь может попытаться ввести в текстовые поля
  • private bool isNumber = false;
  • Выделите текстовое поле txtFirst и через панель Properties в режиме Events создайте обработчик для события KeyDown. Заполните обработчик так
  • private bool isNumber = false;
      
        private void txtFirst_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
        {
          isNumber = 
            e.KeyCode >= Keys.D0  e.KeyCode <= Keys.D9 // keyboard - основная клавиатура
            || e.KeyCode >= Keys.NumPad0  e.KeyCode <= Keys.NumPad9 // keypad - дополнительная клавиатура
            || e.KeyCode == Keys.Back;
        }
  • Выделите текстовое поле txtFirst и через панель Properties в режиме Events создайте обработчик для события KeyPress. Заполните обработчик так
  • private void txtFirst_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
        {
          TextBox box = (TextBox) sender;// Явное преобразование типов
      
          switch(e.KeyChar) // Переключатель
          {
            case '-': // Разрешаем минус, если он первый
              if(box.Text.Length == 0)
                isNumber = true;
              break;
            case '.':  
              // Точка не должна быть первой
              if(box.Text.Length == 0)
                break;
              // Точка не должна следовать сразу за минусом
              if(box.Text[0] == '-'  box.Text.Length == 1)
                break;
              // Точка должна быть одна
              if(box.Text.IndexOf('.') == -1)
                isNumber = true; // Еще не было точек
              break;
          }
      
          // Запрещаем в текстовом поле лишние символы
          if(!isNumber)
            e.Handled = true;
        }
  • Выделите текстовое поле txtSecond и через панель Properties в режиме Events подключите к событиям KeyDown и KeyPress соответствующие обработчики, только что созданные для поля txtFirst. Обработчики подключите через раскрывающиеся списки полей значений
  • Здесь мы одни и те же обработчики используем для разных полей, поскольку необходимо выполнять одинаковые действия. Задача одна - не допускать для ввода в поля никакие другие символы, кроме цифр, одного минуса и одной точки. Возможность ввода цифр реализована для основной ( keyboard ) и дополнительной ( keypad ) частей клавиатуры. Параметр sender передает в обработчик ссылку на активное текстовое поле, вызвавшее событие редактирования.

  • Назначьте стартовым проект WinApp, запустите его и проверьте функциональность простого калькулятора в Упражнении 2, фактически реализованного в Web-службе
  • Страницы:

    Файлы к лабораторной работе Вы можете скачать здесь.

    Web-службы реализуют технологию удаленной активации выполнения блока кода посредством обращения к этому коду самым простым и универсальным способом - по протоколу HTTP, который реализован практически на всех компьютерах.

    Идея Web-служб предполагает, что можно создать какой-то программный продукт, держать его под своим контролем, но предлагать пользователям обращаться к нему для выполнения каких-то оригинальных действий с целью получения результата. Грубой аналогией может служить общественная прачечная, где стиральные машины сдаются в аренду клиентам, находясь под контролем владельца.

    Безусловно, Web-службы относятся к приложениям категории ASP.NET, но имеют некоторую специфику. Важно помнить, что Web-службы должны выполнять определенные действия в ответ на удаленные запросы клиентов (произвести вычисления, считать данные из источника и т.д.) и ждать следующего запроса, поэтому в них недопустимо применять элементы графического интерфейса пользователя. Иными словами, Web-службы можно считать удаленными утилитами.

    Заготовка приложения со стартовой формой

    Применим список ListBox, в который можно добавлять сколько угодно опций вызова упражнений.

  • Выполните команду File/New/Project и заполните, в соответствии с рисунком, мастер создания проекта с именем WinApp в решении WebServiceWinApp (каталог размещения может быть любым)
  • Через панель Solution Explorer переименуйте файл Form1.cs в Start.cs, а свойству заголовка окна формы присвойте значение Text =" Lab50 - Имя студента "
  • Поместите на форму библиотечный компонент ListBox и настройте его в соответствии с таблицей свойств
  • Таблица свойств экземпляра ListBox
    Свойство Значение
    Name listBoxChoice
    Items Упражнение 1.
      Упражнение 2.
    Dock Fill
  • Через панель Properties создайте обработчик для события SelectedIndexChanged объекта listBoxChoice, который заполните так
  • Form frm;   // Объявили поле
            private void listBoxChoice_SelectedIndexChanged(object sender, EventArgs e)
            {
                // Привязали номер упражнения к индексу списка
                ListBox list = (ListBox)sender;
                string formName = "Form" + (list.SelectedIndex + 1);
        
                ///////////////////////////////////////////////////
                // Следующий код взят из лабораторной работы №47
                ///////////////////////////////////////////////////
                // Читаем коллекцию запущенных форм
                FormCollection fc = Application.OpenForms;
                bool IsRun = false;
                // Перебираем коллекцию
                foreach (Form form in fc)
                {
                    // Имя очередной запущенной формы сравниваем с закрепленным за кнопкой
                    if (form.Name == formName)
                    {
                        IsRun = true;   // Нашли, что форма запущена, поднимаем флаг
                        frm = form;     // Сохраняем ссылку на запущенную форму для фокуса
                        break;          // Выходим из цикла
                    }
                }
        
                // Если форма не запущена - запускаем
                if (!IsRun)
                {
                    switch (formName)
                    {
                        case "Form1":
                            frm = new Form1();
                            break;
                        case "Form2":
                            frm = new Form2();
                            break;
                    }
        
                    this.AddOwnedForm(frm);     // Сделать новую frm подчиненной Start
                    // frm.Owner = this;        // Алтернативный способ назначить владельца
                    frm.ShowInTaskbar = false;  // Не отображать метку окна в панели задач
                    frm.Show();                 // Показать новую форму
                }
                else
                    frm.Focus();                // Передать фокус запущенной форме        
            }

    Примененный здесь способ предотвращения одновременного запуска одного и того же упражнения мы уже использовали в предыдущих лабораторных работах.

  • Командой меню оболочки Project/Add Windows Form добавьте в проект WinApp еще две формы с именами Form1, Form2
  • Поместите на каждую форму Form1, Form2 из панели Toolbox какой-нибудь элемент управления (например, Button ) и сразу удалите его, чтобы визуальный редактор явно прописал свойство Name в файле *.Designer.cs
  • Запустите приложение и убедитесь в работоспособности механизма вызова отдельных упражнений
  • Упражнение 1. Создание простой Web-службы генерации поздравления

    Клиентами Web-службы могут быть Web-приложения и приложения рабочего стола: консольные и оконные. В данном упражнении мы в качестве клиента Web-службы создадим оконное приложение Windows Forms, представленное формой Form1. Таким образом, Form1 будет клиентом Web-службы.

    Создание оконного приложения в качестве клиента Web-службы

  • Откройте форму Form1 и поместите на нее экземпляры компонентов пользовательского интерфейса в соответствии с таблицей
  • Таблица свойств экземпляров компонентов на Form1
    Компонент Свойство Значение
    Label ( Name ) label1
      Text Введите ФИО Юбиляра:
    TextBox ( Name ) textBox1
      Text Пусто
    Button ( Name ) btnSubmit
      Text Отправить
      AutoSize True

    Интерфейс формы Упражнения 1 должен быть примерно таким

    Создание самой Web-службы

  • Выполните команду File/Add/New Web Site и заполните окно мастера создания проекта Web-службы в соответствии с рисунком
  • Мастер создаст заготовку проекта приложения Web-службы, в которой застраничный файл ( CodeBehind ) будет выглядеть так

    using System;
    using System.Web;
    using System.Web.Services;
    using System.Web.Services.Protocols;
        
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class Service : System.Web.Services.WebService
    {
        public Service () 
        {
            //Uncomment the following line if using designed components 
            //InitializeComponent(); 
        }
        
        [WebMethod]
        public string HelloWorld() 
        {
            return "Hello World";
        }
    }

    Метод HelloWorld() сгенерирован мастером автоматически точно также, как и дежурное имя службы - файл Service.cs.

  • Замените метод HelloWorld() на следующий код
  • using System;
    using System.Web;
    using System.Web.Services;
    using System.Web.Services.Protocols;
        
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class Service : System.Web.Services.WebService
    {
        public Service () 
        {
            //Uncomment the following line if using designed components 
            //InitializeComponent(); 
        }
        
        [WebMethod]
        public string Hello(string strInput) 
        {
            return "Приветствуем Вас, наш дорогой\n" + strInput;
        }
    }
  • Обязательно сохраните!!! внесенные изменения на диск, поскольку все дальнейшие действия оболочки будут опираться на сохраненный файл App_Em/Service.cs
  • Создание на клиенте класса-переходника

    Для того, чтобы связать удаленную Web-службу с оконным приложением пользователя, нужно создать специальный промежуточный proxy-класс (прокси-класс), который будет служить переходником между Web-службой и оконным приложением и организовывать всю работу по отправке запросов и получению результатов. Этот класс очень сложный для создания вручную, поэтому оболочка создает его с помощью мастера при попытке разработчика добавить к локальному приложению Web-ссылку.

  • В панели Solution Explorer выделите узел локального проекта WinApp и через контекстное меню выполните команду Add Web Reference. Появится окно мастера
  • Выберите ссылку Web services in this solution и в появишемся окне мастера выберите ссылку Service
  • После того, как станет доступной кнопка Add Reference, щелкните на ней
  • Через некоторое время мастер сгенерирует необходимую инфраструктуру для подключения к Web-службе с помощью созданного прокси-класса, которую разместит в папке Web References/localhost, и мы ее можем увидеть в Проводнике Windows Explorer

    Эту инфраструктуру обеспечивают следующие файлы

  • Reference.cs - файл, содержащий код созданного мастером прокси-класса WinApp.localhost.Service
  • Service.disco (discovery service) - XML -файл обнаружения, дающий клиенту информацию о том, что Web-служба существует)
  • Reference.map - карта Web-службы, содержащая справочную информацию о том, что делает эта служба
  • Service.wsdl (Web Services Description Language - язык описания Web-служб) - XML -описание Web-службы, необходимое различным инструментам оболочки для автоматического создания классов, интерфейсов и выполнения другой работы
  • Каталог localhost проекта WinApp в панели Solution Explorer представлен единым значком с одноименным названием

    Разработчики Web-служб обычно работают с файлами *.cs, *.asmx, *.disco, Web.config. Возможно, потребуется еще работа с файлом Global.asax, который предназначен для хранения обработчиков событий глобального уровня. Этого файла в нашем решении нет, но его всегда можно добавить, что мы сейчас и сделаем. Нужно помнить, что в отличие от файлов Web.config, которые должны быть уникальны только в отдельном каталоге, файл Global.asax в приложении должен быть единственным и находиться в корневом узле проекта.

  • В панели Solution Explorer вызовите контекстное меню для узла WebServiceApp и командой Add New Item добавьте к проекту ASP.NET файл Global.asax
  • Автоматически созданная заготовка файла Global.asax содержит несколько пустых обработчиков некоторых глобальных событий уровня всего приложения.

    Если посмотреть на проект WinApp после создания прокси-класса через панель Class View, то можно увидеть сложную конфигурацию автоматически сгенерированного оболочкой кода

  • Откройте файл Form1.cs в режиме View Designer и двойным щелчком на кнопке btnSubmit создайте для нее обработчик, который заполните так
  • private void btnSubmit_Click(object sender, EventArgs e)
            {
                if (textBox1.Text.Length == 0)
                    MessageBox.Show("Заполните текстовое поле");
                else
                {
                    this.Cursor = Cursors.WaitCursor;
                    WinApp.localhost.Service webService = new WinApp.localhost.Service();
                    string mess = webService.Hello(textBox1.Text) + " !!!";
                    this.Cursor = Cursors.Default;
                    MessageBox.Show(mess, "Сообщение от Web-службы");
                }
            }
  • В панели Solution Explorer вызовите контекстное меню для корневого узла проекта WinApp и выполните команду Set as StartUp Project (или просто щелкните курсором мыши по узлу WinApp )
  • Запустите решение и испытайте работу Web-службы
  • Вот один из вариантов полученного результата

    Создание Web-приложения в качестве клиента Web-службы

    В этом упражнении мы создадим сайт с простой главной страницей, на которой по щелчку на кнопке Submit будем получать приветствие от Web-службы.

  • Добавьте к решению командой File/Add/New Web Site новый Web-сайт с именем WebSiteApp, используя модель проекта, показанную на снимке
  • Добавьте к проекту Web-сайта ссылку на Web-службу командой контекстного меню (для узла проекта сайта WebSiteApp ) Add Web Reference
  • В появившемся окне Add Web Reference мастера щелкните на ссылке Web services in this solution, дождитесь, когда станет доступной кнопка Add Reference, и щелкните на этой кнопке
  • В результате мастер создаст папку с именем localhost, в которой разместит файлы, обеспечивающие необходимую инфраструктуру для связи с Web-службой.

  • Service.disco (discovery service) - XML -файл обнаружения, дающий клиенту информацию о том, что Web-служба существует)
  • Service.discomap - карта Web-службы, содержащая справочную информацию о том, что делает эта служба
  • Service.wsdl (Web Services Description Language - язык описания Web-служб) - XML -описание Web-службы, необходимое различным инструментам оболочки для автоматического создания классов, интерфейсов и выполнения другой работы
  • Откройте страницу Default.asp x Web-приложения WebSiteApp, переведите ее в режим редактирования Design и сформируйте интерфейс пользователя из управляющих элементов панели Toolbox согласно таблицы
  • Таблица интерфейсных элементов страницы Default.aspx
    Элемент Свойство Значение
    Label ID mess
      Text Label
    Label ID Label1
      Text Введите ФИО Юбиляра
    TextBox ID textBox1
      Text Пусто
      Width 265px
    Button ID btnSubmit
      Text Отправить
  • Добавьте в открывающий дескриптор <div> контейнера <form> атрибут style выравнивания по центру всего содержимого страницы, чтобы код декларативной части страницы стал таким
  • <%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>
        
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>Страница-клиент Web-службы приветствия</title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div style="text-align: center">
                <asp:Label ID="mess" runat="server" Text="Label"></asp:Label>
                <br />
                <asp:Label ID="Label1" runat="server" Text="Введите ФИО Юбиляра"></asp:Label>
                <br />
                <asp:TextBox ID="textBox1" runat="server" Width="265px"></asp:TextBox>
                <br />
                <asp:Button ID="btnSubmit" runat="server" Text="Отправить" />
            </div>
        </form>
    </body>
    </html>

    В соответствии с приведенным дескрипторным кодом страница Default.aspx на этапе проектирования будет иметь следующее представление

  • Двойным щелчком на кнопке btnSubmit создайте заготовку обработчика события Click и откорректируйте застраничный файл Default.aspx.cs так
  • using System;
    using System.Data;
    using System.Configuration;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
        
    public partial class _Default : System.Web.UI.Page 
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            mess.Text = string.Empty;
            mess.ForeColor = System.Drawing.Color.Red;
        }
        
        protected void btnSubmit_Click(object sender, EventArgs e)
        {
            // Создаем экземпляр класса Web-службы 
            localhost.Service webService=new localhost.Service();
        
            // Формируем сообщение, но прежде будет обращение к методу Web-службы
            if (textBox1.Text.Length != 0)
                mess.Text = "<h2>" + webService.Hello(textBox1.Text) + " !!!" + "</h2>";
            else
                mess.Text = "Заполните текстовое поле";
        }
    }
  • В панели Solution Explorer назначьте проект WebSiteApp стартовым командой Set as StartUp Project контекстного меню и запустите все решение на выполнение
  • Результат с клиентской Web-страничкой будет примерно таким

    Упражнение 2. Создание простой Web-службы калькулятора

    В данном упражнении мы создадим Web-службу и ее клиента, которые в совокупности будут имитировать работу простого калькулятора.

    Создание Web-службы калькулятора

  • Добавьте к решению новый проект Web-службы командой File/Add/New Web Site, присвоив ему имя CalcWebService
  • Откорректируйте вновь созданный файл App_Em/ Service.cs так, чтобы были реализованы 4 простых метода, как показано в листинге
  • using System;
    using System.Web;
    using System.Web.Services;
    using System.Web.Services.Protocols;
        
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class Service : System.Web.Services.WebService
    {
        // Сложить
        [WebMethod]
        public double Add(double x, double y) 
        {
            return x + y;
        }
        
        // Вычесть
        [WebMethod]
        public double Subtract(double x, double y)
        {
            return x - y;
        }
        
        // Умножить
        [WebMethod]
        public double Multiply(double x, double y)
        {
            return x * y;
        }
        
        // Разделить
        [WebMethod]
        public double Divide(double x, double y)
        {
            if (y == 0)
                throw new DivideByZeroException("Деление на ноль!");
            else
                return x / y;
        }
    }

    Создание клиента Web-службы калькулятора

    В качестве клиента Web-службы назначим форму Form2 и сформируем на ней соответствующий пользовательский интерфейс.

  • Откройте файл Form2.cs проекта WinApp в режиме View Designer и добавьте на форму компоненты пользовательского интерфейса в соответствии с таблицей, чтобы компоновка была такой
  • Таблица свойств формы Form2
    Элемент Свойство Значение
    Form Text Клиент калькулятора Web-службы
      FormBorderStyle FixedToolWindow
    Label Name lblFirst
      Text Первое число:
      TextAlign MiddleRight
    Label Name lblSecond
      Text Второе число:
      TextAlign MiddleRight
    Label Name lblResult
      Text Результат:
      TextAlign MiddleRight
    TextBox Name txtFirst
      Text пусто
    TextBox Name txtSecond
      Text пусто
    TextBox Name txtResult
      Text пусто
      ReadOnly True
      TabStop False
    Button Name btnAdd
      Text +
      Font/Bold True
      Font/Size 10
      Size 30; 30
    Button Name btnSubtract
      Text -
      Font/Name Courier New
      Font/Bold True
      Font/Size 10
      Size 30; 30
    Button Name btnMultiply
      Text *
      Font/Name Courier New
      Font/Bold True
      Font/Size 10
      Size 30; 30
    Button Name btnDivide
      Text :
      Font/Name Courier New
      Font/Bold True
      Font/Size 10
      Size 30; 30
    Button Name btnExit
      Text Выход
      AutoSize True
  • Защитите интерфейс формы Form2 от случайных изменений, выполнив команду Format/Lock Controls меню оболочки
  • Подключение Web-службы калькулятора к клиенту

  • Свяжите клиента с Web-службой, добавив к проекту WinApp необходимую инфраструктуру командой Add Web Reference и щелкнув на ссылке Web services in this solution. После этого нужно выбрать Web-службу, представленную проектом CalcWebService, и щелкнуть по соответствующей гиперссылке Service
  • После выбора сервиса CalcWebService кнопка Add Reference станет доступной и щелчок на ней заставит оболочку добавить к проекту WinApp еще одну инфраструктуру для вызова сервиса калькулятора. Созданные файлы будут помещены в папке Web References/localhost1 проекта WinApp
  • Выделите на Form2.cs[Design] одновременно все 4 кнопки операций калькулятора и создайте для них заготовку btnClick() общего обработчика события Click, которую заполните следующим кодом
  • using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
        
    namespace WinApp
    {
        public partial class Form2 : Form
        {
            public Form2()
            {
                InitializeComponent();
            }
        
            // Создаем объект Web-службы 
            WinApp.localhost1.Service calcWebService = 
                new WinApp.localhost1.Service();
        
            double numResult;
          
            private void btnClick(object sender, EventArgs e)
            {
                double numFirst, numSecond;
                // Копируем текстовые поля в локальные переменные
                string strFirst = string.Copy(txtFirst.Text);
                string strSecond = string.Copy(txtSecond.Text);
        
                // Замена в строке точки символом запятой
                // для корректного преобразования в число
                int pos = strFirst.IndexOf('.');
                if (pos != -1)
                {
                    strFirst = strFirst.Substring(0, pos)
                        + ','
                        + strFirst.Substring(pos + 1);
                }
                pos = strSecond.IndexOf('.');
                if (pos != -1)
                {
                    strSecond = strSecond.Substring(0, pos)
                        + ','
                        + strSecond.Substring(pos + 1);
                }
        
                // Преобразуем текст в число для выполнения операций
                if (txtFirst.Text.Length > 0)
                    numFirst = Convert.ToDouble(strFirst);
                else
                    numFirst = 0.0D;
                if (txtSecond.Text.Length > 0)
                    numSecond = Convert.ToDouble(strSecond);
                else
                    numSecond = 0.0D;
        
                // Выполняем нужную операцию
                Button btn = (Button)sender;// Явное приведение типов для распознавания кнопок
                switch (btn.Name)// Переключатель
                {
                    case "btnAdd":// Операция сложения
                        numResult = calcWebService.Add(numFirst, numSecond);
                        break;
                    case "btnSubtract":// Операция вычитания
                        numResult = calcWebService.Subtract(numFirst, numSecond);
                        break;
                    case "btnMultiply":// Операция умножения
                        numResult = calcWebService.Multiply(numFirst, numSecond);
                        break;
                    case "btnDivide":// Операция деления
                        // Корректность деления проверяется Web-службой 
                        numResult = calcWebService.Divide(numFirst, numSecond);
                        break;
                }
        
                // Печатаем результат
                txtResult.Text = Convert.ToString(numResult);
            }
        }
    }

    Здесь мы прежде всего скопировали значения полей ввода в промежуточные текстовые переменные, используя статический метод System.String.Copy() класса String (псевдоним string ). Затем мы проверяем наличие символа "точки" в этих переменных и при обнаружении производим замену на символ "запятая" с полным формированием новой строки. Мы не можем заменить символ "на месте" в существующей строке, обратившись к нему как элементу массива, поскольку индексная форма адресации в строках существует только для чтения.

    Но мы можем, сформировав новую строку справа от знака присваивания, присвоить результат вновь той же самой ссылке, которая фактически будет адресоваться к новой области памяти, а старая строка, как брошенный фрагмент памяти, будет оставлена для сборщика мусора. Операция замены точки на запятую выполняется для того, чтобы корректно преобразовать текстовое значение поля ввода в числовое, иначе генерируется исключение.

  • Создайте обработчик для кнопки btnExit и заполните его кодом завершения работы клиента Web-службы простого калькулятора
  • private void btnExit_Click(object sender, EventArgs e)
            {
                this.Close();
            }

    Теперь нужно защитить поля ввода от всех символов, кроме цифр, одного знака минус и одной точки. Стрелки и клавиша Del в текстовых полях функционируют, но работу клавиши Backspace нужно учесть явно.

  • Объявите в конце класса Form2 логическое поле isNumeric для отфильтровывания нецифровых символов, которые пользователь может попытаться ввести в текстовые поля
  • private bool isNumber = false;
  • Выделите текстовое поле txtFirst и через панель Properties в режиме Events создайте обработчик для события KeyDown. Заполните обработчик так
  • private bool isNumber = false;
      
        private void txtFirst_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
        {
          isNumber = 
            e.KeyCode >= Keys.D0  e.KeyCode <= Keys.D9 // keyboard - основная клавиатура
            || e.KeyCode >= Keys.NumPad0  e.KeyCode <= Keys.NumPad9 // keypad - дополнительная клавиатура
            || e.KeyCode == Keys.Back;
        }
  • Выделите текстовое поле txtFirst и через панель Properties в режиме Events создайте обработчик для события KeyPress. Заполните обработчик так
  • private void txtFirst_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
        {
          TextBox box = (TextBox) sender;// Явное преобразование типов
      
          switch(e.KeyChar) // Переключатель
          {
            case '-': // Разрешаем минус, если он первый
              if(box.Text.Length == 0)
                isNumber = true;
              break;
            case '.':  
              // Точка не должна быть первой
              if(box.Text.Length == 0)
                break;
              // Точка не должна следовать сразу за минусом
              if(box.Text[0] == '-'  box.Text.Length == 1)
                break;
              // Точка должна быть одна
              if(box.Text.IndexOf('.') == -1)
                isNumber = true; // Еще не было точек
              break;
          }
      
          // Запрещаем в текстовом поле лишние символы
          if(!isNumber)
            e.Handled = true;
        }
  • Выделите текстовое поле txtSecond и через панель Properties в режиме Events подключите к событиям KeyDown и KeyPress соответствующие обработчики, только что созданные для поля txtFirst. Обработчики подключите через раскрывающиеся списки полей значений
  • Здесь мы одни и те же обработчики используем для разных полей, поскольку необходимо выполнять одинаковые действия. Задача одна - не допускать для ввода в поля никакие другие символы, кроме цифр, одного минуса и одной точки. Возможность ввода цифр реализована для основной ( keyboard ) и дополнительной ( keypad ) частей клавиатуры. Параметр sender передает в обработчик ссылку на активное текстовое поле, вызвавшее событие редактирования.

  • Назначьте стартовым проект WinApp, запустите его и проверьте функциональность простого калькулятора в Упражнении 2, фактически реализованного в Web-службе
  • Вернуться к учебному плану