Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Using Owin Middleware for MVC Response Logging

0.00/5 (No votes)
28 Sep 2017 1  
How to get MVC response body inside your owin middleware class

Introduction

With Owin Pipeline, you can easily get response body stream inside your custom middleware class, but not in case of MVC, because the MVC framework doesn't stream response body through the owin pipeline. In this tip, we will use a simple trick to get MVC response body inside your custom middleware class.

Background

First of all, let's make a helper class that will manage streams by copying the output stream into a memory stream.

internal class StreamHelper: Stream
    {
        private Stream InnerStream;
        public MemoryStream CapturedData { get; private set; }
 
        public StreamHelper(Stream inner)
        {
            InnerStream = inner;
            CapturedData = new MemoryStream();
        }
 
        public override bool CanRead
        {
            get { return InnerStream.CanRead; }
        }
 
        public override bool CanSeek
        {
            get { return InnerStream.CanSeek; }
        }
 
        public override bool CanWrite
        {
            get { return InnerStream.CanWrite; }
        }
 
        public override void Flush()
        {
            InnerStream.Flush();
        }
 
        public override long Length
        {
            get { return InnerStream.Length; }
        }
 
        public override long Position
        {
            get { return InnerStream.Position; }
            set { CapturedData.Position = InnerStream.Position = value; }
        }
 
        public override int Read(byte[] buffer, int offset, int count)
        {
            return InnerStream.Read(buffer, offset, count);
        }
 
        public override long Seek(long offset, SeekOrigin origin)
        {
            CapturedData.Seek(offset, origin);
            return InnerStream.Seek(offset, origin);
        }
 
        public override void SetLength(long value)
        {
            CapturedData.SetLength(value);
            InnerStream.SetLength(value);
        }
 
        public override void Write(byte[] buffer, int offset, int count)
        {
            CapturedData.Write(buffer, offset, count);
            InnerStream.Write(buffer, offset, count);
        }
    }

Now inside our Middleware class, we can capture response body by using our StreamHelper as a filter for HttpResponse.

public class DebugMiddleware : OwinMiddleware
  {
      OwinMiddleware _next;
   

      public DebugMiddleware(OwinMiddleware next) : base(next)
      {      
          _next = next;
      }

public async override Task Invoke(IOwinContext context)
   {
         // Buffering mvc reponse
         HttpResponse httpResponse = HttpContext.Current.Response;

         StreamHelper outputCapture = new StreamHelper(httpResponse.Filter);

         httpResponse.Filter = outputCapture;

         // Buffering Owin response if any 

         IOwinResponse owinResponse = context.Response;
         Stream owinResponseStream = owinResponse.Body;
         owinResponse.Body = new MemoryStream();

         await Next.Invoke(context);

         if (outputCapture.CapturedData.Length == 0)
         {             
             owinResponse.Body.Position = 0;
             await owinResponse.Body.CopyToAsync(owinResponseStream);
         }
         else
         {           
             // in case we have  captured data from  mvc response copy it into owinResponse
             outputCapture.CapturedData.Position = 0;
             outputCapture.CapturedData.CopyTo(owinResponse.Body);
         }

         // finally  read final reponse  body 
         owinResponse.Body.Seek(0, SeekOrigin.Begin);

      var responseBody = new StreamReader(owinResponse.Body).ReadToEnd();
 

   Debug.WriteLine(responseBody);
}

 

 

Example Proejct 

https://github.com/pashkovdenis/Using-Owin-Middleware-for-MVC-Response-Logging-Example

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here