在将SOAP消息发送到.NET中的WebService之前获取它

时间:2009-01-20 15:26:17

标签: .net web-services soap

我正在调用外部HTTPS网络服务。

为了检查什么是错误,所有者需要我发送的SOAP请求。

我有一个Web引用和由VS 2008生成的生成的代理类...

有没有办法在发送之前看到SOAP消息?

我正在思考一些.net代码......因为我试过的Sniffer没有“看到”web服务调用不知道为什么。

6 个答案:

答案 0 :(得分:11)

您可以在减去之前简单地序列化请求对象,如下所示:

var sreq = new SomeSoapRequest();

// ... fill in here ...

var serxml = new System.Xml.Serialization.XmlSerializer(sreq.GetType());
var ms = new MemoryStream();
serxml.Serialize(ms, sreq);
string xml = Encoding.UTF8.GetString(ms.ToArray());

// in xml string you have SOAP request

答案 1 :(得分:7)

答案 2 :(得分:4)

您可以使用IClientMEssageInspector和IEndpointBehavior来填充此内容。我发现使用这种方式可以捕获确切的肥皂​​请求可能作为小提琴手:

在同一个项目中创建这样的类:

public class ClientMessageInspector : System.ServiceModel.Dispatcher.IClientMessageInspector
    {
        #region IClientMessageInspector Members
        public string LastRequestXml { get; private set; }

        public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
        {

        }

        public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
        {
            string requestHeaderName = request.Headers.Action.Replace("urn:#",string.Empty);
            LastRequestXml = request.ToString();
            string serializedRequestFile = string.Format(requestHeaderName + "_request_{0}.xml", DateTime.Now.ToString("yyyyMMddHHmmss"));
            string exportedFolder = ConfigurationManager.AppSettings["SubmittedRequestXmLocation"];
            printSoapRequest(request, exportedFolder, serializedRequestFile);

            return request;
        }

        public void printSoapRequest(System.ServiceModel.Channels.Message request, string exportedFolder, string fileName)
        {
            if (exportedFolder.Equals(string.Empty))
                return;

            if (!Directory.Exists(exportedFolder))
            {
                Directory.CreateDirectory(exportedFolder);
            }
            string exportedFile = string.Format("{0}\\{1}", exportedFolder, fileName);
            if (File.Exists(exportedFile))
            {
                File.Delete(exportedFile);
            }

            string strRequestXML = request.ToString();
            XDocument xDoc = XDocument.Parse(strRequestXML);
            XmlWriter xw = XmlWriter.Create(exportedFile);
            xDoc.Save(xw);
            xw.Flush();
            xw.Close();
            LogOutput("Request file exported: " + exportedFile);

        }

    }

    public class CustomInspectorBehavior : IEndpointBehavior
    {
        private readonly ClientMessageInspector clientMessageInspector = new ClientMessageInspector();

        public string LastRequestXml
        {
            get { return clientMessageInspector.LastRequestXml; }
        }

        public string LastResponseXml
        {
            get { return clientMessageInspector.LastRequestXml; }
        }

        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(clientMessageInspector);
        }
    }

然后你可以像下面那样调用它:

ProxyClass _class = new ProxyClass();
var requestInterceptor = new CustomInspectorBehavior();
           _client.Endpoint.Behaviors.Add(requestInterceptor);

当您调用服务方法时,它将自动执行拦截器并打印输出。使用这种方式,您还可以在发送到服务器之前操作soap消息!

答案 3 :(得分:3)

@ mting923的建议真的很有帮助,谢谢!

其他想法(例如,利用SoapExtension或在How do I get access to SOAP response中创建'spy'类)很有趣,但是不能在.NET Core中使用。但是生成的SOAP代理类仍然只是一个WCF客户端,因此IClientMessageInspector方法即使对调用较早SOAP Web服务的.NET Core Azure Function来说也可以解决问题。

在上面的示例中,隐含了响应联动,但没有完整显示。另外,在最新的.NET Core API中,MessageInspectors现在为ClientMessageInspectors,而Behaviors现在为EndpointBehaviors。因此,为了完整起见,以下内容在.NET Core 3.1 Azure函数中对我有用:

public class SoapMessageInspector : IClientMessageInspector
{
    public string LastRequestXml { get; private set; }
    public string LastResponseXml { get; private set; }

    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        LastRequestXml = request.ToString();
        return request;
    }

    public void AfterReceiveReply(ref Message reply, object correlationState)
    {
        LastResponseXml = reply.ToString();
    }
}

public class SoapInspectorBehavior : IEndpointBehavior
{
    private readonly SoapMessageInspector inspector_ = new SoapMessageInspector();

    public string LastRequestXml => inspector_.LastRequestXml;
    public string LastResponseXml => inspector_.LastResponseXml;

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
    }

    public void Validate(ServiceEndpoint endpoint)
    {
    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        clientRuntime.ClientMessageInspectors.Add(inspector_);
    }
}

然后可以这样设置:

    var client = new ServiceClient();
    var soapInspector = new SoapInspectorBehavior();
    client.Endpoint.EndpointBehaviors.Add(soapInspector);

在客户端代理上调用Web服务调用之后,soapInspector.LastRequestXmlsoapInspector.LastResponseXml将包含原始的SOAP请求和响应(作为字符串)。

答案 4 :(得分:0)

如果您在更受限制的环境中工作并且没有使用像Fiddler这样的应用程序,您可以执行以下操作:

  1. 照常生成您的网络参考。
  2. 编写代码以执行您要访问的任何Web方法调用。
  3. 创建一个新的ASP .NET项目,我选择MVC 4。
  4. 创建处理程序或控制器/操作,并像这样提取请求流:
  5. using (var reader = new System.IO.StreamReader(Request.InputStream)) { result = reader.ReadToEnd(); }

    1. 在其上放置一个断点并以调试模式运行它。
    2. 在您的客户端上,将SOAP请求的Url设置为新的控制器/处理程序。
    3. 运行您的客户。您应该使用SOAP消息在Web应用程序上捕获断点。
    4. 这不是一个理想或漂亮的解决方案,但如果您在中等受限制的环境中工作,它就能完成工作。

答案 5 :(得分:0)

将此添加到web.config或App.config文件的元素中。它将在项目的bin / Debug文件夹中创建trace.log文件。或者,您可以使用initializeData属性为日志文件指定绝对路径。

  <system.diagnostics>
    <trace autoflush="true"/>
    <sources>
      <source name="System.Net" maxdatasize="9999" tracemode="protocolonly">
        <listeners>
          <add name="TraceFile" type="System.Diagnostics.TextWriterTraceListener" initializeData="trace.log"/>
        </listeners>
      </source>
    </sources>
    <switches>
      <add name="System.Net" value="Verbose"/>
    </switches>
  </system.diagnostics>

它警告说,不允许使用maxdatasize和tracemode属性,但它们会增加可记录的数据量,并避免以十六进制记录所有内容。