Add Response Headers to ASP.NET Core Middleware

前端 未结 6 1316
轻奢々
轻奢々 2020-12-08 06:40

I want to add a processing time middleware to my ASP.NET Core WebApi like this

public class ProcessingTimeMiddleware  
{
    private readonly RequestDelegate         


        
相关标签:
6条回答
  • 2020-12-08 07:04

    Using an overload of OnStarting method:

    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 讨论(0)
  • 2020-12-08 07:07

    Never mind, the code is here

        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.CompletedTask;
            }, context);
    
            await _next(context);
        }
    
    0 讨论(0)
  • 2020-12-08 07:07

    Alternatively you can also add a middleware directly in the Startup.cs Configure method.

            app.Use(
                next =>
                {
                    return async context =>
                    {
                        var stopWatch = new Stopwatch();
                        stopWatch.Start();
                        context.Response.OnStarting(
                            () =>
                            {
                                stopWatch.Stop();
                                context.Response.Headers.Add("X-ResponseTime-Ms", stopWatch.ElapsedMilliseconds.ToString());
                                return Task.CompletedTask;
                            });
    
                        await next(context);
                    };
                });
    
            app.UseMvc();
    
    0 讨论(0)
  • 2020-12-08 07:13

    Response headers can't be set after anything has been written to the response body.Once you pass the request to next middleware and it writes to the Response, then the Middleware can't set the Response headers again.

    However, there is a solution available using a Callback method.

    Microsoft.AspNetCore.Http.HttpResponse defines the OnStarting Method, which Adds a delegate to be invoked just before response headers will be sent to the client. You can think this method as a callback method that will be called right before writing to the response starts.

    public class ResponseTimeMiddleware
        {
            private const string RESPONSE_HEADER_RESPONSE_TIME = "X-Response-Time-ms";
    
            private readonly RequestDelegate _next;
    
            public ResponseTimeMiddleware(RequestDelegate next)
            {
                _next = next;
            }
    
            public Task InvokeAsync(HttpContext context)
            {
                var watch = new Stopwatch();
                watch.Start();
    
                context.Response.OnStarting(() => 
                {
                    watch.Stop();
                    var responseTimeForCompleteRequest = watch.ElapsedMilliseconds;
                    context.Response.Headers[RESPONSE_HEADER_RESPONSE_TIME] =  responseTimeForCompleteRequest.ToString(); 
                    return Task.CompletedTask;
                });
    
                // Call the next delegate/middleware in the pipeline
                return this._next(context);
            }
        }
    
    0 讨论(0)
  • 2020-12-08 07:15

    On a related note, without answering your question as such, there is now a Server-Timing specification, a standard header to provide durations, amongst other metrics. This should allow you to use

    Server-Timing: processingTime;dur=12ms
    

    You can find the specification at https://www.w3.org/TR/server-timing/

    0 讨论(0)
  • 2020-12-08 07:15

    In your example headers already sent, when execution reaches context.Response.Headers.Add(...) statement.

    You can try:

    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 讨论(0)
提交回复
热议问题