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

Ada*_*ene 4 asp.net-mvc dependency-injection unity-container asp.net-web-api

跟进ASP.New MVC 4 Web Api的授权过滤器依赖注入。有没有一种方法可以对所有控制器类上全局设置的过滤器使用依赖项注入:

config.Filters.Add(new WebApplicationApiAuthorizeAttribute());  
Run Code Online (Sandbox Code Playgroud)

看起来该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);
    }
}
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*ven 5

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

GlobalFilters.Filters.Add(container.Resolve<MyFilter>());
Run Code Online (Sandbox Code Playgroud)

或执行类似的操作:

var filter = WebApplicationApiAuthorizeAttribute();
container.BuildUp(filter.Gettype(), filter);
GlobalFilters.Filters.Add(filter);
Run Code Online (Sandbox Code Playgroud)

但是关于使用全局过滤器的一个重大警告。全局过滤器是...全局的。或在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; } }
}
Run Code Online (Sandbox Code Playgroud)

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

GlobalFilters.Filters.Add(
    container.Resolve<UnityActionFilterProxy<MyFilter>>());
Run Code Online (Sandbox Code Playgroud)

全局过滤器并不是Web API中唯一设计有点臭的地方。看一下有关DelegatingHandlers的相关问题