There are 2 parts to how the MS Di Abstractions and Container are working in Sitecore.
1: The Configuration
The config/configurators etc.. don't actually do the registration of the types with the container. Rather, they just add the required registrations into the IServiceCollection
which at the basic level is just a collection. Nothing is done with that collection at this time.
2: The Registration
Once all the configurators and config has been executed, then Sitecore takes the IServiceCollection
data and registers each type with the container. Out of the box, this is using the MS DI Container.
To do this with Autofac, you need to create your own ServiceProviderBuilder
. Something like:
public class AutofacServiceProviderBuilder
: BaseServiceProviderBuilder
{
protected override IServiceProvider BuildServiceProvider(IServiceCollection serviceCollection)
{
var builder = new ContainerBuilder();
// Register Sitecore services in Autofac.
builder.Populate(serviceCollection);
// Register our custom services via a module.
builder.RegisterModule<ServicesModule>();
// Register all MVC controllers in the current assembly.
builder.RegisterControllers(Assembly.GetExecutingAssembly());
IContainer container = builder.Build();
// Return Autofac's service provider adaptor.
return container.Resolve<IServiceProvider>();
}
}
While this doesn't give you the exact same registration syntax as Autofac, its the same thing, you are registering your dependencies with Autofac as the container instead of MS DI.
Why can't I just use the Autofac syntax?
Well... you can, but... you would have to implement a fallback service locator, here would be an example:
public class SitecoreDependencyResolver : IDependencyResolver
{
private readonly IDependencyResolver _innerResolver;
public SitecoreDependencyResolver(IDependencyResolver innerResolver)
{
this._innerResolver = innerResolver;
}
public object GetService(Type serviceType)
{
return ServiceLocator.ServiceProvider.GetService(serviceType) ?? this._innerResolver.GetService(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
IEnumerable<object> source = (IEnumerable<object>) ServiceLocator.ServiceProvider.GetService(typeof (IEnumerable<>).MakeGenericType(serviceType));
object[] objArray = source as object[] ?? source.ToArray<object>();
if (source != null && ((IEnumerable<object>) objArray).Any<object>())
return (IEnumerable<object>) objArray;
return this._innerResolver.GetServices(serviceType);
}
}
Now you can register your dependencies with Autofac using the ContainerBuilder
and finally register the fallback provider as the DependencyResolver
:
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container))
The problem here is you are introducing complexity and multiple containers in the application. I would go with just using a single container for the application and just replace the MS Di with Autofac and use the IServiceCollection
syntax. You can do most things with that.
Update: So why bother replacing the default container at all?
That is exactly the question you need to ask. Because, you are creating extra work for yourself that you might not need.
Reasons to change container:
- Speed, changing for a more performant container
The problem here, you are talking about replacing MS DI with Autofac. Checkout the benchmarks here: http://www.palmmedia.de/blog/2011/8/30/ioc-container-benchmark-performance-comparison - unfortunately Autofac doesn't do well in those tests, its one of the slower containers
My response to that would be, try something new, don't fight the framework for the sake of fighting the framework. The MS DI Container is actually a pretty decent one, its not got loads of features, but it performs well.
- It doesn't have the same features
The question here is, do you need all the features that the other container is going to give you? If yes, then you are going to need to implement the fallback container to make use of them. But chances are, 95% of the time, you just don't need those extra features. I used to use Autofac and Simple Injector a lot, and I probably would use SI on a new non-Sitecore project. But with Sitecore implementations, I just don't need any of the extra bells and whistles. Keep it simple and don't fight the framework.
Ultimately, use the container that suits you best, but don't just change it with out really thinking it through, as it does have the potential to cause issues. The default container, is actually decent and doesn't create any extra work for you!