如何在 .Net Core ActionFilterAttribute 中使用依赖关系注入?



AuthenticationRequiredAttribute Class

public class AuthenticationRequiredAttribute : ActionFilterAttribute
{
ILoginTokenKeyApi _loginTokenKeyApi;
IMemoryCache _memoryCache;
public AuthenticationRequiredAttribute(IMemoryCache memoryCache)
{
_memoryCache = memoryCache;
_loginTokenKeyApi = new LoginTokenKeyController(new UnitOfWork());
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var memory = _memoryCache.Get(Constants.KEYNAME_FOR_AUTHENTICATED_PAGES);
string requestedPath = filterContext.HttpContext.Request.Path;
string tokenKey = filterContext.HttpContext.Session.GetString("TokenKey")?.ToString();
bool? isLoggedIn = _loginTokenKeyApi.IsLoggedInByTokenKey(tokenKey).Data;
if (isLoggedIn == null ||
!((bool)isLoggedIn) ||
!Constants.AUTHENTICATED_PAGES_FOR_NORMAL_USERS.Contains(requestedPath))
{
filterContext.Result = new JsonResult(new { HttpStatusCode.Unauthorized });
}
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
}
}

首页控制器

public class HomeController : Controller
{
IUserApi _userApi;
ILoginTokenKeyApi _loginTokenKey;
IMemoryCache _memoryCache;
public HomeController(IUserApi userApi, ILoginTokenKeyApi loginTokenKey, IMemoryCache memoryCache)
{
_loginTokenKey = loginTokenKey;
_userApi = userApi;
_memoryCache = memoryCache;
}
[AuthenticationRequired] // There is AN ERROR !!
public IActionResult Example()
{
return View();
}
}

错误:

错误 CS7036 没有给出对应于 所需的形式参数"内存缓存"的 'AuthenticationRequiredAttribute.AuthenticationRequiredAttribute(IMemoryCache(' project.Ground.WebUI

的问题实际上是:我不能在属性类中使用依赖注入

我想在没有任何参数的情况下使用该属性。有什么解决方案可以解决吗?我使用依赖注入,但它不能用于属性。我如何使用它?

根据文档,您在这里有几个选项:

如果筛选器具有需要从 DI 访问的依赖项,则有几种受支持的方法。可以使用下列方法之一将筛选器应用于类或操作方法:

  • ServiceFilterAttribute
  • TypeFilterAttribute
  • IFilterFactory在您的属性上实现

服务筛选器或类型筛选器属性

如果只想快速执行此操作,只需使用前两个选项之一即可将筛选器应用于控制器或控制器操作。执行此操作时,筛选器本身不需要是属性:

[TypeFilter(typeof(ExampleActionFilter))]
public IActionResult Example()
=> View();

然后,ExampleActionFilter可以只实现例如IAsyncActionFilter,你可以使用构造函数注入直接依赖事物:

public class ExampleActionFilter : IAsyncActionFilter
{
private readonly IMemoryCache _memoryCache;
public ExampleActionFilter(IMemoryCache memoryCache)
{
_memoryCache = memoryCache;
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{ … }
}

您也可以改用[ServiceFilter]属性来获得相同的效果,但随后您还需要向Startup中的依赖项注入容器注册您的ExampleActionFilter

过滤器工厂

如果需要更大的灵活性,可以实现自己的筛选器工厂。这允许您编写工厂代码以自行创建实际的筛选器实例。上述ExampleActionFilter的可能实现可能如下所示:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class ExampleActionFilterAttribute : Attribute, IFilterFactory
{
public bool IsReusable => false;
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
return serviceProvider.GetService<ExampleActionFilter>();
}
}

然后,可以使用该[ExampleActionFilter]属性使 MVC 框架使用 DI 容器为你创建ExampleActionFilter的实例。

请注意,此实现基本上与ServiceFilterAttribute相同。只是自己实现它避免了直接使用ServiceFilterAttribute,并允许您拥有自己的属性。

使用服务定位器

最后,还有另一个快速选项可以让你完全避免构造函数注入。这将使用服务定位器模式在过滤器实际运行时动态解析服务。因此,您不是注入依赖项并直接使用它,而是从上下文中显式检索它:

public class ExampleActionFilter : ActionFilterAttribute
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var memoryCache = context.HttpContext.RequestServices.GetService<IMemoryCache>();
// …
}
}

ActionExecutingContext.HttpContext.RequestServices不是在构造时解析,而是应该在请求时为您提供对请求服务容器的引用。

所以:

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var svc = filterContext.HttpContext.RequestServices;
var memCache = svc.GetService<IMemoryCache>();
//..etc

对于.Net Core 5,下面的语法对我有用。

IAppUserService _appUserService = (IAppUserService)context.HttpContext.RequestServices.GetService(typeof(IAppUserService));

最新更新