共用方式為


WSDL 和服務合約

Wsutil.exe 公用程式會根據提供的 WSDL 中繼資料產生 C 語言存根,以及使用者撰寫的 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 有兩個類型 為 integer c 的輸出參數,在成功完成之後會傳回給用戶端。 在 SAL 批註 C 語法中,方法定義如下所示:

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

在此定義中,ISimpleService 是具有單一服務作業的服務合約:SimpleMethod。

輸出標頭檔包含外部參考的定義和描述。 這包括:

系統會產生一個全域結構,以封裝應用程式可以參考之架構類型和服務模型類型的所有全域描述。 結構是使用標準化檔案名來命名。 在此範例中,Wsutil.exe 會產生名為 「example_wsdl」 的全域定義結構,其中包含所有 Web 服務描述。 結構定義會在存根檔案中產生。

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 型別結構定義,而不會比對專案描述。

針對 WSDL 輸入,Wsutil.exe 會產生下列原型和定義:

  • 訊息 描述會產生WS_MESSAGE_DESCRIPTION 原型。 此描述可供服務模型和訊息層使用。 訊息描述結構是全域結構中名為 「messagename」 的欄位。 在此範例中,訊息描述會產生為 WSDL 檔案中所指定之ISimpleService_SimpleMethod_InputMessage結構中的ISimpleService_SimpleMethod_InputMessage欄位。
  • WS_CONTRACT_DESCRIPTION產生合約描述的原型。 服務模型會使用此描述。 合約描述結構是全域結構中名為 「contractname」 的欄位。 在此範例中,合約描述會產生為 「_example_wsdl」 結構中的DefaultBinding_ISimpleService欄位。

作業和類型規格對 Proxy 和存根都是常見的,而且會在這兩個檔案中產生。 只有在 Proxy 和存根都在同一個檔案中產生時,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;
};

所有作業都會產生 Proxy 原型。 原型名稱是服務合約的 WSDL 檔案中指定的作業名稱(在此案例中為 「SimpleMethod」。

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

僅限本機描述原型產生

Proxy 和stub 檔案包含全域定義結構的定義,包括包含僅限本機描述的結構原型和定義,以及用戶端 Proxy/服務存根實作。

存根檔案本機的所有原型和定義都會產生為封裝結構的一部分。 這個整體的本機描述結構提供序列化層和服務模型所需的描述清楚階層。 本機描述結構具有類似如下所示的原型:

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;

從其他檔案參考定義

本機定義可以參考另一個檔案中產生的描述。 例如,訊息可能定義于從 WSDL 檔案產生的 C 程式碼檔案中,但訊息元素可能定義于從 XSD 檔案產生的 C 程式碼檔案中其他地方。 在此情況下,Wsutil.exe 會從包含訊息定義的檔案產生全域專案的參考,如下所示:

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

全域專案描述

針對 wsdl:type 或 XSD 檔案中定義的每個全域元素,GlobalElement 欄位內會有名為 elementName 相符欄位。 在此範例中,會產生名為 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:service 下定義的每個 portType 值,在 WSDL 區段下產生欄位。

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

Wsutil.exe 會產生一個欄位 f,其中包含作業所需的所有描述、每個方法每個作業描述的指標符號陣列,以及指定 portType 的一個 WS_CONTRACT_DESCRIPTION

作業所需的所有描述都會在 指定 portType 下的 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 欄位(在下列範例中命名 的 dict )會產生為 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 作業的用戶端 Proxy

Wsutil.exe 會為所有作業產生用戶端 Proxy。 應用程式可以使用前置詞命令列選項覆寫方法簽章。

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 會產生名為 *file_name*LocalDefinitions 之類型 * << service_name >> *Local 的常數靜態 ( const static ) 結構,其中包含所有本機唯一定義。

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>

輸入和輸出訊息資料元素的配置是由工具評估,以產生基礎結構的序列化中繼資料,以及與輸入和輸出訊息相關聯之結果服務作業的實際簽章。

特定 portType 內每個作業的中繼資料都有輸入,並選擇性地輸出訊息,每個訊息都會對應至 WS_MESSAGE_DESCRIPTION 。 在此範例中,portType 中作業的輸入和輸出訊息會分別對應至 inputMessageDescription,以及選擇性 地WS_OPERATION_DESCRIPTION上的 outputMessageDescription。

針對每個 WSDL 訊息,此工具會產生 參考WS_ELEMENT_DESCRIPTION 定義的WS_MESSAGE_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 就會產生該檔案中全域定義結構的參考。 例如,如果在另一個 example.xsd 檔案中定義 SimpleMethodResponse,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 根據 SOAP 1.2 規格的 WSDL 1.1 系結延伸模組,支援檔樣式和 RPC 樣式作業。 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 規格所示。

在伺服器端,每個作業都會產生結果伺服器服務作業的 typedef。 此 typedef 可用來參考函式資料表中的作業,如先前所述。 每個作業也會產生存根函式,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 作業,上述定義 SimpleMethodOperation typedef。 請注意,產生的方法具有展開的引數清單,其中包含 SimpleMethod 作業的輸入和輸出訊息部分做為具名參數。

在用戶端上,每個作業都會對應至 Proxy 服務作業。

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 系結延伸模組。 每個系結都有相關聯的 portType

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 檔案中,ISimpleService 只有一個 portType 。 提供的 SOAP 系結表示 HTTP 傳輸,其指定為 WS_HTTP_BINDING。 請注意,此結構沒有靜態裝飾,因為此結構必須可供應用程式使用。

處理 wsdl:portType

WSDL 中的每個 portType 是由一或多個作業所組成。 作業應該與 wsdl:binding 中所指示的 SOAP 系結延伸模組一致。

<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 portType 只包含 SimpleMethod 作業。 這與系結區段一致,其中只有一個對應至 SOAP 動作的 WSDL 作業。

由於 ISimpleService portType 只有一個作業 -- SimpleMethod -- 對應的函式資料表只包含 SimpleMethod 即服務作業。

就中繼資料而言,每個 portType 都會由 Wsutil.exe 對應至 WS_CONTRACT_DESCRIPTION 。 portType 中的每個作業都會對應至 WS_OPERATION_DESCRIPTION

在此範例中, portType 工具會產生 ISimpleService WS_CONTRACT_DESCRIPTION 。 此合約描述包含 ISimpleService portType 上可用的特定作業數目,以及WS_OPERATION_DESCRIPTION 陣列 ,代表 ISimpleService 之 portType 上定義的個別作業。 由於 ISimpleService 的 ISimpleService portType 上只有一個作業,因此只有一個 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 會使用服務來尋找系結/porttypes,並產生描述類型、訊息、porttype 定義等的合約結構。 合約描述可從外部存取,而且會當做透過產生的標頭所指定之全域定義結構的一部分產生。

WsUtil.exe 支援 wsdl:port 中定義的 EndpointReference 擴充功能。 端點參考定義于 WS-ADDRESSING 中,做為描述 服務端點 資訊的方式。 儲存為 WS_XML_STRING的 輸入端點參考延伸模組文字,以及全域結構的 endpointReferences 區段中會產生相符 的WS_ENDPOINT_ADDRESS_DESCRIPTION

<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
}

若要使用 WsUtil 產生的中繼資料建立 WS_ENDPOINT_ADDRESS

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, 

用戶端 Proxy 或服務存根中的常數位符串會以類型WS_XML_STRING產生,而且 Proxy 或存根檔案中的所有字串都有常數位典。 字典中的每個字串都會產生為本機結構字典部分的欄位,以提升可讀性。

... // 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 僅支援 wsdl:type 規格中的 XML 架構 (XSD) 檔。 其中一個特殊案例是當訊息埠指定全域專案定義時。 如需這些案例中使用的啟發學習法詳細資料,請參閱下一節。

參數處理啟發學習法

在服務模型中,WSDL 訊息會對應至方法中的特定參數。 Wsutil.exe 有兩種參數產生樣式:在第一個樣式中,作業有一個輸入訊息的參數,以及輸出訊息的一個參數(如有必要):在第二個樣式中,Wsutil.exe 會使用啟發學習法,將輸入訊息和輸出訊息結構中的欄位對應並展開至作業中的不同參數。 輸入和輸出訊息都需要有結構類型訊息元素,才能產生這個第二種方法。

從輸入和輸出訊息產生作業參數時,Wsutil.exe 會使用下列規則:

  • 對於具有多個訊息部分的輸入和輸出訊息,每個訊息元件都是作業中的個別參數,訊息部分名稱為參數名稱。
  • 對於具有一個訊息部分的 RPC 樣式訊息,訊息元件是作業中的參數,訊息部分名稱為參數名稱。
  • 對於具有一個訊息部分的檔樣式輸入和輸出訊息:
    • 如果訊息元件的名稱是 「parameters」,而專案類型是 結構,則結構中的每個欄位都會被視為個別參數,而功能變數名稱為參數名稱。
    • 如果訊息元件名稱不是 「parameters」,訊息是作業中的參數,其訊息名稱會當做對應的參數名稱使用。
  • 對於具有 nillable 元素的檔樣式輸入和輸出訊息,訊息會對應至一個參數,並以訊息部分名稱做為參數名稱。 新增一個額外的間接取層級,以指出指標可以是 Null
  • 如果欄位只出現在輸入訊息元素中,則欄位會被視為 [in] 參數。
  • 如果欄位只出現在輸出訊息元素中,欄位會被視為 [out] 參數。
  • 如果輸入訊息和輸出訊息中出現相同名稱和相同類型的欄位,則欄位會被視為 [in,out] 參數。

下列工具可用來判斷參數的方向:

  • 如果欄位只出現在輸入訊息元素中,則欄位只會被視為參數。
  • 如果欄位只出現在輸出訊息元素中,則欄位只會被視為 out 參數。
  • 如果有相同名稱和相同類型出現在輸入訊息和輸出訊息中的欄位,則會將欄位視為 in,out 參數。

Wsutil.exe 僅支援循序專案。 如果 Wsutil.exe 無法將 in 參數和 out 參數合併成單一參數清單,則會拒絕與 [in,out] 參數相關的無效順序。 尾碼可能會新增至參數名稱,以避免名稱衝突。

<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 會將作業視為具有一個輸入參數和一個輸出參數:

  • 輸入或輸出訊息有多個部分。
  • 只有一個訊息部分,而且訊息部分名稱不是 「parameters」。

.. 在上述範例中,假設訊息元件名為 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 結構的一部分 產生。 版本號碼可以視為等位臂選取器,讓結構可延伸。 目前, versionID 設定為 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 Compiler 工具 主題中的 安全性一節。