Easy way to resolve dependency injection in ASP.Net Core

Do Dung
6 min readJul 3, 2020

1. Why do we need to resolve dependency injection?

To explain the problem of dependency injection in asp.net core, I provide an example below:

I need to create an application to manage the students of a class in the school. We have many actors such as Student, Class, School…
Now I will create an interface of Student actor and a class to implement this interface (this is a class in the data access layer — DAL).

Interface IStudentDal

public interface IStudentDal
{
List<Student> GetAll();
Student GetById();
Student GetByName();
}

Implement class

public class StudentDal : IStudentDal
{
private static List<Student> lstStudent = new List<Student>() {
new Student(){ Id = 1, Email ="test1@gmail.com", FullName ="Test 1" },
new Student(){ Id = 2, Email ="test2@gmail.com", FullName ="Test 2" },
new Student(){ Id = 3, Email ="test3@gmail.com", FullName ="Test 3" },
new Student(){ Id = 4, Email ="test4@gmail.com", FullName ="Test 4" }
};
public List<Student> GetAll()
{
return lstStudent;
}
public Student GetById(int id)
{
return lstStudent.FirstOrDefault(x => x.Id == id);
}
public Student GetByName(string name)
{
return lstStudent.FirstOrDefault(x => x.FullName.Equals(name));
}
}

Now we need to create an interface and an implement the class for Student actor in the business layer(BSL) as below :

Interface IStudentBsl

public interface IStudentBsl
{
List<Student> GetAll();
Student GetById(int id);
Student GetByName(string name);
}

Implement class

public class StudentBsl : IStudentBsl
{
public List<Student> GetAll()
{
throw new NotImplementedException();
}
public Student GetById(int id)
{
throw new NotImplementedException();
}
public Student GetByName(string name)
{
throw new NotImplementedException();
}
}

Now the method GetAll() of StudentBsl class needs to call the method GetAll() of StudentDal class to return the list data of students’ information. How can I do it?
In normal we usually use 2 ways below to call:

Way 1: Initial StudentDal class from every method if that method gets info ex:

public List<Student> GetAll()
{
IStudentDal studentDal = new StudentDal();
var lstStudent = studentDal.GetAll();
return lstStudent;
}

Way 2: Initial StudentDal class in constructor of class and use for all method ex :

public class StudentBsl : IStudentBsl
{
private IStudentDal _studentDal;
public StudentBsl()
{
_studentDal = new StudentDal();
}
public List<Student> GetAll()
{
var lstStudent = _studentDal.GetAll();
return lstStudent;
}
}

Uhm hum, you can see the way 2 is better than because you no need to instance class many times. But both ways have the common problem, they have to instance StudentDal class in many places if you have a lot of classes that need to use the StudentDal class, this class will be instantiated at least once in those classes.

And if this class changes the business and needs to change the constructor’s parameters, what will happen? You will have to update code in many places. If your site is big I think it very difficult to maintain. This is called dependency injection in asp.net core. So how to resolve this problem?

2. How to resolve Dependency injection?

Before resolving this problem we need to understand about Inversion of Control(IoC).

2.1 What is Inversion of Control(IoC)?

You can understand the short and simple way that IoC is a programming principle, it helps automatically initialize all instances of classes or interfaces. You just declare the classes, interfaces need to use and IoC will auto inject all instances for them.

Maybe you will feel difficult to understand. If I provide an example you will easily understand but It only is a principle. I will provide some examples when implementing IoC below.

2.2. What is the advantage and disadvantage of IoC?

2.2.1. Advantage

- Making it easier to switch between different implementations
- Easy maintenance.
- Easy write unit test.
- Decouples the application.
- It is only slow for the first visitor and then it is fast for all (if you use singleton).
- Short code.
- Reduced Dependencies.
- Readable Code.

2.2.2. Disadvantage

- Difficult to trace code
- Increases complexity in the linkages between classes. It may become harder to manage such complexity outside the implementation of a class.

2.3. How to implement IoC?

We have many ways to implement IoC, you can use DI, Service Locator, Delegates, Events…. The most popular way is to use DI(Dependency Injection) to implement IoC.

2.4. How to achieve the Dependency Injection?

We have many ways to get Dependency Injection (DI). We can use some DI container like Unity container, Ninject, AutoFac, StructureMap….

2.5. Dependency injection lifetime

Service lifetime is very important because we can determine when a class will be instances and destroy. Microsoft introduced three services lifetime for you choose:

2.5.1. Transient

Transient lifetime services are created each time they’re requested from the service container. This lifetime works best for lightweight, stateless services. So you can understand that a class can be instanced many times for one request if you have many components call that class.

* Note: You need to consider when to use this lifetime because if you use it many times in a request maybe it makes the decrease time load page.

2.5.2. Scoped

Scoped lifetime services are created once per client request. In web apps process requests, scoped services are disposed of at the end of the request.

2.5.3. Singleton

Singleton lifetime services are created once when the application starts, it only destroys when that application stops.

2.6. Setup DI in Asp.Net Core web application

2.6.1 Register class or interface to DI container

In Asp.net core web application, Microsoft has provided DI default, all ready to use.
You can register DI In the method ConfigureServices() of Startup.cs file, IServiceCollection interface looks like a DI container, In this interface provides three methods to help you register DI lifetime for your class or interface.
- AddTransient() : It is a transient lifetime service.

services.AddTransient<IMyInterface, MyImplement>();

- AddScoped() : It is a scoped lifetime service.

services.AddScoped<IMyInterface, MyImplement>();

- AddSingleton() : It is a singleton lifetime service.

services.AddSingleton<IMyInterface, MyImplement>();

We have three ways to implement DI, that is through Constructor, Property and Method. In this article, I will use the Constructor method to resolve dependency injection.
Back to the above example, I will make a constructor for StudentBsl class and initial IStudentDal class here. You can see bellow code:

public class StudentBsl : IStudentBsl
{
private IStudentDal _studentDal;
public StudentBsl(IStudentDal studentDal)
{
_studentDal = studentDal;
}
public List<Student> GetAll()
{
return _studentDal.GetAll();
}
public Student GetById(int id)
{
return _studentDal.GetById(id);
}
public Student GetByName(string name)
{
return _studentDal.GetByName(name);
}
}

Now, this is the most important step, We need to register IStudentBsl and IStudentDal interfaces to the DI container. See syntax above we will use the AddScoped() method to register because I want them to be disposed of after finishing a request. It looks like as below :

public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddScoped<IStudentDal, StudentDal>();
services.AddScoped<IStudentBsl, StudentBsl>();
}

Okay, now they are ready to call anywhere with controllers. I will display all students on the Home page of this example. In HomeController we also register IStudentBsl through the constructor and get all data in Index action and pass it to view for display.

public class HomeController : Controller
{
private IStudentBsl _studentBsl;
public HomeController(IStudentBsl studentBsl)
{
_studentBsl = studentBsl;
}
public IActionResult Index()
{
var lstStudent = _studentBsl.GetAll();
return View(lstStudent);
}
}

And this is in view binding:

@model List<Student>
@if(Model != null && Model.Any())
{
<ul>
<li style="font-weight: bold;"> # | Name | Email</li>
@foreach (var student in Model)
{
<li> @student.Id | @student.FullName | @student.Email</li>
}
</ul>
}

And the result will display as below :

Okay, you can see now that making an instance of the class is very simple and short. You only register one time that class will be auto initial in all other classes you declare.

* Note: If your class has many constructors, DI will default select constructor has the most parameters. So I recommend you should define only one constructor in each class. You also can add a default constructor with no parameter.

2.6.2. DI Service registration methods

We have some way to register a class or interface to a DI container.

- Register interface and implement

Syntax

services.Add{LIFETIME}<{INTERFACE}, {IMPLEMENTATION}>();

Example

services.AddSingleton<IStudentDal, StudentDal>();

- Register interface and implement dynamic with parameter

Syntax

services.Add{LIFETIME}<{INTERFACE}>(sp => new {IMPLEMENTATION});

Examples

services.AddSingleton<IMyImp>(sp => new MyImp()); services.AddSingleton<IMyImp>(sp => new MyImp("A string!"));

- Register with the only implementation

Syntax

services.Add{LIFETIME}<{IMPLEMENTATION}>();

Example:

services.AddSingleton<MyImp>();

3. Summary

In this article, I want to only talk to you about what is IoC? and why we need to resolve Dependency injection in Asp.net core. And how to add DI to your project using Asp.net core. I hope this article is helpful to you.

You can download source code examples from Github here.

Happy code!!!

Originally published at https://quizdeveloper.com.

--

--