How to Effectively Implement Dependency Injection in .NET 5?

In this article, we will see how to implement Dependency Injection in .NET 5? Although, this implementation will be same for .NET Core 2.1 and .Net Core 3.1.

To demonstrate Dependency Injection, I have used .NET 5 with Visual Studio 2019.

What is Dependency Injection?

Dependency Injection (DI) is a design pattern that can assist software developers with decoupling the various bits of their applications. It gives a way to the development of dependency charts autonomous of the class definitions.

You can define Dependency injection as

Dependency injection is a strategy that encourages loose coupling and improves code testability and maintenance.

Dependency Injection in .NET 5

From the beginning of ASP.Net Core (now .NET 5), Dependency Injection is the part of basic development process. More and more developers are using Dependency Injection by help of Microsoft Dependency Injection container.

.NET 5 supports the dependency injection (DI) software design pattern, which is a procedure for accomplishing Inversion of Control (IoC) among classes and their conditions.

.NET 5 injects objects of dependency classes using a constructor or a method by utilizing IoC container.

.NET 5 allows us to enlist our application code with IoC container, in the ConfigureServices method of Startup class (startup.cs).
The ConfigureServices method incorporates a parameter of IServiceCollection type which is utilized to enroll application services.
A service can be injected into the Startup constructor and the Startup.Configure method.

You may configure this in Startup.ConfigureServices method:

public class Startup {
  public void ConfigureServices(IServiceCollection services) {
    services.AddTransient<IProductService, ProductService>();
  }
}

How Dependency Injection Works?

When a request gets invoked to your controller, it will be resolved by container with all its dependencies.

Form of Dependency Injection in .NET 5

Dependency injection in .NET 5 can be defined in 3 forms based on lifetime of service.

  • Transient – .NET 5 will make and share an instance of the service each time to the application when we request it. The service can be added as Transient utilizing AddTransient method for IServiceCollection.
  • Scoped – With AddScoped() method, .NET 5 creates once per scope. Most of the time, scope refers to a single http request request.
  • Singleton – .NET 5 will make and share a single instance of the service through the application life. The service can be added as singleton utilizing AddSingleton method for IServiceCollection. .NET 5 make service occurrence at the time of registration and after that same service instance is used to fulfill the upcoming requests.

.NET 5 framework provides extension methods for each types; AddSingleton(), AddTransient() and AddScoped() methods for singleton, transient and scoped lifetime respectively.

Types of Dependency Injection in .NET 5

Constructor Injection

In Constructor Injection, Services are added as a constructor parameter, and the runtime resolves the service from the help of service container. Services are ordinarily characterized using interfaces.

When we register a service, the IoC container consequently performs constructor injection if an service type is incorporated as a parameter in a constructor.

When utilizing constructor injection, you should make reference to all necessary dependencies in the parameters of the constructor.

Action Injection

Inject the dependency in controller action

Some time, we expected dependency to the specific regulator action method in a controller and not to all actions methods in a controller class. ASP.Net Core (now .NET 5) MVC permits us to inject the dependency to specific action utilizing “FromServices” attribute. This attribute tell the .NET 5 system that parameter ought to be recover from the service container.

The FromServicesAttribute allows injecting a service directly into an action method without using constructor injection:

public IActionResult Index([FromServices] IProductService productService)
 {
 ViewData["ProductName"] = productService.GetProductName();
 return View();
 }

View Injection

Dependency injection into Views

In case you want to utilize the Dependency Injection into Views such as localization or data request only for populating on a particular view.
To fulfill this requirement .NET 5 supports dependency injection into views.

@inject directive is used to inject a service. @inject is just like adding a property to the view, and fetching the property details using Dependency Injection.

@inject DIDemo.Service.IProductervice productervice
<h1>
 @productervice.GetProductName()  
</h1>

Dependency Injection demonstration in .Net 5 with Visual Studio 2019

To demonstrate Dependency Injection, I have created a small .NET 5 API project in Visual Studio 2019. I have used Constructor Injection.

Step1 – Create an interface and add below code.

namespace DotNet5API
{
    public interface IMyClass
    {
        public Task<Users> GetData();
    }
}

Step2- Add a class and implement the interface created in step 1

namespace DotNet5API
{
    public class MyClass:IMyClass
    {
        private readonly HttpClient client = new HttpClient();

        public async Task<Users> GetData()
        {
            var data = client.GetStreamAsync("https://jsonplaceholder.typicode.com/todos/1");
            var result = await JsonSerializer.DeserializeAsync<Users>(await data);
            return result;
        }
    }
}

Step3 – Add a model class

namespace DotNet5API
{
    public class Users
    {
        public int userId { get; set; }
        public int id { get; set; }
        public string title { get; set; }
        public bool completed { get; set; }
       
    }
}

Step4 – Add a controller class to your project

namespace DotNet5API.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class TestController : ControllerBase
    {
        public readonly IMyClass _class1;
        public TestController(IMyClass class1)
        {
            _class1 = class1;
        }

        public async Task<ActionResult<Users>> Test()
        {
            return await _class1.GetData();
        }
    }
}

Step5 – Use Dependency Injection with the AddTransient() method in ConfigureServices() method within startup.cs

public void ConfigureServices(IServiceCollection services)
        {

            services.AddControllers();
            services.AddTransient<IMyClass, MyClass>();
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "DotNet5API", Version = "v1" });
            });
        }

You may use either AddScoped() or AddSingleton() instead of AddTransient(). Make sure to use AddSingleton only if service instance is expensive, but if you are not sure which one to use then better to go with AddTransient<>();

services.AddScoped<IMyClass, MyClass>();
services.AddSingleton<IMyClass, MyClass>();

Now, you don’t want to use MyClass file and you created MyClass1.cs file to define the new logic which is a business requirement. Inherit MyClass1 with same interface i.e. IMyClass

In this case, no need to make changes in your controller classes, simply replace MyClass with MyClass1 in startup.cs file

services.AddTransient<IMyClass, MyClass1>();

You may notice that, I have made changes in ConfigureService() method only and it will work in similar way.

Benefits of using Dependency Injection

  • Loosely coupled application.
  • In case of any change in service implementation, just change the the Service or Implementation file name in startup.cs file.
  • No more changes in any controller class.
  • This makes our life easy

Hope you have now clear idea about Dependency injection in .NET 5. Please feel free to provide your feedback in comment box below.

You may read this article – ASP.Net Core interview Questions and Answers

Leave a Comment

RSS
YouTube
YouTube
Instagram