【问题标题】:How to deserialize WCF message using OperationContract如何使用 OperationContract 反序列化 WCF 消息
【发布时间】:2010-12-26 19:41:18
【问题描述】:

我成功地构建了一个由 WSDL 中的 svcutil.exe 生成的 WCF 客户端。使用生成的客户端代理类,我可以调用外部服务供应商的 Web 服务。我还成功编写了消息检查器,因为我需要将原始 XML 请求和响应作为完整的 SOAP 消息记录到数据库中。

对于紧急情况,我还需要能够“导入”原始 XML 响应。我发现了很多关于使用 XMLSerializer 或基于消息协定反序列化 WCF 消息的提示。

但是如何根据操作契约反序列化原始 XML 响应?对于第一个测试,我使用一个记录的原始响应,将其保存到文件中,然后尝试将其反序列化为客户端代理中生成的响应类型。不知何故,我必须成功地从类ClientOperation 调用DeserializeReply()。但是如何到达那里?

我很乐意接受任何帮助,因为我是 WCF 的新手... TIA, 斯蒂芬

这是我在马克回答后尝试的:

  public static RatingResult DeserializeResponseFromFile(string path)
  {
     var xmlReader = XmlReader.Create(path);
     var message = Message.CreateMessage(xmlReader, int.MaxValue, MessageVersion.Soap11);
     var readerAtBodyContents = message.GetReaderAtBodyContents();
     var dcs = new DataContractSerializer(typeof(RatingResult), "RatingResponse", "http://rating.webservice.xxx.de");

     // Error in line 6 position 7. 'EndElement' 'RatingResponse' from namespace
     // 'http://rating.webservice.xxx.de' is not expected.
     // Expecting element 'commonDataField'.
     var wsResult = (RatingResult)dcs.ReadObject(readerAtBodyContents);

     return wsResult;
  }

这是记录的 XML 响应文件的一部分,我正在尝试反序列化以键入 RatingResponse

<soapenv:Envelope xmlns:soapenv="..." xmlns:soapenc="..." xmlns:xsd="..." xmlns:xsi="...">
  <soapenv:Header soapenv:encodingStyle="..." />
  <soapenv:Body soapenv:encodingStyle="...">
    <p933:RatingResponse xmlns:p933="http://rating.webservice.xxx.de">
      <RatingReturn href="#id0" />
    </p933:RatingResponse>
    <multiRef id="id0" soapenc:root="0" soapenv:encodingStyle="..." xsi:type="p878:RatingResult" xmlns:p878="http://output.rating.webservice.xxx.de">
      <commonData href="#id1" />
      <acctData href="#id2" />
      <resultData href="#id3" />
    </multiRef>
    <multiRef id="id1" soapenc:root="0" soapenv:encodingStyle="..." xsi:type="p719:RatingCommonData" xmlns:p719="http://input.rating.webservice.xxx.de">
      <requestdate xsi:type="xsd:dateTime">2010-12-24T09:45:09.531Z</requestdate>
      ...

我猜数据协定序列化程序在反序列化 href 时存在问题。请注意,我尝试“手动”反序列化的消息是使用我注入的消息检查器捕获的。在 Web 服务的“正常”调用中,此消息会被反序列化而不会出现问题。

【问题讨论】:

  • 好的,现在我看到了更多你想要做的事情。您在窗口中拥有的是整个 SOAP 消息 - 带有标题和正文等等。您要反序列化的“东西”是 元素 inside 标记。我认为您不能(或不应该)反序列化整个 SOAP 消息 - 尝试获取 SOAP 主体中包含的任何内容,然后反序列化 - 那是您的实际 message payload 将从您的 WCF 方法调用 - 其他一切都只是 SOAP 开销......
  • 我已经这样做了。我的测试函数使用message.GetReaderAtBodyContents() 来跳过SOAP 内容。因此,当我调用dcs.ReadObject(readerAtBodyContents) 时,阅读器已经指向节点 的有效负载。我得到的错误让我怀疑反序列化器无法从 href="#id0" 跳到 id="id0" 的多引用节点。这就是为什么它在第 6 行中出现错误的原因,当它看到它已经到达 的结束标记但期待一些实际编码在这些 href 节点中的字段时。

标签: c# wcf xml-deserialization


【解决方案1】:

我真的不明白你想问什么和做什么.... 基于运营合同 ?? 操作契约 只是您在操作/方法调用上添加的一个属性,以将其标记为服务方法.. 操作契约甚至不做任何与序列化或反序列化有关的远程操作。 ...您的意思是如何使用 WCF 默认序列化程序 DataContractSerializer 反序列化 XML 消息??

假设您的意思是HOWTO:使用 DataContractSerializer 反序列化 WCF 消息,然后试试这个:如果您有来自使用默认 WCF DataContractSerializer 的服务调用的响应 XML,您应该能够像这样反序列化它(假设您的 XML 序列化响应在 xmlResponse 变量中):

using(MemoryStream memStm = new MemoryStream())
using(StreamWriter stw = new StreamWriter(memStm))
{
   // write your response to the memory stream
   stw.Write(xmlResponse);
   stw.Flush();

   // "reset" memory stream
   memStm.Seek(0, SeekOrigin.Begin);

   // setup DataContractSerializer     
   DataContractSerializer dcs = new DataContractSerializer(typeof(YourDataType));

   // deserialize result XML into an instance of "YourDataType"
   var result = dcs.ReadObject(memStm);
}

【讨论】:

  • 马克,感谢您的回答。抱歉没有更精确,这是因为 WCF 对我来说很新。我在原始问题中附加了更多信息。 - 斯特凡
【解决方案2】:

对于将来这样做的任何人。我不得不从 MSMSQ 中手动读取 WCF 消息,并从 MSMQ/WCF 消息信封中获取请求对象。方法如下:

根代码:

var q = new MessageQueue(@".\Private$\VishalQ;poison");

var allMessages = q.GetAllMessages().ToList();
var wcfRequests = allMessages.Select(ConvertToWcfRequest<ObjectChangedRequest>);

我的合同:

[ServiceContract]
public interface IWish
{
    [OperationContract(IsOneWay = true)]
    void ObjectChanged(ObjectChangedRequest request);
}

我的数据合同:

[DataContract(Namespace = "http://x.namespaces.x-x.com/")]
public class ObjectChangedRequest
{
    [DataMember]
    public OperationType OperationType { get; set; }
}

我的消息反序列化代码:

    /// <summary>
    /// Converts a WCF MSMQ message to a WCF request object.
    /// </summary>
    public static T ConvertToWcfRequest<T>(Message msmqMessage)
    {
        var buffer = new byte[msmqMessage.BodyStream.Length];
        msmqMessage.BodyStream.Read(buffer, 0, (int)msmqMessage.BodyStream.Length);

        var envelopeStart = FindEnvelopeStart(buffer);

        using var msmqStream = new MemoryStream(buffer, envelopeStart, buffer.Length - envelopeStart);
        var encodingElement  = new BinaryMessageEncodingBindingElement();
        var wcfMessage       = encodingElement.CreateMessageEncoderFactory().Encoder.ReadMessage(msmqStream, int.MaxValue);
        var document         = new XmlDocument();

        document.Load(wcfMessage.GetReaderAtBodyContents());

        var realRoot        = document.FirstChild.FirstChild;
        using var wcfStream = new MemoryStream();
        using var xmlWriter = XmlWriter.Create(wcfStream);

        realRoot.WriteTo(xmlWriter);
        xmlWriter.Flush();
        wcfStream.Seek(0, SeekOrigin.Begin);

        var wcfSerializer = new DataContractSerializer(typeof(T), realRoot.Name, "http://tempuri.org/"); //No idea why this has to be temp uri and not our namespace...

        return (T)wcfSerializer.ReadObject(wcfStream);
    }

    /// <summary>
    /// Locates the start of a WCF message within a MSMQ message.
    /// </summary>
    private static int FindEnvelopeStart(byte[] stream)
    {
        var position = 0;
        var previousByte = stream[position];

        for (position = 0; position < stream.Length; position++)
        {
            var currentByte = stream[position];

            //Some magic numbers that define the start of the WCF message envelope
            if (currentByte == 0x02 && previousByte == 0x56)
                break;

            previousByte = currentByte;
        }

        return position - 1;
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-09
    • 1970-01-01
    • 1970-01-01
    • 2021-03-08
    • 2017-09-30
    • 2016-07-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多