我正在编写定制中间件,它要求我将结果作为响应头附加到给定的请求. 为此,我创建了如下所示的简单中间件:

public class MyCustomMiddleware
{
  private readonly RequestDelegate _next;

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

  public async Task InvokeAsync(Microsoft.AspNetCore.Http.HttpContext context, IConfiguration configuration)
  {
    debug.print("I'm before the next piece of middleware");
    
    await _next(context);
    
    Context.Response.Headers.Add("x-special-header-4", "super secret response header");    
  }
}

这当然会导致以下例外情况:

Exception thrown: 'System.InvalidOperationException' in Microsoft.AspNetCore.Server.Kestrel.Core.dll System.InvalidOperationException: Headers are read-only, response has already started.
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpHeaders.ThrowHeadersReadOnlyException() at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpHeaders.System.Collections.Generic.IDictionary<System.String,Microsoft.Extensions.Primitives.StringValues>.Add(String key, StringValues value)

当我使用ActionResult时,也会发生这种情况--但当我请求了根本无法路由的内容时(结果会返回404).

App启动顺序如下所示:

app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();

app.UseMiddleware<MyCustomMiddleware>();
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

(我有一个帮助器来设置中间件,我在本文中省略了这一点,但只是添加了定制中间件)

中间件的真正目的是测量花费的时间/其他因素,这将需要我‘完成’请求,然后向响应添加标头-所有这些都不需要修改现有的用户代码.

有没有办法做到这一点?

推荐答案

您要在调用await _next(context);之后添加标头,但为时已晚,因为响应已经开始.要解决此问题,您可以try httpContext.Response.OnStarting()代表:

public class MyCustomMiddleware
{
  private readonly RequestDelegate _next;

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

  public async Task InvokeAsync(Microsoft.AspNetCore.Http.HttpContext context, IConfiguration configuration)
  {
    Debug.Print("I'm before the next piece of middleware");

    context.Response.OnStarting(state =>
    {
        var ctx = (HttpContext)state;
        ctx.Response.Headers.Add("x-special-header-4", "super secret response header");
        return Task.FromResult(0);
    }, context);

    await _next(context);
  }
}

Csharp相关问答推荐

如何从Date中剥离Timezone部分以仅保留本地Date部分?(no字符串解析或操作)

Autofac:如何防止丢弃通过ServicCollection注册的服务?

在Linq中调用需要limit和offset的方法''''

为什么这个Reflection. Emit代码会导致一个DDL ViolationException?

从Blob存储中提取tar.gz文件并将提取结果上载到另一个Blob存储

C#XmlSerializer-输出控制新行的多个XML片段

如何在页面重新加载后保持菜单切换状态

UWP中的任务和界面

如何比较C#中的L和ł(波兰字符)返回TRUE

有没有类似于扩展元素的合并元组的语法?

该函数不能检测两条曲线的交点

在两个已具有一对多关系的表之间添加另一个一对多关系

当空判断结果赋给变量时,为什么会出现可能空异常警告的解引用?

在使用UserManager时,如何包含与其他实体的关系?

在';、';附近有错误的语法.必须声明标量变量";@Checkin";.';

在同一个捕获中可以有多种类型的异常吗?

如何在C#中从MongoDB IPipelineStageDefinition中获取聚合命令的字段/选项?

如何在C#.NET桌面应用程序中动态更改焦点工具上的后退 colored颜色

Xamarin.Forms中具有类似AspectFill的图像zoom 的水平滚动视图

NETSDK1201:对于面向.NET 8.0和更高版本的项目,默认情况下,指定RUNTIME标识符将不再生成自包含的应用程序