Dependency injection

Last updated Monday, July 31, 2017 in Sitecore Experience Platform for Developer
Keywords: Development

Dependency injection (DI) is a technique for achieving loose coupling between objects and their collaborators, or dependencies. Without dependency injection, a class must directly instantiate collaborator or use static references. With dependency injection, the objects a class need are provided for it.

Most often, classes will declare their dependencies through their constructor. Sitecore only supports this approach, known as constructor injection.

The Sitecore implementation of DI is based on the Microsoft.Extensions.DependencyInjection abstractions from ASP.NET Core.

Service registration

You can register the abstraction either in configuration or with code.

Registration in configuration

You can configure abstraction in the services node in any Sitecore include config file. For example:

<configuration>
    <sitecore>
        <services>
            <register serviceType="IMyService, MyAbstraction.Assembly" implementationType="MyServiceImplementation, MyImplementation.Assembly" />
            <register serviceType="MyServiceBase, MyAbstraction.Assembly" implementationType="MyServiceBaseImplementation, MyImplementation.Assembly" />
        </services>
    </sitecore>
</configuration>

Registration in code

You use the IServicesConfigurator interface to configure services from code. For example:

  • Implement the IServicesConfigurator interface:
    public class MyServicesConfigurator : IServicesConfigurator    
        {
            public void Configure(IServiceCollection serviceCollection)
            {
                serviceCollection.AddScoped(typeof(IMyService), typeof(MyServiceImplementation));
                serviceCollection.AddTransient(typeof(MyServiceBase), typeof(MyServiceBaseImplementation));
            }
    } 

    There is more information about IServiceServiceCollection on the MSDN website.

  • Register the configurator:
    <configuration>
        <sitecore>
            <services>
                <configurator type= "MyServicesConfigurator, MyAssembly"/>
            </services>
        </sitecore>
    <configuration>

Services lifetime

Read important information about Service Lifetimes and Registration Options on the MSDN website.

To support scoped per request lifetime, Sitecore.DependencyInjection.SitecorePerRequestScopeModule, Sitecore.Kernel was added to the http modules. If the module is disabled, Scoped has the same behavior as Singleton.

Service resolution

This section describes how you resolve (locate) a registered service through DI, using a service locator.

Injection to types created by Factory

You must use the resolve attribute. The following changes enable injection for the ShowReason processor of the shutdown pipeline:

<shutdown>
     <processor type="Sitecore.Pipelines.Shutdown.ShowReason, Sitecore.Kernel" resolve="true"/> </shutdown>

Injection and MVC

To use dependency injection in an MVC controller, add this processor to the pipeline:

<processor type="Sitecore.Mvc.Pipelines.Loader.InitializeDependencyResolver, Sitecore.Mvc"/>

Injection to WebForms and UserControls

Use the [Sitecore.DependencyInjection.AllowDependecyInjection] attribute for Forms and UserControls:

[Sitecore.DependencyInjection.AllowDependecyInjection] 
public partial class Default : System.Web.UI.Page 
{
    protected Default() // important 
    { 
    }
    public Default(IMyService myService, MyServiceBase serviceBase) 
    { 
    } 
} 

The Form must also have a default constructor (this is a limitation of ASP.NET).

[Sitecore.DependencyInjection.AllowDependecyInjection] 
public partial class DefaultControl : System.Web.UI.UserControl 
{ 
    protected DefaultControl() // important 
    {
    }
    public DefaultControl(IMyService myService, MyServiceBase serviceBase)
    {
          ...
    }
}

The Form must also have a default constructor (this is a limitation of ASP.NET).

Service locator

It is currently not possible to use dependency injection with all parts of Sitecore, so sometimes the service locator is the only solution. This is, for example, the case in page handler factories, MVC controller factories, and in static manager for backward compatibility.

Therefore, you can use the Sitecore.DependencyInjection.ServiceLocator class. For example:

var service = ServiceLocator.ServiceProvider.GetService(typeof(IMyService))

Or, for example:

var service = ServiceLocator.ServiceProvider.GetService<MyServiceBase>();

View the dependency injection configuration

You can see the details of the dependency injection at this URL: http://[instance]/sitecore/admin/showservicesconfig.aspx.

You can see configured-in services (node services) at this URL: http://[instance]/sitecore/admin/showconfig.aspx.

Replace service provider

You can replace the service provider. Sitecore uses the Microsoft.Extensions.DependencyInjection package default.

To replace default provider:

  • Inherit from Sitecore.DependencyInjection.BaseServiceProviderBuilder and implement the BuildServiceProvider method:
    public class MyProviderBuilder : BaseServiceProviderBuilder
    {
        protected override IServiceProvider BuildServiceProvider(IServiceCollection serviceCollection)
        {
            return MyFavouriteServiceProvider.Build(serviceCollection);
        }
    } 

    The Framework site has a list of the containers that Sitecore supports.

  • Replace the default builder in Sitecore.config with your builder:
    <serviceProviderBuilder type="Sitecore.DependencyInjection.DefaultServiceProviderBuilder,    Sitecore.Kernel"/> 

    You can also patch this node with an include file:

    <serviceProviderBuilder type="MyProviderBuilder"/>

Send feedback about the documentation to docsite@sitecore.net.