Using Dependency Injection in Asp.Net Core


What is Dependency Injection?

The dependency injection (DI) is a software design pattern, which is a technique for achieving Inversion of control (IOC) between classes and their dependencies.
ASP.NET Core is designed from scratch to support Dependency Injection. ASP.NET Core injects objects of dependency classes through constructor or method by using built-in IoC container.

Why use Dependency Injection?


Using Dependency Injection, we make a class independent of its dependencies. It achieves that by decoupling the usage of an object from its creation. In other terms, the intent of Dependency Injection is to make code maintainable by allowing us to develop loosely-coupled code. Technically saying, DI reduces the hard-coded dependencies among the classes by injecting those dependencies at run time instead of design time.

Overview of Dependency Injection

A dependency is any object, that another object requires. Dependency Injection allows the creation of dependent objects outside of a class and provides those objects to a class in different ways. Using DI, we move the creation and binding of the dependent objects outside of the class that depends on them.
The Dependency Injection pattern involves 3 types of classes which are
Client Class: The client class (dependent class) is a class which depends on the service class
Service Class: The service class (dependency) is a class that provides service to the client class.
Injector Class: The injector class injects the service class object into the client class.
                                                



As you can see, the injector class creates an object of the service class and injects that object to a client object. In this way, the DI pattern separates the responsibility of creating an object of the service class out of the client class.

An instance of the MyServiceClass class can be created to make the WriteMessage method available to a class. The MyServiceClass class is a dependency of the MyClientClass class.

The class creates and directly depends on the MyServiceClass instance. Code dependencies (such as the previous example) are problematic and should be avoided for the following reasons:
  •          To replace MyServiceClass with a different implementation, the class must be modified.
  •          If MyServiceClass has dependencies, they must be configured by the class. In a large project with multiple classes depending on MyServiceClass, the configuration code becomes scattered across the app.
  •          This implementation is difficult to unit test. The app should use a mock or stub MyServiceClass class, which isn't possible with this approach.

Dependency injection addresses these problems through:
  •          The use of an interface or base class to abstract the dependency implementation.
  •          Registration of the dependency in a service container. ASP.NET Core provides a built-in service container, IServiceProvider. Services are registered in the app's Startup.ConfigureServices method.
  •          Injection of the service into the constructor of the class where it's used. The framework takes on the responsibility of creating an instance of the dependency and disposing of it when it's no longer needed.

Let's use Dependency Injection in application

Consider the following example of a simple ILog interface and its implementation class. We will see how to register it with built-in IoC container and use it in our application.
public interface ILog
{
    void info(string str);
}

class MyConsoleLogger : ILog
{
    public void info(string str)
    {
        Console.WriteLine(str);
    }
}

ASP.NET Core allows us to register our application services with IoC container, in the ConfigureServices method of the Startup class. The ConfigureServices method includes a parameter of IServiceCollection type which is used to register application services.
Let's register above ILog with IoC container in ConfigureServices() method, which can be done in 3 ways as shown below:
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
// Singleton:- IoC container will create and sare a single instance of a  service 
throughout the application’s lifetime.
        services.Add(new ServiceDescriptor(typeof(ILog), new MyConsoleLogger()));    
         
// Transient:- IoC container will create a new instance of the specified service 
type every time you ask for it.
         services.Add(new ServiceDescriptor(typeof(ILog), typeof(MyConsoleLogger), 
ServiceLifetime.Transient)); 
         
// Scoped:- IoC container will create an instance of the specified service 
type oce per request and will be shared in a single request.
         services.Add(new ServiceDescriptor(typeof(ILog), typeof(MyConsoleLogger), 
ServiceLifetime.Scoped));    
 
    }
}

Types of Dependency Injection

The injector class injects dependencies broadly in three ways:
  •          Constructor Injection
  •          Method Injection
  •          Property Injection


Constructor Injection

In the constructor injection, the injector supplies the service (dependency) through the client class constructor.
Once we register a service, the IoC container automatically performs constructor injection if a service type is included as a parameter in a constructor.
For example, we can use ILog service type in any MVC controller. Consider the following example:

public class HomeController : Controller
{
    ILog _log; 
    public HomeController(ILog log)
    {
        _log = log;
    }
    public IActionResult Index()
    {
        _log.info("Executing /home/index");
 
        return View();
    }
}
 
In the above example, an IoC container will automatically pass an instance of MyConsoleLogger to the constructor of HomeController. We don't need to do anything else. An IoC container will create and dispose an instance of ILog based on the registered lifetime.

Method Injection

In this type of injection, the client class implements an interface which declares the method(s) to supply the dependency and the injector uses this interface to supply the dependency to the client class. For this, use [FromServices] attribute with the service type parameter in the method:
public class HomeController : Controller
{
    public HomeController()
    {
    } 
    public IActionResult Index([FromServices] ILog log)
    {
        log.info("Index method executing"); 
        return View();
    }
}

Property Injection

Built-in IoC container does not support property injection. You will have to use third party IoC container. For this, use [FromServices] attribute with the service type parameter in the method.

Conclusion


Dependency Injection (DI) describes the pattern of passing dependencies to consuming services at instantiation. DI frameworks provide IoC containers that allow developers to offload control of this process to the framework. This lets us decouple our modules from their concrete dependencies, improving testability and extensibility of our applications.

Comments

Popular posts from this blog

Data Protection API (DPAPI) system in ASP.NET Core

Get Started with GIT Repository and VSTS

Querying Cross Databases in Azure SQL