Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Autofac MVC 5 RegisterWebApiFilterProvider causes unresolveable IOverrideFilter

I have a simple MVC app in which I'm trying to add an exception filter. To do that, I followed the Autofac WebAPI Integration documentation that I believe applies to the Autofac.WebApi2 NuGet package.

First, I created the exception filter:

public class ErrorLoggingExceptionFilter : IAutofacExceptionFilter
{
    public void OnException(HttpActionExecutedContext context)
    {
        // do something 
    }
}

I then added the AutofacControllerConfiguration attribute to my API controller base class that I want the exception filter applied to:

[AutofacControllerConfiguration]
public class ApiControllerBase : ApiController  {}

Then I registered the exception filter with Autofac:

builder.RegisterType<ErrorLoggingExceptionFilter>()
    .AsWebApiExceptionFilterFor<ApiControllerBase>()
    .InstancePerApiRequest();

At this point the application still runs fine, but the exception filter doesn't run, so I then registered autofac's filter provider:

builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);

As soon as that's added I start getting 500's with the following error:

None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'Autofac.Features.Metadata.Meta1[System.Web.Http.Filters.IOverrideFilter]' can be invoked with the available services and parameters: Cannot resolve parameter 'System.Web.Http.Filters.IOverrideFilter value' of constructor 'Void .ctor(System.Web.Http.Filters.IOverrideFilter, System.Collections.Generic.IDictionary2[System.String,System.Object])'.

I'm not using any metadata in this project nor do I know anything about IOverrideFilter.

What am I missing that's preventing my exception filter from working?

UPDATE & Response to Comments

The project is using ASP.NET MVC 5.1, using the following Autofac and WebApi NuGet versions:

<package id="Autofac" version="3.2.0" targetFramework="net45" />
<package id="Autofac.Mvc5" version="3.2.0" targetFramework="net45" />
<package id="Autofac.WebApi2" version="3.2.0" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi" version="5.1.1" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.Client" version="5.1.1" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.1.1" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.HelpPage" version="5.1.1" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.WebHost" version="5.1.1" targetFramework="net45" />

I see the same result with Autofac 3.3.

It turns out I can reproduce it by calling only the RegisterWebApiFilterProvider method, so although I put together a complete sample I didn't bother including the above exception filter. The sample project that can be used to reproduce it is available on my Google Drive.

For reference, here's the full stack trace:

None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'Autofac.Features.Metadata.Meta`1[System.Web.Http.Filters.IOverrideFilter]' can be invoked with the available services and parameters: Cannot resolve parameter 'System.Web.Http.Filters.IOverrideFilter value' of constructor 'Void .ctor(System.Web.Http.Filters.IOverrideFilter, System.Collections.Generic.IDictionary`2[System.String,System.Object])'.
at
Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters) at
Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters) at
Autofac.Core.Resolving.InstanceLookup.Execute() at
Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters) at
System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext() at
System.Linq.Buffer`1..ctor(IEnumerable`1 source) at
System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source) at
Autofac.Features.Collections.CollectionRegistrationSource.<>c__DisplayClass4.<RegistrationsFor>b__0(IComponentContext c, IEnumerable`1 p) at
Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters) at
Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters) at
Autofac.Core.Resolving.InstanceLookup.Execute() at
Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters) at
Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters) at
Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters) at
Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context, IEnumerable`1 parameters) at
Autofac.Integration.WebApi.AutofacWebApiFilterProvider.ResolveControllerScopedOverrideFilter(FilterContext filterContext, String metadataKey) at
Autofac.Integration.WebApi.AutofacWebApiFilterProvider.GetFilters(HttpConfiguration configuration, HttpActionDescriptor actionDescriptor) at
System.Linq.Enumerable.<SelectManyIterator>d__14`2.MoveNext() at
System.Linq.Buffer`1..ctor(IEnumerable`1 source) at
System.Linq.OrderedEnumerable`1.<GetEnumerator>d__0.MoveNext() at
System.Linq.Buffer`1..ctor(IEnumerable`1 source) at
System.Linq.Enumerable.<ReverseIterator>d__a0`1.MoveNext() at
System.Web.Http.Controllers.HttpActionDescriptor.<RemoveDuplicates>d__3.MoveNext() at
System.Linq.Buffer`1..ctor(IEnumerable`1 source) at
System.Linq.Enumerable.<ReverseIterator>d__a0`1.MoveNext() at
System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) at
System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source) at
System.Web.Http.Controllers.HttpActionDescriptor.InitializeFilterPipeline() at
System.Lazy`1.CreateValue() at
System.Lazy`1.LazyInitValue() at
System.Web.Http.Controllers.HttpActionDescriptor.GetFilterPipeline() at
System.Web.Http.Controllers.HttpActionDescriptor.GetFilterGrouping() at
System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken) at
System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken) at
System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__0.MoveNext()
like image 770
Kaleb Pederson Avatar asked Feb 14 '23 19:02

Kaleb Pederson


1 Answers

I would say that this is bug? or at least an unexpected interference between two Autofac features.

So this is what is happening:

  • Because you are using the AnyConcreteTypeNotAlreadyRegisteredSource in your sample Autofac tries to register and resolve every type which is not derictly registered in the controller

  • When calling builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration); Autofac tries to localate all the filter and amongs them the registered IOverrideFilters with calling Resolve<IEnumerable<Meta<IOverrideFilter>>>

  • However if no IOverrideFilter registered then Autofac treats Meta<IOverrideFilter> as unresolvable so the AnyConcreteTypeNotAlreadyRegisteredSource kickc in which tries to instantiate a Meta<IOverrideFilter> and throws the exception.

There are multiple workaround for this problem:

  • Just don't use the AnyConcreteTypeNotAlreadyRegisteredSource altough this is probably not what you want to do.

  • Register at least one filter override

     builder.OverrideWebApiActionFilterFor<SomeController>();
    

    so the container will contain a Meta<IOverrideFilter> so the AnyConcreteTypeNotAlreadyRegisteredSource won't run for this type. Again if you don't have filters to override this is not a good solution.

  • You can tell the AnyConcreteTypeNotAlreadyRegisteredSource which types should it resolve so you can also tell that it should not resolve Meta<T>:

    builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource(
     t => !(t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Meta<>))));
    
like image 60
nemesv Avatar answered Apr 27 '23 16:04

nemesv