步骤 7:实现 Echo 适配器的同步出站处理程序

第 7 步(共 9

完成时间: 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.IOutboundHandlerExecute 方法。 首先,根据输入消息操作获取 Microsoft.ServiceModel.Channels.Common.OperationMetadata 对象。 然后,分析传入的 WCF 消息,并根据每个操作执行关联的回显功能。 最后, 使用传出消息正文的格式创建传出 WCF 响应消息。

实现 EchoAdapterOutboundHandler 类的 Execute 方法

  1. 在解决方案资源管理器中,双击 EchoAdapterOutboundHandler.cs 文件。

  2. 在 Visual Studio 编辑器中,将以下两个 using 指令添加到现有的 using 指令集。

    using System.Xml;  
    using System.IO;  
    
  3. Execute 方法中,将现有逻辑替换为以下内容:

    1. 此逻辑验证请求的操作。

    2. 它基于 SOAP 输入消息操作获取 Microsoft.ServiceModel.Channels.Common.OperationMetadata 对象。

    3. 它根据操作类型分析 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;              
    
  4. 现在添加 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);  
    }  
    
  5. 通过添加 ExecuteEchoGreetings 方法来继续处理 EchoGreetings 操作。 此帮助程序函数读取 WCF 请求消息,通过 ResolveOperationMetadata 接口的 Microsoft.ServiceModel.Channels.Common.IMetadataResolverHandlerResolveTypeMetadata 方法解析操作和类型,然后使用以下格式生成 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);  
    }  
    
  6. 现在添加 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);  
    }  
    
  7. 在 Visual Studio 的“ 文件 ”菜单上,单击“ 全部保存”。

  8. 在“生成”菜单中,单击“生成解决方案”。 它应在编译时不出错。 否则,请确保已执行上述每个步骤。 现在,可以安全地关闭 Visual Studio 或继续执行 步骤 8:实现 Echo 适配器的同步入站处理程序

我只是做什么?

在此步骤中,你已了解如何实现 Echo 适配器的同步出站消息传送功能。 为此,你实现了 Microsoft.ServiceModel.Channels.Common.IOutboundHandler.Execute%2AMicrosoft.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 适配器。

另请参阅

步骤 6:实现 Echo 适配器的元数据解析处理程序
步骤 8:实现 Echo 适配器的同步入站处理程序