目标是使用.AsWebApiAuthorizationFilterFor<ApiController>(c => c.GetType()
将少数Attr转换为来自Autofac的DI过滤器
感觉像我接近了,但是可能做错了,发现了很多关于Peram注射器的帖子,但这不是我想要在这里做的。
当前失败的尝试
builder.RegisterType<SomeFilter>()
.AsWebApiAuthorizationFilterFor<ApiController>(c => c.GetType()
.GetMethods()
.Where(m => m.GetCustomAttributes<SomeAttribute>().Any())
)
.InstancePerRequest();
目标:为具有特定属性的所有api控制器和/或控制器方法添加此过滤器
从提供的答案中创建的解决方案:
IAutofacAuthorizationFilter
,并将ATTR中的当前过滤器逻辑移至该接口的auth方法。builder.RegisterWebApiFilterProvider(config);
添加了呼叫启用过滤器注册我的过滤器
builder.RegisterType<MyFilterFilter>()
.AsWebApiAuthorizationFilterFor<BaseTypeApiController>()
.InstancePerDependency();
添加对控制器或方法上原始属性的检查,如果两者都为空,则返回。
var controllerAttribute = actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AttributeReplacedByFilterAttribute>().FirstOrDefault();
var methodAttribute = actionContext.ActionDescriptor.GetCustomAttributes<AttributeReplacedByFilterAttribute>().FirstOrDefault();
到目前为止,这似乎可以解决问题,并满足了我的要求。
答案 0 :(得分:2)
AsWebApiAuthorizationFilterFor
的第二个参数是一个动作选择器,用于选择一种为其创建过滤器的方法。
要应用条件注册,可以使用OnlyIf
:
// Conditionally register filter for all controller actions
services.GetContainerBuilder()
.RegisterType<Filter>()
.AsWebApiAuthorizationFilterFor<DummyController>()
.OnlyIf(_ => typeof(DummyController).GetCustomAttributes<SomeAttribute>().Any());
// Conditionally register filter for selected controller action
services.GetContainerBuilder()
.RegisterType<Filter>()
// x => x.Get selects Get method defined by DummyController
.AsWebApiAuthorizationFilterFor<DummyController>(x => x.Get())
.OnlyIf(_ =>
typeof(DummyController).GetMethod("Get").GetCustomAttributes<SomeAttribute>().Any());
您还可以构建自己的AsWebApiAuthorizationFilterForOnlyIf
扩展名并执行以下操作:
if (typeof(DummyController).GetCustomAttributes<SomeAttribute>().Any())
{
services.GetContainerBuilder()
.RegisterType<Filter>()
.AsWebApiAuthorizationFilterFor<DummyController>();
}
更新
如果喜欢使用scan-and-add-automatically
方法,则可以使用表达式树为找到的每个控制器和方法动态调用AsWebApiAuthorizationFilterFor
。您将在下面看到很多代码:
ContainerBuilder containerBuilder = ...
Type[] controllerTypes = ...
// Keep the type registration builder here, and use it for all As actions
var typeRegistrationBuilder = containerBuilder
.RegisterType<Filter>()
.InstancePerRequest();
// Scan controllers and methods and build registrations
foreach (Type controllerType in controllerTypes)
{
// Which means ALL actions in the controller should have the filter registered
if (controllerType.GetCustomAttributes<SomeAttribute>().Any())
{
// Because AsWebApiAuthorizationFilterFor doesn't take non-generic type parameter,
// so we need to build delegate to invoke AsWebApiAuthorizationFilterFor<controllerType>.
// Use expression tree.
// This will build:
// () => typeRegistrationBuilder.AsWebApiAuthorizationFilterFor<controllerType>()
Expression.Lambda<Action>(
Expression.Call(
typeof(Autofac.Integration.WebApi.RegistrationExtensions),
"AsWebApiAuthorizationFilterFor",
new[] { controllerType },
Expression.Constant(typeRegistrationBuilder))
).Compile()(); // Just compile and run this Action
continue;
}
// Controller doesn't have the attribute
// Scan action methods
var methods = controllerType.GetMethods()
.Where(mi => mi.GetCustomAttributes<SomeAttribute>().Any());
foreach (MethodInfo method in methods)
{
// Now the method has the attribute
// Again, use expression tree to build method call, but this time, with a selector
// First, build method call expression parameters for each parameter on the method
// Just need to pass default(T) in, because Autofac literally just need the method
IEnumerable<Expression> parameters = method.GetParameters()
.Select(p => p.ParameterType)
.Select(Expression.Default);
// Build method selector
// This will build:
// _ => _.SomeMethod(parameters)
ParameterExpression controller = Expression.Parameter(controllerType, "_");
LambdaExpression methodSelector = Expression.Lambda(
typeof(Action<>).MakeGenericType(controllerType),
Expression.Call(controller, method, parameters),
controller);
// This will build:
// () => typeRegistrationBuilder.AsWebApiAuthorizationFilterFor<controllerType>(
// _ => _.SomeMethod(parameters));
Expression.Lambda<Action>(
Expression.Call(
typeof(Autofac.Integration.WebApi.RegistrationExtensions),
"AsWebApiAuthorizationFilterFor",
new[] { controllerType },
Expression.Constant(typeRegistrationBuilder),
methodSelector)
).Compile()(); // Just compile and run this Action
}
}
答案 1 :(得分:0)
从提供的答案中创建的解决方案:
IAutofacAuthorizationFilter
,并将ATTR中的当前过滤器逻辑移至该接口的auth方法。builder.RegisterWebApiFilterProvider(config);
添加了呼叫启用过滤器注册我的过滤器
builder.RegisterType<MyFilterFilter>()
.AsWebApiAuthorizationFilterFor<BaseTypeApiController>()
.InstancePerDependency();
添加对控制器或方法上原始属性的检查,如果两者都为null,则返回。向过滤器方法添加了检查:OnAuthorizationAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
var controllerAttribute = actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AttributeReplacedByFilterAttribute>().FirstOrDefault();
var methodAttribute = actionContext.ActionDescriptor.GetCustomAttributes<AttributeReplacedByFilterAttribute>().FirstOrDefault();
到目前为止,这似乎可以解决问题,并满足了我的要求。
注意:您可以使用相同的方法将过滤器应用于所有控制器方法,然后检查属性。对于我的用例,我有一个需要影响的控制器的基类。注册以将所有过滤器注册更改为.AsWebApiAuthorizationFilterFor<ApiController>()