ASP.NET Core Filter Attributes Dependency Injection

简介ASP.NET Core action filters use Dependency Injection

在 ASP.NET Core 中经常用到 FilterAttribute 来实现一些特殊的功能,例如授权、记录日志、请求过滤或者请求限制等,当然这些功能同样可以使用中间件 Middleware 实现。

在 FilterAttribute 中实现功能,必然也会用到DI, 本篇记录一下 FilterAttribute 中使用DI的方式。

  1. RequestServices.GetService Service Locator

    public class TestFilterAttribute : Attribute, IActionFilter
    {
        public void OnActionExecuting(ActionExecutingContext context)
        {
            var cache = context.HttpContext.RequestServices.GetService<IDistributedCache>();
            ...
        }
        ...
    }
    
    

    似乎网上的声音是不建议使用这种方式,因为无法直观的识别代码中的依赖项,对于单元测试也不够友好

  2. TypeFilter attribute 和 ServiceFilter attribute

    public class TestFilter : IActionFilter
    {
        private readonly IDistributedCache _cache;
    
        public TestFilter(IDistributedCache cache)
        {
            _cache = cache ?? throw new ArgumentNullException(nameof(cache));
        }
        ...
    }
    

    使用 TypeFilter attribute

    [TypeFilter(typeof(TestFilter))]
    public IActionResult Index()
    {
        return View();
    }
    

    使用 ServiceFilter attribute

    services.AddScoped<TestFilter>();
    
    [ServiceFilter(typeof(TestFilter))]
    public IActionResult Index()
    {
           return View();
    }
    

    TypeFilter 相对 ServiceFilter有两个主要区别,

    (1)无需额外添加类型注入

    (2)可以提供构造类型时提供参数,例如 [TypeFilter(typeof(TestFilter), Arguments = new object[] { 10 })]

  3. 使用 IFilterFactory

    public class TestFilterFactory : Attribute, IFilterFactory
    {
        public int MaxRequestPerSecond { get; set; }
    
        public bool IsReusable => false;
    
        public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
        {
            var filter = serviceProvider.GetService<TestFilter>();
            if (MaxRequestPerSecond > 0)
            {
                filter.MaxRequestPerSecond = MaxRequestPerSecond.Value;
            }
            return filter;
        }
    }
    
    [TestFilterFactory(MaxRequestPerSecond = 10)]
    public IActionResult Example()
    
  4. 全局筛选器 Global action filters

    services.AddMvc(options =>
        {
            options.Filters.Add<TestFilter>();
        });
    
  5. 一种不常见的使用方式,称之为被动属性,相对上面的方式不是很好理解,我也抄两段示例代码放到这里,以便后面查阅。

    public class ThrottleAttribute : Attribute, IFilterMetadata
    {
        public int MaxRequestPerSecond { get; set; }
    }
    
    public class TestFilter : IActionFilter
    {
        private readonly IDistributedCache _cache;
    
        public TestFilter(IDistributedCache cache)
        {
            _cache = cache ?? throw new ArgumentNullException(nameof(cache));
        }
    
        public void OnActionExecuting(ActionExecutingContext context)
        {
            var throttleAttribute = context.ActionDescriptor.FilterDescriptors
                .Select(x => x.Filter).OfType<ThrottleAttribute>().FirstOrDefault();
    
            if (throttleAttribute != null)
            {
                // implementation with access to throttleAttribute.MaxRequestPerSecond value
            }
        }
    }
    

本站发布的文章受知识共享协议保护,转载、收录请标明出处。

评论


昵称:   邮箱:

Top
An error has occurred. This application may no longer respond until reloaded.Reload 🗙