Все типы данных, входящие в WSDL. унаследованы из спецификации XML Schema. Однако следует обратить внимание на тот факт, что WWW консорциум, известный также как W3C, определил три версии этой спецификации (1999, 2000 и 2001 гг.). Но, учитывая относительную новизну языка WSDL, обычно опираются на наиболее свежую версию спецификации XML Schema, датированную 2001 годом.
В WSDL-описаниях разработчик может применять как простые типы, так и составные. Но составные типы, как известно, создаются из простых. Поэтому для начала рассмотрим наиболее часто употребляемые простые типы данных.
1. anyURI. Тип обычно применяется для хранения сетевых идентификаторов URL указывающих на расположение каких-либо ресурсов в Сети. URI являются развитием концепции всем известных стандартных URL и позволяют адресовать не только какие-либо конкретные файлы, но и их фрагменты. В языке Visual Basic.NET этот тип распознается как String.
2. boolean. Это. конечно, логический тип, который полностью соответствует типу Boolean из Visual Basic.NET. Возможные значения — true и false.
3. byte. Тип предназначен для хранения целых чисел. Как можно понять из его наименования, под хранение одного значения отводится один байт, поэтому значение может располагаться в промежутке от -128 до 127. В Visual Basic.NET соответствует типу integer.
4. date. Тип предназначен для хранения дат. В Visual Basic.NET конвертируется в тип Date.
5. Date Time. Значения этого типа хранят не только дату, но и время. Так же, как и предыдущий, этот тип в Visual Basic.NET конвертируется в тип
Date.
6. double. Тип предназначен для хранения числовых данных. Для каждого значения отводится по восемь байтов, что позволяет хранить числа достаточно большого диапазона. В Visual Basic.NET ему соответствует тип
Double.
7. float. Тип предназначен для хранения числовых данных. Для каждого значения отводится по четыре байта. В Visual Basic.NET ему соответствует тип Single.
8. int. Тип используется для представления целочисленных значений. Для хранения каждого числа используются четыре байта. В Visual Basic.NET ему соответствует тип Long.
9. language. Тип предназначен для хранения значений, указывающих на язык некоего текстового содержимого. Все возможные значения этого типа описаны в документе RFC 1766. В языке Visual Basic.NET для хранения подобных значений не предусмотрено отдельного типа, поэтому они хранятся как тип String. Разработчик сам должен будет обрабатывать эти значения.
10. long. Тип также используется для хранения целочисленных значений. Для хранения каждого значения отводится восемь байтов. Соответственно, диапазон хранимых чисел простирается от —9 223 372 036 S54 775 808 до 9 223 372 036 854 775 807. В Visual Basic.NET хранятся как данные типа Variant.
11. negativeInteger. Тип предназначен для хранения отрицательных целочисленных значений. В Visual Basic.NET хранятся как данные типа
Variant.
12. nonnegativeInteger. Тип предназначен для хранения неотрицательных целочисленных значений, то есть положительных чисел и нулевого значения. В Visual Basic.NET хранятся как данные типа Variant.
13. positiveInteger. Этот тип отличается от предыдущего только тем, что не включает в себя нулевое значение — он предназначен только для положительных целых чисел. Как и предыдущие типы, этот в Visual Basic.NET конвертируется в Variant.
14. short. Это тоже целочисленный тип. Его отличием является то. что для хранения каждого значения отводится два байта. В Visual Basic.NET ему соответствует тип Integer.
15. string. Здесь все понятно. Этот тип предназначен для хранения текстовых строк. Он практически идентичен типу String из Visual Basic.NET.
16. time. Этот тип предназначен для хранения значений, указывающих на какое-либо время. В Visual Basic.NET эти значения все равно обрабатываются как Date.
17 unsignedByte. Тип предназначен дня целочисленных значений, как и тип byte, но при этом хранит целые без знаковые числа. В Visual Basic.NET этот тип обрабатывается как обычный Byte.
18 unsignedInt. Как и тип int, этот тип хранит целые числа, отводя для них по четыре байта. Отличие заключается в том, что значения этого типа не имеют знака. В Visual Basic.NET обрабатываются как значения типа
Variant.
19 unsignedLong. Как и тип long, хранит целые числа, отводя дня них по восемь байтов. Отличие заключается в том, что значения этого типа не имеют знака. В Visual Basic.NET обрабатываются как значения типа
Variant.
20 unsignedShort. Как и тип short, хранит целые числа, отводя для них по два байта. Отличие заключается в том, что значения этого типа не имеют знака. В Visual Basic.NET обрабатываются как значения типа Long.
На этом мы заканчиваем рассмотрение простейших типов данных, которые чаше всего используются в документах WSDL. Теперь предстоит рассмотреть способы образования составных типов. Проше всего увидеть структуру этого механизма на несложном примере.
Предположим, нам необходимо создать составной тип, в котором бы хранилась информация о зарегистрированном пользователе сервиса. Мы будем хранить имя и фамилию человека, а также его возраст в годах. Для этого нам потребуются два поля, приспособленные для хранения строк, и одно поле для хранения целочисленного значения. Тогда конструкция объявления составного типа будет выглядеть следующим образом:
< еlement name=" PERSON " >
<xsd:complexType>
<xsd:seguence>
<xsd:element name="firstName" type="xsd:string"/>
<xsd:element name="lastName" type="xsd:string"/>
<xsd:element name="ageInYears" type="xsd:int"/>
</xsd:seguence>
</xsd:complexType>
</element>
Легко заметить, что определение нового типа заключается в теги <element> и </element>. Затем, При помощи тегов <xsd:complexType> и </xsd:complexType>, где префикс xsd указывает на используемое пространство имен XML Schema, определяется, что объявляемый тип будет составным. В объявляющем теге <element> мы также использовали атрибут name, значением которого является наименование создаваемого составного типа. То есть наш объявляемый тип носит наименование PERSON.
Само указание структуры типа должно заключаться в теги <xsd: sequence> и < /xsd:sequence>. Каждая отдельная часть типа объявляется при помощи тега <xsd:element>, у которого используются атрибуты name и type для указания наименования элемента и его типа соответственно. В нашем случае мы объявили два элемента типа string с наименованиями firstName и lastName, соответственно, и один элемент aqeInYears типа int. Как можно видеть, объявление составных типов не является такой уж сложной задачей.
Язык WSDL позволяет объявлять не только отдельные простые и составные типы, но и их массивы, а также перечислимые типы. Для начала рассмотрим создание перечислимых типов.
Основной особенностью перечислимых типов является наличие четко ограниченного и явно объявленного множества значений: все возможные значения, которые может принимать переменная перечислимого типа, объявлены заранее. К перечислимым типам можно отнести перечень наименований дней недели или месяцев в году. Перечислимые типы — это перечни.
Как всегда, для начала рассмотрим простой пример объявления перечислимого типа. Так, для создания типа sex, который будет состоять из двух возможных значений — Male и Female, требуется использовать следующий фрагмент кода:
<element name="Sex">
<xsd:simpleType>
<xsd:restriction base="xsd:strinq">
<xsd:enumeration value="Male" />
<xsd:enumeration value=”Female" />
</xsd: restriction>
</xsd:simpleType>
</element>
Начало объявления типа, как мы видим, — традиционно. Используется тег <element>, внутри которого и размешается все объявление. Однако следующим использован тег <xsd:simpleType>, указывающий, что перечислимые типы не относятся к составным. После этого необходимо указать базовый тип, которому будут соответствовать все значения перечислимого типа. Естественно. значения, входящие в состав объявляемого типа, должны быть однотипными. В нашем случае мы используем значения типа strinq. Для объявления базового типа используется тег <xsd: restriction>. Сам базовый тип указывается в виде значения атрибута base, входящего в состав этого типа. Следует отметить, что тег <xsd: restriction> является не просто объявляющим тегом, он считается охватывающим тегом, поэтому разработчику необходимо использовать закрывающий близнец </xsd: restriction> и размещать перечисление возможных значений в промежутке между этой парой тегов.
Теперь можно переходить к перечислению всех возможных значений создаваемого типа. Для этого мы используем теги <xsd:enumeration>, в которых присутствует атрибут value. Значение этого атрибута и является одним из возможных значений перечислимого типа.
Перейдем к объявлению массивов. Вообще, следует признать, что в WSDL массивы объявляются не при помощи стандартного пространства имен XML Schema. Здесь для этих целей используется тип Аrrау, позаимствованный из языка SOAP. Таким образом, для объявления массива следует воспользоваться пространством имен языка SOAP. Вот простой пример объявления целочисленного массива:
<xsd: complexType name="ArrayOfInt">
<xsd:complexContent>
<xsd:restriction base="soapenc:Array">
<attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:int[ ]"/>
</xsd:restriction»
</xsd:compiexContent>
< / xsd: coiripiexType>
Начнем по порядку рассматривать этот фрагмент кода. Мы объявляем тип с наименованием ArrayOfInt. Массивы считаются сложными типами, поэтому для его объявления мы используем тег <xsd: complexTyре >. Так как одна переменная массива содержит все-таки несколько значений, она сама в некотором роде является составной. Поэтому для создания массивов применяется тег <xsd: complexContent>, который и открывает секцию объявления содержимого типа.
После тега <xsd:complexContent> следует указать тип, на основе которого мы создаем свой массив. Как уже говорилось, в языке WSDL для объявления массивов используется пространство имен языка SOAP, и тип массива заимствуется оттуда. Именно поэтому в теге <xsd:restriction> параметр base имеет значение soapenc:Array. Если обратиться к началу листинга 15.1, то мы увидим, что пространство имен soapenc действительно было объявлено, и его реализация расположена но адресу http://schemas.xmlsoap.org/soap/encoding/.
После того как мы объявили, что создаваемый тип будет массивом, необходимо указать, какого именно типа будут элементы массива. Для этого в нашем объявлении использован следующий тег:
<attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:int[ ]"/>
Для нашего комплексного типа указание типа элементов производится через ссылку на элемент arrayType из пространства имен soapenc. Эта ссылка связывает искомый элемент с конструкцией wsdl:аrrауTуре = "xsd:int[ ]”. То есть тип массива мы задаем через одноименный элемент аrrауTуре, но уже принадлежащий пространству имен wsdl, которое также объявляется в начале WSDL-файла. Соответственно, мы используем тип xsd:int с проставленными квадратными скобками после его наименования. Эта конструкция и создает массив.
Теперь, когда мы знаем, как распознавать определения типов, собранных в разделе WSDL-документа <types>. можно перейти к рассмотрению структуры раздела <messaqe>.
Структура элемента <message>
В элементах <messaqe> описывается структура всех входящих и исходящих сообщений Web-сервиса. Если мы обратимся к WSDL-файлу, описывающему наш первый сервис, то мы увидим там несколько элементов <messaqe>. Полностью этот блок выглядит так:
<message name="MyDateSoapIn">
<part name="parameters" element="s0:MyDate" />
</message>
<message name="MyDateSoapOu t">
<part name="parameters" element="s0:MyDateResponse" />
</message>
<message name="MyDateHttpGetIn">
<part name="ShowTime" type="s:string" />
</message>
<message name="MyDateHttpGetOut" >
<part name="Body" element="s0:string" />
</message>
<message name="MyDateHttpPostln">
<part name="ShowTime" type="s:string" />
</message>
<message name="MyDateHttpPostOut”>
<part name="Body" eiement="s0:string" />
</message>
Легко заметить, что в этом блоке содержится шесть разделов <messaqe>. Так как наш сервис, как и все стандартные Web-сервисы концепции Microsoft.NET, поддерживает три способа передачи и получения информации (get, post и SOAP), то можно убедиться, что на каждый метод приходится по два элемента <messaqe>. То есть для каждого метода один элемент описывает входящее сообщение, а второе — исходящее.
Кстати, эту структуру всего раздела можно распознать и по наименованиям элементов <messaqe>. Они складываются из наименования функции Web-сервиса (MyDate), метода передачи информации (HttpPost, HttpGet, Soap), и направленности сообщения (In, Out). Теперь рассмотрим структуру стандартного элемента <message>. В нашем примере он выглядит следующим образом:
<message name="MyDateSoapIn">
<part name="parameters" element=”s0:MyDate" />
< /message>
В открывающем теге <message> при помощи атрибута name мы указываем наименование сообщения, созданное но образцу, рассмотренному выше. В общем случае совершенно необязательно использовать именно этот алгоритм образования имени. Можно использовать любой уникальный идентификатор. Но для того чтобы клиентское приложение могло самостоятельно распознавать структуру сервиса по его WSDL-файлу, стоит все-таки придерживаться этого правила.
Внутри раздела <message> указываются все передаваемые в нем отдельные элементы. Они объявляются при помощи тегов <part>. В этом теге используются атрибуты name и element для задания наименования передаваемой переменной и типа ее значения, соответственно. В нашем случае мы описываем входящее сообщение на языке SOAP. Поэтому передается переменная с наименованием parameters, тип которой описан в разделе <types> под именем MyDate.
Однако следует отметить, что два вышеописанных атрибута, входящие в состав тега <message>, не являются единственными. Помимо них могут использоваться и другие атрибуты, такие как type для указания типа переменной и иные атрибуты спецификации XML Schema, описывающие тип и ограничения, налагаемые на переменную. Но чаше всего в дополнительных атрибутах нет нужды.
Вернемся к рассматриваемому нами фрагменту кода. Если в разделах <message>, описывающих входящее и исходящее сообщения на языке SOAP, использовались переменные с наименованием parameters, то сообщения, связанные со стандартными методами протокола HTTP, выглядят несколько иначе. Вот типичный пример входящего сообщения, основанного на методе POST:
<message name="MyDateHttpPostIn">
<part name="ShowTime" type="s: string" />
</message>
Как мы помним, вызываемая функция MyDate имеет один параметр с наименованием showTime. Именно он и описывается в теге <part>. При этом для указания типа передаваемого параметра используется пространство имен XML Schema. Теперь обратимся к блоку <message>, который описывает исходящее сообщение. Определение этого сообщения приведено в следующем фрагменте кода:
<message name="MyDateHttpPostOut">
<part name="Body" element="s0:string" />
< /message>
В этом блоке описывается исходящее сообщение, которое возвращает результат выполнения функции Web-сервиса. Следует обратить внимание, что помимо изменения наименования элемента (и это понятно, потому что возвращаемое значение практически никак не связано с переданным параметром), изменено и пространство имен для указания типа возвращаемого значения. Для возвращаемого значения используется внутреннее пространство имен Web-сервиса с общим наименованием s0. Если обратиться к исходному коду контракта Web-сервиса, то можно увидеть, что это пространство имен объявлено следующим образом:
xml ns:s0="http://tempuri.org/" targetNamespace="http://tempuri.org/"
Те же самые правила образования блоков <message> справедливы и для сообщений, связанных со стандартным методом GET протокола HTTP.
Каждое объявление сообщения будет связано с портом, описываемым блоком <port>. Но прежде чем мы будем рассматривать структуру этих блоков, следует обратить внимание на блоки <portType>, которые как раз и призваны задавать структуру портов.
Структура элемента <portType>
Начнем мы как всегда с рассмотрения искомого раздела, приведенного в нашем основном примере. Вот этот фрагмент кода:
<portType name="Service1Soap">
<operation name= "MyDate" >
<input message="s0:MyDateSoapln" />
<output message="s0:MyDateSoapOut" />
</operation>
</portType>
<portType name="Service1HttpGet">
<operation name= "MyDate" >
<input message="s0:MyDateHttpGetln" />
<output message="s0:MyDateHttpGetOut" />
</operation>
</portType>
<portType name="Service1HttpPost">
<operation name= "MyDate">
<input message="s0:MyDateHttpPostln" />
<output message="s0:MyDateHttpPostOut" />
</operation>
</portType>
В этом фрагменте объявлено три блока <portType>. Если обратить внимание на значения атрибутов name, входящих в состав этого тега, то можно увидеть, что все они описывают методы доступа к описываемому Web-сервису. Так, если взять для рассмотрения блок <рогtType>, описывающий доступ к сервису при помощи метода post протокола HTTP, то мы увидим следующий фрагмент кода:
<portType name="ServicelHttpPost">
<operation name="MyDate">
<input message="s0:MyDateHttpPostIn" />
<output message="s0:MyDateHttpPostOut" />
</operation>
</portType>
Структура блока < portTуре >, равно как и остальных блоков файла контракта, достаточно прозрачна. При помощи тега <operation> задается наименование функции, к которой будет предоставлять доступ какой-либо порт. В нашем случае это функция MyDate. Внутри блока <operation> описываются входящие и исходящие данные при помощи тегов <input> и <output>, соответственно. А входящие и исходящие данные, как мы уже знаем, описываются при помощи сообщений. Что и наблюдается в этом блоке. Входные данные для порта, предоставляющего доступ к функции MyDate при помощи метода post, описываются сообщением MyDateHttpPostIn. Это сообщение было рассмотрено в предыдущем разделе. Соответственно, выходные данные задаются сообщением MyDateHttpPostOut. При этом все наименования сообщений указаны с применением внутреннего пространства имен s0.
Следует отметить, что бывает несколько основных видов блоков <portTyре >. В нашем случае рассматривались блоки, которые описывают одновременно и входящие, и исходящие сообщения. В терминологии спецификации WSDL такой тип портов называют запрос-ответ (request-response). Но помимо этого типа могут встречаться блоки <portType>, описывающие функции, которые поддерживают только входящие или только исходящие данные. Такие функции называют однонаправленными (one-way). Пример описания подобного типа порта приведен в следующем фрагменте кода:
<portType name="mySегviсе">
< opeгation name="MyFunction">
<input message="MyFunctionPostIn"/>
</operation>
</portType >
Этот блок описывает порт, который передает только входные данные.
Следует заметить также, что обычный тип порта может описывать не только входящие и исходящие сообщения. В его состав может включаться описание сообщения, выдаваемого сервисом в случае возникновения какой-либо ошибки. Такой блок может выглядеть следующим образом:
<portType name="Service1HttpPost">
<operation name="MyDate ">
<input message="s0:MyDateHttpPostIn" />
<output message="s0:MyDateHttpPostOut" />
<fault message="s0:MyDateHttpPostFault" />
</operation>
</portType>
Естественно, для того, чтобы применять подобный расширенный вариант объявления типа, следует позаботиться и об объявлении соответствующего дополнительного сообщения. Вообще же, дополнительное сообщение, извещающее о возникновении какой-либо ошибки, дублирует концепцию извещения об ошибках языка SOAP. Впрочем, в лабораторной работе, посвященной этому языку, мы увидим принцип действия упомянутой концепции.
Теперь следует рассмотреть формат элементов <binding>, часто называемых привязками, которые определяют формат и протокол передачи данных для каждого объявленного типа порта. Об этом речь пойдет в следующем разделе.
Структура элемента <binding>
Как только что было показано в предыдущем разделе, элементы <binding> детально описывают формат данных и протокол их передачи для каждого определенного типа порта. Типы порта, как известно, задаются блоками <portType>. В нашем примере было три подобных блока. Следовательно, в файле контракта должно находиться и три блока <binding>. Так оно и есть. Фрагмент нашего знакомого WSDL-файла с этими блоками выглядит следующим образом:
<binding name="Service1Soap" type="s0:Service1Soap">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
<operation name= "MyDate">
<soap:operation soapAction="http://tempuri.org/MyDate" style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
</binding>
<binding name="Service1HttpGet" type="s0:Service1HttpGet">
<http:binding verb="GET" />
<operation name="MyDate" >
<http:operation location="MyDate" />
<input>
<http:urlEncoded />
</input>
<output>
<mime:mimeXml part="Body" />
</output>
</operation>
</binding>
<binding name="Service1HttpPost" type="s0:Service1HttpPost">
<http:binding verb="POST" />
<operation name="MyDate" >
<http:operation location="MyDate" />
<input>
<mime:content type="application/x-www-form-urlencoded" />
</input>
<output>
<mime:mimeXml part="Body" />
</output>
</operation>
</binding>
Как можно видеть, наименования элементов, объявляющих привязки, совпадают с наименованиями соответствующих типов портов. Впрочем, это совершенно не обязательно, так как помимо наименований привязок, которые сами по себе могут не нести никакой смысловой нагрузки, лишь бы они были уникальными, в объявляющем теге <binding> используется атрибут type, задающий тип искомой привязки. А значением этого атрибута и будет искомый тип соответствующего порта, определенный при помощи внутреннего пространства имен.
Теперь рассмотрим детально структуру привязки, соответствующую порту, предоставляющему доступ к функциональности Web-сервиса при помощи языка SOAP. Этот фрагмент кода выглядит следующим образом:
<binding name=”Service1Soap" type="s0:ServicelSoap">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="document" />
< operation name= "MyDate ">
<soap:operation soapAction="http://tempuri.org/MyDate"
style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
</binding>
После объявляющего тега <binding>, в котором при помощи атрибутов name и type задаются наименование привязки и соответствующий тип порта, размещается тег, указывающий протокол, по которому будет происходить обмен информацией с портом. Для SOAP в нашем случае этот тег имеет следующий вид:
<soap:binding transport="http: //schemas. xmlsoap.org/soap/http" style="document" />
Как можно видеть, для объявления протокола используется тег <binding>, объявленный в пространстве имен soap. Естественно, этот тег отличается от начального тега блока привязки. Сам протокол передачи данных указывается при помощи атрибута transport, в качестве значения которого используется объявление HTTP в языке SOAP.
Следует отметить, что для привязок, ориентированных на стандартные методы get и post протокола HTTP, объявление протокола, как впрочем, и объявления операций, выглядит несколько иначе. Но об этом — чуть позже. Пока же речь идет о привязке, ориентированной на SOAP.
После того как был объявлен протокол передачи данных от сервиса к клиенту и обратно, следует объявление операции, к которой будет привязываться порт. Объявление операции производится при помощи тега <ореratiоn>. В объявляющем теге <ореration > присутствует атрибут name, значением которого является имя функции, к которой привязывается порт. В нашем случае это, естественно, функция MyDate.
После объявления операции следует указание адреса, по которому производится доступ к функции. В нашем случае, для доступа при помощи SOAP, эта конструкция выглядит следующим образом:
<soap:operation soapAction="http://tempuri.org/MyDate" style= "document" />
После этого остается лишь объявить все входящие и исходящие данные при помощи блоков, задаваемых тегами <input> и <output>, соответственно. В нашем случае входящие и исходящие данные приведены к одному типу, поэтому и содержимое искомых блоков выглядит абсолютно одинаково:
<soap:body use="literal" />
Теперь рассмотрим структуру блока привязки <binding> для использования стандартных методов get и post протокола HTTP. Для метода post блок объявления привязки выглядит следующим образом:
<binding name="Service1HttpPost" type="s0:ServicelHttpPost">
<http:binding verb="POST" />
< operation name="MyDate">
<http:operation location="/MyDate" />
<input>
<mime:content type="application/x-www-form-urlencoded" />
</input>
<output>
<mime: mimeXml part="Body" />
</output>
</operation>
</binding>
Следует обратить внимание на тег, объявляющий протокол передачи данных:
<http:binding verb="POST" />
То есть, ключевое слово binding употреблено в области действия пространства имен http. А наименование используемого метода post передается как значение атрибута verb.
Указание расположения функции, к которой привязывается искомый порт ServicelHttpPost, производится, как и в предыдущем случае, при помощи тега <operation>. Однако он опять задается при помощи пространства имен http, а сам адрес указан в значении атрибута location. При этом указывается не полный адрес, а всего лишь виртуальный каталог.
Следует также обратить внимание, как именно объявляется формат передаваемых и принимаемых данных в блоках <output> и <input>:
<mime:mimeXml part="Body" />
Здесь для ссылки на возвращаемый XML-код используется пространство имен mime, также объявленное в самом начале файла контракта.
Итак, мы рассмотрели структуру блоков <binding>, связывающих порядок передачи данных через порты, которые в свою очередь являются точками доступа к функциям Web-сервиса. Однако структуру объявления портов мы еще не рассматривали. Об этом — в следующем разделе.
Структура элемента <port>
Элементы <port> являются частями элемента <servise>. Их структура чрезвычайно проста для понимания, так как единственное их предназначение указывать адреса для доступа к функциональности Web-сервиса. Таким образом, это точки доступа к функциям. Стандартное объявление одного порта в рассматриваемом нами файле контракта выглядит следующим образом:
<port name="Service1HttpGet" binding="s0:Service1HttpGet">
<http:address location="http://localhost/MyService/Service1.asmx" />
</port>
В объявляющем теге <port> при помощи параметра name задается наименование порта, а при помощи параметра binding — наименование привязки для этого порта. Внутри блока<port> располагается один тег, указывающий на адрес доступа к функции, с которой этот порт связывает привязка. При этом следует обратить внимание на тот факт, что все три порта, используемые в нашем сервисе, указывают на одну и ту же функцию MyDate, следовательно, и адрес точки входа, который указывается в виде значения атрибута location, будет дня всех трех портов одинаковым.
Основные правила для декларирования портов достаточно просты. Каждый порт может объявлять только один адрес доступа к функции Web-сервиса, и каждый порт может использовать только одну привязку.
Итак, как мы убедились, правила объявления портов достаточно просты, и теперь настало время перейти к рассмотрению наивысшего во всей иерархии контракта элемента — <service>.
Структура элемента <service>
Как мы уже знаем, элемент <service> является основным во всей иерархии компонентов WSDL-файла. Он наименее абстрактен, если можно так выразиться. Вся подготовительная работа была уже проведена предыдущими элементами, и осталось лишь описать структуру Web-сервиса в целом.
В рассматриваемом нами WSDL-файле блок <service> выглядит следующим образом:
<service name="Service1">
<port name="Service1Soap" binding="s0:Service1Soap">
<soap:address location="http://Iocalhost/MyService/Service1.asmx"/>
</port>
<port name="Service1HttpGet" binding="s0:Service1HttpGet">
<http:address location="http://localhost/MyService/Service1.asmx"/>
</port>
<port name="Service1HttpPost" binding="s0:Service1HttpPost">
<http:address location="http://Iocalhost/MyService/Service1.asmx"/>
</port>
</service>
Как можно видеть, блок <service> состоит только из портов. И это вполне понятно, так как именно ими и описывается самый верхний уровень абстракции Web-сервиса. Так что, для описания его структуры в целом необходимо лишь перечислить порты. предоставляющие клиентским приложениям доступ ко всем функциям сервиса.
Следует помнить, что в блоке <service> перечисляемые порты не должны ссылаться друг для друга. То есть, исходящая информация какого-либо порта не может напрямую переводиться во входящую информацию для другого порта: вся коммуникация должна быть ориентирована только на клиентские приложения и иные Web-сервисы.
Итак, мы рассмотрели структуру WSDL-файлов, которые описывают функциональность Web-сервисов и правила доступа к его функциям. Теперь нам предстоит познакомиться с языком SOAP, который чаше всего используется для общения с серьезными многофункциональными сервисами.