How to inspect MVC response stream using OWIN middleware component?

后端 未结 1 1706
长发绾君心
长发绾君心 2021-02-09 03:06

This question has been asked before in a few forms but I cannot get any of the answers to work, I\'m losing my hair and unsure if the problem is just that the solutions were fro

1条回答
  •  清歌不尽
    2021-02-09 03:57

    MVC does not pass its request through OWIN pipeline. To capture MVC response we need to make custom response filter that captures response data

    /// 
    /// Stream capturing the data going to another stream
    /// 
    internal class OutputCaptureStream : Stream
    {
        private Stream InnerStream;
        public MemoryStream CapturedData { get; private set; }
    
        public OutputCaptureStream(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);
        }
    }
    

    And then we make a logging middleware that can log both kinds of responses properly

    public class LoggerMiddleware : OwinMiddleware
    {
        public LoggerMiddleware(OwinMiddleware next): base(next)
        {
        }
    
        public async override Task Invoke(IOwinContext context)
        {
            //to intercept MVC responses, because they don't go through OWIN
            HttpResponse httpResponse = HttpContext.Current.Response;
            OutputCaptureStream outputCapture = new OutputCaptureStream(httpResponse.Filter);
            httpResponse.Filter = outputCapture;
    
            IOwinResponse owinResponse = context.Response;
            //buffer the response stream in order to intercept downstream writes
            Stream owinResponseStream = owinResponse.Body;
            owinResponse.Body = new MemoryStream();
    
            await Next.Invoke(context);
    
            if (outputCapture.CapturedData.Length == 0) {
                //response is formed by OWIN
                //make sure the response we buffered is flushed to the client
                owinResponse.Body.Position = 0;
                await owinResponse.Body.CopyToAsync(owinResponseStream);
            } else {   
                //response by MVC
                //write captured data to response body as if it was written by OWIN         
                outputCapture.CapturedData.Position = 0;
                outputCapture.CapturedData.CopyTo(owinResponse.Body);
            }
    
            LogResponse(owinResponse);
        }
    }
    

    0 讨论(0)
提交回复
热议问题