I had problems to correctly register the Mediator
and ServiceLocatorProvider
classes.
I pulled my hair a little, but finally I was able to get around it.
My mistake was to register the ServiceLocatorProvider
in the Autofac root container, for example:
var lazyContainer = new Lazy<IContainer>(() => builder.Build()); builder.Register(x => new ServiceLocatorProvider(() => new AutofacServiceLoator(lazyContainer.Value))); DependencyResolver.SetCurrent(new AutofacDependencyResolver(lazyContainer.Value);
At run time, Autofac threw an exception because one of my Request
depended on my EF DbContext
, which I configured to use in an HTTP request.
The trick is to register a ServiceLocatorProvider
in relation to the current ILifetimeScope
HTTP request.
Fortunately, the Autofac error message is self-evident:
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.
This is because the AutofacServiceLocator
been loaded by the root container.
The container does not know about the internal DbContext
associated with the current HTTP request when requesting DbContext
permission.
Using JustDecompile, I sax that the only class that implements the ILifetimeScopeProvider
interface was AutofacDependencyResolver
, and you can access the current instance with the static AutofacDependencyResolver.Current
property.
You can access the current ILifetimeScope
using AutofacDependencyResolver.Current.RequestLifetimeScope
as described in the error message, so at the end the registration looks like this:
builder .Register(x => new ServiceLocatorProvider(() => new AutofacServiceLocator(AutofacDependencyResolver.Current.RequestLifetimeScope))) .InstancePerHttpRequest();
The InstancePerHttpRequest()
is optional, but since ILifetimeScope
will be the same throughout the entire HTTP request, this will prevent Autofac from creating n instances of AutofacServiceLocator
.
I hope this was clear, feel free to make some changes if you think it is necessary, because it is difficult for me to explain this clearly.