您可以为 Autofac 库的 ContainerBuilder 类使用自定义扩展:
public static class ContainerBuilderExtensions
{
public static void RegisterWebApiFilterAttribute<TAttribute>(this ContainerBuilder builder, Assembly assembly) where TAttribute : Attribute, IAutofacAuthorizationFilter
{
Type[] controllerTypes = assembly.GetLoadableTypes()
.Where(type => typeof(ApiController).IsAssignableFrom(type)).ToArray();
RegisterFilterForControllers<TAttribute>(builder, controllerTypes);
RegisterFilterForActions<TAttribute>(builder, controllerTypes);
}
// We need to call
// builder.RegisterType<TFilter>().AsWebApiAuthorizationFilterFor().InstancePerDependency()
// for each controller marked with TAttribute
private static void RegisterFilterForControllers<TAttribute>(ContainerBuilder builder, IEnumerable<Type> controllerTypes) where TAttribute : Attribute, IAutofacAuthorizationFilter
{
foreach (Type controllerType in controllerTypes.Where(c => c.GetCustomAttribute<TAttribute>(false)?.GetType() == typeof(TAttribute)))
{
GetAsFilterForControllerMethodInfo(controllerType).Invoke(null, new object[] { builder.RegisterType(typeof(TAttribute)) });
}
}
// We need to call
// builder.RegisterType<TFilter>().AsWebApiAuthorizationFilterFor(controller => controller.Action(arg)).InstancePerDependency()
// for each controller action marked with TAttribute
private static void RegisterFilterForActions<TAttribute>(ContainerBuilder builder, IEnumerable<Type> controllerTypes)
where TAttribute : Attribute, IAutofacAuthorizationFilter
{
foreach (Type controllerType in controllerTypes)
{
IEnumerable<MethodInfo> actions = controllerType.GetMethods().Where(method => method.IsPublic && method.IsDefined(typeof(TAttribute)));
foreach (MethodInfo actionMethodInfo in actions)
{
ParameterExpression controllerParameter = Expression.Parameter(controllerType);
Expression[] actionMethodArgs = GetActionMethodArgs(actionMethodInfo);
GetAsFilterForActionMethodInfo(controllerType).Invoke(null,
new object[] {
builder.RegisterType(typeof(TAttribute)),
Expression.Lambda(typeof(Action<>).MakeGenericType(controllerType), Expression.Call(controllerParameter, actionMethodInfo, actionMethodArgs),
controllerParameter)
});
}
}
}
private static Expression[] GetActionMethodArgs(MethodInfo actionMethodInfo)
{
return actionMethodInfo.GetParameters().Select(p => Expression.Constant(GetDefaultValueForType(p.ParameterType), p.ParameterType)).ToArray<Expression>();
}
/// <summary>
/// Returns info for <see cref="Autofac.Integration.WebApi.RegistrationExtensions" />.AsWebApiAuthorizationFilterFor()
/// method
/// </summary>
private static MethodInfo GetAsFilterForControllerMethodInfo(Type controllerType)
{
return GetAsFilterForMethodInfo(controllerType, parametersCount: 1);
}
/// <summary>
/// Returns info for <see cref="Autofac.Integration.WebApi.RegistrationExtensions" />
/// .AsWebApiAuthorizationFilterForerFor(actionSelector) method
/// </summary>
private static MethodInfo GetAsFilterForActionMethodInfo(Type controllerType)
{
return GetAsFilterForMethodInfo(controllerType, parametersCount: 2);
}
private static MethodInfo GetAsFilterForMethodInfo(Type controllerType, int parametersCount)
{
return typeof(RegistrationExtensions).GetMethods()
.Single(m => m.Name == nameof(RegistrationExtensions.AsWebApiAuthorizationFilterFor) && m.GetParameters().Length == parametersCount)
.MakeGenericMethod(controllerType);
}
private static object GetDefaultValueForType(Type t)
{
return typeof(ContainerBuilderExtensions).GetMethod(nameof(GetDefaultGeneric))?.MakeGenericMethod(t).Invoke(null, null);
}
private static T GetDefaultGeneric<T>()
{
return default;
}
}
然后您将能够为整个程序集进行一次注册,而不是为每个控制器:
public class LoggerFilterAttribute : Attribute, IAutofacAuthorizationFilter
{
private readonly ILog _logger;
//if you don't want empty constructor you can use separate "marker" attribute and current class will not have to inherit Attribute, but you will need to modify ContainerBuilderExtensions
public LoggerFilterAttribute() { }
public LoggerFilterAttribute(ILog logger)
{
_logger = logger;
}
public Task OnAuthorizationAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
{
_logger.Trace($"Authorizing action '{actionContext.ControllerContext.ControllerDescriptor.ControllerName}.{actionContext.ActionDescriptor.ActionName}'");
return Task.CompletedTask;
}
}
注册:
builder.RegisterWebApiFilterAttribute<LoggerFilterAttribute>(Assembly.GetExecutingAssembly());
你可以在控制器或动作上使用你的属性:
public class AuthorsController : ApiController
{
// GET api/authors
[LoggerFilter]
public IEnumerable<string> Get()
{
return new string[] { "author1", "author2" };
}
}
[LoggerFilter]
public class BooksController : ApiController
{
// GET api/books
public IEnumerable<string> Get()
{
return new string[] { "book1", "book2" };
}
}
整个演示项目在github