C#-WCF-拦截和更改响应

时间:2018-11-28 22:05:00

标签: c# xml

我有一个与第三方SOAP Web服务交互的应用程序,因此我建立了服务引用,一切正常。

但是,我需要进行一些错误测试,其中我需要Web服务来响应非常特定的XML有效负载(并且由于它是第三方服务,所以我无法使其做我想做的事)。

我试图使用消息检查器的“ AfterReceiveReply”方法用所需的XML覆盖响应(该XML是从其他合法响应中捕获的,因此我知道它是有效的XML)。我的代码如下(基于https://blogs.msdn.microsoft.com/kaevans/2008/01/08/modify-message-content-with-wcf/):

    public void AfterReceiveReply(ref Message reply, object correlationState)
    {
        // Override payload
        string overrideXML = Properties.Resources.WCFOverride.Replace("---ACCOUNT_NUMBER---", "12345");
        MemoryStream ms = new MemoryStream(UTF8Encoding.UTF8.GetBytes(overrideXML));
        ms.Position = 0;

        XmlDictionaryReaderQuotas quotas = new XmlDictionaryReaderQuotas();
        XmlDictionaryReader xdr = XmlDictionaryReader.CreateBinaryReader(ms, quotas);
        Message replacedMessage = Message.CreateMessage(reply.Version, null, xdr);
        replacedMessage.Headers.CopyHeadersFrom(reply.Headers);
        replacedMessage.Properties.CopyProperties(reply.Properties);
        reply = replacedMessage;
    }

代码运行时,在Message.CreateMessage(...)行上出现错误:

System.Xml.XmlException: The input source is not correctly formatted.

在那时的调试器中,我可以在MemoryStream中看到正确的XML,但是XmlDictionaryReader(xdr)似乎为空。如果尝试手动运行xdr.Read(),也会遇到相同的异常。我什至尝试了一个简单的XML结构,如:

overrideXML = "<Document></Document>";

...并且它不起作用,所以我认为我错误地设置了XML阅读器...

有人知道我在做什么错吗?

编辑: 我更新了代码以使用TextReader代替BinaryReader:

XmlDictionaryReader xdr = XmlDictionaryReader.CreateTextReader(ms.ToArray(), XmlDictionaryReaderQuotas.Max);

现在我不再遇到异常,但是更新后的回复对象看起来不正确。

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <ns:ResponseHeader xmlns:ns="[redacted]" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/">
      [redacted]
    </ns:ResponseHeader>
  </s:Header>
  <s:Body>... stream ...</s:Body>
</s:Envelope>

从字面上看,它在主体内部具有字符串值“ ... stream ...”,而不是实际的主体内容。最终结果是,响应WCF调用,我得到一个空对象,而不是预期的对象。

1 个答案:

答案 0 :(得分:0)

  1. “ ... stream ...”主体是红色鲱鱼。主体实际上仍然在那儿,但是reply.ToString()只是返回了本质上是一个占位符的东西。如这篇文章中所述,仍然可以通过缓冲副本访问完整消息: WCF message body showing <s:Body>... stream ...</s:Body> after modification

  2. XmlDictionaryReader.CreateTextReader()方法似乎能够读取XML,但无法正确找到主体(使用Reply.GetBody()方法进行了测试),因此在消息返回之后对于WCF,它无法反序列化对象,因为XmlDictionaryReader认为Envelope元素是主体。

  3. 仅使用XmlReader即可正常工作,并且也更简单:

    public void AfterReceiveReply(ref Message reply, object correlationState)
    {
        // Override payload
        string overrideXML = Properties.Resources.WCFOverride.Replace("---ACCOUNT_NUMBER---", "12345");
    
        // Create the reader
        XmlReader envelopeReader = XmlReader.Create(new StringReader(overrideXML));
    
        // Create the message using the reader
        System.ServiceModel.Channels.Message replacedMessage = System.ServiceModel.Channels.Message.CreateMessage(envelopeReader, int.MaxValue, reply.Version);
        replacedMessage.Headers.CopyHeadersFrom(reply.Headers);
        replacedMessage.Properties.CopyProperties(reply.Properties);
        reply = replacedMessage;
    }