ASP.NET Core Filter Attributes Dependency Injection
在 ASP.NET Core 中经常用到 FilterAttribute 来实现一些特殊的功能,例如授权、记录日志、请求过滤或者请求限制等,当然这些功能同样可以使用中间件 Middleware 实现。
在 FilterAttribute 中实现功能,必然也会用到DI, 本篇记录一下 FilterAttribute 中使用DI的方式。
-
RequestServices.GetService Service Locator
public class TestFilterAttribute : Attribute, IActionFilter { public void OnActionExecuting(ActionExecutingContext context) { var cache = context.HttpContext.RequestServices.GetService<IDistributedCache>(); ... } ... }
似乎网上的声音是不建议使用这种方式,因为无法直观的识别代码中的依赖项,对于单元测试也不够友好
-
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 })]
-
使用 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()
-
全局筛选器 Global action filters
services.AddMvc(options => { options.Filters.Add<TestFilter>(); });
-
一种不常见的使用方式,称之为被动属性,相对上面的方式不是很好理解,我也抄两段示例代码放到这里,以便后面查阅。
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 } } }
评论