WCF请求体有时是流,有时是缓冲的

本文关键字:缓冲 WCF 请求 | 更新日期: 2023-09-27 18:10:44

我有一个WCF webservice。每当通过实现MessageInspector并在AfterReceiveRequest()事件中记录请求时,我都试图做一些日志记录。

出于某种原因,每当我使用WCFTestClient.exe向web服务发送请求时,一切都工作正常。消息被记录下来,请求照常进行。

但是,当我使用SOAPUI作为客户端向web服务发送请求时,复制请求消息会导致正文仅显示<body>... stream ...</body>,并且为了验证而无法将其加载为XML文档。

我猜来自WCFTestClient.exe的请求是用缓冲的消息体接收的,来自SOAPUI的请求是作为流体接收的?这怎么可能呢?

  • 是否有某种方式我可以写一些代码,将安全地使任何一个版本的副本?我还没有弄清楚如何安全地复制一个流版本的CreateBufferedCopy()显然没有实现这一点。

  • 或者我可以配置WCF总是创建一个缓冲的消息体,而不是一个流?

下面是我用来记录和复制请求消息的代码:

object IDispatchMessageInspector.AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
{
    try
    {
        MessageBuffer buffer = request.CreateBufferedCopy(Int32.MaxValue);
        request = buffer.CreateMessage();
        Message copy = buffer.CreateMessage();
        LogRequest(copy);
        ValidateMessage(ref request);
    }
    catch (Exception e)
    {
        throw new FaultException<>()...
    }
    return null;
}

如果请求消息的副本来自带有流体的SOAPUI,则无法在ValidateMessage()方法中将其加载到XML文档中。如果它来自带有缓冲体的WCFTestClient.exe,则成功加载为XML文档。

void validateMessage(ref System.ServiceModel.Channels.Message message)
{
    XmlDocument bodyDoc = new XmlDocument();
    //This load throws exception if request came from SOAPUI with streamed body...
    bodyDoc.Load(message.GetReaderAtBodyContents());
    ...
}

Load()方法抛出的异常是:

系统。InvalidOperationException{"指定的节点不能作为此节点的有效子节点插入,因为指定的节点是错误的类型。"}

在System.Xml.XmlDocument

。AppendChildForLoad (XmlNode newChild,XmlDocument文档)System.Xml.XmlLoader。LoadDocSequence(xmldocumentparentdoc) atSystem.Xml.XmlLoader。加载(XmlDocument文档,XmlReader阅读器,布尔值. xmldocument . load (XmlReader . load

WCF请求体有时是流,有时是缓冲的

我相信SOAPUI总是将它构建的消息请求作为流发送。我不确定这是否可以通过SOAPUI测试中的代码或SOAPUI上的一些SOAPUI配置选项/文件进行修改。

检查绑定的TransferMode属性,如这里和这里所述。您可能有多个端点使用不同的自定义绑定的客户端向您发送缓冲请求和流请求。

抛出的异常是什么?GetReaderAtBodyContents()返回的读取器位于body内的第一个元素,而不是body标签本身。因此,您加载消息的方式是不正确的,因为正文可能包含多个节点,在这种情况下,它将失败。

只是为了检查一下,您是否可以使用以下代码来验证整个消息(副本)的内容,并查看从SOAPUI发送时正文是否包含完全相同的内容?


using (MemoryStream stream = new MemoryStream())
{
    using (XmlWriter writer = XmlWriter.Create(stream))
    {
        message.WriteMessage(writer);
        writer.Flush();
        stream.Position = 0;
    }
}

如果你想让所有的节点都在body中,你可能需要自己创建一个body节点。

GetReaderAtBodyContents()方法返回body的结束元素和soap信封的结束元素之间的任何字符。当XmlReader读取过body的结束元素时,它会失败,并出现线程中前面列出的异常。

更多:http://www.katlaconsulting.co.uk/blog/wcfxmlschemavalidation