步骤 8:实现 Echo 适配器的同步入站处理程序
)
完成时间: 45 分钟
在此步骤中,你将实现回显适配器的入站功能。 此功能允许适配器侦听来自目标系统的数据或事件。 根据 WCF LOB 适配器 SDK,只需在适配器支持入站功能时实现 Microsoft.ServiceModel.Channels.Common.IInboundHandler
接口。 适配器开发向导会自动生成名为 EchoAdpterInboundHandler 的派生类。
在下一部分中,将更新 EchoAdpterInboundHandler 类,以便更好地了解如何实现此接口。 完成此步骤后,将有一个适用于回显适配器的工作入站处理程序。
必备条件
在开始此步骤之前,必须已成功完成 步骤 7:实现 Echo 适配器的同步出站处理程序。 基本熟悉 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 Actions 开始侦听消息。 如果未指定,则侦听所有或默认操作。 |
StopListener | 停止侦听。 |
TryReceive | 尝试从目标系统接收入站消息。 |
WaitForMessage | 等待来自目标系统的入站 WCF 消息。 |
有关每个方法参数的说明的更多详细信息,请参阅 有关 接口的文档 Microsoft.ServiceModel.Channels.Common.IInboundHandler
。
实现 EchoAdpterInboundHandler
回显适配器使用 System.IO.FileSystemWatcher
来模拟目标系统。 在下面,你将在接口 StartListener、StopListener、TryReceive 和 WaitForMessage 中 Microsoft.ServiceModel.Channels.Common.IInboundHandler
实现每个方法。
在 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:生成和部署 Echo 适配器。
我只是做什么?
在回显适配器教程的此步骤中,你提供了入站处理程序的实现。 此实现使用 .NET Framework的 FileSystemWatcher 类为 Echo 适配器提供文件监视功能。
后续步骤
在下一步中,部署适配器。
另请参阅
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈