• SOAP
  • WSDL
  • Службы Web
  • Создание служб Web
  • Типы данных, доступные для служб Web
  • Использование служб Web
  • Расширение примера заказа помещения для проведения мероприятий
  • Служба Web заказа помещения для проведения мероприятий
  • Клиент приложения предварительного заказа помещения для проведения мероприятия
  • Заключение
  • Глава 17

    Службы Web

    Службы Web — это новый способ выполнения удаленного вызова методов посредством HTTP с помощью SOAP (Simple Object Access Protocol — простой протокол доступа к объектам). Раньше это было связано с трудностями, что может засвидетельствовать каждый, кто имеет опыт работы с DCOM (Distributed COM — распределенный COM). Создание экземпляра объекта на удаленном сервере, вызов метода и получение результата были далеко не простыми, а необходимая конфигурация была еще более сложной.

    SOAP существенно упрощает ситуацию. Эта технология является стандартом на основе XML который определяет, как можно делать вызовы методов через HTTP воспроизводимым образом. Удалённый сервер SOAP способен понимать эти вызовы и выполнять всю трудную работу, такую как создание экземпляра требуемого объекта, выполнение вызова и возврат клиенту ответа, форматированного SOAP.

    Как и в случае ASP.NET мы обладаем всеми возможностями технологий C# и .NET на сервере, но более важно, что простое использование служб Web можно получить на любой платформе, имеющей к серверу доступ HTTP. Другими словами, вполне возможно что код Linux мог бы, например, использовать службы .NET.

    Кроме того, службы Web можно полностью описать с помощью WSDL (Web Service Description Language — язык описания служб Web), допуская динамический поиск cлужб Web во время выполнения приложения. WSDL предоставляет с помощью XML со схемами XML описания всех методов (вместе с типами данных, требуемыми для их вызова). Существует широкое множество типов данных, доступных для служб Web, которые простираются от простых примитивных до полноценных объектов

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

    Эту главу мы начнем с синтаксиса SOAP и WSDL, а затем перейдем к их использованию службами Web. Мы обсудим, как предоставлять и использовать службы Web, и разберем полный пример, построенный на основе приложения заказа помещения для проведения мероприятий из предыдущей главы.

    SOAP

    Как упоминалось выше, одним из способов обмена данными со службами Web является SOAP. Эта технология широко обсуждалась в прессе, особенно с тех пор, как компания Microsoft решила принять ее для использования на платформе .NET. Теперь волнение, кажется, слегка успокоилось, так как спецификация SOAP была завершена. Если подумать, то знание того, как точно работает SOAP, похоже на знание того, как работает HTTP, в принципе это интересно, но не существенно. Большую часть времени нам нет необходимости беспокоиться о формате сделанного со службами Web обмена, он просто происходит, а мы получаем требуемый результат, и все довольны. 

    По этой причине здесь не будет представлено подробное рассмотрение, но будет показано несколько простых запросов и ответов SOAP, чтобы можно было получить некоторое представление о том, что происходит за сценой. 

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

    int DoSomething(String stringParam, int intParam)

    Далее представлены требуемые для этого заголовки SOAP и body. Вверху указан адрес службы Web (об этом больше будет сказано далее):

    POST /SomeLocation/myWebService.asmx HTTP/1.1

    Host: karlivaio

    Content-Type: text/xml; charset=utf-8

    Content-Length: length

    SOAPAction: "http://tempuri.org/DoSomething"


    <?xml version="1.0"?>

    <soap:Envelope xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance"

     xmlns:xsd="http://www.w3.org/2000/10/XMLSchema"

     xmlns:soap="http://schemas.xmlsoap.org/soap/envelope">

     <soap:Body>

      <DoSomething xmlns="http://tempuri.org/">

       <stringParam>string</stringParam>

       <intParam>int</intParam>

      </DoSomething>

     </soap:Body>

    </soap:Envelope>

    Параметр

    length
    определяет здесь общую длину содержимого в байтах и будет меняться в зависимости от значений, посланных в параметрах
    string
    и
    int
    .

    Используемое пространство имен soap определяет различные элементы, которые применяются для создания сообщения. При отправке этого кода через HTTP реальные посылаемые данные будут несколько другими. Например, можно было бы вызвать приведенный выше метод с помощью простого метода GET:

    GET /PCSWebSrv1/Service1.asmx/AddEvent?stringParam=string&intParam= int HTTP/1.1 Host.: hostname

    Ответ SOAP этого метода будет следующим:

    HTTP/1.1 200 OK

    Content-Type: text/xml; charset=utf-8

    Content-Length: length


    <?xml version="1.0" ?>

    <soap:Envelope xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance"

     xmlns:xsd="http://www.w3.org/2000/10/XMLSchema"

     xmlns:soap="http://schemas.xmlsoap.org/soap/envelope">

     <soap:Body>

      <DoSomethingResponse xmlns="http://tempuri.org/">

       <DoSomethingResult>int</DoSomethingResult>

      </DoSomethingResponse>

     </soap:Body>

    </soap:Envelope>

    где

    length
    снова изменяется согласно содержимому, в этом случае
    int
    .

    И снова реальный ответ через HTTP может быть значительно проще, например:

    HTTP/1.1 200 OK

    Content-Type: text/xml; charset=utf-8

    Content-Length: length


    <?xml version="1.0"?>

    <int xmlns="http://tempuri.org/">int</int>

    Это совсем простой формат XML.

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

    WSDL

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

    WSDL имеет синтаксис, полностью соответствующий XML, и определяет службы Web по доступным методам, типам данных, используемых этими методами, форматам сообщений запросов и ответов, посылаемых методам и из методов с помощью различных протоколов (чистый SOAP, HTTP GET и т.д.), и различным связываниям между упомянутыми выше элементами.

    Возможно, что наиболее важной частью файла WSDL является раздел определения типов данных. Он использует схемы XML для описания формата обмена данными и их отношениями с помощью элементов XML.

    Например, метод службы Web, использованной в качестве примера в последнем разделе:

    int DoSomething(string stringParam, int intParam)

    будет иметь типы, объявленные для запроса следующим образом:

    <?xml version="1.0" ?>

    <definitions xmlns:s="http://www.w3.org/2000/10/XMLSchema"

     xmlns="http://schemas.xmlsoap.org/wsdl/"

     ... другие пространства имен ... >

     <types>

      <s:schema attributeFormDefault="qualified" elementFormDefault="qualified"

       targetNamespace="http://tempuri.org/">

       <s:import namespace="http://www.w3.org/2000/10/XMLSchema" />

       <s:element name="DoSomething" >

        <s:complexType>

         <s:sequence>

          <s:element name="stringParam" nullable="true" type="s:string" />

          <s:element name="intParam" nullable="true" type="s:int" />

         </s:sequence>

        </s:complexType>

       </s:element>

       <s:element name="DoSomethingResponse">

        <s:complexType>

         <s:sequence>

          <s:element name="DoSomethingResult" type="s:int" />

         </s:sequence>

        </s:complexType>

       </s:element>

       <s:element name="int" type="s:int" />

      </s:schema>

     </types>

     ... другие определения ...

    </definitions>

    Все, что требуется для запросов и ответов SOAP и HTTP, которые мы видели ранее, определяется этими типами, которые далее в этом файле связываются с такими операциями. Все типы определяются с помощью стандартного синтаксиса схемы XML, например:

    <s:element name="DoSomethingResponse">

     <s:complexType>

      <s:sequence>

       <s:element name="DoSomethingResult" type="s:int" />

      </s:sequence>

     </s:complexType>

    </s:element>

    Этот код определяет, что элемент с именем

    <DoSomethingResponse>
    имеет элемент-потомок с именем
    <DoSomethingResult>
    , который содержит целое число.

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

    Теперь, когда мы кратко ознакомились с SOAP и WSDL, пришло время посмотреть, как создаются и используются службы Web.

    Службы Web

    Обсуждение служб Web включает два вопроса:

    □ Создание служб Web, которое связано с написанием служб Web и размещением их на серверах Web.

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

    Создание служб Web

    Службы Web создают, либо помещая код прямо в файлы

    .asmx
    , либо, ссылаясь на классы службы Web из этих файлов. Как и со страницами ASP.NET, создание службы Web в VS.NET применяет последний подход, и он также будет использоваться для целей демонстрации.

    Создание проекта службы Web, называемой

    PCSWebSrv1
    , как показано выше, приводит, как и для проекта приложения Web, к аналогичному множеству созданных файлов. Фактически, единственное различие состоит в том, что вместо создания файла с именем
    WebForm1.aspx
    создается файл с именем
    Service1.asmx
    . Созданный файл
    .vsdisco
    отвечает за идентификацию службы Web, чтобы система Visual Studio .NET, как мы вскоре увидим, могла добавить на него ссылку Web.

    Код в

    Service1.asmx
    не доступен непосредственно через VS.NET, но просмотр с помощью Notepad показывает следующую строку кода:

    <%@ WebService Language="c#" Codebehind="Service1.asmx.cs" Class="PCSWebSrv1.Service1" %>

    Этот код ссылается на файл кода, который можно увидеть в VS.NET, —

    Service1.asmx.cs
    , доступный при щелчке правой кнопкой мыши на
    Service1.asmx
    в Solution Explorer и выборе View Code. Созданный код с удаленными для краткости комментариями показан ниже:

    namespace PCSWebSrv1 {

     using system;

     using System.Collections;

     using System.ComponentModel;

     using System.Data;

     using System.Diagnostics;

     using System.Web;

     using System.Web.Services;


     public class Service1 : System.Web.Services.WebService {

      public Service1() {

       InitializeComponent();

      }


      private void InitializeComponent() {

      }


      public override void Dispose() {

      }

     }

    }

    Этот код определяет пространство имен

    PCSWebSrv1
    с несколькими ссылками на стандартные пространства имен и класс службы Web с именем
    Service1
    (ссылку на который мы видели выше в файле
    Service1.asmx
    ), производный от
    System.Web.Services.WebService
    . Мы должны предоставить методы для этого класса службы Web.

    Добавление метода, доступного через службу Web, требует простого определения метода как

    public
    и задание для него атрибута
    WebMethod
    . Этот атрибут помечает методы, которые мы хотим сделать доступными. Вскоре мы рассмотрим типы данных, которые можно использовать для возвращаемого типа и для параметров, но пока добавим следующий метод:

    [WebMethod]

    public String CanWeFixIt() {

     return "Yes we can!";

    }

    и откомпилируем метод.

    Можно проверить, как это будет работать, направляя браузер Web на файл

    Service1.asmx
    :

    Щелчок на имени метода предоставляет нам информацию о запросе и ответе SOAP, а также примеры того, как запрос и ответ будут выглядеть с помощью методов HTTP GET и HTTP POST. Можно также протестировать метод, нажимая на предоставленную кнопку Invoke (если метод требует простых параметров, их также можно ввести в этой форме). Если сделать это, мы увидим код XML, возвращаемый вызовом метода:

    <?xml version="1.0" ?>

    <string xmlns="http://tempuri.org/">Yes we can!</string>

    Это показывает, что метод работает прекрасно.

    Следование по ссылке Service Description, показанной на экране браузера выше, позволяет увидеть описание WSDL службы Web. Наиболее важной частью, имеющей к нам отношение, является описание типов элементов для запросов и ответов:

    <types>

     <s:schema attributeFormDefault="qualified" elementFormPefault="qualified"

      targetNamespace="http://tempuri.org/">

      <s:element name="CanWeFixIt">

       <s:complexType />

      </s:element>

      <s:element name="CanWeFixItResponse">

       <s:complexType>

        <s:sequence>

         <s:element name="CanWeFixItResult" nullable="true" type="s:string" />

        </s:sequence>

       </s:complexType>

      </s:element>

      <s:element name="string" nullable="true" type="s:string" />

     </s:schema>

    </types>

    Это описание содержит также описание типов данных, требуемых для запросов и ответов, а также различных соединений для службы, делая его достаточно длинным файлом.

    Типы данных, доступные для служб Web

    Службы Web могут использоваться для обмена любыми из следующих типов данных:

    String           Char    Byte

    Boolean          Int16   Int32

    Int64            UInt16  UInt32

    UInt64           Single  Double

    Guid             Decimal DateTime

    XmlQualifiedName class   struct

    XmlNode          DataSet

    Массивы всех приведенных выше типов данных также допустимы. Отметим, также, что маршализуются только открытые свойства и поля типов

    class
    и
    struct
    .

    Использование служб Web

    Теперь, когда мы знаем, как создавать службы Web, пришло время разобраться, как они используются. Чтобы сделать это, необходимо создать в коде класс прокси, который знает, как общаться с заданной службой Web. Любые обращения из кода к службе Web будут проходить через этот прокси, который выглядит идентично службе Web, создавая в коде иллюзию, что имеется локальная копия службы Web. В реальности существует большой объект коммуникации HTTP, но мы защищены от деталей. Для этого существуют два способа. Можно пользоваться либо утилитой командной строки

    WSDL.exe
    , либо пунктом меню Add Web Reference в VS.NET.

    При использовании утилиты

    WSDL.exe
    создается файл
    .cs
    , содержащий класс прокси на основе описания WSDL службы Web. Мы определяем это с помощью URL, например:

    WSDL http://localhost/PCSWebSrv1/Service1.asmx?WSDL

    Для примера из последнего раздела эта утилита создаст файл с именем

    Service1.cs
    класса прокси. Класс называется по имени cлужбы Web, в данном случае
    Service1
    , и будет содержать методы, которые вызывают идентично названные методы службы. Чтобы использовать этот класс, мы просто добавляем файл
    .cs
    , созданный для проекта, и используем следующий код:

    Service1 myService = new Service1();

    String result = myService.CanWeFixIt();

    По умолчанию созданный класс будет помещен в корневое пространство имен, поэтому не нужен никакой оператор

    using
    , но можно определить для использования другое пространство имен с помощью параметра командной строки /n<namespace> утилиты WSDL.exe.

    Эта техника хорошо работает, но может оказаться неудобным непрерывно переделывать код, если служба разрабатывается и постоянно изменяется. Конечно, можно было бы делать это в режиме сборки проекта, чтобы автоматически обновлять созданный прокси перед каждой компиляцией, но существует способ лучше.

    Мы проиллюстрируем его в новом приложении Web с именем

    PCSWebClient1
    , создавая клиента для примера из последнего раздела. В теле формы на созданной странице
    .aspx
    необходимо заменить существующее объявление form на следующий код:

    <form method="post" runat="server">

     <asp:Label Runat="server" ID="resultLabel" />

     <br>

     <asp:Button Runat="server" ID="triggerButton" Text="Invoke CanWeFixIt()" />

    </form>

    Соединим обработчик события нажатия кнопки со службой Web. Для начала добавим в проект ссылку на службу Web. Чтобы сделать это, щелкнем правой кнопкой мыши на приложении в Solution Explorer и выберем пункт Add Web Reference… В появившемся окне введем URL файла

    .vsdisco
    службы Web:

    Здесь можно следовать по ссылкам справа, чтобы получить те же самые описания с границы Web службы, которые мы видели в предыдущем разделе, и добавить ссылку с помощью кнопки Add Reference Нажатие на эту кнопку приведет к следующим изменениям в Solution Explorer:

    Папка, содержащая нашу ссылку Web, называется по имени сервера, где расположена служба, в данном случае —

    localhost
    . Это также пространство имен, на которое необходимо ссылаться, чтобы использовать класс прокси, поэтому имеет смысл переименовать папку, что можно сделать с помощью щелчка правой кнопкой мыши на папке. Если переименовать эту папку в
    myWebService
    и добавить инструкцию
    using
    в код…

    using PCSWebClient1.myWebService;

    …то тогда можно будет использовать службу в нашем классе.

    Добавим обработчик событий к кнопке на форме с помощью следующего кода:

    protected void triggerButton_Сlick(object sender, System.EventArgs e) {

     Service1 myService = new Service1();

     resultLabel.Text = myService.CanWeFixIt();

    }

    Нажатие кнопки во время выполнения приложения приведет к выводу

    CanWeFixIt()
    в окне браузера.

    Служба Web может впоследствии измениться, но с помощью такого метода можно просто сделать щелчок правой кнопкой мыши на ссылке Web в проводнике сервера и выбрать Update Web Reference. Это создаст для нас новый класс прокси.

    Расширение примера заказа помещения для проведения мероприятий

    Теперь, когда мы знакомы с основами создания и использования служб Web, давайте применим наши знания, расширив приложение заказа помещения для проведения мероприятий из предыдущей главы. В частности, извлечем детали доступа к базе данных из приложения и поместим их в службу Web. Эта служба Web имеет два метода:

    □ 

    GetData()
    , который будет возвращать объект
    DataSet
    , содержащий все три таблицы базы данных
    PCSWebApp3
    .

    □ 

    AddEvent()
    , добавляющий событие и возвращающий обновленную версию
    DataSet
    , которая включает изменение

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

    DataSet
    на уровне приложения в приложении службы Web. Это означает, что несколько запросов данных не потребуют работы дополнительных запросов к базе данных. Данные в этом
    DataSet
    уровня приложения обновятся, когда в базу данных добавятся новые данные. Это означает, что изменения, сделанные в базе данных другими средствами, такими как редактирование вручную, не будут отражаться в этом
    DataSet
    . Тем не менее, до тех пор, пока мы знаем, что наша служба Web является единственным местом с прямым доступом к данным, нам не о чем беспокоиться.

    Служба Web заказа помещения для проведения мероприятий

    Создайте новый проект службы Web в VS.NET с именем

    PCSWebSrv2
    . Для начала добавим код в обработчик
    Application_Start()
    в
    global.asax
    . Мы хотим загрузить все данные из
    PCSWebApp3.mdb
    в множество данных и сохранить его. Это будет по большей части включать код, с которым мы знакомы, так как перенос базы данных в
    DataSet
    уже делали. Фактически, можно скопировать весь нужный код из
    WebForm1.aspx.cs
    в
    PCSWebApp3
    из предыдущей главы, включая строку соединения с базой данных (которая здесь не показана, так как у читателя она должна быть, скорее всего, другой):

    protected void Application_Start (Object sender, EventArgs e) {

     System.Data.DataSet ds;

     System.Data.OleDb.OleDbConnection оleDbConnection1;

     System.Data.OleDb.OleDbDataAdapter daAttendees;

     System.Data.OleDb.OleDbDataAdapter daRooms;

     System.Data.OleDb.OleDbDacaAdapter daEvents;

     oleDbConnection1 = new System.Data.OleDb.OleDbConnection();

     oleDbConnection1.ConnectionStnng = @" ... ";

     oleDbConnection1.Open(); ds = new DataSet();

     daAttendees =

      new System.Data.OleDb.OleDbDataAdapter(

      "SELECT * FROM Attendees", oleDbConnection1);

     daRooms =

      new System.Data.OleDb.OleDbDataAdapter(

      "SELECT * FROM Rooms", oleDbConnection1);

     daEvents =

      new System.Data.OleDb.OleDbDataAdapter(

      "SELECT * FROM Events", oleDbConnection1);

     daAttendees.Fill(ds, "Attendees");

     daRooms.Fill(ds, "Rooms");

     daEvents.Fill(ds, "Events");

     oleDbConnection1.Close();

     Application["ds"] = ds;

    }

    Необходимо отметить важный код в последней строке. Объекты

    Application
    Session
    ) имеют коллекцию пар имя/значение, которую можно использовать для хранения данных. Здесь создается имя
    ds
    в хранилище объекта
    Application
    , которое получает сериализованное значение
    DataSet
    из
    ds
    , содержащее таблицы
    Attendees
    ,
    Rooms
    и
    Events
    из базы данных. Это значение будет доступно всем экземплярам службы Web в любое время.

    Чтобы приведенный выше код работал, нам нужно также добавить ссылку на пространство имен

    System.Data
    в пространстве имен
    PCSWebSrv2
    в
    global.asax
    :

    namespace PCSWebSrv2 {

     ...

     using System.Data;

    Эта техника очень полезна для данных, предназначенных только для чтения, так как несколько потоков выполнения смогут к нему обращаться, сокращая нагрузку на базу данных. Отметим, однако, что таблица

    Events
    скорее всего должна измениться и будет обновлять
    DataSet
    на уровне приложения, когда это произойдет. Мы скоро это увидим.

    Затем необходимо добавить к службе в

    Service1.asmx.cs
    метод
    GetData()
    :

    [WebMethod]

    public DataSet GetData() {

     return (DataSet)Application["ds"];

    }

    Здесь для доступа к множеству данных используется тот же синтаксис, что и в

    Application_Load()
    , где просто выполняется преобразование типа данных в правильный тип, а также возврат.

    Метод

    AddEvent()
    немного сложнее. Концептуально нам необходимо сделать следующее:

    □ Получить данные события от клиента.

    □ Создать инструкцию SQL

    INSERT
    с помощью этих данных.

    □ Соединиться с базой данных и выполнить инструкцию SQL.

    □ Если добавление выполнится успешно, то обновить данные в

    Application["ds"]
    .

    □ Вернуть уведомление об успехе или отказе клиенту (мы оставляем клиенту возможность обновить его

    DataSet
    , если потребуется).

    Начиная сверху, принимаем все поля как строки:

    [WebMethod]

    public int AddEvent(String eventName, String eventRoom, String eventAttendees, String eventDate) {

    }

    Затем мы объявляем объекты, которые нужны для доступа к базе данных, соединяемся с базой данных и выполняем запрос, используя код аналогичный коду в

    PCSWebApp3
    (здесь также требуется строка соединения, которая здесь не показана):

    [WebMethod]

    public int AddEvent(String eventName, String eventRoom, String eventAttendees, String eventDate) {

     System.Data.OleDb.OleDbConnection oleDbConnection1;

     System.Data.OleDb.OleDbDataAdapter dbEvents;

     DataSet ds;

     oleDbConnection1 = new System.Data.OleDb.OleDbConnection();

     OleDbConnection1.ConnectionString = @" ... ";

     String oleDbCommand =

      "INSERT INTO Events (Name, Room, AttendeeList, " +

      " EventDate) VALUES ('" + eventName + "', +

      eventRoom + "', '" + eventAttendees + "', '" + eventDate + "')";

     System.Data.OleDb.OleDbCommand insertCommand =

      new System.Data.OleDb.OleDbCommand(oleDbCommand, oleDbConnection1);

     oleDbConnection1.Open();

     queryResult = insertCommand.ExecuteNonQuery();

    }

    Используем, как и прежде,

    queryResult
    для хранения числа строк, затронутых запросом. Мы можем проверить его, чтобы оценить наш успех. Если все происходит хорошо, выполняется новый запрос на базе данных для обновления таблицы
    Events
    в нашем
    DataSet
    . Жизненно важно блокировать данные приложения во время выполнения обновлений, чтобы гарантировать, что никакие другие потоки выполнения не могут получить доступ к
    Application["ds"]
    во время его обновления. Это можно сделать с помощью методов
    Lock()
    и
    UnLock()
    объекта
    Application
    :

    [WebMethod]

    public int AddEvent(String eventName, String eventRoom, String eventAttendees, String eventDate) {

     ...

     int queryResult = insertCommand.ExecuteNonQuery();

     if (queryResult == 1) {

      daEvents =

       new System.Data.OleDb.OleDbDataAdapter(

       "SELECT * FROM Events", oleDbConnection1);

      Application.Lock();

      ds = (DataSet) Application["ds"];

      ds.Tables["Events"].Clear();

      daEvents.Fill(ds, "Events");

      Application["ds"] = ds;

      Application.UnLock();

      oleDbConnection1.Close();

     }

    }

    Наконец, мы возвращаем

    queryResult
    , позволяя клиенту узнать, что запрос был успешным:

    [WebMethod]

    public int AddEvent(String eventName, String eventRoom, String eventAttendees, String eventDate) {

     ...

     return queryResult;

    }

    Это завершает создание службы Web. Как и прежде, есть возможность протестировать эту службу, направляя браузер Web на файл

    .asmx
    , поэтому мы можем добавить записи и взглянуть на представление XML для
    DataSet
    , возвращаемое
    GetData()
    , не создавая никакого клиентского кода.

    Клиент приложения предварительного заказа помещения для проведения мероприятия

    Используемый клиент является разработкой приложения Web

    PCSWebApp3
    из предыдущей главы. Назовем это приложение
    PCSWebApp4
    и воспользуемся кодом из
    PCSWebApp3
    в качестве начальной точки.

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

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

    Прежде всего в нашем новом приложении Web необходимо добавить ссылку Web на службу

    PCSWebSrv2/Service1.asmx
    . Это можно сделать точно таким же образом, как мы видели ранее в этой главе, определяя местонахождение файла
    .vsdisco
    и вызывая его
    eventDataService
    .

    После этого добавляем код в

    Global.asax
    , по большей части, таким же образом, как это было сделано для службы Web. Этот код, однако, будет существенно проще. Сначала мы ссылаемся на службу Web и пространство имен
    System.Data
    :

    namespace PCSWebApp4 {

     ...

     using System.Data;

     using eventDataService;

    Затем заполняем множество данных (

    dataset
    ) и помещаем его в хранилище данных уровня приложения с именем
    ds
    :

    protected void Application_Start(Object sender, EventArgs e) {

     Service1 dataService = new Service1();

     DataSet ds = dataService.GetData();

     Application["ds"] = ds;

    }

    Теперь

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

    Теперь, когда имеется это

    DataSet
    , необходимо изменить
    WebForm1.aspx.cs
    для его использования. Прежде всего можно удалить объявления
    oleDbConnection1
    ,
    daAttendees
    ,
    daRooms
    и
    daEvents
    , так как не будет осуществляться никакого обращения к базе данных. Затем необходимо изменить
    Page_Load()
    следующим образом:

    private void Page_Load(object sender, System.EventArgs e) {

     validationSummary.Enabled = false;

     foreach (System.Web.UI.WebControls.WebControl validator in this.Validators) {

      validator.Enabled = false;

     }

     ds = (DataSet)Application["ds"];

     attendeeList.DataSource = ds.Tables["Attendees"];

     roomList.DataSource = ds.Tables["Rooms"];

     eventTable = ds.Tables["Events"];

     eventDetails1.DataSource = eventTable; eventDetails2.DataSource = eventTable;

     if (!this.IsPostBack) {

      System.DateTime trialDate = System.DateTime.Now;

      calendar.SelectedDate = getFreeDate(trialDate);

      this.DataBind();

     } else {

      eventDetails1.DataBind();

      eventDetails2.DataBind();

     }

    }

    Большая часть кода остается без изменений, необходимо только использовать

    Application["ds"]
    вместо получения
    DataSet
    .

    Необходимо также изменить

    submitButton_Click()
    для использования метода
    AddData()
    службы Web. В этом случае также большая часть кода остается без изменений:

    protected void submitButton_Click(object sender, System.EventArgs e) {

     foreach (System.Web.UI.WebControls.WebControl validator in this.Validators) {

      validator.Enabled = true;

     }

     this.Validate();

     if (this.IsValid) {

      String attendees = "";

      foreach (ListItem attendee in attendeeList.Items) {

       if (attendee.Selected) {

        attendees += attendee.Text + " (" + attendee.Value + "), ";

       }

      }

      attendees += " and " + nameBox.Text;

      String dateString = calendar.SelectedDate.Date.Date.ToShortDateString();

      Service1 dataService = new Service1();

      int queryResult =

       dataService.AddEvent(eventBox.Text, roomList.SelectedItem.Value,

       attendees, dateString);

      if (queryResult == 1) {

       resultLabel.Text = "Event Added";

       ds = dataService.GetData();

       Application.Lock();

       Application["ds"] = da;

       eventTable = ds.Tables["Events"];

       calendar.SelectedDate = getFreeDate(calendar.SelectedDate.AddDays(1));

       eventDetails1.DataSource = eventTable;

       eventDetails1.DataBind();

       eventDetails2.DataSource = eventTable;

       eventDetails2.DataBind();

      } else {

       resultLabel.Text = "Event not added due to DB access problem.";

      }

     } else {

      validationSummary.Enabled = true;

     }

    }

    Фактически, мы существенно упростили систему. Это часто бывает при правильном проектировании служб Web — можно забыть о большей части работы приложения и вместо этого сосредоточиться на работе пользователя.

    К этому коду почти не требуется комментариев. Продолжающееся использование

    queryResult
    является дополнительной премией, а блокирование приложения существенно, как уже было отмечено.

    Приложение Web

    PCSWebApp4
    выглядит и функционирует точно также, как
    PCSWebApp3
    , но выполняется существенно лучше. Можно также очень легко использовать эту же службу Web для других приложений, просто выводя на странице мероприятия, например, или редактируя мероприятия, имена почетных гостей и помещения, если добавить несколько других методов. Все это не разрушит
    PCSWebApp4
    , так как мы будем просто игнорировать все вновь созданные методы.

    Заключение

    В этой главе мы увидели, как создавать и использовать службы Web с помощью C# и платформы разработки VS.NET. Сделать это достаточно просто, но какая это невероятно полезная возможность. Уже сейчас мы видим множество объявлений о новых службах Web и можно ожидать, что скоро они будут повсюду.

    Также было отмечено, что службы Web могут быть доступны с любой платформы. Это связано с простотой протокола SOAP, который не ограничивается платформой .NET.

    Пример, разработанный в этой главе, иллюстрирует, как можно легко создавать распределенные приложения .NET. Здесь предполагается, что для тестирования используется один сервер, но почему бы службу Web полностью не отделить от клиента. Она может даже находиться на отдельном от базы данных сервере, если требуется дополнительная связь данных.

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

    Наконец, стоит помнить, что потребителями службы Web не обязательно должны быть приложения Web. Нет причин, по которым нельзя использовать службы Web из приложений платформы Windows, что может оказаться привлекательным для корпоративных сетей интранет. 







     

    Главная | В избранное | Наш E-MAIL | Добавить материал | Нашёл ошибку | Наверх