endpointfilter仅作用于minimal api单个端点且须显式注册;必须在mapget/mappost后、build()前链式调用addendpointfilter,不可在services或useendpoints中注册,短路需赋值context.result并返回completedtask。

EndpointFilter 不是中间件,也不是 ActionFilter,它只作用于 Minimal API 的单个端点,且必须显式注册——漏掉 AddEndpointFilter 就完全不生效。
为什么 AddEndpointFilter 后还是没进过滤器
最常见原因是注册位置错了:必须在 MapGet/MapPost 之后、Build() 之前链式调用,不能写在 services.Add... 区块里,也不能在 app.UseEndpoints 里混用。
- ✅ 正确写法:
app.MapGet("/api/data", () => "ok").AddEndpointFilter<myfilter>();</myfilter> - ❌ 错误写法:
services.AddEndpointFilter<myfilter>();</myfilter>(不存在这个 API) - ❌ 错误写法:
app.UseEndpoints(e => e.MapGet(...).AddEndpointFilter(...));(Minimal API 不走 UseEndpoints) - 如果用 Lambda 注册,确保
await next(context)被调用,否则端点逻辑被跳过
IEndpointFilter.InvokeAsync 中如何安全访问 HttpContext
InvokeAsync 的 context 参数是 EndpointFilterInvocationContext,不是 HttpContext;它只提供 HttpContext 属性和 Arguments,但直接读取 context.HttpContext 是安全的——因为 EndpointFilter 生命周期绑定到当前请求 scope。
- 可直接用:
var user = context.HttpContext.User; - 需要 DI 服务时,从
context.HttpContext.RequestServices获取,例如:context.HttpContext.RequestServices.GetRequiredService<ilogger>>()</ilogger> - 不要在构造函数里注入
HttpContext或IHttpContextAccessor——EndpointFilter 实例是 transient,但构造注入会触发 root provider 解析,导致Cannot resolve scoped service from root provider
EndpointFilter 和 ActionFilter 能否混用
能,但它们不共享执行上下文,也不参与同一调度链:ActionFilter 只对 MVC Controller/Action 生效,EndpointFilter 只对 Minimal API 端点生效。两者注册位置、生命周期、参数模型完全不同,强行混用只会让逻辑分散、调试困难。
- 同一个项目里同时存在 Minimal API 和 MVC?那就得维护两套过滤逻辑
- 想统一处理所有 HTTP 端点?别用 EndpointFilter,改用中间件(
app.Use(...)),它才是跨风格的通用层 - 想复用已有 ActionFilter 逻辑?不能直接套用,需重写为
IEndpointFilter,因为ActionExecutingContext和EndpointFilterInvocationContext结构不兼容
短路响应时要注意什么
EndpointFilter 支持提前返回结果(即“短路”),但必须赋值给 context.Result 并返回 ValueTask.CompletedTask,不能抛异常或 return null。
- ✅ 正确短路:
context.Result = new TextResult("forbidden") { StatusCode = StatusCodes.Status403Forbidden };+return ValueTask.CompletedTask; - ❌ 错误短路:
throw new InvalidOperationException();(会触发全局异常过滤器,不是你想要的“拦截”) - ❌ 错误短路:
return new ValueTask<object>(null);</object>(运行时报NullReferenceException) - 短路后
next(context)不会被调用,后续过滤器和端点委托也跳过
EndpointFilter 的真正复杂点不在写法,而在于它和 DI scope、执行时机、短路语义三者的耦合——稍不注意,context.Result 赋了值却没 return task,或者用了 RequestServices 却忘了服务注册,都会静默失败。










