2015-04-26 25 views
5

Bu soru daha önce birkaç formda sorulmuştur fakat işe yarayacak cevapları alamıyorum, saçlarımı kaybediyorum ve sorunun çözümlerin sadece 2 yıl önce olduğu ve şeylerin değiştiğinden emin olmadığından emin değilim. yöntem imzası çalışmaz, çünkü farklı bir Owin sürümünü gibi görünüyor -OWIN katman yazılımı bileşeni kullanarak MVC yanıt akışı nasıl denetlenir?

How can I safely intercept the Response stream in a custom Owin Middleware - bu çalışması gerekir gibi bu benim kod dayanarak, görünüyor, ama değil

OWIN OnSendingHeaders Callback - Reading Response Body yapar

Yapmak istediğim, yanıt akışını MVC'den inceleyebilen bir OMC yazmaktır.

Ben, bir MemoryStream için context.Response.Body ayarlayan bir OMC'yi eklemektir, bu yüzden geri sarmak ve mansap bileşenleri tarafından yazılmıştır neyi inceleyebilir (birkaç diğer girişimleri arasında) yaptığı şey:

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; 
     ....... 

Bulduğum şey, başka bir OMC'den yazmadığım sürece, MemoryStream öğesinin her zaman boş olmasıdır. Yani aşağı akım OMC'ler benim MemoryStream kullanıyor, ancak MVC yanıtları, istek MVC'ye gitmeden önce OWIN boru hattı tamamlanmış gibi değil, ama doğru değil mi?

Komple kodu: ben de sadece bu yüzden tuhaf dere ve yazılanları takip olabilir, response.Body akışı, bir Akış alt sınıfa ayarlanmış bir öneri çalıştı Ne değer için

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); 

    } 

} 

Stream.Write yöntemi çağrılır, ancak boş bir bayt dizisiyle, hiçbir zaman gerçek içerik ...

cevap

6

MVC, isteğini OWIN hattından geçirmez. MVC tepkisini yakalamak için biz yanıt verilerini

/// <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); 
    } 
} 

yakalar Sonra düzgün tepkilerin her iki türlü

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); 
    } 
} 
giriş yapabilen günlüğü ortakatmanını yapmak özel yanıtı filtresi yapmak gerekir
İlgili konular