Dependency Injection – ASP.Net

  • by

Now that we have learnt about the components that are present in StartUp class let’s understand more about the concept of Dependency Injection. Dependency injection is one of the design patterns that is used by the dotnet core framework. When service A requires the functions or properties from another service B to execute some functionality , then service A  is said to be dependent on service B.

Let’s take an example, the following code is written without using the dependency injection.

public class B

{

   public void Print(string message)

   {

       Console.WriteLine($”This function executed from service B. Message: {message}”);

   }

}

public class A

{

   private readonly B _b = new B();

   public void PrintMessage()

   {

       _b.Print(“This A calling B’s method”);

   }

}

 In the above code, we see that class A is dependent on class B for the Print method. Clearly A is dependent on B. Inorder to establish this dependency, we had to create an instance of class B in class A. This will create a lot of problems because,

  1. When dependencies of B increases A needs to instantiate and register those services as well. In an application where lots of services are interdependent on each other this becomes chaotic.
  2. The code becomes difficult to unit test as well.
  3. The services A and B are very tightly coupled, any change in implementation to B might need to be reflected back in A.

To avoid these problems dependency injection is used. In dotnet core, the DI container takes care of instantiating and injecting the dependent services for a service. For this we create an interface for the dependent service and wire up that as dependency to the service that requires it using the constructor. Let’s take our A and  B services, with dependency injection.

public interface IB

{

   void WriteMessage(string message)

}

public class B : IB

{

   public void WriteMessage(string message)

   {

       Console.WriteLine($”This function executed from service B. Message: {message}”);

   }

}

public class A

{

   private readonly IB _b;

    A(IB b){

        _b = b;

    }

   public void OnGet()

   {

       _b.WriteMessage(“This A calling B’s method”);

   }

}

public void ConfigureServices(IServiceCollection services)

{

   services.AddScoped<IB, B>();

   services.AddRazorPages();

}

Here, in startup class the AddScoped  method registers the service with a scoped lifetime. We’ll learn more about the lifetime concept in the next section. The order in which we specify the dependent services doesn’t matter because whenever the DI container recognises that a service is dependent on another service, it comes to the configure services method, instantiates it with appropriate implementation and injects it to the service.

Registering Services And Extension methods

     In StartUp.cs we have already seen the AddControllers method, this is one good example of adding a group of services. We can use the Add method followed by the Group name to do so. These are called the group extension methods. Some of the examples of group extension methods that are provided by the framework are AddControllers, AddDefaultIdentity, AddDbContext etc.

      It is also possible for us to group similar services together and create our own extension methods and call them from the StartUp file.Following is an example of the extension file that can be created for our services.

Later this extension method can be added in the Startup class in the following way under the ConfigureServices method.

Service Lifetimes and Registration Methods

The Service lifetimes are often defined using the registration methods. Service lifetime refers to the time period between which the service instance is created and cleared. The three registration methods are Singleton, Transient and Scoped. Depending on the way you want to initialise and dispose of the instance of the service we can make use of one of the three registration methods. The the service instance will be created based on the registration method in the following way,

  1. Scoped : The framework will create an instance of the service for each request. To make use of this feature we can make use of the AddScoped() method provided by the framework.
  2. Transient: The framework will create an instance of the service whenever we are in need of it. To make use of this feature we can make use of the AddTransient() method provided by the framework.
  3. Singleton: The framework will create an instance of the service once and this instance will stay intact throughout the running time of the application.To make use of this feature we can use the AddSingleton() method provided by the framework.

Leave a Reply

Your email address will not be published. Required fields are marked *