扩展ActionDescriptorFilterProvider以允许依赖注入类级别过滤器

时间:2014-03-26 23:47:23

标签: asp.net-mvc asp.net-web-api dependency-injection unity-container

跟进Authorization Filter Dependency Injection with ASP.New MVC 4 Web Api。有没有办法在所有控制器类上全局设置的过滤器上使用依赖注入:

config.Filters.Add(new WebApplicationApiAuthorizeAttribute());  

GetFilters中的ActionDescriptorFilterProvider方法似乎只适用于方法级过滤器。

public class UnityWebApiFilterAttributeFilterProvider : ActionDescriptorFilterProvider,
    System.Web.Http.Filters.IFilterProvider
{
private readonly IUnityContainer _container;

public UnityWebApiFilterAttributeFilterProvider(IUnityContainer container)
{
    _container = container;
}

public IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, 
    HttpActionDescriptor actionDescriptor)
{
    var filters = base.GetFilters(configuration, actionDescriptor);

    this.BuildUpAttributes(filters);

    return filters;
}

private void BuildUpAttributes(IEnumerable filterInfo)
{
    foreach (FilterInfo filter in filterInfo)
    {
        object o = _container.BuildUp(filter.GetType(), filter);
    }
}
}

1 个答案:

答案 0 :(得分:4)

如果您希望注入这些全局过滤器,则必须从容器中解析它们并将它们添加到过滤器集合中:

GlobalFilters.Filters.Add(container.Resolve<MyFilter>());

或做类似的事情:

var filter = WebApplicationApiAuthorizeAttribute();
container.BuildUp(filter.Gettype(), filter);
GlobalFilters.Filters.Add(filter);

但是关于使用全局过滤器的一个重要警告。全局过滤器是......全局的。或者在IoC术语中:它们是单身人士。这意味着它的所有依赖关系也将有效地成为单例,这可能会导致各种并发错误,因为它们在应用程序期间不会存在。

因此,只有当所有过滤器的直接和间接依赖关系都是单例时,才应该这样做,如果你能做到这一点,这很好,但通常情况并非如此。所以另一个选择是创建一个允许动态解析实例的代理:

public sealed class UnityActionFilterProxy<TActionFilter> : IActionFilter
    where TActionFilter : IActionFilter
{
    private readonly IUnityContainer container;
    public UnityActionFilterProxy(IUnityContainer container) {
        this.container = container;
    }

    public Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext context,
        CancellationToken token, Func<Task<HttpResponseMessage>> continuation) {
        return this.container.Resolve<TActionFilter>().ExecuteActionFilterAsync(
            context, token, continuation);
    }

    public bool AllowMultiple { get { return false; } }
}

此代理可以在全局过滤器集合中作为单例注入,如下所示:

GlobalFilters.Filters.Add(
    container.Resolve<UnityActionFilterProxy<MyFilter>>());

全局过滤器并不是Web API中唯一一个设计有点......臭的地方。请查看有关DelegatingHandlers的this related question