Do multiple registrations of IFilterProvider still work in MVC5?

835 views Asked by At

I am sure that this code used to work. I have a UnityFilterProvider and a UnityGlobalFilterProvider both registered in my Unity config.

I would have expected it to pick up both IFilterProviders, but if they are both registered it will only pick up the GlobalFilterProvider. If the only one registered is the basic UnityFilterProvider then that works fine.

But I cannot get them both working together.

Am I doing something wrong? Did this used to work, but not in MVC5? Did this never work and should I do something different?

UnityFilterProvider.cs

namespace Website.Infrastructure
{
    public class UnityFilterProvider : FilterAttributeFilterProvider
    {
        private IUnityContainer container;

        public UnityFilterProvider(IUnityContainer container)
        {
            this.container = container;
        }

        public override IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
        {
            var filters = base.GetFilters(controllerContext, actionDescriptor);

            foreach (var filter in filters)
            {
                container.BuildUp(filter.Instance.GetType(), filter.Instance);
            }

            return filters;
        }
    }
}

UnityGlobalFilterProvider.cs

namespace Website.Infrastructure
{
    public class UnityGlobalFilterProvider : IFilterProvider
    { 
        private readonly IUnityContainer container;
        private readonly IGlobalFilterRegistrationList filterList;

        public UnityGlobalFilterProvider(IUnityContainer container, IGlobalFilterRegistrationList filterList)
        {
            this.container = container;
            this.filterList = filterList;
        }

        public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
        {
            var filters = new List<Filter>();
            if (filterList == null || filterList.Count == 0)
                return filters;

            foreach (GlobalFilterRegistration registration in filterList)
            {
                var actionFilter = container.Resolve(registration.Type);
                var filter = new Filter(actionFilter, FilterScope.Global, registration.Order);
                filters.Add(filter);
            }

            return filters;
        }
    }

    public class GlobalFilterRegistration
    {
        public GlobalFilterRegistration(Type type, int? order)
        {
            this.Type = type;
            this.Order = order;
        }

        public Type Type { get; set; }
        public int? Order { get; set; }
    }

    public class GlobalFilterRegistrationList : List<GlobalFilterRegistration>, IGlobalFilterRegistrationList
    {
    }

    public interface IGlobalFilterRegistrationList
    {
        int Count { get; }
        List<GlobalFilterRegistration>.Enumerator GetEnumerator();
        void Add(GlobalFilterRegistration item);
    }
}

UnityConfig (snip)

container.RegisterType<IFilterProvider, UnityFilterProvider>(new ContainerControlledLifetimeManager());
container.RegisterType<IFilterProvider, UnityGlobalFilterProvider>(new ContainerControlledLifetimeManager());
container.RegisterType<IGlobalFilterRegistrationList, GlobalFilterRegistrationList>(
    new ContainerControlledLifetimeManager());

Anyone got any ideas?

Adding names to the provider registrations solved the problem

container.RegisterType<IFilterProvider, UnityFilterProvider>("UnityFilterProvider", new ContainerControlledLifetimeManager());
container.RegisterType<IFilterProvider, UnityGlobalFilterProvider>("UnityGlobalFilterProvider", new ContainerControlledLifetimeManager());
2

There are 2 answers

1
Mike Dymond On BEST ANSWER

Adding names to the Filter registrations solved the problem.

    container.RegisterType<IFilterProvider, UnityFilterProvider>("UnityFilterProvider", new ContainerControlledLifetimeManager());
    container.RegisterType<IFilterProvider, UnityGlobalFilterProvider>("UnityGlobalFilterProvider", new ContainerControlledLifetimeManager());

Cheers Mike

1
Spock On

Probably this is due to the way the filters being registered. The works for me.

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        var container = new UnityContainer();
        container.RegisterType<IFilterProvider, UnityFilterProvider>(new ContainerControlledLifetimeManager());
        container.RegisterType<IFilterProvider, UnityGlobalFilterProvider>(new ContainerControlledLifetimeManager());
        container.RegisterType<IGlobalFilterRegistrationList, GlobalFilterRegistrationList>(
            new ContainerControlledLifetimeManager());

        container.RegisterType<I, C>();
        container.RegisterType<IActionFilter, SomeActionFilterAttribute>();

        AreaRegistration.RegisterAllAreas();

        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

        GlobalFilters.Filters.Add(new SomeGlobalFilterAttribute());

        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);

    }
}

public interface I
{ }

public class C : I
{ }


public class SomeGlobalFilterAttribute : ActionFilterAttribute
{
    [Dependency]
    public I C { get; set; }
    public SomeGlobalFilterAttribute()
    {

    }
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var c = C;
        base.OnActionExecuting(filterContext);
    }
}

public class SomeActionFilterAttribute : ActionFilterAttribute
{
    [Dependency]
    public I C { get; set; }
    public SomeActionFilterAttribute()
    {

    }
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var c = C;
        base.OnActionExecuting(filterContext);
    }
}