完成时间: 30 分钟
在此步骤中,你将实现 Echo 适配器的同步出站功能。 根据 WCF LOB 适配器 SDK,若要支持同步出站功能,必须实现 Microsoft.ServiceModel.Channels.Common.IOutboundHandler
接口。 对于 Echo 适配器,适配器开发向导自动生成一个名为 EchoAdapterOutboundHandler 的派生类。
在以下部分中,更新 EchoAdapterOutboundHandler 类,以便更好地了解如何实现 Microsoft.ServiceModel.Channels.Common.IOutboundHandler.Execute%2A
、如何分析传入的 WCF 请求消息以及如何生成传出 WCF 响应消息。
先决条件
在开始此步骤之前,必须成功完成 步骤 6:实现 Echo 适配器的元数据解析处理程序。 对 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
等于Microsoft.ServiceModel.Channels.Common.OperationResult.Empty%2A
,则此方法将返回一个带有空正文的 WCF 响应消息。 否则,它应返回包含对象中的 Microsoft.ServiceModel.Channels.Common.OperationResult
值的正文的 WCF 响应消息。 若要构造响应作字符串,请使用 Microsoft.ServiceModel.Channels.Common.OperationMetadata.OutputMessageAction%2A
。
Echo Adapter 同步出站
根据目标系统的操作,有多种方法可以实现Microsoft.ServiceModel.Channels.Common.IOutboundHandler.Execute%2A
方法。 对于 Echo 适配器,有三个出站操作,其分配的节点 ID 和显示名称为:
string[] EchoStrings(字符串数据),节点 ID = Echo/EchoString,显示名称=EchoString
Greeting[] EchoGreetings(问候问候语),节点 ID=Echo/EchoGreetings,显示名称=EchoGreetings
CustomGreeting EchoCustomGreetingFromFile(Uri greetingInstancePath),nodeID=Echo/EchoCustomGreetingFromFile,display name=EchoGreetings
若要正确分析传入的 WCF 请求消息并生成传出 WCF 响应消息,必须熟悉 WCF LOB 适配器 SDK 使用的 SOAP 消息中的以下元素:
对于传入的 WCF 请求消息:
WCF 输入消息操作 = 操作的节点 ID
传入消息正文 = 正文的起始元素是 <displayname><参数名称>{data}</参数名称></displayname>
对于发出的 WCF 响应消息:
WCF 输出消息动作 = 操作的节点ID + "/response"
传出消息正文 = 正文的 start 元素为 <displayname + “Response”>,后跟 <displayname + “Result”>,后跟 <数据类型>数据</datatype></displayname+“Result”></displayname+“Response”>
例如,操作 字符串[] EchoStrings(字符串数据),节点 ID = Echo/EchoStrings,显示名称 = 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 编辑器中,将以下两个 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方法来处理字符串数组EchoStrings(string data)操作。 此帮助函数读取 WCF 请求消息,检查 echoInUpperCase URI 元素是否设置为 true,如果是,它会根据计数变量所指示的次数将输入字符串转换为大写。 然后,它以以下格式生成 WCF 响应消息:<EchoStringsResponse><EchoStringResult><字符串>{data}</字符串></EchoStringResult></EchoStringsResponse>。
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); }
继续通过添加 ExecuteEchoGreetings 方法来处理 EchoGreetings 操作。 此辅助函数读取 WCF 请求消息,通过
ResolveOperationMetadata
和ResolveTypeMetadata
方法解析Microsoft.ServiceModel.Channels.Common.IMetadataResolverHandler
接口的操作和类型,然后使用以下格式生成 WCF 响应消息:<EchoGreetingsResponse><EchoGreetingsResult>...消息...</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); }
现在添加 ExecuteEchoCustomGreetingFromFile 方法来处理 EchoCustomGreetingFromFile 操作。 此帮助程序函数读取 WCF 请求消息,从指定文件中读取消息,然后使用以下格式生成 WCF 响应消息: <EchoGreetingsFromFileResponse><EchoGreetingsFromFileResult>...消息。。。</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:实现 Echo 适配器的同步入站处理程序。
我刚刚做了什么?
在此步骤中,你学习了如何实现 Echo 适配器的同步出站消息传送功能。 为此,你实现了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 消息时,用于 System.Xml.XmlDictionaryReader
读取传入的 WCF 请求消息,并用于 System.Xml.XmlWriter
写入传出 WCF 响应消息。
后续步骤
生成并部署 Echo 适配器。