0

Assuming I am doing webservice request from the client. The request is made by POST with json parameters.
In the server, Context.Request.RawUrl hold the request url. But what holds the request json data?

I need this property in order to log requests.

Here is the code for the http module:

  public class RequestResponseLoggerModule : IHttpModule
    {
        //private static Logger logger = LogManager.GetCurrentClassLogger();

        #region ResponseCaptureStream

        private class ResponseCaptureStream : Stream
        {
            private readonly Stream _streamToCapture;
            private readonly Encoding _responseEncoding;

            public string StreamContent { get; private set; }            

            public ResponseCaptureStream(Stream streamToCapture, Encoding responseEncoding)
            {
                _responseEncoding = responseEncoding;
                _streamToCapture = streamToCapture;
            }

            public override bool CanRead { get { return _streamToCapture.CanRead; } }
            public override bool CanSeek { get { return _streamToCapture.CanSeek; } }
            public override bool CanWrite { get { return _streamToCapture.CanWrite; } }
            public override long Length { get { return _streamToCapture.Length; } }
            public override long Position
            {
                get { return _streamToCapture.Position; }
                set { _streamToCapture.Position = value; }
            }


            public override void Flush()
            {
                _streamToCapture.Flush();
            }           

            public override int Read(byte[] buffer, int offset, int count)
            {
                return _streamToCapture.Read(buffer, offset, count);
            }

            public override long Seek(long offset, SeekOrigin origin)
            {
                return _streamToCapture.Seek(offset, origin);
            }

            public override void SetLength(long value)
            {
                _streamToCapture.SetLength(value);
            }

            public override void Write(byte[] buffer, int offset, int count)
            {
                StreamContent += _responseEncoding.GetString(buffer);
                _streamToCapture.Write(buffer, offset, count);
            }

            public override void Close()
            {
                _streamToCapture.Close();
                base.Close();
            }
        }

        #endregion

        #region IHttpModule Members

        private HttpApplication _context;
        public void Dispose()
        {

        }

        private static string Extensions_Key = "RequestResponseLoggerModule.Extensions";
        private static string Files_Key = "RequestResponseLoggerModule.Files";
        private static string Request_Key = "RequestResponseLoggerModule.Request";
        private static string Response_Key = "RequestResponseLoggerModule.Response";

        private IEnumerable<string> _Extenstions = new string[] { };
        private IEnumerable<string> _Files = new string[] { };
        private bool _LogAlwaysRequest = false;
        private bool _LogAlwaysResponse = false;

        public void Init(HttpApplication context)
        {
            _Extenstions = ConfigurationManager.AppSettings[Extensions_Key].ToLower().Split(',').
                Select(x => x.Trim()).ToArray();
            _Files = ConfigurationManager.AppSettings[Files_Key].ToLower().Split(',').
                Select(x => x.Trim()).ToArray();
            _LogAlwaysRequest = ConfigurationManager.AppSettings[Request_Key] == "ALWAYS";
            _LogAlwaysResponse = ConfigurationManager.AppSettings[Response_Key] == "ALWAYS";

            _context = context;

            context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);
            context.PreSendRequestContent += new EventHandler(context_PreSendRequestContent);
        }

        void context_PreRequestHandlerExecute(object sender, EventArgs e)
        {
            _context.Response.Filter = new ResponseCaptureStream(_context.Response.Filter, _context.Response.ContentEncoding);
        }

        void context_PreSendRequestContent(object sender, EventArgs e)
        {
            bool isMatch = false;
            if (_Extenstions.Count() > 0)
            {
                string ext = VirtualPathUtility.GetExtension(_context.Request.FilePath).
                    Substring(1).ToLower();
                if (_Extenstions.Contains(ext))
                {
                    isMatch = true;
                }
            }
            if (_Files.Count() > 0)
            {
                string fileName = VirtualPathUtility.GetFileName(_context.Request.FilePath).                   ToLower();
                if (_Files.Contains(fileName))
                {
                    isMatch = true;
                }
            }

            if (_LogAlwaysRequest || isMatch)
            {
                string requestText = _context.Request.RawUrl; <------------------

                //log the responseText, but this reurns just the url while I need the data of the webservice call
            }
            if (_LogAlwaysResponse || isMatch)
            {
                ResponseCaptureStream filter = _context.Response.Filter as ResponseCaptureStream;
                if (filter != null)
                {
                    string responseText = filter.StreamContent;
                    //log the responseText
                }
            }        
        }

        #endregion
    }
Naor
  • 23,465
  • 48
  • 152
  • 268

2 Answers2

2

If you have made a POST with the json in the payload, then you need to read the request body. You would do this by consuming Request.InputStream, for example:

        string json;
        using (var reader = new StreamReader(Request.InputStream))
        {
            json = reader.ReadToEnd();
        }

You need to be careful, though - since consuming the body may mean that your actual code can't read it. Which would be bad.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • So there is no way to log the request data?? – Naor Jul 13 '11 at 12:15
  • @Naor it is tricky - you could *try* spoofing the incoming request stream, especially if your code is using the MVC abstractions etc, but it might be tricky. I can't give you a "this will definitely work" answer, I'm afraid. – Marc Gravell Jul 13 '11 at 12:30
  • @ Marc Gravell: What about this: http://stackoverflow.com/questions/1038466/logging-raw-http-request-response-in-asp-net-mvc-iis7/1792864#1792864 – Naor Jul 13 '11 at 12:37
  • I added an answer that is work. Can you give me your opinion about it? – Naor Jul 13 '11 at 12:56
1
public class RequestResponseLoggerModule : IHttpModule
{
    //private static Logger logger = LogManager.GetCurrentClassLogger();

    #region CaptureStream

    private class CaptureStream : Stream
    {
        private readonly Stream _streamToCapture;
        private readonly Encoding _encoding;

        public string StreamContent { get; private set; }

        public CaptureStream(Stream streamToCapture, Encoding encoding)
        {
            _encoding = encoding;
            _streamToCapture = streamToCapture;
        }

        public override bool CanRead { get { return _streamToCapture.CanRead; } }
        public override bool CanSeek { get { return _streamToCapture.CanSeek; } }
        public override bool CanWrite { get { return _streamToCapture.CanWrite; } }
        public override long Length { get { return _streamToCapture.Length; } }
        public override long Position
        {
            get { return _streamToCapture.Position; }
            set { _streamToCapture.Position = value; }
        }


        public override void Flush()
        {
            _streamToCapture.Flush();
        }           

        public override int Read(byte[] buffer, int offset, int count)
        {
            return _streamToCapture.Read(buffer, offset, count);
        }

        public override long Seek(long offset, SeekOrigin origin)
        {
            return _streamToCapture.Seek(offset, origin);
        }

        public override void SetLength(long value)
        {
            _streamToCapture.SetLength(value);
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            StreamContent += _encoding.GetString(buffer);
            _streamToCapture.Write(buffer, offset, count);
        }

        public override void Close()
        {
            _streamToCapture.Close();
            base.Close();
        }
    }

    #endregion

    #region IHttpModule Members

    private HttpApplication _context;
    public void Dispose()
    {

    }

    private static string Extensions_Key = "RequestResponseLoggerModule.Extensions";
    private static string Files_Key = "RequestResponseLoggerModule.Files";
    private static string Request_Key = "RequestResponseLoggerModule.Request";
    private static string Response_Key = "RequestResponseLoggerModule.Response";

    private IEnumerable<string> _Extenstions = new string[] { };
    private IEnumerable<string> _Files = new string[] { };
    private bool _LogAlwaysRequest = false;
    private bool _LogAlwaysResponse = false;
    private bool _IsMatch = false;

    public void Init(HttpApplication context)
    {
        _Extenstions = ConfigurationManager.AppSettings[Extensions_Key].ToLower().Split(',').
            Select(x => x.Trim()).ToArray();
        _Files = ConfigurationManager.AppSettings[Files_Key].ToLower().Split(',').
            Select(x => x.Trim()).ToArray();
        _LogAlwaysRequest = ConfigurationManager.AppSettings[Request_Key] == "ALWAYS";
        _LogAlwaysResponse = ConfigurationManager.AppSettings[Response_Key] == "ALWAYS";

        _context = context;

        context.BeginRequest += new EventHandler(context_BeginRequest);
        context.PreSendRequestContent += new EventHandler(context_PreSendRequestContent);
    }

    void context_PreRequestHandlerExecute(object sender, EventArgs e)
    {
        _context.Response.Filter = new CaptureStream(_context.Response.Filter, _context.Response.ContentEncoding);
    }

    void context_BeginRequest(object sender, EventArgs e)
    {
        if (_Extenstions.Count() > 0)
        {
            string ext = VirtualPathUtility.GetExtension(_context.Request.FilePath).
                Substring(1).ToLower();
            if (_Extenstions.Contains(ext))
            {
                _IsMatch = true;
            }
        }
        if (_Files.Count() > 0)
        {
            string fileName = VirtualPathUtility.GetFileName(_context.Request.FilePath).ToLower();
            if (_Files.Contains(fileName))
            {
                _IsMatch = true;
            }
        }

        if (_LogAlwaysRequest || _IsMatch)
        {
            StreamReader reader = new StreamReader(_context.Request.InputStream);
            string requestText = reader.ReadToEnd();
            _context.Request.InputStream.Position = 0;
            //LOG requestText
        }
    }

    void context_PreSendRequestContent(object sender, EventArgs e)
    {
        if (_LogAlwaysResponse || _IsMatch)
        {
            CaptureStream filter = _context.Response.Filter as CaptureStream;
            if (filter != null)
            {
                string responseText = filter.StreamContent;
                //LOG responseText
            }
        }
    }

    #endregion
}
Naor
  • 23,465
  • 48
  • 152
  • 268
  • We have an issue. The string responseText = filter.StreamContent; is getting as binary format. We are trying to filter the json data before sending it to client. Are we doing right way? Can you advice me? We are checking this in IIS with ARR extension enabled. – user867662 Jul 18 '13 at 12:56