2016-05-23 13 views
12

voglio aggiungere un middleware tempo di elaborazione alla mia ASP.NET Nucleo WebAPI come questoaggiungere intestazioni di risposta ad ASP.NET core Middleware

public class ProcessingTimeMiddleware 
{ 
    private readonly RequestDelegate _next; 

    public ProcessingTimeMiddleware(RequestDelegate next) 
    { 
     _next = next; 
    } 

    public async Task Invoke(HttpContext context) 
    { 
     var watch = new Stopwatch(); 
     watch.Start(); 

     await _next(context); 

     context.Response.Headers.Add("X-Processing-Time-Milliseconds", new[] { watch.ElapsedMilliseconds.ToString() }); 
    } 
} 

Ma facendo questo genera un'eccezione dicendo

System.InvalidOperationException: Headers are readonly, reponse has already started. 

Come posso aggiungere intestazioni alla risposta?

risposta

17

Non importa, il codice è qui

public async Task Invoke(HttpContext context) 
    { 
     var watch = new Stopwatch(); 
     watch.Start(); 

     //To add Headers AFTER everything you need to do this 
     context.Response.OnStarting(state => { 
      var httpContext = (HttpContext)state; 
      httpContext.Response.Headers.Add("X-Response-Time-Milliseconds", new[] { watch.ElapsedMilliseconds.ToString() }); 
      return Task.FromResult(0); 
     }, context); 

     await _next(context); 
    } 
+0

vorrei aggiungere anche che attendono '_next (contesto)' dovrebbe essere l'ultima dichiarazione (dopo 'context.Response.Headers.Add '). Più semanticamente corretto. –

+0

Esiste un equivalente di .NET 4 o ci si può aggirare per questo? Ancora alcuni clienti di Server 2003 :( – apc

+0

C'è un motivo per cui hai utilizzato il sovraccarico di stato su OnStarting? –

3

nel tuo esempio headers already sent, quando l'esecuzione raggiunge dichiarazione context.Response.Headers.Add (...).

Si può provare:

public async Task Invoke(HttpContext context) 
{ 
    var watch = new Stopwatch(); 
    context.Response.OnSendingHeaders(x => 
    { 
     watch.Stop(); 
     context.Response.Headers.Add("X-Processing-Time-Milliseconds", new[] { watch.ElapsedMilliseconds.ToString() }); 
    }, null); 

    watch.Start(); 
    await _next(context); 
    watch.Stop(); 
} 
+0

Da quale pacchetto è OnSendingHeaders? –

4

Utilizzando un sovraccarico di metodo OnStarting:

public async Task Invoke(HttpContext context) 
{ 
    var watch = new Stopwatch(); 

    context.Response.OnStarting(() => 
    { 
     watch.Stop(); 

     context 
       .Response 
       .Headers 
       .Add("X-Processing-Time-Milliseconds", 
         new[] { watch.ElapsedMilliseconds.ToString() }); 

     return Task.CompletedTask; 
    }); 

    watch.Start(); 

    await _next(context); 
} 
0

In alternativa è anche possibile aggiungere un middleware direttamente nel metodo Startup.cs Configura.

0

In una nota correlata, senza rispondere alla tua domanda, come tale, v'è ora una specifica Server-Timing, un'intestazione standard per fornire durate, tra le altre metriche. Questo dovrebbe consentire di utilizzare

Server-Timing: processingTime;dur=12ms 

Si possono trovare le specifiche a https://www.w3.org/TR/server-timing/

Problemi correlati