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

时间:2010-04-12 19:04:09

标签: asp.net web-services soap asmx

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

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

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

Logger.LogMessage(incomingSoapRequest);
  • 是否有任何简单的解决方案来捕获传入SOAP请求的原始XML?
  • 您将处理哪些事件来访问此对象和相关属性?
  • 无论如何,IIS是否可以捕获传入的请求并推送到日志?

4 个答案:

答案 0 :(得分:19)

捕获原始邮件的一种方法是使用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();
    }
}

答案 1 :(得分:18)

您也可以通过将代码放在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);

}

我在我的网络服务中有一个实用工具方法,用于在发生某些事情时捕获请求,我不期望这是一个未处理的异常。

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

答案 2 :(得分:12)

您知道实际需要创建HttpModule权利吗?

您还可以在asmx Request.InputStream中阅读WebMethod的内容。

这是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;
    }
  }
}

答案 3 :(得分:-2)

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

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


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

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