【问题标题】:Intercept SOAP messages from and to a web service at the client在客户端拦截来自和发往 Web 服务的 SOAP 消息
【发布时间】:2011-04-22 04:58:43
【问题描述】:

我有一个与 Web 服务通信的客户端。我与之通信的类是通过 wsdl.exe 生成的 C# 类。我现在想记录所有传入和传出的消息。

到目前为止,我所做的是编写一个继承自自动生成的 C# 类的类,并且我已经覆盖了 GetReaderForMessage 方法。这样我就可以或多或少地像这样访问传入的消息:

protected override XmlReader GetReaderForMessage(SoapClientMessage message, int bufferSize)
{
    System.Xml.XmlReader aReader = base.GetReaderForMessage(message, bufferSize);
    System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
    doc.Load(aReader);
    string content = doc.InnerXml.ToString();
    System.Xml.XmlReader aReader2 = System.Xml.XmlReader.Create(new System.IO.StringReader(content));

    return aReader2;
}

显然我对这个解决方案不太满意,因为基本上我正在创建两个 xml 阅读器。一种用于读取 SOAP 消息的内容,另一种用于返回给方法调用者。另外,我不能用 GetWriterForMessage 方法做同样的事情。

但也许我只是做的事情太难开始了。例如,是否可以直接读取 SoapClientMessage 对象的内容?我读过一些文章,建议我应该在这里使用 SoapExtensions,但据我所知,只有当我创建的“客户端”本身是一个 Web 服务时才有效,在这种情况下它不是。

有什么建议吗?

【问题讨论】:

  • 您没有使用 WCF 有什么原因吗?
  • 我可以回答你的问题@JohnSaunders。我正在使用大量“有效”的遗留代码,而企业不希望它“无效”,因此对“有效”代码的任何更改都是不受欢迎的。
  • @ChrisHayes:你是@trabart 吗?如果不是,那你怎么回答我问他的问题。顺便说一句,我同意“如果它没有坏,就不要修复它”。但在我看来,修改现有代码的需要(例如,通过添加日志记录)意味着代码“损坏”。特别是,使用 WCF 比使用 ASMX 更容易完成 OP 想要做的事情。如果该代码将继续需要更改,则值得考虑升级。同样,需要频繁更改的 VB6 代码应该升级到 .NET,因为它会使更改变得更加容易。
  • Trabart,我有类似的项目边界 - 服务是带有 basicHttpBinding 的 WCF 服务,但客户端仅限使用 .Net Framework 2.0。我发现了很多 WCF 客户端/服务器解决方案,但不是那种混合的。最后,我使用了@Ceottaki 的I am consuming a WCF service that requires headers from a .NET 2 website. How can I programmatically add the headers to the messages? 文章中描述的解决方案。希望对您有所帮助。

标签: c# web-services soap asmx


【解决方案1】:

您需要使用“添加服务引用”而不是“添加 Web 引用”功能来使用此解决方案,如果服务是 ASMX 或 WCF,则可以使用它。 (您需要使用 .NET Framework 3.X 才能使用此功能)

This article 将帮助您将服务引用添加到您的 C# 项目中。

要拦截请求和响应的XML,实现这两个类:

public class InspectorBehavior : IEndpointBehavior
{
    public string LastRequestXML { 
        get
        {
            return myMessageInspector.LastRequestXML;
        }
    }

    public string LastResponseXML { 
        get
        {
            return myMessageInspector.LastResponseXML;
        }
    }


    private MyMessageInspector myMessageInspector = new MyMessageInspector();
    public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
    {

    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {

    }

    public void Validate(ServiceEndpoint endpoint)
    {

    }


    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        clientRuntime.MessageInspectors.Add(myMessageInspector );
    }
}





public class MyMessageInspector : IClientMessageInspector
{
    public string LastRequestXML { get; private set; }
    public string LastResponseXML { get; private set; }
    public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
    {
        LastResponseXML = reply.ToString();
    }

    public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
    {
        LastRequestXML = request.ToString();
        return request;
    }
}

然后,将调用代码更改为:

MyTestServiceSoapClient client = new MyTestServiceSoapClient();
var requestInterceptor = new InspectorBehavior();
client.Endpoint.Behaviors.Add(requestInterceptor );
client.DoSomething("param1", "param2", "param3");
string requestXML = requestInterceptor.LastRequestXML;
string responseXML = requestInterceptor.LastResponseXML;

****编辑**** 这与服务器端技术无关,您可以将它与 WCF、ASMX、PHP、... Web 服务一起使用,我已经测试过: http://www.w3schools.com/webservices/tempconvert.asmx

并得到以下 XML:

requestXML=

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/CelsiusToFahrenheit</Action>
  </s:Header>
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <CelsiusToFahrenheit xmlns="http://tempuri.org/">
      <Celsius>50</Celsius>
    </CelsiusToFahrenheit>
  </s:Body>
</s:Envelope>

responseXML=

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <s:Header xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" />
  <soap:Body>
    <CelsiusToFahrenheitResponse xmlns="http://tempuri.org/">
      <CelsiusToFahrenheitResult>122</CelsiusToFahrenheitResult>
    </CelsiusToFahrenheitResponse>
  </soap:Body>
</soap:Envelope>

****编辑 2****

“添加Web引用”不是ASMX专用的,不是ASMX客户端技术,“添加服务引用”不是WCF客户端技术,可以同时使用ASMX、WCF、 JSP 开发或 PHP 开发的 web 服务,您需要您的应用程序使用 .Net framework 3.5 才能使用“添加服务引用”。

This article 提及:

在 Visual Studio 中使用“添加 Web 引用”对话框时,客户端 代理使用 WSDL 信息生成并添加到 Visual 工作室项目。这通常用于 ASMX 服务,但您可以 还可以使用“添加 Web 引用”对话框为 WCF 服务。但是,您需要手动键入服务 URL,并且 生成的代理使用 XML 序列化,这是唯一的 支持的序列化类型。为 WCF 创建客户端代理 支持数据协定序列化程序的服务,您可以使用 Svcutil.exe 工具或使用添加服务引用功能的 .NET Framework 3.x 的 Visual Studio 开发工具。

【讨论】:

  • 他似乎使用的是 ASMX 客户端技术“添加 Web 引用”,而不是 WCF 客户端技术“添加服务引用”。
  • 你错了。 WCF 包括客户端代码和服务器端代码。 “添加服务引用”为任何类型的服务创建 WCF 客户端。
  • 但是他可以改变生成代理类的方式,用svcutil.exe代替wsdl.exe,按照你说的生成WCF客户端!!即使他的服务不是 WCF 服务,他也可以轻松做到这一点,我在我的解决方案中提到了这一点。
  • 完美!谢谢!要从 C# 客户端的 Java Web 服务 SoapFault 异常中获取非常详细的信息让我很难过,使用这种技术我可以解决问题。干杯! ;-)
【解决方案2】:

【讨论】:

  • OK... 还有一个问题。我现在有一个继承自 wsdl 生成的类的类。这个类有一个 Login 方法,它从 'wsdl' 类调用 Login 方法。当我将扩展应用到这个 wsdl 类时,一切似乎都正常工作,但我不希望这样,因为当 Web 服务更改时可以重新生成这个类。所以现在我想将此扩展应用于我自己的类,但是扩展类中的方法没有被调用......有什么建议吗?
猜你喜欢
  • 1970-01-01
  • 2010-11-16
  • 2013-01-16
  • 1970-01-01
  • 2017-06-18
  • 2017-02-20
  • 1970-01-01
  • 1970-01-01
  • 2011-10-11
相关资源
最近更新 更多