0

我实现了一个自定义消息检查器(通过 IDispatchMessageInspector)来拦截在 WCF 服务的服务器端接收到的消息,因此我可以尝试反序列化消息并应用一些特定的业务逻辑。我遇到的问题是,当我将 MessageBuffer 的内容写入新的 MemoryStream 然后尝试反序列化时,我收到一条错误消息,提示“根级别的数据无效。第 1 行,第 1 行。” 我确实知道传入的数据是有效的,因为跳过检查器会使一切正常。

示例代码:

public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
    {
        MessageBuffer buffer = request.CreateBufferedCopy(Int32.MaxValue);
        request = buffer.CreateMessage();
        string msg = buffer.CreateMessage().ToString();

        var dc = new DataContractSerializer(typeof(Adder));

        using (var stream = new MemoryStream())
        {
            buffer.WriteMessage(stream);

            stream.Position = 0;

            //deserializing error occurs here
            var c = dc.ReadObject(stream);
        }

        return null;
    }

这是 Adder 类/接口:

    [DataContract(Name = "adder", Namespace = "http://test.com")]
public class Adder
{
    [DataMember(Name = "first")]
    public int First { get; set; }

    [DataMember(Name = "second")]
    public int Second { get; set; }
}

    [ServiceContract(Namespace = "http://test.com")]
public interface ITestSvc
{
    [OperationContract(Name = "add")]
    int Add(Adder adder);
}

有什么建议或有更好的选择吗?我的主要目标是读取进入我服务的每个 WCF 请求的 XML(在反序列化对象中)。

4

3 回答 3

5

请求对象包含 WCF 消息标头以及有效负载。您需要去掉标头,然后您应该能够反序列化消息正文。

例如,一条 SOAP 消息将具有:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
               xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>

</soap:Header>
<soap:Body>
  <!-- your payload -->
</soap:Body>

您可以使用 XML 导航来访问 body 元素,然后单独反序列化该元素。

编辑:实际上只是偶然发现了这种我认为应该为您解决问题的方法:

Message.GetReaderAtBodyContents

于 2012-10-24T01:39:06.690 回答
0

我只是这样做了。只需将以下所有代码粘贴到您的类中,然后调用DeserializedResponse()。您需要将MyResponseObject更改为您尝试反序列化的任何对象的名称。此外,您需要将“ _requestInspector.Response ”替换为您自己的响应 xml 字符串变量。GetSoapBodyInnerXml()方法将剥离 Soap Envelope,并仅返回您希望反序列化的响应 xml。

    private MyResponseObject DeserializedResponse()
    {
        var rootAttribute = new XmlRootAttribute("MyResponseObject ");
        rootAttribute.Namespace = @"http://www.company.com/MyResponseObjectNamespace";

        XmlSerializer serializer = new XmlSerializer(typeof(MyResponseObject ), rootAttribute);
        string responseSoapBodyInnerXml = GetSoapBodyInnerXml(_requestInspector.Response);
        AddXmlDeclaration(ref responseSoapBodyInnerXml);
        MemoryStream memStream = new MemoryStream(Encoding.UTF8.GetBytes(responseSoapBodyInnerXml));
        MyResponseObject resultingResponse = (MyResponseObject )serializer.Deserialize(memStream);

        return resultingResponse;
    }

    private string GetSoapBodyInnerXml(string soapMessage)
    {
        XDocument xDoc = XDocument.Parse(soapMessage);
        XNamespace nsSoap = @"http://schemas.xmlsoap.org/soap/envelope/";
        return xDoc.Descendants(nsSoap + CONST_SoapBody).Descendants().First().ToString();
    }

    private void AddXmlDeclaration(ref string xmlString)
    {
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(xmlString);

        //Create an XML declaration. 
        XmlDeclaration xmldecl;
        xmldecl = doc.CreateXmlDeclaration("1.0", "UTF-8", null);

        //Add the new node to the document.
        XmlElement root = doc.DocumentElement;
        doc.InsertBefore(xmldecl, root);

        //Return updated xmlString with XML Declaration
        xmlString = doc.InnerXml;
    }
于 2014-01-10T17:30:27.180 回答
-3

就像 Mike Parkhill 建议的那样,我最终选择了消息头路由。

于 2012-10-27T03:22:02.273 回答