65.9K
CodeProject is changing. Read more.
Home

Using Owin Middleware for MVC Response Logging

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.54/5 (7 votes)

Sep 26, 2017

CPOL
viewsIcon

16791

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