【问题标题】:Get SOAP Message before sending it to the WebService in .NET在将 SOAP 消息发送到 .NET 中的 WebService 之前获取它
【发布时间】:2009-01-20 15:26:16
【问题描述】:

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

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

我有一个 web 参考和 VS 2008 生成的代理类...

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

我正在考虑一些 .net 代码...因为我尝试的嗅探器没有“看到”网络服务调用不知道为什么。

【问题讨论】:

    标签: .net web-services soap


    【解决方案1】:

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

    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
    

    【讨论】:

      【解决方案2】:

      【讨论】:

      • 第二个链接有多个选项。公认的答案不一定是最好的(所有三个解决方案都是好的)。仅供参考,我最喜欢 Fiddler 选项。
      【解决方案3】:

      您可以使用 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消息!

      【讨论】:

      • 我使用 Web 服务参考不是 WCF 参考
      • 如果您使用Web Service Reference,您可以完全从头开始构建整个soap 信封。但是,我不推荐它,因为它实现可靠且现代。
      • Soap 扩展(公认的答案)有些过时了。一般来说,这种方法 - Message Inspectors - 通常是“更好”的选择。
      【解决方案4】:

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

      其他想法(例如利用 SoapExtension,或创建类似于 How do I get access to SOAP response 的“间谍”类)很有趣,但不能在 .NET Core 中使用。但是生成的 SOAP 代理类在底层仍然只是一个 WCF 客户端,因此 IClientMessageInspector 方法很有效,即使对于调用旧 SOAP Web 服务的 .NET Core Azure 函数也是如此。

      在上面的示例中,响应连接是隐含的,但未完全显示。此外,在最新的 .NET Core API 中,MessageInspectors 现在是 ClientMessageInspectorsBehaviors 现在是 EndpointBehaviors。因此,为了完整起见,以下内容适用于 .NET Core 3.1 Azure Function:

      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 请求和响应(作为字符串)。

      【讨论】:

        【解决方案5】:

        将此添加到 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 属性,但它们会增加可记录的数据量,并避免以十六进制记录所有内容。

        【讨论】:

        • 诊断显示请求和响应 SOAP 信封以及一些网络跟踪。
        【解决方案6】:

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

        1. 照常生成您的网络参考。
        2. 编写代码来执行你要给我的任何网络方法调用。
        3. 创建一个您选择的新 ASP .NET 项目,我使用 MVC 4。
        4. 创建一个处理程序或控制器/动作,并像这样提取请求流:

        using (var reader = new System.IO.StreamReader(Request.InputStream)) { result = reader.ReadToEnd(); }

        1. 在其上放置断点并在调试模式下运行。
        2. 在您的客户端上,将 SOAP 请求的 URL 设置为您的新控制器/处理程序。
        3. 运行您的客户端。您应该使用 SOAP 消息捕获 Web 应用程序上的断点。

        这不是一个理想或漂亮的解决方案,但如果您在适度受限的环境中工作,它就能完成工作。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-05-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多