如何在 ASP.NET CORE 中使用具有依赖注入的动作过滤器?
Posted
技术标签:
【中文标题】如何在 ASP.NET CORE 中使用具有依赖注入的动作过滤器?【英文标题】:How to use Action Filters with Dependency Injection in ASP.NET CORE? 【发布时间】:2017-01-08 10:35:47 【问题描述】:我在我的ASP.NET CORE
应用程序中到处使用基于构造函数的依赖注入,我还需要在我的操作过滤器中解决依赖关系:
public class MyAttribute : ActionFilterAttribute
public int Limit get; set; // some custom parameters passed from Action
private ICustomService CustomService get; // this must be resolved
public MyAttribute()
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
// my code
...
await next();
然后在控制器中:
[MyAttribute(Limit = 10)]
public IActionResult()
...
如果我将 ICustomService 放入构造函数,那么我将无法编译我的项目。那么,我应该如何在动作过滤器中获取接口实例?
【问题讨论】:
能否在属性 CustomService 中添加 setter 使其也可写?并在构造函数中添加 ICustomService 作为参数? ASP.Net Core (MVC 6) - Inject service into Action Filter的可能重复 How do I add a parameter to an action filter in asp.net?的可能重复 【参考方案1】:如果您想避免使用服务定位器模式,您可以通过 TypeFilter
的构造函数注入来使用 DI。
在你的控制器中使用
[TypeFilter(typeof(MyActionFilterAttribute), Arguments = new object[] 10)]
public IActionResult() NiceAction
...
您的ActionFilterAttribute
不再需要访问服务提供者实例。
public class MyActionFilterAttribute : ActionFilterAttribute
public int Limit get; set; // some custom parameters passed from Action
private ICustomService CustomService get; // this must be resolved
public MyActionFilterAttribute(ICustomService service, int limit)
CustomService = service;
Limit = limit;
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
await next();
对我来说注释[TypeFilter(typeof(MyActionFilterAttribute), Arguments = new object[] 10)]
似乎很尴尬。为了得到像[MyActionFilter(Limit = 10)]
这样更易读的注解,你的过滤器必须继承自TypeFilterAttribute
。我对How do I add a parameter to an action filter in asp.net? 的回答展示了这种方法的一个示例。
【讨论】:
如果你需要异步,你也可以使用IAsyncActionFilter
而不是IActionFilter
【参考方案2】:
你可以使用Service Locator
:
public void OnActionExecuting(ActionExecutingContext actionContext)
var service = actionContext.HttpContext.RequestServices.GetService<IService>();
请注意,泛型方法 GetService<>
是一个扩展方法,位于命名空间 Microsoft.Extensions.DependencyInjection
中。
如果你想使用构造函数注入,请使用TypeFilter
。见How do I add a parameter to an action filter in asp.net?
【讨论】:
这是一个很好的建议,但是它需要更多的工作来进行单元测试。 为我工作 - 当我的类 'ApiKeyAuthAttribute : Attribute, IAsyncActionFilter' 使用构造函数注入时,我无法装饰我的控制器 '[ApiKeyAuth(thingToInject)]' 也不能使用 '[ServiceFilter(typeof( ApiKeyAuthAttribute))]',而使用上述方法完全避免构造函数注入并直接从 RequestServices 中获取已解析的 thingToInject 实现。【参考方案3】:您可以使用 ServiceFilters 在控制器中实例化您需要的 ActionFilters。
在控制器中:
[ServiceFilter(typeof(TrackingAttribute), Order = 2)]
你需要在依赖容器中注册TrackingAttribute,这样ServiceFilter才能解析它。
在https://www.strathweb.com/2015/06/action-filters-service-filters-type-filters-asp-net-5-mvc-6/了解更多信息
【讨论】:
【参考方案4】:这样做是一个不错的选择(在 .NET Core 3.1 中测试):
在 Filter 类里面放这个:
公共静态类FilterContainer
public class GenericFilter : ActionFilterAttribute
public override void OnActionExecuting(ActionExecutingContext filterContext)
string Action = filterContext.ActionDescriptor.RouteValues["action"];
Console.WriteLine($"[action]: Action STARTING");
public override void OnActionExecuted(ActionExecutedContext filterContext)
string Action = filterContext.ActionDescriptor.RouteValues["action"];
Console.WriteLine($"[action]: Action FINISHED");
public override void OnResultExecuting(ResultExecutingContext filterContext)
string Action = filterContext.ActionDescriptor.RouteValues["action"];
Console.WriteLine($"[action]: Action GIVING RESULT");
public override void OnResultExecuted(ResultExecutedContext filterContext)
string Action = filterContext.ActionDescriptor.RouteValues["action"];
ObjectResult ObjectResult = (ObjectResult)filterContext.Result;
Console.WriteLine($"[action]: Action RESULT GIVEN. Value: ObjectResult.Value");
在 Startup.cs/ConfigureServices(IServiceCollection services) 里面放这个:
services.AddControllers().AddMvcOptions(options => options.Filters.Add(new FilterContainer.GenericFilter()));
结果是,对 .NET Core 应用程序中任何类型的操作的请求都将通过此管道进出,而无需在任何操作之上声明过滤器属性。
让我在 Visual Studio 的“输出”窗口中向您展示一个示例:
[action]: JSON STARTING
[action]: JSON FINISHED
[action]: JSON GIVING RESULT
[action]: JSON RESULT GIVEN. Value: TestId: 103, FullName:...
【讨论】:
以上是关于如何在 ASP.NET CORE 中使用具有依赖注入的动作过滤器?的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET Core Web 应用程序系列- 在ASP.NET Core中使用Autofac替换自带DI进行批量依赖注入(MVC当中应用)
如何在 ASP.NET Core 中转储解析的 JWT 令牌?
如何在 ASP.NET Core MVC 中使用依赖注入设计存储库模式?
ASP.NET Core Web 应用程序系列- 在ASP.NET Core中使用Autofac替换自带DI进行构造函数和属性的批量依赖注入(MVC当中应用)