Difference between AddSingleton vs AddScoped vs AddTransient in asp.net core

Introduction :

In this tutorial we will discuss the differences between AddSingleton() vs AddScoped() vs AddTransient() in asp.net core with an example.

DI (Dependency Injection) is a technique for achieving loose coupling between objects and their dependencies. To implement Dependency Injection, we need to configure a DI container with classes. DI Container has to decide whether to provide an existing instance or return a new instance of the service. In Startup.cs class file, we perform this activity on the ConfigureServices() method.

ASP.NET core provides the following 3 methods to register services with the dependency injection container.

  • AddSingleton()
  • AddScoped()
  • AddTransient()

Difference between AddSingleton vs AddScoped vs AddTransient

Parameter Add Singleton Add Scoped Add Transient
Instance Same each request/ each user One per request. Different for everytime.
Disposed App shutdown End of request End of request
Used in When Singleton implementation is required Applications which have different behavior per user. Light weight and stateless services.

 

Example of  Add Singleton vs Add Scoped vs Add Transient

IEmployeeRepository interface

Consider the following IEmployeeRepository interface. AddEmployee() method adds a new employee to the repository. GetAllEmployees() method returns all the Employees in the repository.

    public interface IEmployeeRepository
    {
        EmployeeModel AddUpdateEmployee(EmployeeModel employee);

        List GetAllEmployee();

    }

EmployeeModel Class

    public class EmployeeModel
    {
        public int UserID { get; set; }
        public string UserName { get; set; }
        public string Profile { get; set; }
    }

InMemoryEmployeeRepository :

InMemoryEmployeeRepository implements IEmployeeRepository. To keep the example simple we are storing the list of employees in-memory in a private field _empList

    public class InMemoryEmployeeRepository : IEmployeeRepository
    {
        private readonly List _empList;

        public InMemoryEmployeeRepository()
        {
            _empList = new List()
            {
                new EmployeeModel() { UserID=1,UserName="DotnetUser",Profile="IT Developer"},
                new EmployeeModel() { UserID=2,UserName="TechUSER",Profile="Tech Developer"},
            };
        }
        public EmployeeModel AddUpdateEmployee(EmployeeModel employee)
        {
            employee.UserID = _empList.Max(e => e.UserID) + 1;
            _empList.Add(employee);
            return employee;

        }
       public List GetAllEmployee()
        {
          return _empList;
        }

    }

EmployeeController.cs

IEmployeeRepository is injected in to the EmployeeController. The AddEmployee() action method that responds to the POST request, uses the injected instance to add the employee object to the repository.

AddEmplyee View

We are injecting IEmployeeRepository service in to the AddEmployee view using @inject directive. We are using the injected service to display the total number of employees in the repository.

@model EmployeeModel
@using DotNetCoreRepository.Repository
@inject IEmployeeRepository _emp

<h5>Create New Employee</h5>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Index">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="UserID" class="control-label"></label>
<input asp-for="UserID" class="form-control" />
<span asp-validation-for="UserID" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="UserName" class="control-label"></label>
<input asp-for="UserName" class="form-control" />
<span asp-validation-for="UserName" class="text-danger"></span>
</div>

<div class="form-group">
<label asp-for="Profile" class="control-label"></label>
<input asp-for="Profile" class="form-control" />
<span asp-validation-for="Profile" class="text-danger"></span>
</div>

<div class="form-group">
<input type="submit" value="Create" asp-action="AddEmployee" class="btn btn-primary" />
</div>
<div class="form-group">
Number Of employee Count : @_emp.GetAllEmployee().Count()
</div>
</form>
</div>
</div>

Register Services

ASP.NET core provides the following 3 methods to register services with the dependency injection container. The method that we use determines the lifetime of the registered service.

AddSingleton() :

AddSingleton() method creates a Singleton service. A Singleton service is created when it is first requested. So in general, a Singleton service is created only one time per application and that single instance is used throughout the application life time.

AddTransient() :

In an AddTransient() method creates a Transient service. A new instance of a Transient service is created each time it is requested.

AddScoped() :

This method creates a Scoped service. A new instance of a Scoped service is created once per request within the scope.

In ASP.NET Core, services are registered in ConfigureServices() method of the Startup.cs file.

AddSingleton() :

Use AddSingleton() method to register InMemoryEmployeeRepository  service.

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
            services.AddSingleton<IEmployeeRepository, InMemoryEmployeeRepository>();
        }

  1. AddSingleton() creates a single instance of the service when it is first requested and reuses that same instance in all the places where that service is needed.
  2. This means all the requests throughout the life time of the application use that same instance.
  3. At the moment, in our example we need InMemoryEmployeeRepositoryservice instance in 2 places – Create action method in the EmployeeController and in the Create view.
  4. At this point when we navigate to http://localhost:60107/employee/addemployee we see the Total Employees Count is 2
  5. To serve this request an instance of the EmployeeController is created first. EmployeeController has a dependency on IEmployeeRepository.
  6. This is the first time, the instance of the service is requested. So asp.net core creates an instance of the service and injects it into the EmployeeController.
  7. AddEmployee view also needs an instance of the service to calculate the total number of employees. With singleton, the same service instance is used. So the instance of the service that is already created is provided to the Create view also.
  8. AddEmployee view also needs an instance of the service to calculate the total number of employees. With singleton, the same service instance is used. So the instance of the service that is already created is provided to the Create view also.
  9. This is because with Singleton, the same object is used, so changes made to the object can be viewed in all the places across all the HTTP requests.

Difference between AddSingleton vs AddScoped vs AddTransient in asp.net core

 

AddScoped:

Use AddScoped() method to register InMemoryEmployeeRepository  service.

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
            services.AddScoped<IEmployeeRepository, InMemoryEmployeeRepository>();
        }

  1. Execute requested url http://localhost:60107/employee/addemployee.
  2. We will see here Total Employees Count is 2.
  3. when filling the form and click on button,The Total Employees Count increases to 3.

This is because for a scoped service with every http request we get a new instance. However, with in the same http request if the service is required in multiple places like in the view and in the controller then the same instance is provided for the entire scope of that http request.

But every new http request will get a new instance of the service. This is the reason an employee added by one http request cannot be seen in another http request. So this means every time we click the Create button we are issuing a new http request and hence the Total Employees Count does not go beyond 3.

AddTransient :

Use AddTransient () method to register InMemoryEmployeeRepository  service.

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
            services.AddTransient<IEmployeeRepository, InMemoryEmployeeRepository>();
        }

  1. Execute requested url http://localhost:60107/employee/addemployee.
  2. We see the Total Employees Count is 2
  3. when filling the form and click on button.
  4. Notice, on the AddEmployee view, we still see the Total Employees Count as 2

This because with a transient service a new instance is provided every time a service instance is requested whether it is in the scope of the same http request or across different http requests.

 

Also Learn More Tutorial :

1 Comment

Leave a Reply

Your email address will not be published.