次の方法で共有


手順 7: エコー アダプターの同期送信ハンドラーを実装する

手順 7/9

完了までの時間: 30 分

この手順では、エコー アダプターの同期送信機能を実装します。 WCF LOB アダプター SDK に従って、同期送信機能をサポートするには、 Microsoft.ServiceModel.Channels.Common.IOutboundHandler インターフェイスを実装する必要があります。 Echo アダプターの場合、アダプター開発ウィザードは、EchoAdapterOutboundHandler という 1 つの派生クラスを自動的に生成します。

以降のセクションでは、EchoAdapterOutboundHandler クラスを更新して、 Microsoft.ServiceModel.Channels.Common.IOutboundHandler.Execute%2Aを実装する方法、受信 WCF 要求メッセージを解析する方法、および送信 WCF 応答メッセージを生成する方法について理解を深めます。

[前提条件]

この手順を開始する前に、「 手順 6: エコー アダプターのメタデータ解決ハンドラーを実装する」を正常に完了している必要があります。 Microsoft.ServiceModel.Channels.Common.IOutboundHandlerに関する基本的な知識も役立ちます。

IOutboundHandler インターフェイス

Microsoft.ServiceModel.Channels.Common.IOutboundHandler は次のように定義されます。

public interface IOutboundHandler : IConnectionHandler, IDisposable  
{  
    Message Execute(Message message, TimeSpan timeout);  
}  

Microsoft.ServiceModel.Channels.Common.IOutboundHandler.Execute%2A メソッドは、ターゲット システムで対応するメソッドを呼び出して受信 WCF 要求メッセージを実行し、送信 WCF 応答メッセージを返します。 パラメーターの定義を次の表に示します。

パラメーター 定義
メッセージ WCF 要求メッセージを受信しました。
タイムアウト この操作を完了する時間間隔。 操作が完了する前に指定したタイムアウトを超えた場合、操作は System.TimeoutException をスローする必要があります。

アダプターが一方向の送信を実行している場合 (アダプターで予期される応答メッセージがない)、このメソッドは null を返す必要があります。 アダプターが Microsoft.ServiceModel.Channels.Common.OperationResult.Empty%2A と等しいMicrosoft.ServiceModel.Channels.Common.OperationResult双方向操作を実行している場合、このメソッドは空の本文を含む WCF 応答メッセージを返します。 それ以外の場合は、 Microsoft.ServiceModel.Channels.Common.OperationResult オブジェクトの値を含む本文を含む WCF 応答メッセージを返す必要があります。 応答アクション文字列を作成するには、 Microsoft.ServiceModel.Channels.Common.OperationMetadata.OutputMessageAction%2Aを使用します。

エコー アダプター同期送信

ターゲット システムの操作に応じて、 Microsoft.ServiceModel.Channels.Common.IOutboundHandler.Execute%2A メソッドを実装する方法は多数あります。 エコー アダプターの場合、3 つの送信操作があり、割り当てられたノード ID と表示名は次のとおりです。

  • string[] EchoStrings(string data), node ID = Echo/EchoString, display name=EchoString

  • Greeting[] EchoGreetings(Greeting greeting), node ID=Echo/EchoGreetings, display name=EchoGreetings

  • カスタム挨拶 EchoCustomGreetingFromFile(Uri greetingInstancePath), nodeID=Echo/EchoCustomGreetingFromFile、表示名=EchoGreetings

    受信 WCF 要求メッセージを正しく解析し、送信 WCF 応答メッセージを生成するには、WCF LOB アダプター SDK で使用される SOAP メッセージ内の次の要素を理解している必要があります。

    受信 WCF 要求メッセージの場合:

  • WCF 入力メッセージ アクション = 操作のノード ID

  • 受信メッセージ本文 = 本文の開始要素は、 <displayname><パラメーター名>{data}</パラメーター名></displayname です。>

    送信される WCF 応答メッセージの場合:

  • WCF 出力メッセージ アクション = 操作のノード ID + "/response"

  • 送信メッセージ本文 = 本文の開始要素は、 <displayname + "Response">、その後に <displayname + "Result">、その後に <datatype>data</datatype></displayname+"Result></displayname + "Response" です。>

    たとえば、operation string[] EchoStrings(string data)、node ID = Echo/EchoStrings、display name= EchoStrings:

    WCF 入力メッセージ アクション = "Echo/EchoStrings";パラメーター名が dataされているため、入力本文は次のようになります。

<EchoStrings>  
<data>{data}  
</data>  
</EchoStrings>  

WCF 出力メッセージ アクション = "Echo/EchoStrings/response";データ型が 文字列であるため、出力本文は次のようになります。

<EchoStringsResponse>  
<EchoStringsResult>  
<string>{data}</string>  
</EchoStringsResult>  
</EchoStringsResponse>  

受信 WCF 要求メッセージを解析するときは、 System.Xml.XmlDictionaryReader を使用して WCF メッセージ内のコンテンツを取得できます。WCF 応答メッセージを作成するときは、 System.Xml.XmlWriter を使用してこれを行うことができます。

IOutboundHandler の実装

Microsoft.ServiceModel.Channels.Common.IOutboundHandlerの Execute メソッドを実装します。 まず、入力メッセージ アクションに基づいて Microsoft.ServiceModel.Channels.Common.OperationMetadata オブジェクトを取得します。 次に、受信 WCF メッセージを解析し、各操作に基づいて関連付けられているエコー機能を実行します。 最後に、送信メッセージ本文の形式を使用して、送信 WCF 応答メッセージを作成します。

EchoAdapterOutboundHandler クラスの Execute メソッドを実装するには

  1. ソリューション エクスプローラーで、 EchoAdapterOutboundHandler.cs ファイルをダブルクリックします。

  2. Visual Studio エディターで、次の 2 つの using ディレクティブを既存の using ディレクティブセットに追加します。

    using System.Xml;  
    using System.IO;  
    
  3. Execute メソッド内で、既存のロジックを次のように置き換えます。

    1. このロジックは、要求された操作を検証します。

    2. SOAP 入力メッセージ アクションに基づいて Microsoft.ServiceModel.Channels.Common.OperationMetadata オブジェクトを取得します。

    3. アクションの種類に基づいて、WCF 要求メッセージを解析し、適切な操作を呼び出します。

    // Trace input message  
    EchoAdapterUtilities.Trace.Trace(System.Diagnostics.TraceEventType.Verbose, "http://Microsoft.Adapters.Samples.Sql/TraceCode/InputWcfMessage", "Input WCF Message", this, new MessageTraceRecord(message));  
    // Timeout is not supported in this sample  
    OperationMetadata om = this.MetadataLookup.GetOperationDefinitionFromInputMessageAction(message.Headers.Action, timeout);  
    if (om == null)  
    {  
        throw new AdapterException("Invalid operation metadata for " + message.Headers.Action);  
    }  
    if (timeout.Equals(TimeSpan.Zero))  
    {  
        throw new AdapterException("time out is zero");  
    }  
    
    switch (message.Headers.Action)  
    {  
        case "Echo/EchoStrings":  
            return ExecuteEchoStrings(om as ParameterizedOperationMetadata, message, timeout);  
    
        case "Echo/EchoGreetings":  
            return ExecuteEchoGreetings(om as ParameterizedOperationMetadata, message, timeout);  
    
        case "Echo/EchoCustomGreetingFromFile":  
            return ExecuteEchoCustomGreetingFromFile(om, message, timeout);  
    }  
    return null;              
    
  4. 次に 、ExecuteEchoStrings メソッドを追加して、string[] EchoStrings(string data) 操作を処理します。 このヘルパー関数は WCF 要求メッセージを読み取り、echoInUpperCase URI 要素が true に設定されているかどうかを確認します。その場合は、count 変数が示す回数の入力文字列を大文字に変換します。 次に、><EchoStringsResponse><EchoStringResponse><string>{data}</string></EchoStringResult></EchoStringsResponse> の形式で WCF 応答メッセージを生成します。

    private Message ExecuteEchoStrings(ParameterizedOperationMetadata om, Message message, TimeSpan timeout)  
    {  
        // ** Read the WCF request  
        // ** <EchoStrings><name>{text}</name></EchoStrings>  
        XmlDictionaryReader inputReader = message.GetReaderAtBodyContents();  
        while (inputReader.Read())  
        {  
            if ((String.IsNullOrEmpty(inputReader.Prefix) && inputReader.Name.Equals("data"))  
                || inputReader.Name.Equals(inputReader.Prefix + ":" + "data")) break;  
        }  
        inputReader.Read();  
        // if the connection property "echoInUpperCase" is set to true, it echoes the data in upper case  
        bool echoInUpperCase = this.Connection.ConnectionFactory.ConnectionUri.EchoInUpperCase;  
        string inputValue = echoInUpperCase ? inputReader.Value.ToUpper() : inputReader.Value;  
        int arrayCount = this.Connection.ConnectionFactory.Adapter.Count;  
    
        // ** Generate the WCF response  
        // ** <EchoStringsResponse><EchoStringResult>{Name}</EchoStringResult></EchoStringsResponse >  
        StringBuilder outputString = new StringBuilder();  
        XmlWriterSettings settings = new XmlWriterSettings();  
        settings.OmitXmlDeclaration = true;  
        XmlWriter replywriter = XmlWriter.Create(outputString, settings);  
        replywriter.WriteStartElement(om.DisplayName + "Response", EchoAdapter.SERVICENAMESPACE);  
        replywriter.WriteStartElement(om.DisplayName + "Result", EchoAdapter.SERVICENAMESPACE);  
        if (om.OperationResult.IsArray)  
        {  
            for (int count = 0; count < arrayCount; count++)  
            {  
                replywriter.WriteElementString("string", "http://schemas.microsoft.com/2003/10/Serialization/Arrays", inputValue);  
            }  
        }  
        replywriter.WriteEndElement();  
        replywriter.WriteEndElement();  
        replywriter.Close();  
        XmlReader replyReader = XmlReader.Create(new StringReader(outputString.ToString()));  
        return Message.CreateMessage(message.Version, om.OutputMessageAction, replyReader);  
    }  
    
  5. 続行するには 、EchoGreetings 操作を処理する ExecuteEchoGreetings メソッドを追加します。 このヘルパー関数は、WCF 要求メッセージを読み取り、Microsoft.ServiceModel.Channels.Common.IMetadataResolverHandler インターフェイスのResolveOperationMetadataメソッドとResolveTypeMetadata メソッドによる操作と型を解決し、次の形式を使用して WCF 応答メッセージを生成します: <EchoGreetingsResponse><EchoGreetingsResult>...message...</EchoGreetingsResult></EchoGreetingsResponse>。

    private Message ExecuteEchoGreetings(ParameterizedOperationMetadata om, Message message, TimeSpan timeout)  
    {  
        // NOTE this method doesn't return response in upper case based on   
        // connection property echoInUpperCase  
    
        // ** Read the WCF request  
        String inputValue = String.Empty;  
        using (XmlDictionaryReader inputReader = message.GetReaderAtBodyContents())  
        {  
    
            bool foundGreeting = inputReader.ReadToDescendant("greeting");  
            if (foundGreeting)  
            {  
                inputValue = inputReader.ReadInnerXml();  
            }  
        }  
    
        int arrayCount = this.Connection.ConnectionFactory.Adapter.Count;  
    
        // ** Generate the WCF response  
        StringBuilder outputString = new StringBuilder();  
        XmlWriterSettings settings = new XmlWriterSettings();  
        settings.OmitXmlDeclaration = true;  
        XmlWriter replywriter = XmlWriter.Create(outputString, settings);  
        replywriter.WriteStartElement(om.DisplayName + "Response", EchoAdapter.SERVICENAMESPACE);  
        replywriter.WriteStartElement(om.DisplayName + "Result", EchoAdapter.SERVICENAMESPACE);  
        for(int i = 0; i < arrayCount; i++ )  
        {  
            ComplexQualifiedType cqtResult = om.OperationResult.QualifiedType as ComplexQualifiedType;  
            StructuredTypeMetadata tmResult = MetadataLookup.GetTypeDefinition(cqtResult.TypeId, timeout) as StructuredTypeMetadata;  
            replywriter.WriteStartElement(tmResult.TypeName, tmResult.TypeNamespace);  
            replywriter.WriteRaw(inputValue);  
            replywriter.WriteEndElement();  
        }  
        replywriter.WriteEndElement();  
        replywriter.WriteEndElement();  
        replywriter.Close();  
        XmlReader replyReader = XmlReader.Create(new StringReader(outputString.ToString()));  
        return Message.CreateMessage(message.Version, om.OutputMessageAction, replyReader);  
    }  
    
  6. 次に 、EchoCustomGreetingFromFile 操作を処理する ExecuteEchoCustomGreetingFromFile メソッドを追加します。 このヘルパー関数は、WCF 要求メッセージを読み取り、指定されたファイルからメッセージを読み取り、次の形式を使用して WCF 応答メッセージを生成します。 <EchoGreetingsFromFileResponse><EchoGreetingsFromFileResult>...message...</EchoGreetingsFromFileResult></EchoGreetingsFromFileResponse>。

    private Message ExecuteEchoCustomGreetingFromFile(OperationMetadata om, Message message, TimeSpan timeout)  
    {  
        // NOTE this method doesn't return response in upper case based on   
        // connection property echoInUpperCase  
    
        // ** Read the WCF request  
        Uri path;  
        using (XmlDictionaryReader inputReader = message.GetReaderAtBodyContents())  
        {  
            inputReader.MoveToContent();  
            inputReader.ReadStartElement(om.DisplayName);  
            inputReader.MoveToContent();  
            // The path contains the ___location of the XML file that contains the instance of Greeting object to read   
            path = new Uri(inputReader.ReadElementContentAsString());  
            inputReader.ReadEndElement();  
        }  
    
        // ** Generate the WCF response  
        StringBuilder outputString = new StringBuilder();  
        XmlWriterSettings settings = new XmlWriterSettings();  
        settings.OmitXmlDeclaration = true;  
        XmlWriter replywriter = XmlWriter.Create(outputString, settings);  
        replywriter.WriteStartElement(om.DisplayName + "Response", EchoAdapter.SERVICENAMESPACE);  
        replywriter.WriteStartElement(om.DisplayName + "Result", EchoAdapter.SERVICENAMESPACE);  
        // Read the XML file and set it to the reply writer here  
        FileStream stream = new FileStream(path.AbsolutePath, FileMode.Open);  
        XmlDictionaryReader xdr = XmlDictionaryReader.CreateTextReader(stream, new XmlDictionaryReaderQuotas());  
        xdr.MoveToContent();  
        string rawGreeting = xdr.ReadInnerXml();  
        replywriter.WriteRaw(rawGreeting);  
        replywriter.WriteEndElement();  
        replywriter.WriteEndElement();  
        replywriter.Close();  
        XmlReader replyReader = XmlReader.Create(new StringReader(outputString.ToString()));  
        return Message.CreateMessage(message.Version, om.OutputMessageAction, replyReader);  
    }  
    
  7. Visual Studio の [ ファイル ] メニューの [ すべて保存] をクリックします。

  8. [ビルド] メニューの [ソリューションのビルド] をクリックします。 エラーなしでコンパイルする必要があります。 そうでない場合は、上記のすべての手順に従っていることを確認します。 これで、Visual Studio を安全に閉じるか、「 手順 8: エコー アダプターの同期受信ハンドラーを実装する」に進むことができます。

私は何をしましたか?

この手順では、エコー アダプターの同期送信メッセージング機能を実装する方法について説明しました。 これを行うには、Microsoft.ServiceModel.Channels.Common.IOutboundHandlerMicrosoft.ServiceModel.Channels.Common.IOutboundHandler.Execute%2Aメソッドを実装しました。 このメソッドは、受信 WCF 要求メッセージを解析し、必要なアクションを実行した後、送信 WCF 応答メッセージを生成しました。

具体的には、受信 WCF 要求メッセージに対して、WCF System.ServiceModel.Channels.Message.Headers.Action%2A を使用して、受信メッセージ本文の基本構造をさらに理解することで、入力メッセージ アクションを取得しました。 送信 WCF 応答メッセージの場合、 Microsoft.ServiceModel.Channels.Common.OperationMetadata.OutputMessageAction%2A を使用して、送信メッセージ本文の基本構造をさらに理解することで、出力メッセージ アクションを取得しました。 WCF メッセージを解析および作成するときに、受信 WCF 要求メッセージを読み取るために System.Xml.XmlDictionaryReader を使用し、送信 WCF 応答メッセージを書き込む System.Xml.XmlWriter を使用しました。

次のステップ

Echo アダプターをビルドして展開します。

こちらもご覧ください

手順 6: エコー アダプターのメタデータ解決ハンドラーを実装する
手順 8: エコー アダプターの同期受信ハンドラーを実装する