步骤 7:实现 Echo 适配器的同步出站处理程序
完成时间: 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 响应消息。 下表列出了其参数的定义:
参数 | 定义 |
---|---|
message | 传入的 WCF 请求消息。 |
timeout | 完成此操作的时间间隔。 如果在操作完成之前超过指定的超时,则操作应引发 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
。 对于 Echo 适配器,有三个出站操作,其分配的节点 ID 和显示名称为:
string[] EchoStrings (字符串数据) ,节点 ID = Echo/EchoString,显示名称=EchoString
Greeting[] EchoGreetings (greeting greeting) , node ID=Echo/EchoGreetings, display name=EchoGreetings
CustomGreeting EchoCustomGreetingFromFile (Uri greetingInstancePath) , nodeID=Echo/EchoCustomGreetingFromFile, display name=EchoGreetings
若要正确分析传入的 WCF 请求消息并生成传出 WCF 响应消息,必须熟悉 WCF LOB 适配器 SDK 使用的 SOAP 消息中的以下元素:
对于传入的 WCF 请求消息:
WCF 输入消息操作 = 操作的节点 ID
传入消息正文 = 正文的起始元素是 <displayname><参数名称>{data}</parameter name></displayname>
对于传出 WCF 响应消息:
WCF 输出消息操作 = 操作的节点 ID + “/response”
传出消息正文 = 正文的 start 元素是 <displayname + “Response”>,后跟 <displayname + “Result”>,后跟 <datatype>data</datatype></displayname+“Result></displayname + ”Response”>
例如,操作 string[] 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 方法以处理 string[] EchoStrings (字符串数据) 操作。 此帮助程序函数读取 WCF 请求消息,检查 echoInUpperCase URI 元素是否设置为 true;如果是这样,它将输入字符串转换为大写的次数与 count 变量指示的次数一样多。 然后,它生成以下格式的 WCF 响应消息:EchoStringsResponse><EchoStringResult><字符串>{data}</string></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
接口的Microsoft.ServiceModel.Channels.Common.IMetadataResolverHandler
和ResolveTypeMetadata
方法解析操作和类型,然后使用以下格式生成 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.Execute%2A
的 Microsoft.ServiceModel.Channels.Common.IOutboundHandler
方法。 此方法分析传入的 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 适配器。
另请参阅
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈