拦截来自客户端的Web服务的SOAP消息

时间:2021-07-29 00:28:18

I have a client that communicates with a web service. The class that I communicate with is a C# class that is generated through wsdl.exe. I now want to log all incoming and outgoing messages.

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

What I've done so far is to write a class that inherits from the automatically generated C# Class and I have overridden the GetReaderForMessage method. That way I can access the incoming message more or less like this:

到目前为止我所做的是编写一个继承自动生成的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;
}

Obviously I'm not too happy with this solution, because basically I'm creating two xml readers. One to read the contents of the SOAP message and one to return to the method caller. Plus I can't really do the same with the GetWriterForMessage method.

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

But may be I'm just doing things too difficult to start with. Is it for instance possible to read the contents of the SoapClientMessage object directly? I've read some articles suggesting that I should use SoapExtensions here, but from what I can understand, that would only work if the 'client' that I am creating is itself a web service which in this case it is not.

但可能我只是做起来太困难了。例如,是否可以直接读取SoapClientMessage对象的内容?我已经阅读了一些文章,建议我应该在这里使用SoapExtensions,但是从我能理解的情况来看,这只有在我创建的'客户端'本身就是一个Web服务时才会起作用,在这种情况下它不是。

Any suggestions?

有什么建议么?

2 个解决方案

#1


5  

I would suggest looking into using a SOAP extension, which in my opinion is ideal for this scenario. Here are a few links that describe the process.

我建议使用SOAP扩展,我认为这是这种情况的理想选择。以下是一些描述该过程的链接。

http://msdn.microsoft.com/en-us/magazine/cc164007.aspx

http://msdn.microsoft.com/en-us/magazine/cc164007.aspx

https://ebay.custhelp.com/cgi-bin/ebay.cfg/php/enduser/std_adp.php?p_faqid=350

https://ebay.custhelp.com/cgi-bin/ebay.cfg/php/enduser/std_adp.php?p_faqid=350

http://www.codeproject.com/KB/webservices/efficientsoapextension.aspx

http://www.codeproject.com/KB/webservices/efficientsoapextension.aspx

#2


48  

You need to use "Add Service Reference" and not "Add Web Reference" feature to use this solution, it can be used if the service is ASMX or WCF. (You need to use .NET Framework 3.X to use this feature)

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

This article will help you to add the service reference to your C# project.

本文将帮助您将服务引用添加到C#项目中。

To intercept and XMLs of the request and the response, Implement these two classes:

要拦截请求和响应的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;
    }
}

Then, change the call code to:

然后,将呼叫代码更改为:

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;

****EDIT**** This is not related with the serverside technology, you can use it with WCF, ASMX, PHP, ... web services, I have tested on: http://www.w3schools.com/webservices/tempconvert.asmx

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

And got the following XMLs:

并获得以下XML:

requestXML=

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=

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>

****EDIT 2****

****编辑2 ****

"Add Web Reference" is not specialized for ASMX and is not an ASMX client-side technology, and "Add Service Reference"is not the WCF client-side technology, you can use both to add reference to ASMX, WCF, JSP-developed or PHP-developed, web service, you need your application to use .Net framework 3.5 to use "Add Service Reference".

“添加Web引用”不是专用于ASMX而不是ASMX客户端技术,而“添加服务引用”不是WCF客户端技术,您可以使用它们来添加对ASMX,WCF,JSP开发的引用或PHP开发的Web服务,您需要您的应用程序使用.Net framework 3.5来使用“添加服务引用”。

This article mentions:

本文提到:

When using the Add Web Reference dialog box in Visual Studio, a client proxy is generated using WSDL information and is added to the Visual Studio project. This is usually used for ASMX services, but you can also use the Add Web Reference dialog box to create a client proxy for WCF services. However, you need to manually type the service URL, and the proxy that is generated uses XML serialization, which is the only type of serialization supported. To create client proxies for WCF services that support the data contract serializer, you can use the Svcutil.exe tool or use the Add Service Reference feature of the Visual Studio Development Tools for the .NET Framework 3.x.

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

#1


5  

I would suggest looking into using a SOAP extension, which in my opinion is ideal for this scenario. Here are a few links that describe the process.

我建议使用SOAP扩展,我认为这是这种情况的理想选择。以下是一些描述该过程的链接。

http://msdn.microsoft.com/en-us/magazine/cc164007.aspx

http://msdn.microsoft.com/en-us/magazine/cc164007.aspx

https://ebay.custhelp.com/cgi-bin/ebay.cfg/php/enduser/std_adp.php?p_faqid=350

https://ebay.custhelp.com/cgi-bin/ebay.cfg/php/enduser/std_adp.php?p_faqid=350

http://www.codeproject.com/KB/webservices/efficientsoapextension.aspx

http://www.codeproject.com/KB/webservices/efficientsoapextension.aspx

#2


48  

You need to use "Add Service Reference" and not "Add Web Reference" feature to use this solution, it can be used if the service is ASMX or WCF. (You need to use .NET Framework 3.X to use this feature)

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

This article will help you to add the service reference to your C# project.

本文将帮助您将服务引用添加到C#项目中。

To intercept and XMLs of the request and the response, Implement these two classes:

要拦截请求和响应的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;
    }
}

Then, change the call code to:

然后,将呼叫代码更改为:

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;

****EDIT**** This is not related with the serverside technology, you can use it with WCF, ASMX, PHP, ... web services, I have tested on: http://www.w3schools.com/webservices/tempconvert.asmx

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

And got the following XMLs:

并获得以下XML:

requestXML=

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=

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>

****EDIT 2****

****编辑2 ****

"Add Web Reference" is not specialized for ASMX and is not an ASMX client-side technology, and "Add Service Reference"is not the WCF client-side technology, you can use both to add reference to ASMX, WCF, JSP-developed or PHP-developed, web service, you need your application to use .Net framework 3.5 to use "Add Service Reference".

“添加Web引用”不是专用于ASMX而不是ASMX客户端技术,而“添加服务引用”不是WCF客户端技术,您可以使用它们来添加对ASMX,WCF,JSP开发的引用或PHP开发的Web服务,您需要您的应用程序使用.Net framework 3.5来使用“添加服务引用”。

This article mentions:

本文提到:

When using the Add Web Reference dialog box in Visual Studio, a client proxy is generated using WSDL information and is added to the Visual Studio project. This is usually used for ASMX services, but you can also use the Add Web Reference dialog box to create a client proxy for WCF services. However, you need to manually type the service URL, and the proxy that is generated uses XML serialization, which is the only type of serialization supported. To create client proxies for WCF services that support the data contract serializer, you can use the Svcutil.exe tool or use the Add Service Reference feature of the Visual Studio Development Tools for the .NET Framework 3.x.

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