代码之家  ›  专栏  ›  技术社区  ›  canmustu

如何在.Net核心ActionFilterAttribute中使用依赖项注入?

  •  1
  • canmustu  · 技术社区  · 7 年前

    AuthenticationRequiredAttribute类

    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();
        }
    }
    

    错误:

    的必需形式参数“memoryCache” 'AuthenticationRequiredAttribute.AuthenticationRequiredAttribute(IMemoryCache)'项目.Ground.WebUI

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

    我想不带任何参数地使用那个属性。有什么解决办法吗?我使用依赖注入,但它不能用于属性。如何使用它?

    2 回复  |  直到 7 年前
        1
  •  31
  •   spender    7 年前

    而不是在施工中解决, ActionExecutingContext.HttpContext.RequestServices 应该在请求时提供对请求的服务容器的引用。

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var svc = filterContext.HttpContext.RequestServices;
        var memCache = svc.GetService<IMemoryCache>();
        //..etc
    
        2
  •  47
  •   poke    7 年前

    根据 the documentation

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

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

    [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] 属性来获得相同的效果,但是您还需要注册 示例ActionFilter 在您的 Startup .

    过滤器厂

    如果您需要更多的灵活性,您可以实现自己的过滤器工厂。这允许您自己编写工厂代码来创建实际的过滤器实例。上述的一个可能的实现 示例ActionFilter

    [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框架创建 示例ActionFilter

    服务筛选器属性 做。只是自己实现它可以避免使用 服务筛选器属性

    使用服务定位器

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

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