Josh Heyse

Thoughts Defragmented

Archive for October, 2007

HttpRequest/Response Logging HttpModule

Posted by admin on 24th October 2007

One of the clients I am at has been having some issues tracking down errors in SOAP messages.  In most environments I would suggest installing ethereal, or another packet sniffing application to capture the incoming request and returning response. 

But, another way to accomplish this is to create a HttpModule to capture the data.  Logging the incoming request is simple by using the Request.SaveAs method.  To capture the outgoing response is a little harder and requires creating a filter, which extends System.IO.Stream.

Code Example

public class LogModule : IHttpModule
{
    private HttpResponseLogFilter _logFilter;
    private string _logPath;
 
    public string LogDirectory
    {
        get
        {
            return System.Configuration.ConfigurationManager.AppSettings["LogModuleDirectory"];
        }
    }
 
    private string GetLogPath(HttpApplication context, string type)
    {
        string fileName = string.Format("{0}.{1}.{2:yyyy.MM.dd.HH.mm.ss.ff}.{3}.txt", context.Request.UserHostName, context.Request.Path, DateTime.Now, type);
        fileName = fileName.Replace("/", "").Replace(@"", "");
        if(!string.IsNullOrEmpty(LogDirectory))
            fileName = Path.Combine(LogDirectory, fileName);
        return fileName;
    }
 
    public void Dispose()
    {
        _logFilter.Dispose();
    }
 
    public void Init(HttpApplication context)
    {
        if (string.IsNullOrEmpty(LogDirectory))
            return;
 
        context.BeginRequest += new EventHandler(context_BeginRequest);
    }
 
    void context_BeginRequest(object sender, EventArgs e)
    {
        HttpApplication context = (HttpApplication)sender;
        context.Request.SaveAs(GetLogPath(context, "request"), true);
        _logFilter = new HttpResponseLogFilter(context.Response.Filter, GetLogPath(context, "reply"));
        context.Response.Filter = _logFilter;
    }
 
    public class HttpResponseLogFilter : Stream, IDisposable
    {
        private Stream _stream;
        private FileStream _logStream;
        private int _disposed = 0;
 
        public HttpResponseLogFilter(Stream stream, string path)
        {
            _stream = stream;
            _logStream = new FileStream(path, FileMode.Create);
        }
 
        public override bool CanRead
        {
            get { return false; }
        }
 
        public override bool CanSeek
        {
            get { return false; }
        }
 
        public override bool CanWrite
        {
            get { return true; }
        }
 
        public override void Flush()
        {
            _stream.Flush();
            _logStream.Flush();
        }
 
        public override long Length
        {
            get { throw new Exception("The method or operation is not implemented."); }
        }
 
        public override long Position
        {
            get
            {
                throw new Exception("The method or operation is not implemented.");
            }
            set
            {
                throw new Exception("The method or operation is not implemented.");
            }
        }
 
        public override int Read(byte[] buffer, int offset, int count)
        {
            throw new Exception("The method or operation is not implemented.");
        }
 
        public override long Seek(long offset, SeekOrigin origin)
        {
            throw new Exception("The method or operation is not implemented.");
        }
 
        public override void SetLength(long value)
        {
            throw new Exception("The method or operation is not implemented.");
        }
 
        public override void Write(byte[] buffer, int offset, int count)
        {
            _logStream.Write(buffer, offset, count);
            _stream.Write(buffer, offset, count);
        }
 
        protected override void Dispose(bool disposing)
        {
            if (System.Threading.Interlocked.CompareExchange(ref _disposed, 1, 0) == 0)
                _logStream.Dispose();
            base.Dispose(disposing);
        }
    }
}

Configuration File

<configuration>
  <appSettings>
    <add key="LogModuleDirectory" value="C:" />
  </appSettings>
 
  <system.web>
    <httpModules>
      <add name="HTTPLog" type="WebApplication1.LogModule"/>
    </httpModules>
  </system.web>
</configuration>

Posted in .NET, ASP.NET, C# | No Comments »