Singleton vs Scoped vs Transient Services in ASP.NET Core

Singleton vs. Scoped vs. Transient Services in ASP.NET Core:

In this article, I will discuss the Singleton vs. Scoped vs. Transient Services in ASP.NET Core Application with Real-Time Examples. Please read our previous article before proceeding to this article, where we discussed ASP.NET Core Dependency Injection with Examples.

Example to Understand Singleton vs. Scoped vs. Transient Services in ASP.NET Core:

Let us understand the differences between Singleton vs. Scoped vs. Transient Services in ASP.NET Core with an example. 

Creating Student Model:
namespace FirstCoreMVCWebApplication.Models
{
    public class Student
    {
        public int StudentId { get; set; }
        public string? Name { get; set; }
        public string? Branch { get; set; }
        public string? Section { get; set; }
        public string? Gender { get; set; }
    }
}
IStudentRepository Interface:
namespace FirstCoreMVCWebApplication.Models
{
    public interface IStudentRepository
    {
        Student GetStudentById(int StudentId);
        List<Student> GetAllStudent();
    }
}
StudentRepository:
namespace FirstCoreMVCWebApplication.Models
{
    public class StudentRepository : IStudentRepository
    {
        //When a new instance of StudentRepository is created,
        //we need to log the Date and time into a text file
        //using the constructor
        public StudentRepository()
        {
            //Please Change the Path to your file path
            string filePath = @"D:\MyProjects\FirstCoreMVCWebApplication\FirstCoreMVCWebApplication\Log\Log.txt";
            string contentToWrite = $"StudentRepository Object Created: @{DateTime.Now.ToString()}";
            using (StreamWriter writer = new StreamWriter(filePath, true))
            {
                writer.WriteLine(contentToWrite);
            }
        }
        public List<Student> DataSource()
        {
            return new List<Student>()
            {
                new Student() { StudentId = 101, Name = "James", Branch = "CSE", Section = "A", Gender = "Male" },
                new Student() { StudentId = 102, Name = "Smith", Branch = "ETC", Section = "B", Gender = "Male" },
                new Student() { StudentId = 103, Name = "David", Branch = "CSE", Section = "A", Gender = "Male" },
                new Student() { StudentId = 104, Name = "Sara", Branch = "CSE", Section = "A", Gender = "Female" },
                new Student() { StudentId = 105, Name = "Pam", Branch = "ETC", Section = "B", Gender = "Female" }
            };
        }

        public Student GetStudentById(int StudentId)
        {
            return DataSource().FirstOrDefault(e => e.StudentId == StudentId) ?? new Student();
        }

        public List<Student> GetAllStudent()
        {
            return DataSource();
        }
    }
}

Note: We log the object creation date and time within the Constructor to a text file. This will tell us how many times the object of the Student Repository class is created.

SomeOtherService:

The Student Repository can also be consumed from a controller or other services. So, let us create a service that will consume the Student Repository service. So, create a class file named SomeOtherService.cs and then copy and paste the following code:

namespace FirstCoreMVCWebApplication.Models
{
    public class SomeOtherService
    {
        //Create a reference variable of IStudentRepository
        private readonly IStudentRepository? _repository = null;

        //Initialize the variable through constructor
        public SomeOtherService(IStudentRepository repository)
        {
            _repository = repository;
        }

        public void SomeMethod()
        {
            //This Method is also going to use the StudentRepository Service
        }
    }
}
Home Controller:

Please modify the Home Controller as follows. Here, we inject the services of Student Repository and SomeOtherService through the constructor, and within the Index and GetStudentDetails, we invoke the methods of both services.

using FirstCoreMVCWebApplication.Models;
using Microsoft.AspNetCore.Mvc;
namespace FirstCoreMVCWebApplication.Controllers
{
    public class HomeController : Controller
    {
        //Create a reference variable of IStudentRepository
        private readonly IStudentRepository? _repository = null;
        private readonly SomeOtherService? _someOtherService = null;

        //Initialize the variable through constructor
        public HomeController(IStudentRepository repository, SomeOtherService someOtherService)
        {
            _repository = repository;
            _someOtherService = someOtherService;
        }

        public JsonResult Index()
        {
            List<Student>? allStudentDetails = _repository?.GetAllStudent();
            _someOtherService?.SomeMethod();

            return Json(allStudentDetails);
        }

        public JsonResult GetStudentDetails(int Id)
        {
            Student? studentDetails = _repository?.GetStudentById(Id);
            _someOtherService?.SomeMethod();
            return Json(studentDetails);
        }
    }
}

Singleton Service in ASP.NET Core Dependency Injection

Singleton services are created the first time they are requested. This single instance is then used by all subsequent requests throughout the application’s lifetime. Singleton services are suitable for services that require a shared and consistent state across the application. Configuration service that reads data from an external source once and caches it for future use, or a service that manages a shared resource like a cache or a pool of resources.

Let’s first understand the singleton service with our example. Add the following code to the Program.cs class file to register the SomeOtherService and StudentRepository service as Singletons.

builder.Services.AddSingleton<IStudentRepository, StudentRepository>();
builder.Services.AddSingleton<SomeOtherService>();

Singleton service means only one instance of the service is available throughout the application lifetime, no matter how many times and how many requests are sent to the server. In our application, the SomeOtherService also uses the StudentRepository service.

When we send a request to our application (e.g., to the Index or GetStudentDetails method), it creates singleton instances of both the SomeOtherService and StudentRepository services and uses the same StudentRepository service within the SomeOtherService.

Run the application, access the Index or GetStudentDetails method, and verify the log file. If you open the log file, you will see the following: Only one object is created for the StudentRepository service. This proves that a singleton service means only one instance of the service is available throughout the application’s lifetime.

Singleton Service in ASP.NET Core Dependency Injection

When to Use Singleton Services:
  • This is for services that need to maintain state across the entire application.
    For services that are expensive to create and can be reused, such as configuration settings, caching, logging, and database connections.

Scoped Service in ASP.NET Core Dependency Injection

Scoped services are created once per request. This means one instance is shared within a single request but separate across different requests. Scoped services are useful for services that need to maintain data consistency during an operation and are tied to a specific request, such as a web request in ASP.NET Core. A database context in Entity Framework Core, where each web request gets its own database context instance to track changes and perform database operations committed at the end of the request.

Let’s first understand the scoped service in our example. To register the SomeOtherService and StudentRepository services as Scoped, add the following code to the Program.cs class file.

builder.Services.AddScoped<IStudentRepository, StudentRepository>();
builder.Services.AddScoped<SomeOtherService>();

Scoped service means one instance per HTTP request. In our example, when we send a request to our application (i.e., either to the Index or GetStudentDetails method), it will create a scoped instance of both SomeOtherService and StudentRepository service and use the same StudentRepository service within the SomeOtherService.

First, clear the log file, run the application, access the Index or GetStudentDetails method, and verify the log file. If you open the log file, you will see the following: Two objects are created for the StudentRepository service. This proves that scoped service means one instance per HTTP request. It will create one instance when we access the Index method and another instance when we access the GetStudentDetails method. Internally, when it accesses the SomeOtherService, it will use the same StudentRepository instance.

Scoped Service in ASP.NET Core Dependency Injection

When to Use Scoped Services:
  • For services that should maintain state within a single request but should not be shared across different requests.
  • Ideal for unit-of-work patterns where a single instance should be used across multiple operations within a request.

Transient Service in ASP.NET Core Dependency Injection

Transient services are created each time they are requested from the DI container. A new instance is provided to every controller, service, or component that requires it. Since a new instance is created every time, there are no concurrency issues, but this can lead to higher memory usage if instances are large or contain a lot of data. A service that performs a simple calculation or operation and does not maintain any state between requests.

So, let us understand Transient’s service with our example. So, add the following code to the Program.cs class file to register the SomeOtherService and StudentRepository services as Transient.

builder.Services.AddTransient<IStudentRepository, StudentRepository>();
builder.Services.AddTransient<SomeOtherService>();

Transient service means a new service instance is created whenever requested. In our example, when we send a request to our application (i.e., either to the Index or GetStudentDetails method), it will create new instances of both SomeOtherService and StudentRepository service; further, it will create a new StudentRepository instance when we request it in the SomeOtherService.

First, clear the log file, run the application, access the Index or GetStudentDetails method, and verify the log file. If you open the log file, you will see the following: Four objects are created for the StudentRepository service. This proves that the Transient service means a new service instance whenever requested. In our example, when we access the Index action method, it will create one instance within the Home Controller and another instance within the SomeOtherService, and this will happen again when we call the GetStudentDetails action method.

Transient Service in ASP.NET Core Dependency Injection

When to Use Transient Services:
  • For lightweight, stateless services.
  • This is for services that do not need to maintain any state between requests or operations.
Conclusion:
  • Singleton: One instance for the entire application lifetime. Use for shared, long-lived services.
  • Scoped: One instance per request. Use for maintaining state within a request.
  • Transient: A new instance each time it is requested. Use for lightweight, stateless services.

Choosing the correct service lifetime is essential for optimizing the application’s performance and resource usage. Understanding and applying these lifetimes helps ensure your application is efficient and maintainable.

In the next article, I will discuss Creating an ASP.NET Core Application using the MVC Template with Examples. In this article, I try to explain Singleton vs. Scoped vs. Transient Services in ASP.NET Core Application with examples. I hope this article will help you understand Singleton vs. Scoped vs. Transient Services in ASP.NET Core Application. 

Registration Open For New Online Training

Enhance Your Professional Journey with Our Upcoming Live Session. For complete information on Registration, Course Details, Syllabus, and to get the Zoom Credentials to attend the free live Demo Sessions, please click on the below links.

Leave a Reply

Your email address will not be published. Required fields are marked *