完了までの時間: 45 分
この手順では、エコー アダプターの受信機能を実装します。 この機能により、アダプターはターゲット システムからのデータまたはイベントをリッスンできます。 WCF LOB アダプター SDK によると、アダプターが受信機能をサポートしている場合にのみ、 Microsoft.ServiceModel.Channels.Common.IInboundHandler
インターフェイスを実装する必要があります。 アダプター開発ウィザードでは、EchoAdpterInboundHandler という名前の派生クラスが自動的に生成されます。
次のセクションでは、EchoAdpterInboundHandler クラスを更新して、このインターフェイスの実装方法について理解を深めます。 この手順を完了すると、エコー アダプターの受信ハンドラーが動作します。
[前提条件]
この手順を開始する前に、「 手順 7: エコー アダプターの同期送信ハンドラーを実装する」を正常に完了している必要があります。
Microsoft.ServiceModel.Channels.Common.IInboundHandler
に関する基本的な知識も役立ちます。
IInboundHandler インターフェイス
Microsoft.ServiceModel.Channels.Common.IInboundHandler
は次のように定義されます。
public interface IInboundHandler : IConnectionHandler, IDisposable
{
void StartListener(string[] actions, TimeSpan timeout);
void StopListener(TimeSpan timeout);
bool TryReceive(TimeSpan timeout, out Message message, out IInboundReply reply);
bool WaitForMessage(TimeSpan timeout);
}
メソッドの説明は次のとおりです。
メソッド | 説明 |
---|---|
StartListener | 指定された WS-Addressing アクションでメッセージの受信を開始します。 何も指定されていない場合は、すべてまたは既定のアクションをリッスンします。 |
ストップリスナー | 聞くのを停止します。 |
受信試行 | ターゲット システムからの受信メッセージの受信を試みます。 |
WaitForMessage | ターゲット システムからの受信 WCF メッセージを待機します。 |
各メソッド パラメーターの説明の詳細については、 Microsoft.ServiceModel.Channels.Common.IInboundHandler
インターフェイスのドキュメントを参照してください。
EchoAdpterInboundHandler の実装
エコー アダプターは、 System.IO.FileSystemWatcher
を使用してターゲット システムをシミュレートします。 次の例では、 Microsoft.ServiceModel.Channels.Common.IInboundHandler
インターフェイス、StartListener、StopListener、TryReceive、WaitForMessage 内に各メソッドを実装します。
EchoAdpterInboundHandler クラスで IInboundHandler インターフェイスを実装するには
ソリューション エクスプローラーで、 EchoAdapterInboundHandler.cs ファイルをダブルクリックします。
Visual Studio エディターで、既存の using ディレクティブのセットに次の行を追加します。
using System.IO; using System.ServiceModel.Channels; using System.Xml; using System.Diagnostics;
次に、クラス レベルの変数を EchoAdapterInboundHandler クラスに追加します。 これらの変数は、ファイル システムのファイル アクティビティを監視するために使用されます。 以下の宣言をコンストラクターの前のクラスにコピーします。
private Queue<Message> inboundQueue; private FileSystemWatcher inboundWatcher; private Object inboundQueueSynchronizationLock; private string path; private string filter;
EchoAdapterInboundHandler コンストラクター メソッド内に、次のコードを追加して、ファイル監視インフラストラクチャを初期化し、監視パスとフィルターをキャプチャします。
inboundWatcher = null; inboundQueueSynchronizationLock = new Object(); path = connection.ConnectionFactory.Adapter.InboundFileSystemWatcherFolder; filter = connection.ConnectionFactory.Adapter.InboundFileFilter;
次に、 StartListener メソッドに次のコードを追加します。 このコードは、パラメーターを検証し、ファイル アクティビティの監視を開始するロジックを実装します。
// if no actions are provided, log an error in the trace log // and throw an exception if (actions.Length == 0) { EchoAdapterUtilities.Trace.Trace(TraceEventType.Error, "http://echoadapterv2/startlistener/noactions", "No operation actions were received for listener to do specific processing.", this); throw new AdapterException("Unable to receive any actions for inbound handler to start listening."); } inboundQueue = new Queue<Message>(); foreach (string action in actions) { // for the OnReceiveEcho action listen for a new file created event if ("Echo/OnReceiveEcho".Equals(action)) { if (inboundWatcher == null) { inboundWatcher = new FileSystemWatcher(path); inboundWatcher.Filter = filter; // Begin monitoring inboundWatcher.EnableRaisingEvents = true; } inboundWatcher.Created += new FileSystemEventHandler(FileMonitor_Created); EchoAdapterUtilities.Trace.Trace(TraceEventType.Information, "http://echoadapterv2/startlistener", "Listening for file created event for " + filter + " in path " + path, this); } }
StopListener メソッドの実装を追加して続行します。
if (inboundWatcher != null) { // End monitoring inboundWatcher.EnableRaisingEvents = false; inboundWatcher = null; } lock (inboundQueueSynchronizationLock) { inboundQueue.Clear(); inboundQueue = null; }
TryReveive メソッドの実装を提供します。 このメソッドは、内部キューから最新のファイル受信メッセージを取得します (使用可能な場合)。
reply = new EchoAdapterInboundReply(); message = null; TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); while (true) { lock (inboundQueueSynchronizationLock) { if (inboundQueue == null) { //listener has been closed return false; } if (inboundQueue.Count != 0) { message = inboundQueue.Dequeue(); if (message != null) { return true; } } } if (timeoutHelper.IsExpired) { return false; } //wait for sometime, and check again System.Threading.Thread.Sleep(500); }
WaitForMessage メソッドの実装を追加して続行します。
while (inboundQueue.Count == 0) { }; Message msg = inboundQueue.Peek(); if (msg != null) { return true; } else { return false; }
次に、ファイル ウォッチャーのコールバックを指定します。 これを行うには、新しいメソッド FileMonitor_Created を EchoAdapterInboundAdapter クラスに追加します。
private void FileMonitor_Created(object sender, FileSystemEventArgs e) { lock (inboundQueueSynchronizationLock) { if (e.ChangeType == WatcherChangeTypes.Created) { // wait for file to close - should do this in a better manner System.Threading.Thread.Sleep(500); try { EchoAdapterUtilities.Trace.Trace(TraceEventType.Information, "http://echoadapterv2/FileMonitorCreated", "File " + e.FullPath + " created.", this); FileInfo fileInfo = new FileInfo(e.FullPath); // Create WCF message to send to the inbound service // that is listening for messages from adapter String xmlData = String.Format(@"<OnReceiveEcho xmlns=""{0}""><path>{1}</path><length>{2}</length></OnReceiveEcho>", EchoAdapter.SERVICENAMESPACE, e.FullPath, fileInfo.Length); // set action string XmlReader reader = XmlReader.Create(new StringReader(xmlData)); // create WCF message Message requestMessage = Message.CreateMessage(MessageVersion.Default , "Echo/OnReceiveEcho" , reader); requestMessage.Headers.To = new Uri(path); inboundQueue.Enqueue(requestMessage); } catch (Exception ex) { String message = String.Format("An exception was thrown while trying to open file {1}.", e.FullPath); EchoAdapterUtilities.Trace.Trace(System.Diagnostics.TraceEventType.Error, "http://echoadapterv2/FileMonitorCreated", message, this, ex); throw new AdapterException(message, ex); } } } }
次に、内部クラス EchoAdapterInboundReply によってスローされたNotImplementedException 例外を削除しなければなりません。 これを行うには、 Abort メソッドと Reply メソッドから次のステートメントを削除します。
throw new NotImplementedException("The method or operation is not implemented.");
Abort メソッドと Reply メソッドは次のようになります。
/// <summary> /// Abort the inbound reply call /// </summary> public override void Abort() { } /// <summary> /// Reply message implemented /// </summary> public override void Reply(System.ServiceModel.Channels.Message message , TimeSpan timeout) { }
受信ハンドラーの実装を完了するには、次のクラスを EchoAdapterOutboundHandler.csに追加します。 このクラスは、受信ハンドラーの実装のタイムアウトサポートを提供します。
/// <summary> /// Utility class containing helper functions for measuring timeout /// </summary> class TimeoutHelper { private TimeSpan timeout; private DateTime creationTime; private Boolean isInfinite; /// <summary> /// Constructor /// </summary> /// <param name="timeout"></param> public TimeoutHelper(TimeSpan timeout) { this.creationTime = DateTime.Now; this.timeout = timeout; if (timeout.Equals(Infinite)) this.isInfinite = true; } /// <summary> /// Value of infinite timespan /// </summary> public static TimeSpan Infinite { get { return TimeSpan.MaxValue; } } /// <summary> /// Value indicating remaining timeout /// </summary> public TimeSpan RemainingTimeout { get { if (this.isInfinite) return Infinite; return this.timeout.Subtract(DateTime.Now.Subtract(this.creationTime)); } } /// <summary> /// Get remaining timeout value and throw an exception if the timeout /// has expired. /// </summary> /// <param name="exceptionMessage"></param> /// <returns></returns> public TimeSpan GetRemainingTimeoutAndThrowIfExpired(String exceptionMessage) { if (this.isInfinite) return Infinite; if (RemainingTimeout < TimeSpan.Zero) { throw new TimeoutException(exceptionMessage); } return RemainingTimeout; } /// <summary> /// Throw an exception if the timeout has expired. /// </summary> /// <param name="exceptionMessage"></param> public void ThrowIfTimeoutExpired(String exceptionMessage) { if (RemainingTimeout < TimeSpan.Zero) { throw new TimeoutException(exceptionMessage); } } /// <summary> /// Value indicating whether timeout has expired. /// </summary> public Boolean IsExpired { get { if (this.isInfinite) return false; return RemainingTimeout < TimeSpan.Zero; } } }
Visual Studio の [ ファイル ] メニューの [ すべて保存] をクリックします。
[ビルド] メニューの [ソリューションのビルド] をクリックします。 エラーなしでコンパイルする必要があります。 そうでない場合は、上記のすべての手順に従っていることを確認します。
注
作業を保存しました。 この時点で Visual Studio を安全に閉じるか、次の手順「 手順 9: エコー アダプターをビルドして展開する」に進むことができます。
私は何をしましたか?
エコー アダプターチュートリアルのこの手順では、受信ハンドラーの実装を指定しました。 この実装では、.NET Framework の FileSystemWatcher クラスを使用して、エコー アダプターのファイル監視機能を提供します。
次のステップ
次の手順では、アダプターを展開します。