I use constructor-based dependency injection everywhere in my ASP.NET CORE
application and I also need to resolve dependencies in my action filters:
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();
}
}
Then in Controller:
[MyAttribute(Limit = 10)]
public IActionResult()
{
...
If I put ICustomService to the constructor, then I'm unable to compile my project. So, how do I supossed to get interface instances in action filter?
答案 0 :(得分:16)
如果您想避免使用服务定位器模式,可以使用构造函数注入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?的回答显示了这种方法的一个例子。
答案 1 :(得分:3)
You can use Service Locator
:
public void OnActionExecuting(ActionExecutingContext actionContext)
{
var service = actionContext.HttpContext.RequestServices.GetService<IService>();
}
Note that the generic method GetService<>
is an extension method and lives in namespace Microsoft.Extensions.DependencyInjection
.
If you want to use constructor injection use TypeFilter
. See How do I add a parameter to an action filter in asp.net?
答案 2 :(得分:2)
您可以使用 ServiceFilters 在控制器中实例化所需的ActionFilter。
在控制器中:
func mergedDict(dictionaries: [[String: Any]]) -> [String: Int] {
guard dictionaries.count != 0 else { return [:] }
var result = [String: Int]()
dictionaries.forEach { dict in
var name: String?
var amount: Int?
dict.forEach{ arg in
switch arg.key {
case "fruit":
name = arg.value as! String
case "amount":
amount = arg.value as! Int
default:
fatalError("does not exist.")
}
}
guard let fruit = name else { fatalError("name is nil.") }
guard let newAmount = amount else { fatalError("amount is nil.") }
guard let priorAmount = result[fruit] else {
result[fruit] = newAmount
return
}
result[fruit] = priorAmount + newAmount
}
return result
}
您需要在依赖项容器中注册TrackingAttribute,以便ServiceFilter可以解决它。
有关详情,请访问https://www.strathweb.com/2015/06/action-filters-service-filters-type-filters-asp-net-5-mvc-6/
答案 3 :(得分:-1)
这样做是一个不错的选择(在 .NET Core 3.1 中测试):
在过滤器类中输入:
公共静态类 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:...