Симон Робинсон - C# для профессионалов. Том II
<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()" />