How To Add Dependency Injection In Your Sitecore Application

What is Dependency Injection?

Dependency Injection is a software design pattern that will allow developers to develop loosely coupled codes between two components. It allows better management for future changes.

Along with better management, it allows for a better unit testing process and increases code reusability and maintainability.

There are a few ways of implementing DI.

  1. Constructor Injection: This injector supplies the dependency through the constructor of the class.
  2. Property Injection: The injector supplies dependency through the setter of the property of the class. As this is being done through Setter, this is also called Setter Injections.
  3. Method Injection: Over here client class implements an interface that declares the method to supply the dependency and using this interface the injector supplies the dependency to the client class.

In Sitecore, we will design with constructor injection.

To start off, create your project (either Foundation or Feature) in Solution.

Create a new interface and write down the methods you need. After that, add your concrete class and implement the interface.

Let’s say we are working on the article section of a project and this is a feature of articles and we need a repository to save articles.

Model

namespace Feature.Articles.Models  
{  
    public class Article  
    {  
        public string Subject { get; set; }  
        public string Body { get; set; }  
        public List<string> AttachementList { get; set; }  
        public string Username { get; set; }  
        public List<string> Tags { get; set; }  
    }  
}  

Interface

public interface ISaveArticleReository  
{  
    bool SaveArticle(Article article);  
}  

Class

public class SaveArticleRepository : ISaveArticleReository  
{  
    public bool SaveArticleInSQLServer(Article article)  
    {  
        // do your code for saving in SQL Server  
    }  
}  
public class SaveArticleRepository : ISaveArticleReository  
{  
    public bool SaveArticleInMongoDB(Article article)  
    {  
        // do your code for saving in Mongo DB  
    }  
}  

Set up the connection between the Interface and class.

You need to connect both the class and interface in the RegisterDependencies class. For the same, create a folder named DependencyInjection and create a class. Make sure the class is implemented from the interface. ISaveArticleReository.

Within the configure method, connect the class to the interface using three methods.

  • AddTransient<TService, TImplementation>(): Transient objects are always different; a new instance is provided to every controller and every service.
  • AddScoped<TService, TImplementation>(): Scoped objects are the same within a request, but different across different requests.
  • AddSingleton<TService, TImplementation>(): Singleton objects are the same for every object and every request.

For more please visit .NET documentation.

namespace Feature.Articles.DependenyInjection     
{     
    public class RegisterDependencies : IServicesConfigurator     
    {     
        public void Configure(IServiceCollection serviceCollection)     
        {     
            serviceCollection.AddTransient<ISaveArticleReository, SaveArticleInSQLServer>();     
            // serviceCollection.AddTransient<ISaveArticleReository, SaveArticleInMongoDB>();     
            // Switch the concrete class name as per your need.     
        }     
    }     
}

Note. We have two concrete classes from one interface, one is saving the data into SQL server and another one in MongoDB with two different implementations. Switch the concrete class in the dependency injections to switch between implementations.

After this, you need to register the Dependency Injection class RegisterDependencies.

Creating the RegisterDependencies class is not enough to enable the Dependency injection in Sitecore, you have to identify the Sitecore engine using a patch config file.

Create a config file in the App Config folder. Location should be like App_Config -> Include -> <Fature/Foundation> -> <CompoenentName>.Config

Add the below lines to the file.

<?xml version="1.0"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <services>
      <configurator type="<Namespace>.<Class Name>, <Project Name>" />
    </services>
  </sitecore>
</configuration>

As per our solution, the config file will be like this.

<?xml version="1.0"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <services>
      <configurator type="Feature.Articles.DependenyInjection.RegisterDependencies, Feature.Articles" />
    </services>
  </sitecore>
</configuration>

After then we have to inject the Interface into the controller file. For the same create a read-only private variant of interface type in the controller.

namespace Feature.Articles.Controllers  
{  
    public class ArticleCommentAPIController : SitecoreController  
    {  
        private readonly ISaveArticleReository _saveArticleReository;  

        public ArticleCommentAPIController(ISaveArticleReository saveArticleReository) => 
            _saveArticleReository = saveArticleReository;  

        public JsonResult SaveArticle(Article article)  
        {  
            return Json(_saveArticleReository.SaveArticle(article));  
        }  
    }  
}  

Now build your project and upload the DLL and Config file to test.