2

We have changed the Dependency Injector in our Sitecore 9.1 solution to use Autofac, following this description as well as receiving a support .dll from Sitecore support.

We register our types using this configurator code:

public class SitecoreExtensionsConfigurator : IServicesConfigurator
{
    public void Configure(IServiceCollection serviceCollection)
    {
        serviceCollection.AddTransient<ITrackerService, TrackerService>();
        serviceCollection.AddSingleton<IRenderingPropertiesRepository, RenderingPropertiesRepository>();
    }
}

However, as far as I understand it, it just uses the Microsoft DI framework to register the types. What if I want to register my components using Autofac syntax, like:

public void Configure(IServiceCollection serviceCollection)
{
    var builder = new ContainerBuilder();
    builder.RegisterType<TrackerService>()
        .As<ITrackerService>();
}

However, that makes my site fail, with an exception, stating that ITrackerService is not registered.

2
  • Have you registered your sevices in your custom (Autofac) ServiceProviderBuilder class (the one that inherits from BaseServiceProviderBuilder)?
    – sitecorium
    Commented Mar 26, 2019 at 15:19
  • We are trying to follow Helix principles, so I guess that would make our Dependency Injection project reference all the projects that need DI.
    – Hos
    Commented Mar 26, 2019 at 19:38

1 Answer 1

4

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

  • It's what I'm used too.

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!

2
  • Thanks for your elaborate reply. I will mark it as the answer, but could you explain what the usage of replacing the builtin Sitecore DI mechanism is, if I cannot fully re-use Autofac's (in this example) synta, i.e why not just use Sitecores DI? The reason why we want to replace Sitecores DI, is because we already use Autofac.
    – Hos
    Commented Mar 26, 2019 at 19:44
  • Answer updated with some info on that.
    – Richard Seal
    Commented Mar 26, 2019 at 19:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.