I have configured my EF context configured like so
b.RegisterAssemblyTypes(webAssembly, coreAssembly)
.Where(t => t.IsAssignableTo<DbContext>())
.InstancePerLifetimeScope();
I would like to use it from a custom authorization attribute that hits the database using my EF context. This means no constructor-injection. I achieve this by using CommonSeviceLocator
var csl = new AutofacServiceLocator(container);
ServiceLocator.SetLocatorProvider(() => csl);
...
var user = await ServiceLocator.Current
.GetInstance<SiteContext>().FindAsync(id);
I am finding that this fails with a "multiple connections not supported" error if the browser issues two simultaneous requests to routes using this attribute. It seems like this might be due to what is mentioned in this answer. My guess is that ServiceLocator
resolves from the root scope rather than the web request scope and the two request are conflicting (either request in isolation works fine).
This seems confirmed by that when I change to InstancePerRequest()
I get this from any invocation of the attribute.
Autofac.Core.DependencyResolutionException 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.
So it seems like maybe ServiceLocator
is simply not the way to go.
How do I resolve the request-scoped SiteContext
from inside the attribute (using a service-locator pattern)?
Your issue derives from the fact that you are trying to put behavior inside of an Attribute. Attributes are for defining meta-data on code elements and assemblies, not for behavior.
Microsoft's marketing of Action Filter Attributes has led people implementing DI down the wrong path by putting both the Filter and the Attribute into the same class. As described in the post passive attributes, the solution is to break apart filter attributes into 2 classes:
See the following for more examples:
Unity Inject dependencies into MVC filter class with parameters
Implementing passive attributes with dependencies that should be resolved by a DI container
Injecting dependencies into ASP.NET MVC 3 action filters. What's wrong with this approach?
How can I test for the presence of an Action Filter with constructor arguments?
Another option is to use IFilterProvider
to resolve the filters as in IFilterProvider and separation of concerns.
Once you get your head around the fact that Attributes should not be doing anything themselves, using them with DI is rather straightforward.