Прочитать на английском

Поделиться через


WSDL и контракты служб

Служебная программа Wsutil.exe создает заглушку языка C в соответствии с предоставленными метаданными WSDL, а также определениями типов данных и описаниями для типов данных, описанных в схемах XML, созданных пользователем.

Ниже приведен пример документа WSDL и XML-схемы, которая служит основой для обсуждения, следующего:

<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://Example.org" 
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" targetNamespace="http://Example.org" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
 <wsdl:types>
  <xs:schema xmlns:tns="http://Example.org" elementFormDefault="qualified" 
  targetNamespace="http://Example.org" xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <xs:element name="SimpleMethod">
    <xs:complexType>
     <xs:sequence>
      <xs:element name="a" type="xs:int" />
      <xs:element name="b" type="xs:int" />
     </xs:sequence>
    </xs:complexType>
   </xs:element>
   <xs:element name="SimpleMethodResponse">
    <xs:complexType>
     <xs:sequence>
      <xs:element name="b" type="xs:int" />
      <xs:element name="c" type="xs:int" />
     </xs:sequence>
    </xs:complexType>
   </xs:element>
  </xs:schema>
 </wsdl:types>
 <wsdl:message name="ISimpleService_SimpleMethod_InputMessage">
  <wsdl:part name="parameters" element="tns:SimpleMethod" />
 </wsdl:message>
 <wsdl:message name="ISimpleService_SimpleMethod_OutputMessage">
  <wsdl:part name="parameters" element="tns:SimpleMethodResponse" />
 </wsdl:message>
 <wsdl:portType name="ISimpleService">
  <wsdl:operation name="SimpleMethod">
   <wsdl:input wsaw:Action="http://Example.org/ISimpleService/SimpleMethod" 
   message="tns:ISimpleService_SimpleMethod_InputMessage" />
   <wsdl:output wsaw:Action="http://Example.org/ISimpleService/SimpleMethodResponse" 
   message="tns:ISimpleService_SimpleMethod_OutputMessage" />
  </wsdl:operation>
 </wsdl:portType>
 <wsdl:binding name="DefaultBinding_ISimpleService" type="tns:ISimpleService">
  <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
  <wsdl:operation name="SimpleMethod">
   <soap:operation soapAction="http://Example.org/ISimpleService/SimpleMethod" 
   style="document" />
   <wsdl:input>
    <soap:body use="literal" />
   </wsdl:input>
   <wsdl:output>
    <soap:body use="literal" />
   </wsdl:output>
  </wsdl:operation>
 </wsdl:binding>
 <wsdl:service name="SimpleService">
  <wsdl:port name="ISimpleService" binding="tns:DefaultBinding_ISimpleService">
   <soap:address location="http://Example.org/ISimpleService" />
  </wsdl:port>
 </wsdl:service>
</wsdl:definitions>

В этом примере представлен контракт ISimpleService с одним методом SimpleMethod. SimpleMethod имеет два входных параметра целочисленного типа, a и b, отправляемые клиентом в службу. Аналогичным образом SimpleMethod имеет два выходных параметра целочисленного типа b и c, которые возвращаются клиенту после успешного завершения. В синтаксисе SAL-annotated C определение метода отображается следующим образом:

void SimpleMethod(__in int a, __inout int *  b, __out int * c );

В этом определении ISimpleService — это контракт службы с одной операцией службы: SimpleMethod.

Выходной файл заголовка содержит определения и описания для внешней ссылки. В том числе:

  • Определения структуры C для глобальных типов элементов.
  • Прототип операции, определенный в текущем файле.
  • Прототип таблицы функций для контрактов, указанных в WSDL-файле.
  • Прототипы заглушки и заглушки клиента для всех функций, указанных в текущем файле.
  • Структура данных WS_ELEMENT_DESCRIPTION для глобальных элементов схемы, определенных в текущем файле.
  • Структура данных WS_MESSAGE_DESCRIPTION для всех сообщений, указанных в текущем файле.
  • Структура данных WS_CONTRACT_DESCRIPTION для всех контрактов, указанных в текущем файле.

Одна глобальная структура создается для инкапсулации всех глобальных описаний типов схем и типов моделей служб, к которым может ссылаться приложение. Структура называется с помощью нормализованного имени файла. В этом примере Wsutil.exe создает глобальную структуру определений с именем "example_wsdl", которая содержит все описания веб-службы. Определение структуры создается в файле заглушки.

typedef struct _example_wsdl
{
  struct {
    WS_ELEMENT_DESCRIPTION SimpleMethod;
    WS_ELEMENT_DESCRIPTION SimpleMethodResponse;
  } elements;
  struct {
    WS_MESSAGE_DESCRIPTION ISimpleService_SimpleMethod_InputMessage;
    WS_MESSAGE_DESCRIPTION ISimpleService_SimpleMethod_OutputMessage;
  } messages;
  struct {
    WS_CONTRACT_DESCRIPTION DefaultBinding_ISimpleService;
  } contracts;
} _example_wsdl;

extern const _stockquote_wsdl stockquote_wsdl;

Для глобальных определений элементов в документе схемы XML (XSD) создается один прототип WS_ELEMENT_DESCRIPTION , а также соответствующее определение типа C для каждого элемента. Прототипы для описаний элементов Для SimpleMethod и SimpleMethodResponse создаются в виде элементов в приведенной выше структуре. Структуры C создаются следующим образом:

typedef struct SimpleMethod
{
  int   a;
  int   b;
} SimpleMethod;

typedef struct SimpleMethodResponse
{
  int   b;
  int   c;
} SimpleMethodResponse;

Аналогично для глобальных сложных типов Wsutil.exe создает определения структуры C типа C, как показано выше, без сопоставления описаний элементов.

Для входных данных WSDL Wsutil.exe создает следующие прототипы и определения:

  • Для описания сообщения создается прототип WS_MESSAGE_DESCRIPTION. Это описание может использоваться моделью службы, а также уровнем сообщений. Структуры описания сообщений — это поля с именем messagename в глобальной структуре. В этом примере описание сообщения создается в виде поля ISimpleService_SimpleMethod_InputMessage в структуре ISimpleService_SimpleMethod_InputMessage, как указано в WSDL-файле.
  • WS_CONTRACT_DESCRIPTION прототип создается для описания контракта. Это описание используется моделью службы. Структуры описания контракта — это поля с именем contractname в глобальной структуре. В этом примере описание контракта создается в виде поля DefaultBinding_ISimpleService в структуре "_example_wsdl".

Спецификации операций и типов являются общими для прокси-сервера и заглушки, и они создаются в обоих файлах. Wsutil.exe создает одну копию, только если прокси-сервер и заглушка создаются в одном файле.

Создание идентификаторов

Созданные выше структуры C создаются на основе имени, указанного в WSDL-файле. Xml NCName обычно не считается допустимым идентификатором C, и имена нормализуются по мере необходимости. Шестнадцатеричные значения не преобразуются, а общие буквы, такие как ":", "/" и ""., преобразуются в символ подчеркивания "_", чтобы улучшить удобочитаемость.

Заголовок для заглушки

Для каждой операции в контракте службы создается одна подпрограмма обратного вызова с именем operationname<> Callback. (Например, операция SimpleMethod в примере контракта службы имеет созданный обратный вызов SimpleMethodCallback).)

typedef HRESULT (CALLBACK *SimpleMethodCallback) (
  const WS_OPERATION_CONTEXT * context,
  int a, int *b, int *c,
  const WS_ASYNC_CONTEXT *asyncContext,
  WS_ERROR * error);

Для каждого WSDL portType Wsutil.exe создается таблица функций, представляющая portType. Каждая операция в portType имеет соответствующий указатель функции на обратный вызов, присутствующих в таблице функций.

struct ISimpleServiceMethodTable
{
  ISimpleService_SimpleMethodCallback SimpleMethod;
};

Прототипы прокси-сервера создаются для всех операций. Имя прототипа — это имя операции (в данном случае SimpleMethod), указанное в WSDL-файле контракта службы.

HRESULT WINAPI SimpleMethod(WS_CHANNEL *channel,
  WS_HEAP *heap,
  int a,
  int *b,
  int *c,
  const WS_ASYNC_CONTEXT * asyncContext,
  WS_ERROR * error );

Создание прототипа прототипов только для локального использования

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

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

struct _filenameLocalDefinitions
{
  struct {
  // schema related output for all the embedded 
  // descriptions that needs to describe global complex types.
  } globalTypes;
  // global elements.
  struct {
  // schema related output, like field description
  // structure description, element description etc.
  ...
  } globalElements;
  struct {
  // messages and related descriptions
  } messages;
  struct {
  // contract and related descriptions.
  } contracts;
  struct {
  // XML dictionary entries.
  } dictionary;
} _filenameLocalDefinitions;

Ссылки на определения из других файлов

Локальные определения могут ссылаться на описания, созданные в другом файле. Например, сообщение может быть определено в файле кода C, созданном из WSDL-файла, но элемент сообщения может быть определен в другом месте файла кода C, созданного из XSD-файла. В этом случае Wsutil.exe создает ссылку на глобальный элемент из файла, содержащего определение сообщения, как показано ниже:

{  // WS_MESSAGE_DESCRIPTION
...
(WS_ELEMENT_DESRIPTION *)b_xsd.globalElement.<elementname>
  };

Описания глобальных элементов

Для каждого глобального элемента, определенного в файле wsdl:type или XSD, в поле GlobalElement имеется соответствующее поле с именем элементаName. В этом примере создается структура SimpleMethod:

typedef struct _SimpleServiceLocal
{
  struct  // global elements
  {
    struct // SimpleMethod
    {
    ...
    WS_ELEMENT_DESCRIPTION SimpleMethod;
    } SimpleMethod;
    ...
  } globalElements;
}

Другие описания, необходимые описанию элемента, создаются как часть содержащей структуры. Если элемент является простым элементом типа, существует только одно поле WS_ELEMENT_DESCRIPTION. Если тип элемента является структурой, все связанные поля и описания структуры создаются как часть структуры элемента. В этом примере элемент SimpleMethod представляет собой структуру, содержащую два поля, а и b. Wsutil.exe создает структуру следующим образом:

...
struct // SimpleMethod
{
  struct // SimpleMethod structure
  {
    WS_FIELD_DESCRIPTION a;
    WS_FIELD_DESCRIPTION b;
    WS_FIELD_DESCRIPTION * SimpleMethodFields [2];
    WS_STRUCT_DESCRIPTION structDesc;
  } SimpleMethoddescs; // SimpleMethod
  WS_ELEMENT_DESCRIPTION elementDesc;
} SimpleMethod;
...

Внедренные структуры и внедренные элементы создаются как вложенные структуры по мере необходимости.

Wsutil.exe создает поле в разделе WSDL для каждого из значений portType, определенных в указанной службе wsdl:service.

...
struct { // WSDL
    struct { // portTypeName
        struct { // operationName
        } operationName;
    ...
    WS_OPERATION_DESCRIPTION* operations[numOperations];
    WS_CONTRACT_DESCRIPTION contractDesc;
    } portTypeName;
}
...

Wsutil.exe создает одно поле f, содержащее все описания, необходимые для операции, массив указателей на каждый из описаний операций для каждого метода и один WS_CONTRACT_DESCRIPTION для указанного портаType.

Все описания, необходимые операциями, создаются внутри поля operationName в указанном порттипе. К ним относятся поле WS_ELEMENT_DESCRIPTION , а также подстроку входных и выходных параметров. Аналогичным образом, поля WS_MESSAGE_DESCRIPTION для входного сообщения и необязательного выходного сообщения включаются вместе с ним; WS_PARAMETER_DESCRIPTION поле списка для всех параметров операции и поля WS_OPERATION_DESCRIPTION для самой операции. В этом примере создается структура кода для описания SimpleMethod, как показано ниже:

...
struct // messages
{
  WS_MESSAGE_DESCRIPTION ISimpleService_SimpleMethod_InputMessage;
  WS_MESSAGE_DESCRIPTION ISimpleService_SimpleMethod_OutputMessage;
} messages;
struct // contracts
{
  struct // DefaultBinding_ISimpleService
  {
    struct // SimpleMethod
    {
      WS_PARAMETER_DESCRIPTION params[3];
      WS_OPERATION_DESCRIPTION SimpleMethod;
    } SimpleMethod;
    WS_OPERATION_DESCRIPTION* operations[1];
    WS_CONTRACT_DESCRIPTION contractDesc;
  } DefaultBinding_ISimpleService;
} contracts;
...

Имена и пространства имен, используемые в различных описаниях, создаются в виде полей типа WS_XML_STRING. Все эти строки создаются как часть словаря констант для каждого файла. Список строк и поля WS_XML_DICTIONARY (именованный дикт в приведенном ниже примере) создаются как часть поля словаря структуры fileNameLocal .

struct { // fileNameLocal
...
  struct { // dictionary
    struct { // XML string list
      WS_XML_STRING firstFieldName;
      WS_XML_STRING firstFieldNS;
      ...
    } xmlStrings;
  WS_XML_DICTIONARY dict;
  } dictionary;
}; // fileNameLocal;

Массив WS_XML_STRING создается в виде ряда полей типа WS_XML_STRING с именами, понятными для пользователя. Созданная заглушка использует понятные имена в различных описаниях для повышения удобочитаемости.

Прокси-сервер клиента для операций WSDL

Wsutil.exe создает прокси-сервер клиента для всех операций. Приложения могут перезаписать сигнатуру метода с помощью параметра командной строки префикса.

HRESULT WINAPI bindingName_SimpleMethod(WS_SERVICE_PROXY *serviceProxy,
  WS_HEAP *heap,
  int a,
  int *b,
  int *c,
  const WS_CALL_PROPERTY* callProperties,
  ULONG callPropertyCount,
  const WS_ASYNC_CONTEXT * asyncContext,
  WS_ERROR * error )
{
  void* argList[] = {&a, &b, &c};
  return WsCall(_serviceProxy,
    (WS_OPERATION_DESCRIPTION*)&example_wsdlLocalDefinitions.contracts.DefaultBinding_ISimpleService.SimpleMethod.SimpleMethod,
    (void **)&_argList,
    callProperties,
    callPropertyCount,
    heap,
    asyncContext,
    error
  );      
}

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

Wsutil.exe создает заглушку службы для всех операций, описанных в привязке.

HRESULT CALLBACK ISimpleService_SimpleMethodStub(
  const WS_OPERATION_CONTEXT *context,
  void * stackStruct,
  void * callback,
  const WS_ASYNC_CONTEXT * asyncContext,
  WS_ERROR *error )
{
  SimpleMethodParamStruct *pstack = (SimpleMethodParamStruct *) stackstruct;
  SimpleMethodOperation operation = (SimpleMethodOperation)callback;
  return operation(context, pstack->a, &(pstack->b), &(pstack->c ), asyncContext, error );
}

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

Создание определения WSDL

Wsutil.exe создает статическую структуру константной (const static) с именем *<file_name>*LocalDefinitions типа *<service_name>*Local, которая содержит все локальные только определения.

const static _SimpleServiceLocal example_wsdlLocalDefinitions =
{
  {  // global types
  ...
  }, // global types
  {  // global elements
  ...
  }, // global elements
  {  // messages
  ...
  }, //messages
  ...
  {  // dictionary
  ...
  }, // dictionary
},

Поддерживаются следующие описания WSDL:

  • wsdl:service
  • wsdl:binding
  • wsdl:portType
  • wsdl:operation
  • wsdl:message

Обработка wsdl:operation и wsdl:message

Каждая операция, указанная в документе WSDL, сопоставляется с операцией службы Wsutil.exe. Средство создает отдельные определения операций службы как для сервера, так и для клиента.

<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://Example.org" 
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" targetNamespace="http://Example.org" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
 <wsdl:portType name="ISimpleService">
  <wsdl:operation name="SimpleMethod">
   <wsdl:input wsaw:Action="http://Example.org/ISimpleService/SimpleMethod" 
   message="tns:ISimpleService_SimpleMethod_InputMessage" />
   <wsdl:output wsaw:Action="http://Example.org/ISimpleService/SimpleMethodResponse" 
   message="tns:ISimpleService_SimpleMethod_OutputMessage" />
  </wsdl:operation>
 </wsdl:portType>
 <wsdl:message name="ISimpleService_SimpleMethod_InputMessage">
  <wsdl:part name="parameters" element="tns:SimpleMethod" />
 </wsdl:message>
 <wsdl:message name="ISimpleService_SimpleMethod_OutputMessage">
  <wsdl:part name="parameters" element="tns:SimpleMethodResponse" />
 </wsdl:message>
</wsdl:definitions>

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

Метаданные для каждой операции в определенном порттипе имеют входные данные и при необходимости выходное сообщение, каждое из этих сообщений сопоставляется с WS_MESSAGE_DESCRIPTION. В этом примере входные и выходные сообщения операции в portType, сопоставленные с inputMessageDescription, и при необходимости выходные данныеMessageDescription в WS_OPERATION_DESCRIPTION соответственно.

Для каждого сообщения WSDL средство создает WS_MESSAGE_DESCRIPTION, которая ссылается на определение WS_ELEMENT_DESCRIPTION, как показано ниже:

... 
{    // message description for ISimpleService_SimpleMethod_InputMessage
  (WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings.DefaultBinding_ISimpleServiceISimpleService_SimpleMethod_InputMessageactionName,
  (WS_ELEMENT_DESCRIPTION*)&(WS_ELEMENT_DESCRIPTION*)&example_wsdl.globalElements.SimpleMethodReponse
},  // message description for ISimpleService_SimpleMethod_InputMessage
...

Описание сообщения относится к описанию входного элемента. Так как элемент определяется глобально, описание сообщения ссылается на глобальное определение вместо локального статического элемента. Аналогичным образом, если элемент определен в другом файле, Wsutil.exe создает ссылку на глобально определенную структуру в этом файле. Например, если SimpleMethodResponse определен в другом файле example.xsd, Wsutil.exe создает следующее:

...
{    // message description for ISimpleService_SimpleMethod_InputMessage
(WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings.DefaultBinding_ISimpleServiceISimpleService_SimpleMethod_InputMessageactionName,
(WS_ELEMENT_DESCRIPTION*)&(WS_ELEMENT_DESCRIPTION*)&example_xsd.globalElements.SimpleMethodReponse
},  // message description for ISimpleService_SimpleMethod_InputMessage
...

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

Поддержка стиля RPC

Wsutil.exe поддерживает операции в стиле документов, а также операции в стиле RPC в соответствии с расширением привязки WSDL 1.1 для спецификации SOAP 1.2. Операции в стиле RPC и литерала помечены как WS_RPC_LITERAL_OPERATION. Модель службы игнорирует имя элемента оболочки текста ответа в операциях RPC/литералов.

Wsutil.exe не поддерживает операции стиля кодирования в собственном кодировании. Параметр WS_XML_BUFFER создается для кодирования сообщений, и разработчики должны заполнять непрозрачный буфер напрямую.

Поддержка нескольких частей сообщения

Wsutil.exe поддерживает несколько частей сообщений в одном сообщении. Сообщение с несколькими компонентами можно указать следующим образом:

<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://Example.org" 
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" targetNamespace="http://Example.org" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
 <wsdl:message name="ISimpleService_MutipleParts_InputMessage">
  <wsdl:part name="part1" element="tns:SimpleElement1" />
  <wsdl:part name="part2" element="tns:SimpleElement2" />
 </wsdl:message>
</wsdl:definitions>

Wsutil.exe создает поле WS_STRUCT_TYPE для элемента сообщения, если сообщение содержит несколько частей. Если сообщение представлено с помощью стиля документа, Wsutil.exe создает элемент оболочки с типом структуры. Элемент-оболочка не имеет имени или определенного пространства имен, а структура оболочки содержит все элементы во всех частях в виде полей. Элемент оболочки предназначен только для внутреннего использования, и он не будет сериализован в тексте сообщения.

Если сообщение использует представление стиля RPC или литерала, Wsutil.exe создает элемент оболочки с именем операции в качестве имени элемента и указанного пространства имен в качестве пространства имен службы в соответствии со спецификацией расширения WSDL SOAP. Структура элемента содержит массив полей, представляющих типы, указанные в частях сообщения. Элемент оболочки сопоставляется с фактическим верхним элементом в тексте сообщения, как указано в спецификации SOAP.

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

typedef HRESULT (CALLBACK *SimpleMethodCallback) (
  const WS_OPERATION_CONTEXT* context,
  unsigned int  a,
  unsigned int * b,
  unsigned int * c,
  const WS_ASYNC_CONTEXT* asyncContext,
  WS_ERROR* error
  );

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

На стороне клиента каждая операция сопоставляется с операцией прокси-службы.

HRESULT WINAPI SimpleMethod (
  WS_SERVICE_PROXY* serviceProxy,
  ws_heap *heap,
  unsigned int  a,
  unsigned int * b,
  unsigned int * c,
  const WS_ASYNC_CONTEXT* asyncContext,
  WS_ERROR* error);

Обработка wsdl:binding

Модель службы WWSAPI поддерживает расширение привязкиSOAP. Для каждой привязки существует связанный портТип.

Транспорт, указанный в расширении привязки soap, является только консультативным. Приложению необходимо предоставить сведения о транспорте при создании канала. В настоящее время мы поддерживаем привязки WS_HTTP_BINDING и WS_TCP_BINDING.

<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://Example.org" 
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" targetNamespace="http://Example.org" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
 <wsdl:binding name="DefaultBinding_ISimpleService" type="tns:ISimpleService">
  <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
  <wsdl:operation name="SimpleMethod">
   <soap:operation soapAction="http://Example.org/ISimpleService/SimpleMethod" 
   style="document" />
   <wsdl:input>
    <soap:body use="literal" />
   </wsdl:input>
   <wsdl:output>
    <soap:body use="literal" />
   </wsdl:output>
  </wsdl:operation>
 </wsdl:binding>
</wsdl:definitions>

В нашем примере документ WSDL у нас есть только один портType для ISimpleService. Указанная привязка SOAP указывает на транспорт HTTP, указанный как WS_HTTP_BINDING. Обратите внимание, что эта структура не имеет статического оформления, так как эта структура должна быть доступна приложению.

Обработка wsdl:portType

Каждый тип порта в WSDL состоит из одной или нескольких операций. Операция должна соответствовать расширению привязки SOAP, указанному в wsdl:binding.

<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://Example.org" 
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" targetNamespace="http://Example.org" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
 <wsdl:portType name="ISimpleService">
  <wsdl:operation name="SimpleMethod">
   ...
  </wsdl:operation>
 </wsdl:portType>
</wsdl:definitions>

В этом примере тип порта ISimpleService содержит только операцию SimpleMethod. Это соответствует разделу привязки, где существует только одна операция WSDL, которая сопоставляется с действием SOAP.

Так как тип порта ISimpleService имеет только одну операцию - SimpleMethod - соответствующую таблицу функций содержит только SimpleMethod в качестве операции службы.

С точки зрения метаданных каждый портТип сопоставляется wsutil.exe с WS_CONTRACT_DESCRIPTION. Каждая операция в портТипе сопоставляется с WS_OPERATION_DESCRIPTION.

В этом примере средство portType создает WS_CONTRACT_DESCRIPTION для ISimpleService. Это описание контракта содержит определенное количество операций, доступных на портТипе ISimpleService, а также массив WS_OPERATION_DESCRIPTION, представляющий отдельные операции, определенные в портТипе для ISimpleService. Так как для ISimpleService portType для ISimpleService существует только одна операция, существует только одно определение WS_OPERATION_DESCRIPTION .

...  part of LocalDefinitions structure
{    // array of operations for DefaultBinding_ISimpleService
(WS_OPERATION_DESCRIPTION*)&example_wsdlLocalDefinitions.contracts.DefaultBinding_ISimpleService.SimpleMethod.SimpleMethod,
},    // array of operations for DefaultBinding_ISimpleService
{    // contract description for DefaultBinding_ISimpleService
1,
(WS_OPERATION_DESCRIPTION**)example_wsdlLocalDefinitions.contracts.DefaultBinding_ISimpleService.operations,
WS_HTTP_CHANNEL_BINDING,
},  // end of contract description for DefaultBinding_ISimpleService
},    // DefaultBinding_ISimpleService       ...

Обработка wsdl:service

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

WsUtil.exe поддерживает расширения EndpointReference, определенные в wsdl:port. Ссылка на конечную точку определяется в WS-ADDRESSING как способ описания сведений о конечной точке службы. Текст расширения ссылки на входную конечную точку, сохраненный как WS_XML_STRING, вместе с соответствующими WS_ENDPOINT_ADDRESS_DESCRIPTION создается в разделе endpointReferences в глобальной структуре.

<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://Example.org" 
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" targetNamespace="http://Example.org" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
 <wsdl:service name="SimpleService">
  <wsdl:port name="ISimpleService" binding="tns:DefaultBinding_ISimpleService">
   <soap:address location="http://Example.org/ISimpleService" />
   <wsa:EndpointReference>
    <wsa:Address>http://example.org/wcfmetadata/WSHttpNon</wsa:Address>
   </wsa:EndpointReference> 
  </wsdl:port>
 </wsdl:service>
</wsdl:definitions>
  const _example_wsdl example_wsdl =
  {
  ... // global element description
  {// messages
  {    // message description for ISimpleService_SimpleMethod_InputMessage
  (WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings.ISimpleService_SimpleMethod_InputMessageactionName,
  (WS_ELEMENT_DESCRIPTION*)&example_wsdl.globalElements.SimpleMethod,
},    // message description for ISimpleService_SimpleMethod_InputMessage
{    // message description for ISimpleService_SimpleMethod_OutputMessage
(WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings.ISimpleService_SimpleMethod_OutputMessageactionName,
  (WS_ELEMENT_DESCRIPTION*)&example_wsdl.globalElements.SimpleMethodResponse,
},    // message description for ISimpleService_SimpleMethod_OutputMessage
}, // messages
{// contracts
{   // DefaultBinding_ISimpleService
1,
(WS_OPERATION_DESCRIPTION**)example_wsdlLocalDefinitions.contracts.DefaultBinding_ISimpleService.operations,
WS_HTTP_CHANNEL_BINDING,
},    // end of DefaultBinding_ISimpleService
    }, // contracts
    {
        {
            {   // endpointAddressDescription
                WS_ADDRESSING_VERSION_0_9,
            },                    
            (WS_XML_STRING*)&xml_string_generated_in_stub // endpointReferenceString
        }, //DefaultBinding_ISimpleService
    }, // endpointReferences
}

Чтобы создать WS_ENDPOINT_ADDRESS с помощью созданных метаданных WsUtil, выполните следующие действия.

WsCreateReader      // Create a WS_XML_READER
Initialize a WS_XML_READER_BUFFER_INPUT
WsSetInput          // Set the encoding and input of the reader to generate endpointReferenceString
WsReadType        // Read WS_ENDPOINT_ADDRESS from the reader
    // Using WS_ELEMENT_TYPE_MAPPING, WS_ENDPOINT_ADDRESS_TYPE and generated endpointAddressDescription, 

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

... // dictionary part of LocalDefinitions structure
{    // xmlStrings
  { // xmlStrings
    WS_XML_STRING_DICTIONARY_VALUE("a",&example_wsdlLocalDefinitions.dictionary.dict, 0), 
    WS_XML_STRING_DICTIONARY_VALUE("http://Sapphire.org",&example_wsdlLocalDefinitions.dictionary.dict, 1), 
    WS_XML_STRING_DICTIONARY_VALUE("b",&example_wsdlLocalDefinitions.dictionary.dict, 2), 
    WS_XML_STRING_DICTIONARY_VALUE("SimpleMethod",&example_wsdlLocalDefinitions.dictionary.dict, 3),
    ...
  },  // end of xmlStrings
  {   // SimpleServicedictionary
    // 45026280-d5dc-4570-8195-4d66d13bfa34
    { 0x45026280, 0xd5dc, 0x4570, { 0x81, 0x95, 0x4d,0x66, 0xd1, 0x3b, 0xfa, 0x34 } },
    (WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings,
    stringCount,
    TRUE,
  },
}
...

Обработка wsdl:type

Wsutil.exe поддерживает только документы СХЕМЫ XML (XSD) в спецификации wsdl:type. Одним из особых случаев является то, что порт сообщения задает определение глобального элемента. Дополнительные сведения об эвристиках, используемых в этих случаях, см. в следующем разделе.

Эвристика обработки параметров

В модели службы сообщения WSDL сопоставляются с определенными параметрами в методе. Wsutil.exe имеет два стиля создания параметров: в первом стиле операция имеет один параметр для входного сообщения, а один параметр для выходного сообщения (при необходимости); во втором стиле Wsutil.exe использует эвристика для сопоставления и расширения полей в структурах для входных сообщений и выходных сообщений с разными параметрами в операции. Входные и выходные сообщения должны иметь элементы сообщения типа структуры для создания этого второго подхода.

Wsutil.exe использует следующие правила при создании параметров операции из входных и выходных сообщений:

  • Для входных и выходных сообщений с несколькими частями сообщения каждая часть сообщения является отдельным параметром в операции с именем части сообщения в качестве имени параметра.
  • Для сообщения стиля RPC с одной частью сообщения часть сообщения является параметром в операции с именем части сообщения в качестве имени параметра.
  • Для входных и выходных сообщений в стиле документа с одной частью сообщения:
    • Если имя части сообщения — "параметры", а тип элемента является структурой, каждое поле в структуре рассматривается как отдельный параметр с именем поля, являющегося именем параметра.
    • Если имя части сообщения не является "параметрами", сообщение является параметром в операции с именем сообщения, используемым в качестве соответствующего имени параметра.
  • Для входных и выходных сообщений стиля документа с неиллируемым элементом сообщение сопоставляется с одним параметром с именем части сообщения в качестве имени параметра. Добавляется один дополнительный уровень косвенного обращения, чтобы указать, что указатель может иметь значение NULL.
  • Если поле отображается только в элементе входного сообщения, поле рассматривается как параметр [in].
  • Если поле отображается только в элементе выходного сообщения, поле рассматривается как параметр [out].
  • Если есть поле с одинаковым именем и тем же типом, которое отображается как в входном сообщении, так и в выходном сообщении, поле обрабатывается как параметр [in,out].

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

  • Если поле отображается только в элементе входного сообщения, поле обрабатывается как только в параметре.
  • Если поле отображается только в элементе выходного сообщения, поле обрабатывается только как исходящий параметр.
  • Если есть поле с одинаковым именем и тем же типом, которое отображается как в входном сообщении, так и в выходном сообщении, поле рассматривается как параметр in,out.

Wsutil.exe поддерживает только последовательность элементов. Он отклоняет недопустимое упорядочение в отношении параметров [in,out], если Wsutil.exe не может объединить параметры в параметрах и вне в один список параметров. Суффиксы могут быть добавлены в имена параметров, чтобы избежать конфликтов имен.

<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://Example.org" 
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" targetNamespace="http://Example.org" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
 <wsdl:message name="ISimpleService_SimpleMethod_InputMessage">
  <wsdl:part name="parameters" element="tns:SimpleMethod" />
 </wsdl:message>
 <wsdl:message name="ISimpleService_SimpleMethod_OutputMessage">
  <wsdl:part name="parameters" element="tns:SimpleMethodResponse" />
 </wsdl:message>
</wsdl:definitions>

Wsutil.exe рассматривает поля в tns:SimpleMethod и tns:SimpleMethodResponse ato, как показано в определениях параметров ниже:

<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://Example.org" 
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" targetNamespace="http://Example.org" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
 <wsdl:types>
  <xs:schema xmlns:tns="http://Example.org" elementFormDefault="qualified" 
  targetNamespace="http://Example.org" xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <xs:import namespace="http://Example.org" />
   <xs:element name="SimpleMethod">
    <xs:complexType>
     <xs:sequence>
      <xs:element name="a" type="xs:unsignedInt" />
      <xs:element name="b" type="xs:unsignedInt" />
     </xs:sequence>
    </xs:complexType>
   </xs:element>
   <xs:element name="SimpleMethodResponse">
    <xs:complexType>
     <xs:sequence>
      <xs:element name="b" type="xs:unsignedInt" />
      <xs:element name="c" type="xs:unsignedInt" />
     </xs:sequence>
    </xs:complexType>
   </xs:element>
  </xs:schema>
 </wsdl:types>
</wsdl:definitions>

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

typedef struct SimpleMethodParamStruct {
  unsigned int   a;  
  unsigned int   b;
  unsigned int   c;
} ;

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

  // following are local definitions for the complex type
  { // field description for a
  WS_ELEMENT_FIELD_MAPPING,
  (WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings.aLocalName,
(WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings.aNamespace,
  WS_INT32_TYPE,
  0,
  WsOffsetOf(_SimpleMethod, a),
  0,
  0,
  },    // end of field description for a
  { // field description for b
  WS_ELEMENT_FIELD_MAPPING,
  (WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings.bLocalName,
(WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings.aNamespace,
  WS_INT32_TYPE,
  0,
  WsOffsetOf(_SimpleMethod, b),
  0,
  0,
  },    // end of field description for b
  {    // fields description for _SimpleMethod
  (WS_FIELD_DESCRIPTION *)&example_wsdlLocalDefinitions.globalElements.SimpleMethod._SimpleMethoddescs.a,
  (WS_FIELD_DESCRIPTION *)&example_wsdlLocalDefinitions.globalElements.SimpleMethod._SimpleMethoddescs.b,
  },
  {  // structure definition
  sizeof(_SimpleMethod),
  __alignof(_SimpleMethod),
  (WS_FIELD_DESCRIPTION**)&example_wsdlLocalDefinitions.globalElements.SimpleMethod._SimpleMethoddescs._SimpleMethodFields,
  WsCountOf(example_wsdlLocalDefinitions.globalElements.SimpleMethod._SimpleMethoddescs._SimpleMethodFields),
  (WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings._SimpleMethodTypeName,
(WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings.aNamespace,
  0,
  },   // struct description for _SimpleMethod
  // following are global definitions for the out parameter
  ...
  {  // element description
  (WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings._SimpleMethodTypeName,
  (WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings.aNamespace,
  WS_STRUCT_TYPE,
  (void *)&example_wsdlLocalDefinitions.globalElements.SimpleMethod._SimpleMethoddescs.structDesc,
  },
  {    // message description for ISimpleService_SimpleMethod_InputMessage
  (WS_XML_STRING*)&example_wsdlLocalDefinitions.dictionary.xmlStrings.ISimpleService_SimpleMethod_InputMessageactionName,
(WS_ELEMENT_DESCRIPTION*)&example_wsdl.globalElements.SimpleMethod,
  },    // message description for ISimpleService_SimpleMethod_InputMessage

Как правило, для всех параметров [out] и [in,out] добавляется один уровень косвенного обращения.

Операция без параметров

Для операций с документами и литеральными операциями Wsutil.exe обрабатывает операцию как один входной параметр и один выходной параметр, если:

  • Входное или выходное сообщение имеет несколько частей.
  • Существует только одна часть сообщения, а имя части сообщения не является "параметрами".

.. В приведенном выше примере предполагается, что части сообщения называются ParamIn и ParamOut, подпись метода становится следующим кодом:

typedef struct SimpleMethod{
unsigned int a;
unsigned int b;
};

typedef struct SimpleMethodResponse {
unsigned int b;
unsigned int c;
};

typedef  struct ISimpleService_SimpleMethodParamStruct
{
SimpleMethod  * SimpleMethod;
SimpleMethodResponse  * SimpleMethodResponse;
} ISimpleService_SimpleMethodParamStruct;

Wsutil.exe создает сигнатуру версии для описания операции, чтобы подсистема модели WsCall и серверная модель службы могли проверка, если созданное описание применимо для текущей платформы.

Эта информация о версии создается как часть структуры WS_OPERATION_DESCRIPTION. Номер версии можно рассматривать как селектор руки объединения, чтобы сделать структуру расширяемой. В настоящее время идентификатор версии имеет значение 1 без последующих полей. Будущий versiosn может увеличить номер версии и включить дополнительные поля по мере необходимости. Например, Wsutil.exe в настоящее время создает следующий код на основе идентификатора версии:

{ // SimpleMethod
{ // parameter descriptions for SimpleMethod
{ WS_PARAMETER_TYPE_NORMAL, (USHORT)0, (USHORT)-1 },
{ WS_PARAMETER_TYPE_NORMAL, (USHORT)1, (USHORT)-1 },
{ WS_PARAMETER_TYPE_NORMAL, (USHORT)-1, (USHORT)1 },
},    // parameter descriptions for SimpleMethod
{    // operation description for SimpleMethod
1,
(WS_MESSAGE_DESCRIPTION*)&example_wsdl.messages.ISimpleService_SimpleMethod_InputMessage,
(WS_MESSAGE_DESCRIPTION*)&example_wsdl.messages.ISimpleService_SimpleMethod_OutputMessage,
3,
(WS_PARAMETER_DESCRIPTION*)example_wsdlLocalDefinitions.contracts.DefaultBinding_ISimpleService.SimpleMethod.params,
SimpleMethodOperationStub
}, //operation description for SimpleMethod
},  // SimpleMethod

В будущем его можно расширить следующим образом:

WS_OPERATION_DESCRIPTION simpleMethodOperationDesc =
{
  2,
  &ISimpleService_SimpleMethod_InputputMessageDesc,
  &ISimpleService_SimpleMethod_OutputMessageDesc,
  WsCountOf(SimpleMethodParameters),
  SimpleMethodParameters,
  ISimpleService_SimpleMethod_Stub,
  &forwardToString;   // just as an example.
};

Безопасность

См. раздел безопасности в разделе средства компилятора Wsutil.