In one of the previous article, we have mentioned File upload on AWS S3 using C# in ASP.NET Core but now in this article, I have mentioned the difference between AddTransient, AddScoped, and AddSingleton in C# ASP.NET Core/MVC, so you can choose which one to use when, while creating Dependency Injection in your .NET Core project.

Let's understand each of them one, by it's definition and then we will see an example in Visual Studio.

  • AddTransient: 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. Basically, for every request, a new service instance is provided. Transient creates a new instance for every service/controller as well as for every request and every user.
    public void ConfigureServices(IServiceCollection services){
       services.AddSingleton<ILog,Logger>()
    }?
  • AddScoped: In a scoped service, with every HTTP request, we get a new instance. However, within 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. Add scoped specifies that a single object is available per request.
    public void ConfigureServices(IServiceCollection services){
       services.AddScoped<ILog,Logger>()
    }?
  • AddSingleton: 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. Basically, it remains the same for all instances of service, throughout the application, and for each subsequent request.
    public void ConfigureServices(IServiceCollection services){
       services.AddTransient<ILog,Logger>()
    }?

Example of AddTransient, AddScoped, and AddSingleton in ASP.NET Core

Let's create a new project in Visual Studio 2019 for ASP.NET Core MVC with basic template.

Step 1: Create a new Class in Models folders, using which we will create Interface for all three Service type.

using System;

namespace ScopeNetCore.Models
{
    public interface IRandomValueSingletonService
    {
       int GetRandomValue();
    }
    public interface IRandomValueScopedService
    {
        int GetRandomValue();
    }
    public interface IRandomValueTransientService
    {
        int GetRandomValue();
    }

    public class RandomValueService : IRandomValueSingletonService, IRandomValueScopedService, IRandomValueTransientService
    {
        private int randomValue = new Random().Next();
        public int GetRandomValue() => randomValue;
    }
}

Note: In the above Class we have declared all Interfaces for all three services and then extended a class, which is not a good practice, this is just for demo purposes, we should create separate Interface for each Service.

Step 2: Navigate to Startup.cs-> ConfigureServices and use the below code

  public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
            services.AddSingleton<IRandomValueSingletonService, RandomValueService>();
            services.AddScoped<IRandomValueScopedService, RandomValueService>();
            services.AddTransient<IRandomValueTransientService, RandomValueService>();
        }

Step 3: Now we will use the above Service in HomeController.cs and get the value of each of the Services.

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using ScopeNetCore.Models;

namespace ScopeNetCore.Controllers
{
    public class HomeController : Controller
    {
        private readonly ILogger<HomeController> _logger;
        private readonly IRandomValueTransientService _transientService1;
        private readonly IRandomValueTransientService _transientService2;
        private readonly IRandomValueScopedService _scopedService1;
        private readonly IRandomValueScopedService _scopedService2;
        private readonly IRandomValueSingletonService _singletonService1;
        private readonly IRandomValueSingletonService _singletonService2;


        public HomeController(ILogger<HomeController> logger,
            IRandomValueTransientService transientService1,
            IRandomValueTransientService transientService2,
            IRandomValueScopedService scopedService1,
            IRandomValueScopedService scopedService2,
            IRandomValueSingletonService singletonService1,
            IRandomValueSingletonService singletonService2)
        {
            _logger = logger;
            _transientService1 = transientService1;
            _transientService2 = transientService2;
            _scopedService1 = scopedService1;
            _scopedService2 = scopedService2;
            _singletonService1 = singletonService1;
            _singletonService2 = singletonService2;
        }

        public IActionResult Index()
        {
            ViewBag.transient1 = _transientService1.GetRandomValue().ToString();
            ViewBag.transient2 = _transientService2.GetRandomValue().ToString();
            ViewBag.scoped1 = _scopedService1.GetRandomValue().ToString();
            ViewBag.scoped2 = _scopedService2.GetRandomValue().ToString();
            ViewBag.singleton1 = _singletonService1.GetRandomValue().ToString();
            ViewBag.singleton2 = _singletonService2.GetRandomValue().ToString();
            return View();
        }

    }
}

In Index.cshtml, we are getting ViewBag Values and showing it in a table.

@{
    ViewData["Title"] = "Home Page";
}

<table class="table table-bordered table-hover">
    <thead>
        <tr>
            <th>Service Type</th>
            <th>First Instance Operation ID</th>
            <th>Second Instance Operation ID</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>
                Transient
                </td>
                <td >
                    @ViewBag.transient1
                </td>
                <td >
                    @ViewBag.transient2
              </td>
        </tr>
        <tr>
            <td>Scoped</td>
            <td>@ViewBag.scoped1</td>
            <td>@ViewBag.scoped2</td>
        </tr>
        <tr>
            <td>
                Singleton
              </td>
              <td>
                  @ViewBag.singleton1
              </td>
             <td>
                 @ViewBag.singleton2
            </td>
        </tr>
</tbody>
</table>  

Once you will build above project, you will see output like below in your browser:

AddTransient-AddScoped-AddSingleton-example-min.png

That's it, I have explained the difference between all the scopes, using 2 requests in the above image

As you can see Singleton ID value remains the same. It creates the instance for the first time and reuses the same object in the all calls.

While for Scoped, it is the same instance ID that is provided for the entire scope of that HTTP request. But every new HTTP request will get a new instance of the service

While for Transient every instance is new even in same HTTP request, this lifetime works best for lightweight, stateless services.

You may also like to read:

Connect to Oracle Database in C# (ASP.NET Web-Forms Example)

Using Generics in C# (With Example)

7 Ways to Merge or Split PDF Files in Java

RGB to Hex and Hex to RGB using Javascript

Solving error "the breakpoint will not currently be hit" in Visual studio ( Multiple ways)