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.

There are lot of great blog post, referenced in end of this article, describing DI technique and the way of implementing it in sitecore. Here in this article we will implement it step by step. We will be using the existing Habitat sample project to demonstrate DI integration.

Dependency Injection really fits in the Foundation layer. So we will create a Foundation layer project.

Preparing Solution

We assume that, you have already downloaded sample habitat solution from github and it is up and running at your local environment. If not, please go through the steps mentioned in wiki of Habitat github repository or follow step by step guidelines in my last article from here, and configure your solution accordingly.

Once you are Habitat site is up and running, we will prepare our Habitat solution for a new Foundation module “DependencyInjection” by following steps listed below.

  1. Open Habtat solution project from the project location.
  2. Add a new solution folder under Foundation folder and name it as “DependencyInjection”.
  3. Create a new ASP.NET Web Application project and choose Empty MVC Template under this folder with the project name code.

This will create a folder “code” on disk to ensure proper folder structure convention suggested for Helix based solutions.

Rename solution name code to “Sitecore.Foundation.DependencyInjection” and change assembly name and default namespace accordingly.

Container Initialization

First of all we need to initialize our dependency injection container. Our primary framework for sitecore integration is Simple Injector, but of course you can choose any framework you like.

Simple Injector’s main type is the Container class. An instance of Container is used to register mappings between each abstraction (service) and its corresponding implementation (component). Your application code should depend on abstractions and it is the role of the Container to supply the application with the right implementation. The easiest way to view the Container is as a big dictionary where the type of the abstraction is used as key, and each key’s related value is the definition of how to create that particular implementation. Each time the application requests a service, a look up is made within the dictionary and the correct implementation is returned.

As discussed previously, we will create a dependency container using SimpleInjector and we will set its accessibility as static. So that we can use it as a ServiceLocator and can be accessed/resolve dependency from anywhere including pipeline processors.

We will implement all related code to initialize dependency injection in this module.

Add a new class with the name “Container” and replace below code into newly created class.

Every pipeline needs pipeline arguments. In our custom pipeline, we need to have a reference to the container. The pipeline arguments for our custom pipeline can be implemented as follow

  1. Create another folder under the project with name “Pipelines”
  2. Add a new class file and name it “InitializeDependencyInjectionArgs” and replace the content with below code

Then we need to create a new processor for the <initialize>-pipeline. This processor basically configures Simple Injector and starts our custom pipeline.

  1. Create one more folder under “Pipelines” folder called “Pipelines\Initialize”
  2. Add a new class file with the name “Pipelines\Initialize\InitializeDependencyInjection”
  3. In this class, we would create a container by calling static method of Container class. After creating container, we would register all MVC controllers from Feature and Foundation projects by using reflection. Finally we would set the dependency resolver with this container.
  4. Replace below code into this class file.

We need to register our pipeline processor to the <initialize>-pipeline. It’s important to do this before Sitecore registered the ControllerFactory

Create folders under root of this project called “App_Config\Include\Foundation” and add a configuration file Foundation.DependencyInjection.config with below content

The overall structure and solution tree in visual studio for DependencyInjection foundation module, would be looking like this.

Registering Dependencies

Of course an IoC container is useless if it has no registered dependencies to resolve! Sitecore’s container can be configured in multiple ways, all of which involve some level of XML.

Keep in mind when wiring dependencies that the IoC container is not multitenant. Your dependencies are sharing the container with Sitecore’s – and if you have more than one site, potentially other sites as well. So don’t go expecting to have IFoo resolve to different implementations in different sites!

Now we have a dependency injection container set up, but we don’t have any dependencies configured. This is now the job of each module. The following example adds the configuration for the existing Feature Layer Module named Nevigation. All we need to add is a new pipeline processor in the module:

  1. Navigate to the Neviation module solution project in Feature layer folder.
  2. Create a folder at root and name it “Pipelines” and create one more folder under Pipelines folder called “InitializeDependencyInjection”.
  3. Add a new class file in this folder with the name “RegisterServices”
  4. Replace existing code with this code statements

Next, add a new config file, if not already added, under “App_Config\Include\Feature\Feature.Navigation.config” and initializeDependencyInjection section under pipelines node as below.

Confirm your solution tree and referenced folders with screen shot.

Resolving Dependencies

Habitat is already prepared to use dependency injection, as it uses poor man’s dependency injection. With our new configuration, we want to use constructor injection for all the Mvc controllers. For the NavigationController this means we only need to remove this constructor:

The only constructor left is:

public NavigationController(INavigationRepository navigationRepository)

This is how it looks like in the updated NavigationController.

As I mentioned earlier, this is fine for Mvc controllers, but can’t be used e.g. int pipeline processors. If you need a reference in a pipeline processor (e.g. to the INavigationRepositoryFactory) you can now resolve the dependency over the service locator implementation with the following line of code:

That’s all. What do you think about this implementation? How do you implement dependency injection in a modular architecture? Please add a comment to this blog post if you have other ideas or remarks.

References

My very special thanks to Mr. Kevin Brechbühl, who has originally implemented this concept in Component based architecture.  Apart from it, I would also like to thank Neil Bailey, who suggested me to write this step by step guidelines to implement DI in Sitecore.

https://ctor.io/one-way-to-implement-dependency-injection-for-sitecore-habitat/

https://doc.sitecore.net/sitecore_experience_platform/developing/developing_with_sitecore/dependency_injection

https://kamsar.net/index.php/2016/08/Dependency-Injection-in-Sitecore-8-2/

Although, this approach might not be the best approach of implementing dependency injection in Helix based architecture and there are some better and effective approaches available for implementing it in component based architecture and I would be happier to analyze and implement those as well. I would certainly share my experience on that soon.

Stay tuned.