Click here to Skip to main content
15,887,683 members
Articles / Programming Languages / C#
Tip/Trick

Using Owin Middleware for MVC Response Logging

Rate me:
Please Sign up or sign in to vote.
3.54/5 (7 votes)
28 Sep 2017CPOL 15.8K   4   4
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.

C#
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.

C#
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionSample Source Code Solution Pin
Ehsan Sajjad28-Sep-17 3:08
professionalEhsan Sajjad28-Sep-17 3:08 
AnswerRe: Sample Source Code Solution Pin
Denis Pashkov28-Sep-17 10:13
Denis Pashkov28-Sep-17 10:13 
BugMinor type mistake. Pin
Nick Polideropoulos27-Sep-17 13:24
Nick Polideropoulos27-Sep-17 13:24 
GeneralRe: Minor type mistake. Pin
Denis Pashkov28-Sep-17 2:57
Denis Pashkov28-Sep-17 2:57 
Hi, thanks

Owin Pipeline is basically a chain of responsibility, so you can control order of execution by registering classes in specific order

ex
1 - app.use<middleware1>();
2 - app.use<middleware2>() ;
.....

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.