首页 文章

捕获SOAP请求到ASP.NET ASMX Web服务

提问于
浏览
28

考虑将传入的SOAP请求记录到ASP.NET ASMX Web服务的要求 . 任务是捕获发送到Web服务的原始XML .

需要记录传入消息以进行调试检查 . 该应用程序已经有自己的日志库,因此理想的用法是这样的:

//string or XML, it doesn't matter.
string incomingSoapRequest = GetSoapRequest();

Logger.LogMessage(incomingSoapRequest);
  • 是否有任何简单的解决方案来捕获传入SOAP请求的原始XML?

  • 您将处理哪些事件来访问此对象和相关属性?

  • 无论如何,IIS是否可以捕获传入的请求并推送到日志?

4 回答

  • -2

    捕获原始消息的一种方法是使用SoapExtensions .

    SoapExtensions的另一种选择是实现IHttpModule并在输入流时抓取输入流 .

    public class LogModule : IHttpModule
    {
        public void Init(HttpApplication context)
        {
            context.BeginRequest += this.OnBegin;
        }
    
        private void OnBegin(object sender, EventArgs e)
        {
            HttpApplication app = (HttpApplication)sender;
            HttpContext context = app.Context;
    
            byte[] buffer = new byte[context.Request.InputStream.Length];
            context.Request.InputStream.Read(buffer, 0, buffer.Length);
            context.Request.InputStream.Position = 0;
    
            string soapMessage = Encoding.ASCII.GetString(buffer);
    
            // Do something with soapMessage
        }
    
        public void Dispose()
        {
            throw new NotImplementedException();
        }
    }
    
  • 19

    您也可以通过将代码放在Global.asax.cs中来实现

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        // Create byte array to hold request bytes
        byte[] inputStream = new byte[HttpContext.Current.Request.ContentLength];
    
        // Read entire request inputstream
        HttpContext.Current.Request.InputStream.Read(inputStream, 0, inputStream.Length);
    
        //Set stream back to beginning
        HttpContext.Current.Request.InputStream.Position = 0;
    
        //Get  XML request
        string requestString = ASCIIEncoding.ASCII.GetString(inputStream);
    
    }
    

    我在我的Web服务中有一个Utility方法,用于在发生某些事情时捕获请求,我并不期望这是一个未处理的异常 .

    /// <summary>
        /// Captures raw XML request and writes to FailedSubmission folder.
        /// </summary>
        internal static void CaptureRequest()
        {
            const string procName = "CaptureRequest";
    
            try
            {
                log.WarnFormat("{0} - Writing XML request to FailedSubmission folder", procName);
    
                byte[] inputStream = new byte[HttpContext.Current.Request.ContentLength];
    
                //Get current stream position so we can set it back to that after logging
                Int64 currentStreamPosition = HttpContext.Current.Request.InputStream.Position;
    
                HttpContext.Current.Request.InputStream.Position = 0;
    
                HttpContext.Current.Request.InputStream.Read(inputStream, 0, HttpContext.Current.Request.ContentLength);
    
                //Set back stream position to original position
                HttpContext.Current.Request.InputStream.Position = currentStreamPosition;
    
                string xml = ASCIIEncoding.ASCII.GetString(inputStream);
    
                string fileName = Guid.NewGuid().ToString() + ".xml";
    
                log.WarnFormat("{0} - Request being written to filename: {1}", procName, fileName);
    
                File.WriteAllText(Configuration.FailedSubmissionsFolder + fileName, xml);
            }
            catch
            {
            }
    
        }
    

    然后在web.config中我存储了几个AppSetting值,这些值定义了我想用来捕获请求的级别 .

    <!-- true/false - If true will write to an XML file the raw request when any Unhandled exception occurrs -->
        <add key="CaptureRequestOnUnhandledException" value="true"/>
    
        <!-- true/false - If true will write to an XML file the raw request when any type of error is returned to the client-->
        <add key="CaptureRequestOnAllFailures" value="false"/>
    
        <!-- true/false - If true will write to an XML file the raw request for every request to the web service -->
        <add key="CaptureAllRequests" value="false"/>
    

    然后在我的Application_BeginRequest中,我将其修改为如此 . 请注意,Configuration是我创建的静态类,用于从web.config和其他区域读取属性 .

    protected void Application_BeginRequest(object sender, EventArgs e)
        {
    
            if(Configuration.CaptureAllRequests)
            {
                Utility.CaptureRequest();
            }
        }
    
  • 11

    你知道你不需要创建一个 HttpModule 对吗?

    您还可以从asmx WebMethod 中读取 Request.InputStream 的内容 .

    这是an article I wrote on this approach .

    代码如下:

    using System;
    using System.Collections.Generic;
    using System.Web;
    using System.Xml;
    using System.IO;
    using System.Text;
    using System.Web.Services;
    using System.Web.Services.Protocols;
    
    namespace SoapRequestEcho
    {
      [WebService(
      Namespace = "http://soap.request.echo.com/",
      Name = "SoapRequestEcho")]
      public class EchoWebService : WebService
      {
    
        [WebMethod(Description = "Echo Soap Request")]
        public XmlDocument EchoSoapRequest(int input)
        {
          // Initialize soap request XML
          XmlDocument xmlSoapRequest = new XmlDocument();
    
          // Get raw request body
          Stream receiveStream = HttpContext.Current.Request.InputStream;
    
          // Move to beginning of input stream and read
          receiveStream.Position = 0;
          using (StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8))
          {
            // Load into XML document
            xmlSoapRequest.Load(readStream);
          }
    
          // Return
          return xmlSoapRequest;
        }
      }
    }
    
  • 18

    没有简单的方法可以做到这一点 . 你必须实现一个SoapExtension . 上一个链接的示例显示了可用于记录数据的扩展 .

    如果您一直在使用WCF,那么您只需设置配置即可生成消息日志 .


    根据Steven de Salas,您可以在webmethod中使用 Request.InputStream 属性 . 我没试过这个,但他说它有效 .

    我想用http和https来测试它,并且同时运行和不运行其他SoapExtensions . 这些可能会影响 InputStream 设置的流类型 . 例如,某些流无法搜索,这可能会使您在数据结束后定位流,并且您无法移动到开头 .

相关问题