次の方法で共有


WSDL とサービス コントラクト

Wsutil.exe ユーティリティは、指定された WSDL メタデータ、およびユーザーが作成した XML スキーマによって記述されるデータ型の定義と説明に従って C 言語スタブを生成します。

以下は、以下のディスカッションの基礎として機能する 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>

この例では、1 つのメソッド SimpleMethod を使用してコントラクト ISimpleService を提供します。 "SimpleMethod" には、クライアントからサービスに送信される整数型、ab の 2 つの入力パラメーターがあります。 同様に、SimpleMethod には、成功した後にクライアントに返される整数型、bc の 2 つの出力パラメーターがあります。 SAL 注釈付き 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 データ構造。

アプリケーションが参照できるスキーマ型とサービス モデル型のすべてのグローバル記述をカプセル化するために、1 つのグローバル構造が生成されます。 構造体には、正規化されたファイル名を使用して名前が付けられます。 この例では、Wsutil.exe は、すべての Web サービスの説明を含む "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) のグローバル要素定義の場合、1 つの 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 フィールドとして生成されます。

操作と型の仕様は、プロキシとスタブの両方に共通であり、両方のファイルで生成されます。 Wsutil.exe では、プロキシとスタブの両方が同じファイルに生成されている場合にのみ、1 つのコピーが生成されます。

識別子の生成

上記の自動生成された C 構造体は、WSDL ファイルで指定された名前に基づいて作成されます。 XML NCName は一般的に有効な C 識別子とは見なされず、必要に応じて名前が正規化されます。 16 進値は変換されず、読みやすくするために、':'、'/'、'.' などの共通文字がアンダースコア '_' 文字に変換されます。

スタブのヘッダー

サービス コントラクト内の操作ごとに、"<operationname>Callback" という名前のコールバック ルーチンが 1 つ生成されます。 (たとえば、サービス コントラクトの例の操作 "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;
};

プロキシ プロトタイプはすべての操作に対して生成されます。 プロトタイプ名は、サービス コントラクトの 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 );

ローカルのみの説明プロトタイプの生成

プロキシファイルとスタブファイルには、ローカルのみの説明とクライアント プロキシ/サービス スタブの実装を含む構造体のプロトタイプと定義など、グローバル定義構造の定義が含まれています。

スタブ ファイルに対してローカルなプロトタイプと定義はすべて、カプセル化構造の一部として生成されます。 この包括的なローカル記述構造は、シリアル化レイヤーとサービス モデルで必要な説明の明確な階層を提供します。 ローカル記述構造には、次に示すようなプロトタイプがあります:

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 フィールドは 1 つだけです。 要素型が構造体の場合、関連するすべてのフィールドと構造体の説明が要素構造の一部として生成されます。 この例では、SimpleMethod 要素は、ab の 2 つのフィールドを含む構造体です。 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 は、操作に必要なすべての説明を含む 1 つのフィールド f、各メソッドの各操作の説明へのポインターの符号付き配列、および指定された portType の 1 つのWS_CONTRACT_DESCRIPTION を生成します。

操作に必要なすべての説明は、指定された portTypeoperationName フィールド内に生成されます。 これには、 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 操作のクライアント プロキシ

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 は、すべてのローカルのみの定義を含む *<service_name>*Local 型の *<file_name>*LocalDefinitions という名前の定数静的 (const static) 構造体を生成します。

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

次の WSDL の説明がサポートされていますa:

  • 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 はそのファイル内のグローバルに定義された構造体への参照を生成します。 たとえば、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 では、SOAP 1.2 仕様の WSDL 1.1 バインド拡張機能に従って、ドキュメント スタイルと RPC スタイルの操作がサポートされています。 RPC およびリテラル スタイルの操作は、WS_RPC_LITERAL_OPERATION としてマークされます。 サービス モデルは、RPC/リテラル操作の応答本文ラッパー要素の名前を無視します。

Wsutil.exe は、エンコード スタイルの操作をネイティブにサポートしていません。 メッセージをエンコードするために WS_XML_BUFFER パラメーターが生成され、開発者は不透明バッファーを直接設定する必要があります。

複数のメッセージ パーツのサポート

Wsutil.exe では、1 つのメッセージ内の複数のメッセージ部分がサポートされます。 マルチパート メッセージは、次のように指定できます:

<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 は、前に説明したように関数テーブルの操作を参照するために使用されます。 また、すべての操作によってスタブ関数が生成され、実際のメソッドへのデリゲートの代わりに インフラストラクチャー が呼び出されます。

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 操作の入力メッセージと出力メッセージのメッセージ部分を名前付きパラメーターとして含む拡張引数リストがあることに注意してください。

クライアント側では、各操作はプロキシ サービス操作にマップされます。

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 は 1 つだけです。 指定された SOAP バインディングは、WS_HTTP_BINDINGとして指定される HTTP トランスポートを示します。 この構造体は、アプリケーションで使用できる必要があるため、静的装飾を持たないことに注意してください。

wsdl:portType の処理

WSDL の各 portType は、1 つ以上の操作で構成されます。 この操作は、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 操作が 1 つだけ存在するバインディング セクションと一致します。

ISimpleService portType には -- SimpleMethod -- という 1 つの操作しかないため、対応する関数テーブルにはサービス操作として SimpleMethod のみが含まれます。

メタデータの観点からすると、各 portType は Wsutil.exe によって WS_CONTRACT_DESCRIPTION にマップされます。 portType 内の各操作は、WS_OPERATION_DESCRIPTION にマップされます。

この例では、portType ツールによって ISimpleService の WS_CONTRACT_DESCRIPTION が生成されます。 このコントラクトの説明には、ISimpleService portType で使用できる特定の数の操作と、ISimpleService の portType で定義された個々の操作を表す WS_OPERATION_DESCRIPTION の配列が含まれています。 ISimpleService の ISimpleService portType に対する操作は 1 つだけなので、WS_OPERATION_DESCRIPTION 定義も 1 つだけ存在します。

...  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 では、wsdl:port で定義されている EndpointReference 拡張機能がサポートされています。 エンドポイント参照は、サービスの エンドポイント 情報 記述する方法として 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
}

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, 

クライアント プロキシまたはサービス スタブの定数文字列は、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 では、wsdl:type 仕様の XML スキーマ (XSD) ドキュメントのみがサポートされます。 特殊なケースの 1 つは、メッセージ ポートがグローバル要素定義を指定する場合です。 このような場合に使用されるヒューリスティックの詳細については、次のセクションを参照してください。

パラメーター処理ヒューリスティック

サービス モデルでは、WSDL メッセージはメソッド内の特定のパラメーターにマップされます。 Wsutil.exe には、パラメーター生成の 2 つのスタイルがあります。最初のスタイルでは、操作には入力メッセージ用のパラメーターが 1 つ、出力メッセージ用のパラメーターが 1 つあります (必要な場合)。2 番目のスタイルでは、Wsutil.exe はヒューリスティックを使用して、入力メッセージと出力メッセージの両方の構造体内のフィールドを操作内の異なるパラメーターにマップおよび展開します。 この 2 つ目の方法を生成するには、入力メッセージと出力メッセージの両方に構造体型のメッセージ要素が必要です。

Wsutil.exe は、入力メッセージと出力メッセージから操作パラメーターを生成するときに、次の規則を使用します:

  • 複数のメッセージ部分を含む入力メッセージと出力メッセージの場合、各メッセージ 部分は操作内の個別のパラメーターであり、メッセージ パーツ名はパラメーター名です。
  • 1 つのメッセージ 部分を含む RPC スタイルのメッセージの場合、メッセージ パーツは操作のパラメーターであり、メッセージ パーツ名はパラメーター名です。
  • 1 つのメッセージ部分を含むドキュメント スタイルの入力メッセージと出力メッセージの場合:
    • メッセージ 部分の名前が "parameters" で、要素型が構造体の場合、構造体内の各フィールドは個別のパラメーターとして扱われ、フィールド名はパラメーター名になります。
    • メッセージ部分名が "parameters" でない場合、メッセージは、対応するパラメーター名として使用されるメッセージ名を持つ操作のパラメーターです。
  • nillable 要素を持つドキュメント スタイルの入力メッセージと出力メッセージの場合、メッセージは 1 つのパラメーターにマップされ、メッセージ パーツ名はパラメーター名になります。 ポインターを NULL にできることを示すために、追加の間接参照レベルが 1 つ追加されます。
  • 入力メッセージ要素にのみフィールドが表示される場合、フィールドは [in] パラメーターとして扱われます。
  • 出力メッセージ要素にのみフィールドが表示される場合、フィールドは [out] パラメーターとして扱われます。
  • 入力メッセージと出力メッセージの両方に同じ名前と同じ型のフィールドがある場合、フィールドは [in,out] パラメーターとして扱われます。

パラメーターの方向を決定するには、次のツールを使用します:

  • 入力メッセージ要素にのみフィールドが表示される場合、フィールドはパラメーターとしてのみ扱われます。
  • フィールドが出力メッセージ要素にのみ表示される場合、フィールドは出力専用のパラメーターとして扱われます。
  • 入力メッセージと出力メッセージの両方に同じ名前と同じ型のフィールドがある場合、フィールドは in,out パラメーターとして扱われます。

Wsutil.exe では、シーケンスされた要素のみがサポートされます。 Wsutil.exe が in パラメーターと out パラメーターを 1 つのパラメーター リストに結合できない場合、[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] パラメーターに対して 1 レベルの間接参照が追加されます。

パラメーターなしの操作

ドキュメント操作とリテラル操作の場合、Wsutil.exe は操作を次の場合に 1 つの入力パラメーターと 1 つの出力パラメーターを持つものとして扱います:

  • 入力メッセージまたは出力メッセージには、複数の部分があります。
  • メッセージ部分は 1 つだけで、メッセージ パーツ名は "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 に設定され、後続のフィールドはありません。 将来のバージョンでは、バージョン番号が増加して、必要に応じてより多くのフィールドを含めることができます。 たとえば、Wsutil.exe は現在、バージョン ID に基づいて次のコードを生成します:

{ // 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.
};

Security

Wsutil Compiler ツール のトピックの「セキュリティ」セクションを参照してください。