The author provides an example of how to use MediatR in a console application using Autofac:
var builder = new ContainerBuilder();
builder.RegisterSource(new ContravariantRegistrationSource());
builder.RegisterAssemblyTypes(typeof (IMediator).Assembly).AsImplementedInterfaces();
builder.RegisterAssemblyTypes(typeof (Ping).Assembly).AsImplementedInterfaces();
builder.RegisterInstance(Console.Out).As<TextWriter>();
var lazy = new Lazy<IServiceLocator>(() => new AutofacServiceLocator(builder.Build()));
var serviceLocatorProvider = new ServiceLocatorProvider(() => lazy.Value);
builder.RegisterInstance(serviceLocatorProvider);
I took this example and attempted to make it work with ASP MVC 5 and the Autofac.Mvc5 package:
var builder = new ContainerBuilder();
builder.RegisterSource(new ContravariantRegistrationSource());
builder.RegisterAssemblyTypes(typeof(IMediator).Assembly).AsImplementedInterfaces();
builder.RegisterAssemblyTypes(typeof(AddPostCommand).Assembly).AsImplementedInterfaces();
builder.RegisterControllers(typeof(HomeController).Assembly);
var container = builder.Build();
var lazy = new Lazy<IServiceLocator>(() => new AutofacServiceLocator(container));
var serviceLocatorProvider = new ServiceLocatorProvider(() => lazy.Value);
builder.RegisterInstance(serviceLocatorProvider);
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
When I run the web application, I get an error page telling me that the ServiceLocationProvider
dependency has not been registered. What am I doing wrong?
I suspect that the problem is due to the fact that I am registering the ServiceLocatorProvider
instance after calling Build
- in the author's example, the Build
method is invoked afterwards thanks to Lazy<>
. I do not know how to work around this, though.
I had issues to properly register both the
Mediator
andServiceLocatorProvider
classes.I pulled my hair for a while, but finally managed to get around it.
My mistake was to register
ServiceLocatorProvider
against the root Autofac container, like this:At runtime, Autofac was throwing an exception because one of my
Request
had a dependency on my EFDbContext
that I configured to be scoped by HTTP request.The trick is to register the
ServiceLocatorProvider
against the current HTTP requestILifetimeScope
.Thankfully, the error message from Autofac is self explanatory:
This happens because the
AutofacServiceLocator
was fed with the root container.The container, when asking to resolve the
DbContext
, has no knowledge of an inner - associated with to the current HTTP request - scope.Using JustDecompile, I sax that the only class implementing the
ILifetimeScopeProvider
interface wasAutofacDependencyResolver
, and you can access the current instance with the static propertyAutofacDependencyResolver.Current
.You can access the current
ILifetimeScope
by usingAutofacDependencyResolver.Current.RequestLifetimeScope
as explained in the error message, so in the end the registration looks like:The
InstancePerHttpRequest()
part is optional but since theILifetimeScope
will be the same during the whole HTTP request, this prevents Autofac from creating n instances ofAutofacServiceLocator
.Hope this was clear, don't hesitate to make some edits if you feel like it's necessary, because I have a hard time explaining this clearly.