自定义 ASP.NET Core 操作筛选器中的用户范围依赖项?

Mil*_*hev 3 dependency-injection custom-action-filter actionfilterattribute asp.net-core

根据这里的官方文档:

https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/filters#authorization-filters

ActionFilter要在 ASP.NET Core 中实现自定义,我有三种选择:

  • 服务过滤器属性
  • 类型过滤器属性
  • IFilterFactory

但对于这三个人来说:

不应与依赖于生命周期而非单例服务的过滤器一起使用。

那么如何在我的自定义中注入范围服务呢ActionFilter?我可以轻松地从当前获得范围服务,HttpContext如下所示:

public override void OnActionExecuting(ActionExecutingContext actionContext)
{
    ISubscriptionHelper subscriptionHelper =
        actionContext.HttpContext.RequestServices
            .GetRequiredService<ISubscriptionHelper>();
}
Run Code Online (Sandbox Code Playgroud)

但后来我想知道我是否做错了什么?在自定义 ActionFilterAttribute 中依赖范围服务的正确方法是什么?

Ste*_*ven 7

解析来自 的服务HttpContext.RequestServices将正确解析作用域和瞬态实例,而不会导致任何问题,例如强制依赖关系。如果已解析的组件实现了IDisposable,它们将在请求结束时被处理。ASP.NET Core 将当前对象传递HttpContext给过滤器的OnActionExecuting方法,并HttpContext提供对 DI 容器的访问。

\n

这与将这些服务注入到构造函数中完全不同,因为操作过滤器将在应用程序的生命周期内进行缓存。因此,存储在私有字段中的任何依赖项都将与该过滤器一样长久存在。这导致了所谓的俘虏依赖问题。

\n

访问 DI 容器(这HttpContext.RequestServices是进入 DI 容器的网关)的代码应集中在应用程序启动路径\xe2\x80\x94(所谓的组合根)的基础设施代码中。访问组合根外部的 DI 容器不可避免地会导致服务定位器反模式\xe2\x80\x94,这不应掉以轻心。

\n

为了防止这种情况,建议使操作过滤器内的代码量尽可能小,并将过滤器实现为Humble Object。这意味着过滤器内的唯一代码行最好如下:

\n
actionContext.HttpContext.RequestServices\n    .GetRequiredService<ISomeService>() // resolve service\n    .DoSomeOperation(); // delegate work to service\n
Run Code Online (Sandbox Code Playgroud)\n

这意味着所有(应用程序)逻辑都转移到ISomeService实现中,允许操作过滤器成为一个低级对象。

\n