Support us .Net Basics C# SQL ASP.NET Aarvi MVC Slides C# Programs Subscribe Download

AddSingleton vs AddScoped vs AddTransient

Suggested Videos
Part 41 - ASP.NET Core Model Binding | Text | Slides
Part 42 - ASP.NET Core model validation | Text | Slides
Part 43 - Select list validation in asp.net core | Text | Slides

In this video we will discuss the differences between AddSingleton(), AddScoped() and AddTransient() methods in ASP.NET Core with an example.


IEmployeeRepository interface

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


public interface IEmployeeRepository
{
    IEnumerable<Employee> GetAllEmployees();
    Employee Add(Employee employee);
}

Employee Class

public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
}

MockEmployeeRepository

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

public class MockEmployeeRepository : IEmployeeRepository
{
    private List<Employee> _employeeList;

    public MockEmployeeRepository()
    {
        _employeeList = new List<Employee>()
    {
        new Employee() { Id = 1, Name = "Mary" },
        new Employee() { Id = 2, Name = "John" },
        new Employee() { Id = 3, Name = "Sam" },
    };
    }

    public Employee Add(Employee employee)
    {
        employee.Id = _employeeList.Max(e => e.Id) + 1;
        _employeeList.Add(employee);
        return employee;
    }

    public IEnumerable<Employee> GetAllEmployees()
    {
        return _employeeList;
    }
}

HomeController

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

public class HomeController : Controller
{
    private IEmployeeRepository _employeeRepository;

    public HomeController(IEmployeeRepository employeeRepository)
    {
        _employeeRepository = employeeRepository;
    }

    [HttpGet]
    public ViewResult Create()
    {
        return View();
    }

    [HttpPost]
    public IActionResult Create(Employee employee)
    {
        if (ModelState.IsValid)
        {
            Employee newEmployee = _employeeRepository.Add(employee);
        }

        return View();
    }
}

Create View

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

@model Employee
@inject IEmployeeRepository empRepository

<form asp-controller="home" asp-action="create" method="post">
    <div>
        <label asp-for="Name"></label>
        <div>
            <input asp-for="Name">
        </div>
    </div>

    <div>
        <button type="submit">Create</button>
    </div>

    <div>
        Total Employees Count = @empRepository.GetAllEmployees().Count().ToString()
    </div>
</form>

Registering 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() - As the name implies, AddSingleton() method creates a Singleton service. A Singleton service is created when it is first requested. This same instance is then used by all the subsequent requests. 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() - This 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. For example, in a web application it creates 1 instance per each http request but uses the same instance in the other calls within that same web request.

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

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddSingleton<IEmployeeRepository, MockEmployeeRepository>();
}
  1. At the moment we are using AddSingleton() method to register MockEmployeeRepository service. 
  2. 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.
  3. This means all the requests throughout the life time of the application use that same instance.
  4. At the moment, in our example we need MockEmployeeRepository service instance in 2 places - Create action method in the HomeController and in the Create view.
  5. At this point when we navigate to http://localhost:/home/create we see the Total Employees Count is 3
  6. To serve this request an instance of the HomeController is created first. HomeController has a dependency on IEmployeeRepository
  7. 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 HomeController.
  8. Create 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. Now if you provide a Name in the Name textbox and click Create button you will see the count goes up every time you click the button.
  10. 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.
AddScoped

Now, use AddScoped() method to register the service. 

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddScoped<IEmployeeRepository, MockEmployeeRepository>();
}
  1. Issue a request to http://localhost:/home/create. 
  2. We see the Total Employees Count is 3.
  3. Provide a Name and click the Create button.
  4. The Total Employees Count increases to 4.
  5. When we click the Create button again, the Total Employees Count is still 4.
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.

If we relate this to our example, both the HomeController and the Create view will use the same instance of the service for a given http request. This is the reason Create view is also able to see the new employee added by the Create action method of the HomeController. Hence we see the Total Employees Count as 4.

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 4.

AddTransient

Finally let’s use AddTransient() method to register our service

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddTransient<IEmployeeRepository, MockEmployeeRepository>();
}
  1. Issue a request to http://localhost:/home/create
  2. We see the Total Employees Count is 3
  3. Provide a Name and click the Create button.
  4. Notice, on the Create view, we still see the Total Employees Count as 3
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.

Since a new instance is provided even within the same scope of a given http request, the Create view is not able to see the new employee added by the Create action of the HomeController. This is the reason the count of employees is 3 even after adding a new employee.

Scoped Service vs Transient Service vs Singleton Service

The following is the main difference between a scoped service and a transient service. 

With a scoped service we get the same instance within the scope of a given http request but a new instance across different http requests

With a transient service a new instance is provided every time an instance is requested whether it is in the scope of the same http request or across different http requests

With a singleton service, there is only a single instance. An instance is created, when the service is first requested and that single instance is used by all http requests throughout the application.

asp.net core tutorial for beginners

4 comments:

  1. So by which approach we can create a new record after submitting Create button to display a new record on that same page. As we can see by using "AddTransient" it doesn't allow us to increase the count for more than 3

    ReplyDelete
  2. So by which approach we can add a new record to display on the same page after the submission of Create button. As we can see by using "AddTransient" count is not going beyond 3 even after inserting a new post.

    ReplyDelete
  3. To put this topic in such an easy to understand way is truly the work of a genius.

    ReplyDelete

It would be great if you can help share these free resources