完了までの時間: 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 メソッドを実装するには
ソリューション エクスプローラーで、 EchoAdapterOutboundHandler.cs ファイルをダブルクリックします。
Visual Studio エディターで、次の 2 つの using ディレクティブを既存の using ディレクティブセットに追加します。
using System.Xml; using System.IO;
Execute メソッド内で、既存のロジックを次のように置き換えます。
このロジックは、要求された操作を検証します。
SOAP 入力メッセージ アクションに基づいて
Microsoft.ServiceModel.Channels.Common.OperationMetadata
オブジェクトを取得します。アクションの種類に基づいて、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;
次に 、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); }
続行するには 、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); }
次に 、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); }
Visual Studio の [ ファイル ] メニューの [ すべて保存] をクリックします。
[ビルド] メニューの [ソリューションのビルド] をクリックします。 エラーなしでコンパイルする必要があります。 そうでない場合は、上記のすべての手順に従っていることを確認します。 これで、Visual Studio を安全に閉じるか、「 手順 8: エコー アダプターの同期受信ハンドラーを実装する」に進むことができます。
私は何をしましたか?
この手順では、エコー アダプターの同期送信メッセージング機能を実装する方法について説明しました。 これを行うには、Microsoft.ServiceModel.Channels.Common.IOutboundHandler
のMicrosoft.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: エコー アダプターの同期受信ハンドラーを実装する