質問

Following up on Authorization Filter Dependency Injection with ASP.New MVC 4 Web Api . Is there a way to use dependency injection on filters that are set globally on all controller classes:

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

It looks like the GetFilters method in the ActionDescriptorFilterProvider only works on method level filters.

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);
    }
}
}
役に立ちましたか?

解決

If you want these global filters to get injected, you will have to resolve them from the container and add them to the filters collection:

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

Or do something like:

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

But one big warning about using global filters. Global filters are... global. Or in IoC terminology: they are singletons. This means that all its dependencies will effectively become singletons as well, which might cause all sorts of concurrency bugs when they are not expected to live for the duration of the application.

So you should only do this when all the filter's direct and indirect dependencies are singletons, which is great if you can do this, but often isn't the case. So another option is to create a proxy that allows resolving the real instance on the fly:

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; } }
}

This proxy can be injected as singleton in the global filters collection as follows:

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

The global filters isn't the only place in Web API where the design is a bit... smelly. Take a look at this related question about DelegatingHandlers.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top