Capturing SOAP requests to an ASP.NET ASMX web service Capturing SOAP requests to an ASP.NET ASMX web service asp.net asp.net

Capturing SOAP requests to an ASP.NET ASMX web service


You can also implement by placing the code in 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);}

I have a Utility method in my web service that I use to capture the request when something happens that I am not expecting like a unhandled exception.

    /// <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        {        }    }

Then in web.config I store several AppSetting values that define what level I want to use to capture the request.

    <!-- 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"/>

Then in my Application_BeginRequest I have it modified like so. Note that Configuration is a static class I create to read properties from web.config and other areas.

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


One way to capture the raw message is to use SoapExtensions.

An alternative to SoapExtensions is to implement IHttpModule and grab the input stream as it's coming in.

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


You know that you dont actually need to create a HttpModule right?

You can also read the contents of the Request.InputStream from within your asmx WebMethod.

Here is an article I wrote on this approach.

Code is as follows:

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