Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebApi, Autofac, System.Web.Http.Filters.ActionFilterAttribute Instance Per Request

We have been using Autofac in our application (MVC 4 now) for a long time, we have dozens of attributes on the base controller everything inherits from and it has all been working fine so when the request begins our service is created and then available through all the attributes and on the controller action.

We are now looking at WebApi and have created our WebApi controller and created an attribute on the base controller using the ActionFilterAttribute from the HTTP namespace. However the problem starts here where the service injected on the property on the attribute is not the same instance as that on the ApiController. Looking at the link below this seems to be known ASP.NET Web API and dependencies in request scope

However the solution here is not ideal as we don't want our controllers to know about the dependency injection, we just want to use the service we are injecting to the property and know it is one instance per request.

We are calling this:

  builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);

And

  GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);

Our classes are currently registered with Autofac as InstancePerLifetimeScope, what we want is to be able to have per request working for MvcControllers and ApiControllers.

Is that possible?

EDIT:

So basically this line returns the right service for the request (i.e. the same instance that is also on the ApiController)

var service = actionContext.Request.GetDependencyScope().GetService(typeof(IOurService);

But the property injection instance on the ActionFilterAttribute is not the same and if I change the Autofac registration to be InstancePerApiRequest I get the following error:

"No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself."

like image 827
user351711 Avatar asked May 14 '14 15:05

user351711


1 Answers

This is a known issue and a design problem in Web API. When filter instances are first created in Web API they are cached, so Autofac has to resolve the property injection using the root lifetime scope, not the request lifetime scope. There is no opportunity on a per-request basis for Autofac to do any property injection - the filters are effectively singletons within Web API and there's no hook to change that.

Thereafter, if you need per-request services in your filter, you have to use that GetDependencyScope() trick.

See these issues on Autofac for more details:

  • Issue #452: Property Injection in Web API ActionFilterAttribute does not use Http request scope
  • Issue #525: Filter not getting instance per http request
like image 112
Travis Illig Avatar answered Oct 14 '22 14:10

Travis Illig