在将SOAP消息发送到.NET中的Web服务之前获取该消息

在将SOAP消息发送到.NET中的Web服务之前获取该消息,.net,web-services,soap,.net,Web Services,Soap,我正在调用外部HTTPS Web服务 为了检查错误,所有者需要我发送的SOAP请求 我有一个web引用和VS2008生成的代理类 是否有办法在发送SOAP消息之前查看它? 我在想一些.net代码。。。因为我尝试的嗅探器没有“看到”Web服务调用,所以不知道为什么。您需要的是一个SoapExtension。这里有很多很好的例子: 其中一篇文章链接到: 还可以搜索:如果您在更严格的环境中工作,并且没有使用Fiddler之类的应用程序的特权,您可以执行以下操作: ProxyClass _cla

我正在调用外部HTTPS Web服务

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

我有一个web引用和VS2008生成的代理类

是否有办法在发送SOAP消息之前查看它?


我在想一些.net代码。。。因为我尝试的嗅探器没有“看到”Web服务调用,所以不知道为什么。

您需要的是一个SoapExtension。这里有很多很好的例子:

其中一篇文章链接到:


还可以搜索:

如果您在更严格的环境中工作,并且没有使用Fiddler之类的应用程序的特权,您可以执行以下操作:

ProxyClass _class = new ProxyClass();
var requestInterceptor = new CustomInspectorBehavior();
           _client.Endpoint.Behaviors.Add(requestInterceptor);
  • 像往常一样生成您的web引用
  • 编写代码来执行您要调用的任何web方法
  • 创建一个新的ASP.NET项目,我选择了MVC4
  • 创建处理程序或控制器/操作,并按如下方式提取请求流:
  • 
    使用(var reader=new System.IO.StreamReader(Request.InputStream))
    {
    结果=reader.ReadToEnd();
    }
    

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

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

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

    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
    
        var client = new ServiceClient();
        var soapInspector = new SoapInspectorBehavior();
        client.Endpoint.EndpointBehaviors.Add(soapInspector);
    

    您可以使用IClientMEssageInspector和IEndpointBehavior来完成此操作。我发现使用这种方法可以捕获准确的soap请求,就像fiddler请求一样:

    在同一项目中创建如下类:

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

    @mting923的建议非常有用,谢谢

    其他想法(例如利用SoapExtension,或创建“spy”类a la)很有趣,但不能用于.NETCore。但生成的SOAP代理类仍然只是一个隐藏的WCF客户机,因此IClientMessageInspector方法非常有效,即使对于调用旧SOAP web服务的.NET核心Azure函数也是如此

    在上面的示例中,暗示了响应wireup,但未完全显示。另外,在最新的.NET核心API中,
    MessageInspectors
    现在是
    ClientMessageInspectors
    行为现在是
    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 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
    
        var client = new ServiceClient();
        var soapInspector = new SoapInspectorBehavior();
        client.Endpoint.EndpointBehaviors.Add(soapInspector);
    

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

    第二个链接有多个选项。公认的答案不一定是最好的(所有三种解决方案都是好的)。仅供参考,我最喜欢Fiddler选项。我使用Web服务引用,而不是WCF引用。如果您使用Web服务引用,您完全可以从头构建整个soap信封。但是,我不推荐它,因为它有可靠的实现和现代的.Soap扩展(公认的答案)有些过时。一般来说,这种方法——通常是“更好”的选择。非常容易添加并立即工作。诊断显示请求和响应SOAP信封以及一些网络跟踪。