2015-04-26 5 views
5

Diese Frage wurde schon früher in einigen Formen gestellt, aber ich bekomme keine Antworten auf die Arbeit, ich verliere meine Haare und bin unsicher, ob das Problem nur darin besteht, dass die Lösungen vor 2 Jahren entstanden sind und sich die Dinge geändert haben.Wie MVC Antwort Stream mit OWIN Middleware-Komponente zu prüfen?

How can I safely intercept the Response stream in a custom Owin Middleware - ich basierend meinen Code auf diesem, es sieht aus wie es funktionieren sollte, aber es funktioniert nicht

OWIN OnSendingHeaders Callback - Reading Response Body - scheint eine andere OWIN Version zu sein, weil Methodensignatur nicht funktioniert

Was ich tun möchte, ist eine OMC schreiben, die den Antwort-Stream von MVC überprüfen kann.

Was ich getan habe (unter mehreren anderen Versuchen), ist eine OMC hinzuzufügen, die context.Response.Body zu einem Memorystream setzt, so kann ich es zurückspulen und kontrollieren, was durch nachgeschaltete Komponenten geschrieben wurde:

public async Task Invoke(IDictionary<string, object> env) 
    { 

     IOwinContext context = new OwinContext(env); 

     // Buffer the response 
     var stream = context.Response.Body; 
     var buffer = new MemoryStream(); 
     context.Response.Body = buffer; 
     ....... 

Was ich finde ist, dass der MemoryStream immer leer ist, es sei denn, ich schreibe es von einem anderen OMC. So scheint es, dass Downstream OMCs meine MemoryStream verwenden, aber MVC Antworten sind nicht, als ob die OWIN-Pipeline abgeschlossen ist, bevor die Anfrage an MVC geht, aber das ist nicht richtig, oder?

kompletter Code:

public partial class Startup 
{ 
    public void Configuration(IAppBuilder app) 
    { 
     ConfigureAuth(app); 
     app.Use(new ResponseExaminerMiddleware()); 

     // Specify the stage for the OMC 
     //app.UseStageMarker(PipelineStage.Authenticate); 
    } 


} 




public class ResponseExaminerMiddleware 
{ 
    private AppFunc next; 

    public void Initialize(AppFunc next) 
    { 
     this.next = next; 
    } 

    public async Task Invoke(IDictionary<string, object> env) 
    { 

     IOwinContext context = new OwinContext(env); 

     // Buffer the response 
     var stream = context.Response.Body; 
     var buffer = new MemoryStream(); 
     context.Response.Body = buffer; 

     await this.next(env); 

     buffer.Seek(0, SeekOrigin.Begin); 
     var reader = new StreamReader(buffer); 
     string responseBody = await reader.ReadToEndAsync(); 

     // Now, you can access response body. 
     System.Diagnostics.Debug.WriteLine(responseBody); 

     // You need to do this so that the response we buffered 
     // is flushed out to the client application. 
     buffer.Seek(0, SeekOrigin.Begin); 
     await buffer.CopyToAsync(stream); 

    } 

} 

Für was es wert Ich habe auch versucht, einen Vorschlag, wo der response.Body Strom auf eine Stream-Unterklasse festgelegt ist, nur so konnte ich beobachten, was in den Stream geschrieben wird und bizarr die Die Stream.Write-Methode wird aufgerufen, aber bei einem leeren Byte-Array wird niemals ein tatsächlicher Inhalt ...

Antwort

6

MVC gibt seine Anforderung nicht über die OWIN-Pipeline weiter. Zur Erfassung MVC Antwort müssen wir individuelle Antwortfilter machen die Antwortdaten

/// <summary> 
/// Stream capturing the data going to another stream 
/// </summary> 
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); 
    } 
} 

fängt Und dann machen wir eine Logging-Middleware, die beide Arten von Antworten anmelden können richtig

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); 
    } 
} 
Verwandte Themen