WCF请求主体有时是一个流,有时是缓冲的?

时间:2011-10-09 22:20:05

标签: c# .net wcf web-services logging

我有一个WCF网络服务。我试图通过实现MessageInspector并登录AfterReceiveRequest()事件来收到请求时进行一些日志记录。

出于某种原因,每当我使用WCFTestClient.exe向webservice发送请求时,一切正常。记录消息并且请求正常进行。

但是当我使用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()方法抛出的异常是:

  

System.InvalidOperationException {“指定的节点不能   作为此节点的有效子项插入,因为指定的节点   是错误的类型。“}

     

在System.Xml.XmlDocument.AppendChildForLoad(XmlNode newChild,   XmlDocument doc)at   System.Xml.XmlLoader.LoadDocSequence(XmlDocument parentDoc)at at   System.Xml.XmlLoader.Load(XmlDocument doc,XmlReader reader,Boolean   保存在System.Xml.XmlDocument.Load(XmlReader   读者)...

3 个答案:

答案 0 :(得分:2)

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

按照herehere的说明,修改绑定的TransferMode属性。对于向您发送缓冲请求和流量请求的客户端,您可能有多个端点使用不同的自定义绑定。

希望这有帮助。

答案 1 :(得分:1)

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

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


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

如果您想要身体内的所有节点,您可能必须自己创建一个Body节点。

答案 2 :(得分:0)

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

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