Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Capturing SOAP requests to an ASP.NET ASMX web service

Consider the requirement to log incoming SOAP requests to an ASP.NET ASMX web service. The task is to capture the raw XML being sent to the web service.

The incoming message needs to be logged for debug inspection. The application already has its own logging library in use, so the ideal usage would be something like this:

//string or XML, it doesn't matter. string incomingSoapRequest = GetSoapRequest();  Logger.LogMessage(incomingSoapRequest); 
  • Are there any easy solutions to capture the raw XML of the incoming SOAP requests?
  • Which events would you handle to get access to this object and the relevant properties?
  • Is there anyway IIS can capture the incoming request and push to a log?
like image 592
p.campbell Avatar asked Apr 12 '10 19:04

p.campbell


People also ask

Does Asmx use soap?

ASMX provides the ability to build web services that send messages using the Simple Object Access Protocol (SOAP). SOAP is a platform-independent and language-independent protocol for building and accessing web services.

Is Asmx SOAP or REST?

It is based on SOAP and return data in XML form. It support only HTTP protocol. It is not open source but can be consumed by any client that understands xml.


2 Answers

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();         }     } 
like image 63
Jim Scott Avatar answered Sep 27 '22 17:09

Jim Scott


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();     } } 
like image 25
nivlam Avatar answered Sep 27 '22 17:09

nivlam