【问题标题】:How do I capture incoming and outgoing XML from WCF service end如何从 WCF 服务端捕获传入和传出 XML
【发布时间】:2014-03-12 01:47:22
【问题描述】:

在我的解决方案中,我有三个项目。一个是 WCF 服务,另一个是 Winforms 应用程序,我从中调用 Web 服务,最后一个是一个类库,其中的类已设计扩展了 soap 扩展类。

我的目标是在我从 Winforms 应用程序调用 WCF 服务时捕获响应和请求 xml。我在尝试捕获 xml 时遇到对象引用未设置错误。

这是我的类库源代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.IO;
using System.Net;
using System.Xml;

namespace SoapLogger
{
public class TraceExtension : SoapExtension
{
    private Stream oldStream;
    private Stream newStream;

    private static XmlDocument xmlRequest;
    /// <summary>
    /// Gets the outgoing XML request sent to PayPal
    /// </summary>
    public static XmlDocument XmlRequest
    {
        get { return xmlRequest; }
    }

    private static XmlDocument xmlResponse;
    /// <summary>
    /// Gets the incoming XML response sent from PayPal
    /// </summary>
    public static XmlDocument XmlResponse
    {
        get { return xmlResponse; }
    }

    /// <summary>
    /// Save the Stream representing the SOAP request
    /// or SOAP response into a local memory buffer.
    /// </summary>
    /// <param name="stream">
    /// <returns></returns>
    public override Stream ChainStream(Stream stream)
    {
        oldStream = stream;
        newStream = new MemoryStream();
        return newStream;
    }

    /// <summary>
    /// If the SoapMessageStage is such that the SoapRequest or
    /// SoapResponse is still in the SOAP format to be sent or received,
    /// save it to the xmlRequest or xmlResponse property.
    /// </summary>
    /// <param name="message">
    public override void ProcessMessage(SoapMessage message)
    {
        switch (message.Stage)
        {
            case SoapMessageStage.BeforeSerialize:
                break;
            case SoapMessageStage.AfterSerialize:
                xmlRequest = GetSoapEnvelope(newStream);
                CopyStream(newStream, oldStream);
                break;
            case SoapMessageStage.BeforeDeserialize:
                CopyStream(oldStream, newStream);
                xmlResponse = GetSoapEnvelope(newStream);
                break;
            case SoapMessageStage.AfterDeserialize:
                break;
        }
    }

    /// <summary>
    /// Returns the XML representation of the Soap Envelope in the supplied stream.
    /// Resets the position of stream to zero.
    /// </summary>
    /// <param name="stream">
    /// <returns></returns>
    private XmlDocument GetSoapEnvelope(Stream stream)
    {
        XmlDocument xml = new XmlDocument();
        stream.Position = 0;
        StreamReader reader = new StreamReader(stream);
        xml.LoadXml(reader.ReadToEnd());
        stream.Position = 0;
        return xml;
    }

    /// <summary>
    /// Copies a stream.
    /// </summary>
    /// <param name="from">
    /// <param name="to">
    private void CopyStream(Stream from, Stream to)
    {
        TextReader reader = new StreamReader(from);
        TextWriter writer = new StreamWriter(to);
        writer.WriteLine(reader.ReadToEnd());
        writer.Flush();
    }
    #region NoOp
    /// <summary>
    /// Included only because it must be implemented.
    /// </summary>
    /// <param name="methodInfo">
    /// <param name="attribute">
    /// <returns></returns>
    public override object GetInitializer(LogicalMethodInfo methodInfo,
        SoapExtensionAttribute attribute)
    {
        return null;
    }

    /// <summary>
    /// Included only because it must be implemented.
    /// </summary>
    /// <param name="WebServiceType">
    /// <returns></returns>
    public override object GetInitializer(Type WebServiceType)
    {
        return null;
    }

    /// <summary>
    /// Included only because it must be implemented.
    /// </summary>
    /// <param name="initializer">
    public override void Initialize(object initializer)
    {
    }
    #endregion NoOp
}

这是我从 Winforms 应用程序调用 Web 服务的方式:

private void button1_Click(object sender, EventArgs e)
{

    using (ServiceRef.TestServiceSoapClient oService = new ServiceRef.TestServiceSoapClient())
    {
        textBox1.Text = oService.HelloWorld("Sudip");
        var soapRequest = SoapLogger.TraceExtension.XmlRequest.InnerXml;
        var soapResponse = SoapLogger.TraceExtension.XmlResponse.InnerXml;
    }
}

这两行导致对象引用错误

var soapRequest = SoapLogger.TraceExtension.XmlRequest.InnerXml;
var soapResponse = SoapLogger.TraceExtension.XmlResponse.InnerXml;

我就是不知道为什么会出错。

Winforms 应用程序有一个app.config,我在其中注册了我的类库程序集以捕获 xml。这是我的app.config 详细信息

<?xml version="1.0"?> 
<configuration> 
<system.serviceModel> 
<bindings> 
<basicHttpBinding> 
<binding name="TestServiceSoap"/> </basicHttpBinding> 
</bindings> <client> <endpoint address="http://localhost:6804/Service1.asmx" 
binding="basicHttpBinding" bindingConfiguration="TestServiceSoap" 
contract="ServiceRef.TestServiceSoap" name="TestServiceSoap"/> 
</client> 
</system.serviceModel> 
<system.web> 
<compilation debug="true" targetFramework="4.0" /> 
<webServices> <soapExtensionTypes> 
<add type="SoapLogger.TraceExtension,SoapLogger" priority="1" group="0" /> 
</soapExtensionTypes> </webServices> 
</system.web> 
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> 
</startup> </configuration>

当我搜索谷歌只是为了知道如何捕获请求/响应 xml 时,我得到了很多这样的文章。我关注了很多,但没有任何效果。

我为完成工作而关注的这个网址http://jramirezdev.net/blog/c-tip-capturar-los-mensajes-soap-de-un-servicio-asmx-que-hemos-referenciado

我不清楚是什么错误。我在类库方法中的每个方法处都设置了断点,但是当 Web 服务调用时,类库中没有执行任何方法。我不想使用任何像wireshark、fiddler这样的工具来捕获请求/响应xml,而是想以编程方式做同样的事情。

所以请指导我我的错误是什么?为什么我得到对象引用未设置错误?请查看我的代码或转到 url 链接并告诉我我的方法有什么问题

【问题讨论】:

标签: c# xml wcf web-services


【解决方案1】:

我们可以简单地跟踪请求消息。

OperationContext context = OperationContext.Current;

if (context != null && context.RequestContext != null)

{

Message msg = context.RequestContext.RequestMessage;

string reqXML = msg.ToString();

}

【讨论】:

  • 对使用 WebService ASMX 的客户端有效?
【解决方案2】:
  1. 配置WCF Tracing
  2. 发送/接收一些消息
  3. 获取SvcTraceViewer.exe 日志查看器并打开跟踪输出。
  4. 利润。

【讨论】:

    【解决方案3】:

    这个错误是因为xmlRequest/xmlResponse在你访问它们时没有被初始化。因此,请尝试检查 null,或为它们创建默认实例。

    从您的代码中,它们仅在ProcessMessage(SoapMessage message){} 中初始化,请确保在调用之前调用该方法

     var soapRequest = SoapLogger.TraceExtension.XmlRequest.InnerXml;
     var soapResponse = SoapLogger.TraceExtension.XmlResponse.InnerXml;
    

    希望这会有所帮助。

    编辑:

    仔细检查您的代码后,我意识到您编写的扩展程序 (SoapExtension) 是针对 ASP.NET XML Web 服务 的,它与 WCF 无关服务。

    要检查 WCF 服务中的请求和回复,您可以通过实现 System.ServiceModel.Dispatcher.IDispatchMessageInspector 在服务端扩展您的调度程序。

    你可以在这里找到例子http://msdn.microsoft.com/en-us/library/ms733104%28v=vs.100%29.aspx

    【讨论】:

    • 你能不能把我重定向到关于这个主题的正确文章,从那里我可以获得完整的工作代码示例,我可以在我的电脑上运行。谢谢
    • 任何使用System.ServiceModel.Dispatcher.IDispatchMessageInspector的完整真实世界代码?
    • 除了使用 IDispatchMessageInspector 之外还有其他选择吗?
    【解决方案4】:

    还有另一种查看 XML SOAP 的方法 - custom MessageEncoder。与 IDispatchMessageInspector / IClientMessageInspector 的主要区别在于它在较低级别上工作,因此它捕获原始字节内容,包括任何格式错误的 xml。

    为了使用这种方法实现跟踪,您需要将标准textMessageEncodingcustom message encoder 包装为新的binding element,并将该自定义绑定应用到config 中的端点。

    你也可以看看我在我的项目中是如何做到的—— wrapping textMessageEncoding,记录 encoder,自定义绑定 elementconfig

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多