在服务器上反序列化WCF消息

时间:2012-10-23 23:41:48

标签: c# wcf deserialization

我实现了一个自定义消息检查器(通过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(在反序列化的对象中)。

3 个答案:

答案 0 :(得分: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

答案 1 :(得分: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;
    }

答案 2 :(得分:-3)

我最终走上了消息标题路线,就像Mike Parkhill建议的那样。