将响应标头添加到ASP.NET核心中间件

Gil*_*rdo 34 c# asp.net-core

我想像这样在我的ASP.NET Core WebApi中添加一个处理时中间件

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() });
    }
}
Run Code Online (Sandbox Code Playgroud)

但这样做会引发异常

 System.InvalidOperationException: Headers are readonly, reponse has already started.
Run Code Online (Sandbox Code Playgroud)

如何在响应中添加标头?

Gil*_*rdo 46

没关系,代码在这里

    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);
    }
Run Code Online (Sandbox Code Playgroud)


Tee*_*Tee 6

或者,您也可以直接在Startup.cs Configure方法中添加中间件.

        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();
Run Code Online (Sandbox Code Playgroud)


Abh*_*dha 6

在将任何内容写入响应主体之后,无法设置响应头。一旦将请求传递给下一个中间件并将其写入响应,那么中间件就无法再次设置响应头。

但是,有一种使用回调方法的解决方案。

Microsoft.AspNetCore.Http.HttpResponse定义OnStarting方法,该方法将在响应标头发送到客户端之前添加要调用的委托。您可以将此方法视为回调方法,该方法将在写入响应开始之前立即被调用。

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);
        }
    }
Run Code Online (Sandbox Code Playgroud)


Ser*_*Seb 5

在相关说明中,在不回答您的问题的情况下,现在有一个Server-Timing规范,一个标准标头来提供持续时间以及其他指标。这应该允许您使用

Server-Timing: processingTime;dur=12ms
Run Code Online (Sandbox Code Playgroud)

您可以在https://www.w3.org/TR/server-timing/找到该规范