Прежде чем завершить предварительное знакомство с протоколом SOAP и языком WSDL, мы более пристально рассмотрим взаимосвязь между протоколом SOAP, языком WSDL и спецификацией XML Schema. Как упоминалось раньше, способ кодирования данных, которые передаются по протоколу SOAP между удаленными приложениями, построенными на основе технологии .NET, отличается от способа кодирования данных, который используется Web-службами и параллельно-последовательным преобразователем (serializer) языка XML.
Чтобы проиллюстрировать отличия между этими двумя способами кодирования данных, передающихся по протоколу SOAP, мы рассмотрим две программы, которые преобразуют один и тот же объект в последовательную форму. Обе программы создают кольцевой, или циклический список, состоящий из двух элементов типа customer (клиент). Первая программа кодирует данные, используя параллельно-последовательный преобразователь (serializer) SOAP платформы .NET. Вторая программа кодирует данные, передающиеся по протоколу SOAP, так, как это делают Web-службы. Программы расположены в каталоге SOAP Differences в подкаталогах Formatter (Форматер) и WebServ-ice соответственно.
Первая программа, Formatter (Форматер), сначала создает циклический список, а затем с помощью SOAP-форматера среды .NET, преобразует его в последовательную форму и сохраняет на диске в файле cust.xml. Чтобы продемонстрировать именно SOAP-сериализацию (и ее отличие от методики, применяемой Web-службами), мы создадим класс Test (Тест), производный от класса WebService. Ниже приведено содержимое файла Formatter.h. Обратите внимание, что класс Customer (Клиент) имеет атрибут Serializ-able (Преобразуемый в последовательную форму).
[Serializable]
// [Преобразуемый в последовательную форму]
public _gc class Customer
// класс сборщика мусора Клиент
{
public:
String *name; // Строка
long id; // идентификатор
Customer *next; // Клиент
};
public _gc class Test : public WebService
// класс сборщика мусора Испытание: WebService
{
public:
static void Main()
{
Test *test = new Test; // Испытание
Customer *list = test->GetList();
FileStream *s =
new FileStream("cust.xml", FileMode::Create);
// Создать файл
SoapFormatter *f = new SoapFormatter;
f->Serialize (s, list);
// Преобразовать в последовательную форму (s, список);
s->Close ();
}
Customer *GetList() // Клиент
{
Customer *custl = new Customer;
// Клиент *custl = новый Клиент;
cust1->name = "John Smith"; // Джон Смит
cust1->id = 1; // идентификатор = 1
Customer *cust2 = new Customer;
// Клиент *cust2 = новый Клиент;
cust2->name = "Mary Smith"; // Мэри Смит
cust2->id =2; // идентификатор = 2
cust2->next = custl; // следующий
custl->next = cust2; // следующий
return custl;
}
};
Данная программа генерирует файл [В приведенном ниже файле для удобства ориентирования вставлены комментарии вида <! — комментарий -->, в самом файле, их, естественно, не будет. — Прим. ред.] cust.xml, который содержит кодированные данные, передающиеся по протоколу SOAP. Обратите внимание, что для идентификации объектов и полей используется атрибут id (идентификатор). Атрибут href используется в качестве объектной ссылки.
<SOAP-ENV:Body>
<al:Customer id="ref-1">
<name id="ref-3">John Smith</name> <!-- Джон Смит -->
<id>1</id> <!— идентификатор —>
<next href="#ref-4"/>
</a1:Customer>
<a1:Customer id="ref-4">
<name id="ref-5">Mary Smith</name> <!-- Мэри Смит -->
<id>2</id> <!-- идентификатор -->
<next href="#ref-1"/>
</a1:Customer>
</SOAP-ENV:Body>
Вторая программа WebService, как можно догадаться из ее названия, является Web-службой. Ниже приведено содержимое файла CustomerList. asmx.
<%@ WebService class="Test" %>
Исходный файл WebService.h содержит следующий код. Обратите внимание, что на этот раз класс Customer (Клиент) не имеет атрибута Serializable (Преобразуемый в последовательную форму).
public _gc class Customer
// класс сборщика мусора Клиент
{
public:
String *name; // Строка
long id; // идентификатор
Customer *next; // Клиент
};
public _gc class Test : public WebService
// класс сборщика мусора Испытание: WebService
{
public:
[WebMethod]
Customer *GetList() // Клиент
{
Customer *custl = new Customer;
// Клиент *custl = новый Клиент;
custl->name = "John Smith"; // Джон Смит
custl->id = 1; // идентификатор = 1
Customer *cust2 = new Customer;
// Клиент *cust2 = новый Клиент;
cust2->name = "Mary Smith"; // Мэри Смит
cust2->id =2; // идентификатор = 2
cust2->next = custl; // следующий
cust1->next = cust2; // следующий
return cust1;
}
};
Чтобы запустить данную профамму, создайте на основе каталога SOAP Differ-ences\WebService виртуальный каталог SOAPWebServiceTest. Затем укажите в адресной строке Internet Explorer следующий унифицированный указатель информационного ресурса (URL) http://localhost/SOAPWebServiceTest/CustomerList.asmx?op=GetList. Internet Explorer распознает, что файл, определяемый этим указателем информационного ресурса (URL), реализует Web-службу. Вид окна Internet Explorer приведен на Рисунок 11.3.
Если вы попытаетесь активизировать Web-службу прямо сейчас, то будет выдано следующее сообщение об ошибке:
System.Exception: There was an error generating the XML
document. ---> System.Exception: A circular reference
Пере вод такой [Добавлен редактором русского перевода. — Прим. ред.]:
Система.Исключение: Была ошибка при генерации XML-
документа.---> Система.Исключение: циклическая ссылка
была обнаружена при преобразовании в последовательную
форму объекта типа
Клиент.
в Системе.Xml.Преобразование в последовательную
форму XmlSerializationWriter.
WriteStartElement (Строковое имя, Строка ns, Объект о,
Булева переменная wrxtePrefixed)
...
в Системе.Xml.Преобразование в последовательную
форму.XmlSerializer.Преобразовать в последовательную форму
(XmlWriter xmlWriter, Объект о,
XmlSerializerNamespaces пространство имен)
...