我想将处理时中间件添加到我的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() });
}
}
但这样做会抛出一个例外
System.InvalidOperationException: Headers are readonly, reponse has already started.
如何在回复中添加标题?
答案 0 :(得分:41)
没关系,代码在这里
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);
}
答案 1 :(得分: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();
答案 2 :(得分:4)
使用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);
}
答案 3 :(得分:4)
在将任何内容写入响应主体之后无法设置响应标头。一旦将请求传递给下一个中间件并将其写入响应,则中间件无法设置响应标题。
但是,有一种使用Callback方法的解决方案。
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);
}
}
答案 4 :(得分:2)
在已经发送的示例标头中,当执行到达context.Response.Headers.Add(...)语句时。
您可以尝试:
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();
}