Разработка распределенных приложений в Microsoft.NET Framework

         

Язык XML и схемы XML


Язык XML (Extensible Markup Language) в настоящее время нашел множество разнообразных применений и является основой для большого числа общепринятых спецификаций. На рис. 3.2 представлены основные используемые в распределенных системах спецификации, основанные на языке XML – XSD, SOAP, WSDL, – которые будут рассмотрены далее.


Рис. 3.2.  XML и основанные на нем спецификации

Язык XML представляет собой язык разметки текстового документа, представленного совокупностью именованных, древовидно вложенных элементов. Каждый элемент может иметь некоторое текстовое значение и набор атрибутов, имеющих имя и простое значение (строку). Язык XML является абстрактным языком разметки, не определяющим как либо смысл элементов документа. Документы XML достаточно хорошо читаются как человеком, так и многочисленными программными анализаторами. При естественном подходе к именам элементов и атрибутов он является самодокументирующимся языком. Перед древовидной структурой элементов, имеющих единственный корень, могут идти отдельные элементы с метаинформацией, указывающий в частности кодировку документа и версию языка, как показано в следующем примере.

<?xml version="1.0" encoding="utf-8"?> <GeomFigures> <Point X="2" Y="-1" /> <Line> <A X="-1" Y="-1" /> <B X="2" Y="2" /> </Line> </GeomFigures>

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

Поскольку свойственное XML открытое представление информации не всегда удобно с точки зрения безопасности, то существует спецификации XML-DigitalSignature и XML-Encrypton, предназначенные для передачи в XML конфиденциальной информации. Первая из них позволяет добавить к XML-документу цифровую подпись, вторая – зашифровать XML-документ или отдельные его элементы.


Для определения назначения элементов и атрибутов XML- документа введено понятие пространства имен XML (XML namespace), которое должно иметь уникальный идентификатор. Обычно пространство имен идентифицируется некоторым URI (Uniform Resource Identifier), связанным с доменом организации, предложившее пространство имен. По данному URI может располагаться некоторое описание пространства имен, однако это не обязательно. Все используемые в XML документе пространства имен описываются в корневом элементе документа в атрибутах с именем вида xmlns:schema_id. Таким образом схема связывается с некоторым коротким идентификатором schema_id, который затем используется как префикс атрибутов и элементов. Например, в следующей строчке пространству имен http://www.w3.org/2001/XMLSchema> дается идентификатор xs, используемый в имени элемента xs:schema.

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> Часть имени элемента после двоеточия является локальной, а часть перед двоеточием должна быть связана со схемой в корневом атрибуте. Благодаря такой нотации разные пространства имен могут иметь совпадающие имена элементов. Пространства имен используются оперирующими с XML программами.

Одним из достоинств XML является наличия языков спецификаций, определяющих правильный XML документ. Первоначально эту функцию выполнял DTD (Document Type Definition), однако в настоящий момент общепринятым стандартом является спецификация схем XML (XML Schema Definition, XSD). XSD документ является также документом на языке XML, использующим пространство имен http://www.w3.org/2001/XMLSchema. Файл с описанием схемы XML определяет:

словарь документа (имена элементов и атрибутов);синтаксис корректного документа; сложные типы данных. Элементарные типы данных описаны в самом пространстве имен http://www.w3.org/2001/XMLSchema. Синтаксис схемы позволяет описать сложные типы данных, включающие в себя поля простых типов, сложных типов, а также сложные последовательности, каждый элемент которых может принадлежать к одному из нескольких сложных или простых типов данных.Таким образом, синтаксис схемы XML позволяет описать результат сериализации контейнера (списка или массива), в котором могут храниться объекты нескольких известных классов. В состав .NET Framework входит утилита xsd.exe, создающая схему по заданному классу, которая будет подробно рассмотрена в следующей главе. Соответствие между классами .NET и схемами не является взаимно однозначным. В частности, при использовании утилиты xsd.exe любым видам списочных контейнеров соответствует одинаковая последовательность в схемах XML.


Сервисы и интерфейс программной компоненты


Для работы с сервисами программной компоненты обращающийся к ним клиент должен иметь полное представление об интерфейсе используемой компоненты. Несмотря на значительные отличия модели передачи сообщений и модели удаленного вызова, для них обеих интерфейс компоненты распределенной системы можно описать как совокупность адресов и форматов сообщений ее сервисов. В роли сервиса, предоставляемой программной компонентой, созданной с помощью .NET Framework, выступает одно из следующих понятий:

методы активируемого сервером объекта;активируемый клиентом объект вместе со своими полями, свойствами и методами;очередь с сообщениями запросами, которые считываются программной компонентой.

Адрес сервиса зависит от промежуточной среды и является совокупностью сетевого адреса компоненты и некоторого публичного имени сервиса. Сетевой адрес программной компоненты основан на имени ее компьютера для систем удаленного вызова или на адресе менеджера очереди для систем обмена сообщениями. Данный адрес является адресом нижестоящего протокола, на котором основана данная промежуточная среда. В роли него может выступать HTTP, TCP, NetBIOS, или протокол нижестоящей промежуточной среды. Второй составляющей адреса сервиса является идентификатор сервиса. В роли него может выступать некий идентификатор активируемого класса для сред удаленного вызова или же имя очереди сообщений, из которой сервис считывает сообщения запросы. Хотя имя вызываемого метода часто фактически описывается в самом сообщении, его следует рассматривать как составную часть адреса сервиса, поскольку форматы сообщений, очевидно, различаются для различных методов одного и того же класса.

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

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



К первым относятся сообщения с параметрами удаленного вызова и сообщения запросы в очередях сообщений, ко вторым – сообщения с результатом выполнения метода и сообщения ответы. К параметрам удаленного метода следует отнести и некоторый идентификатор активированного объекта сервера для случая активации объектов по запросу клиента. Можно постулировать, что каждому сервису компоненты должна соответствовать единственная спецификация формата принимаемых им сообщений и единственная спецификация принимаемых от него сообщений (в частном случае это спецификация информирует об отсутствии ответа компоненты).

Важным различием систем обмена сообщениями от систем удаленного вызова является отсутствие ограничений на формат сообщения. Таким образом, формально в них существует возможность использования для описания формата сообщения, например, контекстно свободных формальных грамматик. Однако было бы естественным считать, что формат сообщения должен быть эквивалентен описанию полей некоторого класса CLI. Объект данного класса преобразуется в результате сериализации в передаваемое сообщение.

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

Итого, каждый сервис программной компоненты характеризуется тремя сущностями:

полным адресом сервиса;единственной спецификацией принимаемых сервисом сообщений (запросов); единственной спецификацией принимаемых от сервиса сообщений (ответов). Совокупность спецификаций всех сервисов программной компоненты образует ее интерфейс (рис. 3.1).




Рис. 3.1.  Интерфейс компоненты распределенной системы

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

язык передаваемых в распределенной системе сообщений, обычно описывающий результат сериализации объектов; язык описания спецификаций сообщений, определяющий корректные сообщения для сервисов компоненты; язык описания интерфейса компоненты, определяющий набор ее сервисов.Языки описания интерфейса и спецификаций сообщений часто представлены на практике одним языком.

Поскольку сообщение обычно представлено результатом сериализации того или иного класса, то одной из спецификаций сообщения можно считать совокупность сериализуемых полей и свойств маршализируемого по значению объекта. Для систем удаленного вызова спецификацией интерфейса может являться описание класса .NET. Таким образом, метаданные из сборок с описанием интерфейса или класса удаленного объекта и классами параметров его методов полностью определяют интерфейс программной компоненты, созданной при помощи .NET Framework. Однако такой подход часто неудобен, поскольку не только уменьшает открытость системы, привязывая описание интерфейса программной компоненты к используемому для ее создания средству разработки, но и требует предоставления в общем случае сборок с классами компоненты клиенту. Поэтому существует потребность в общепринятых и независимых от средств разработки программных компонент языках описания интерфейса компоненты.


SOAP: язык сообщений распределенной системы


Стандартизация описания языка XML дала широкие возможности для построения на его основе языков описания сообщений, передаваемых между программными компонентами, и языков описания сервисов программной компоненты. В конце 90-х годов началась разработка двух спецификаций для построения распределенных гетерогенных систем – SOAP и XML RPC. Спецификация XML RPC поддерживается в настоящий момент большим числом языков, но имеет меньше возможностей и не поддерживается стандартной библиотекой .NET Framework.

Поскольку в момент разработки данных спецификаций протокол HTTP был как наиболее распространенным, так и повсеместно разрешенным в межсетевых экранах протоколом, то он был выбран в качестве стандартного транспортного протокола для создания гетерогенных промежуточных сред. В силу этого, хотя спецификация SOAP не привязана жестко к какому либо транспортному протоколу, использующая SOAP и WSDL промежуточная среда получила названия веб служб (web services ). Она использует два дополнительных языка – язык описания сообщения SOAP (пространство имен SOAP версии 1.1 – http://schemas.xmlsoap.org/soap/envelope/, версии 1.2 – http://schemas.xmlsoap.org/wsdl/soap12/) и язык описания сервисов и интерфейсов WSDL (пространство имен http://schemas.xmlsoap.org/wsdl/).

Рекомендация SOAP изначально разрабатывалась как спецификация для удаленного вызова методов и расшифровывалась как Simple Object Access Protocol . Сообщение SOAP представляет собой XML-документ, называемый конвертом или пакетом (envelope ), содержащий заголовки с метаинформацией в элементе soap:Header и тело сообщения в элементе soap:Body . В заголовках пакета содержится дополнительная информация, которая может использоваться промежуточной средой. Благодаря тому, что основной стандарт не ограничивает содержание заголовков, SOAP является расширяемой спецификацией, и в настоящее время все еще идет процесс стандартизации ее расширений.

Что касается представления тела сообщения, то в силу различных причин в настоящий момент существует два различных способа представления информации в теле пакета SOAP – кодирование SOAP RPC (в двух вариантах) и кодирование SOAP Document.
Кодирование SOAP RPC предназначено исключительно для передачи параметров удаленного вызова и определяет сообщение как имя метода и список параметров. При использовании кодирования SOAP Document, которое является фактическим стандартом в настоящий момент, сообщение представляет собой XML документ со схемой и пространством имен, заданными в описании сервиса на языке WSDL. Хотя обычно сообщение и состоит из имени метода удаленного объекта и списка его параметров, но сама спецификация кодирования не фиксирует как либо его содержание.

В качестве примера рассмотрим простейшие сообщения SOAP версии 1.2 для сервиса, складывающего два числа. Сообщение запрос использует пространство имен http://summa.test/webservices, которое описано в интерфейсе компоненты, что будет показано далее. В элементе message содержатся сами складываемые числа.

<?xml version="1.0" encoding="utf-8"?> <soap12:Envelope xmlns:soap12="http://www.w3.org/2003/05/soap-envelope"> <soap12:Body> <Add xmlns="http://summa.test/webservices"> <message> <a>1</a> <b>2</b> </message> </Add> </soap12:Body> </soap12:Envelope> Сообщение с ответов программной компоненты.

<?xml version="1.0" encoding="utf-8"?> <soap12:Envelope xmlns:soap12="http://www.w3.org/2003/05/soap-envelope"> <soap12:Body> <AddResponse xmlns="http://summa.test/webservices"> <AddResult>3</AddResult> </AddResponse> </soap12:Body> </soap12:Envelope>

Выводы по описанию интерфейса компоненты


Для создания открытой распределенной системы необходимо использование общепринятых языков описания интерфейса программной компоненты. В настоящий момент существует ряд апробированных на практике стандартов для передачи данных в гетерогенных распределенных системах: XML, XSD, SOAP и WSDL. Их использование позволяет создавать системы, не привязанные жестко к какому либо средству разработки программ или транспортному протоколу. Однако открытый характер спецификации SOAP допускает как реализацию использующей ее промежуточной средой некоторой дополнительной функциональности, так и принятие все новых стандартов и расширений, использующих заголовки SOAP. Это может привести к определенным сложностям при взаимодействии основанных на WSDL и SOAP программных компонент различных разработчиков.



WSDL: описание интерфейса программной компоненты


Для описания интерфейса программной компоненты, включая спецификацию корректных сообщений, был разработан язык WSDL (Web Service Definition Language). Описание на языке WSDL включает в себя следующие семь составляющих (рис. 3.3).


Рис. 3.3.  Составные части WSDL документа

.Описание типов передаваемых данных. При использовании кодирования SOAP Document оно состоит из схемы XML, определяющей корректные сообщения, получаемые программной компонентой в теле пакета SOAP. Описание входящих и исходящих сообщений, которые связываются с описанными типами данных. Описание операций (сервисов программной компоненты), с каждой из которых связывается входящее и исходящее сообщение. Описание типов портов (идентификаторов программных компонент), с каждым из которых связывается некоторый набор операций. Описание привязок ( binding ), связывающие типы портов и их сообщений с определенным типом кодирования тела пакета, а также с версией протокола SOAP. Описание портов, связывающие типы портов и соответствующие им привязки с конкретными URL.Общее описание службы (интерфейса программной компоненты) как совокупности портов.

Далее рассмотрено описание на языке WSDL интерфейса компоненты, которое содержит два сервиса – сложение двух чисел и сложение последовательности чисел. В корневом элементе указаны все используемые пространства имен, включая пространство протокола SOAP 1.2 – http://schemas.xmlsoap.org/wsdl/soap12/.

<?xml version="1.0" encoding="utf-8"?> <wsdl:definitions xmlns:tns="http://summa.test/webservices" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" targetNamespace="http://summa.test/webservices" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">

В элементе wsdl:types описываются все типы данных. Тип Add будет связан со входящим сообщением сервиса сложения двух чисел, а тип AddResponse – с его исходящим сообщением.

<wsdl:types> <s:schema elementFormDefault="qualified" targetNamespace="http://summa.test/webservices"> <s:element name="Add"> <s:complexType> <s:sequence> <s:element minOccurs="1" maxOccurs="1" name="message" type="tns:AddMessage" /> </s:sequence> </s:complexType> </s:element> <s:complexType name="AddMessage"> <s:sequence> <s:element minOccurs="1" maxOccurs="1" name="a" type="s:int" /> <s:element minOccurs="1" maxOccurs="1" name="b" type="s:int" /> </s:sequence> </s:complexType> <s:element name="AddResponse"> <s:complexType> <s:sequence> <s:element minOccurs="1" maxOccurs="1" name="AddResult" type="s:int" /> </s:sequence> </s:complexType> </s:element>

Типы SumList и SumListResponse предназначены для сообщений сервиса сложения списка чисел.


<s:element name="SumList"> <s:complexType> <s:sequence> <s:element minOccurs="0" maxOccurs="1" name="list" type="tns:ArrayOfInt" /> </s:sequence> </s:complexType> </s:element> <s:complexType name="ArrayOfInt"> <s:sequence> <s:element minOccurs="0" maxOccurs="unbounded" name="int" type="s:int" /> </s:sequence> </s:complexType> <s:element name="SumListResponse"> <s:complexType> <s:sequence> <s:element minOccurs="1" maxOccurs="1" name="SumListResult" type="s:int" /> </s:sequence> </s:complexType> </s:element> </s:schema> </wsdl:types> В элементах wsdl:message типы данных связываются с идентификаторами сообщений.

<wsdl:message name="AddSoapIn"> <wsdl:part name="parameters" element="tns:Add" /> </wsdl:message> <wsdl:message name="AddSoapOut"> <wsdl:part name="parameters" element="tns:AddResponse" /> </wsdl:message> <wsdl:message name="SumListSoapIn"> <wsdl:part name="parameters" element="tns:SumList" /> </wsdl:message> <wsdl:message name="SumListSoapOut"> <wsdl:part name="parameters" element="tns:SumListResponse" /> </wsdl:message> В элементе wsdl:portType описываются абстрактные операции и используемые ими сообщения.

<wsdl:portType name="MathServiceSoap"> <wsdl:operation name="Add"> <wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> Операция Add складывает два числа </wsdl:documentation> <wsdl:input message="tns:AddSoapIn" /> <wsdl:output message="tns:AddSoapOut" /> </wsdl:operation> <wsdl:operation name="SumList"> <wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> Операция SumList складывает несколько чисел </wsdl:documentation> <wsdl:input message="tns:SumListSoapIn" /> <wsdl:output message="tns:SumListSoapOut" /> </wsdl:operation> </wsdl:portType> В элементе wsdl:binding операции связываются с транспортным протоколом (HTTP), версией протокола SOAP (1.2) и типом кодирования тела пакета (SOAP-Document).



<wsdl:binding name="MathServiceSoap12" type="tns:MathServiceSoap"> <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" /> <wsdl:operation name="Add"> <soap12:operation soapAction="http://summa.test/webservices/Add" style="document" /> <wsdl:input> <soap12:body use="literal" /> </wsdl:input> <wsdl:output> <soap12:body use="literal" /> </wsdl:output> </wsdl:operation> <wsdl:operation name="SumList"> <soap12:operation soapAction="http://summa.test/webservices/SumList" style="document" /> <wsdl:input> <soap12:body use="literal" /> </wsdl:input> <wsdl:output> <soap12:body use="literal" /> </wsdl:output> </wsdl:operation> </wsdl:binding> В элементе wsdl: service интерфейс программной компоненты связывается с типом порта, с некоторой привязкой, а также с конкретным URL, используемым в дальнейшем для вызова веб службы.

<wsdl:service name="MathService"> <wsdl:port name="MathServiceSoap12" binding="tns:MathServiceSoap12"> <soap12:address location="http://summa.test/webservices/summa.asmx" /> </wsdl:port> </wsdl:service> </wsdl:definitions> Как видно из примера, структура документа на языке WSDL является достаточно сложной, однако благодаря ей одни и те же абстрактные операции могут быть связаны с различными способами передачи информации, включая как разные транспортные протоколы, так и различные версии спецификации SOAP. Для реализации удаленного вызова на основе данной спецификации необходимы средства как для создания WSDL документа по описанию используемого удаленно класса, так и средство создания по известному WSDL документу посредника удаленного вызова.