Dependency Injection Lifetime: Transient, Singleton & Scoped

Understanding the lifetime of the services created using the Dependency injection is very essential, before starting to using them. Creating services without understanding the difference between Transient, Singleton & Scoped lifetime can result in application behaving erratically. When a service requests another service via DI, knowing whether it receives the new instance or an already created instance is very important. Hence correctly specifying the lifetime while registering the service are utmost important.

Managing the Service Lifetime

Whenever we ask for the service, the DI Container has to decide whether to return a new instance of the service or provide an existing instance. The Lifetime of the Service depends on when the dependency is instantiated and how long does it live. We define the lifetime when we register the service.

We learnt how to register services in the article Dependency injection in ASP.NET core. There are three ways, by which you can do that, which in turn decides how the lifecycle of the services are managed.

  1. Transient: New instance is created, every time you create a service
  2. Scoped: New instance is generated for every scope. ( Each request is a Scope). Within the scope, service is reused.
  3. Singleton: Service is created only once, and used everywhere

Let us understand the difference between these by using an example

Example Project

Let us create a sample project, to demonstrate how these Service lifetimes work.

Create an ASP.NET Core project using the empty template and call it DependencyInjection. Add the HomeController with index method. You can follow these tutorials do that.

Creating the Service Interface

Create the service SomeService in the services folder.

Add the three interfaces. One for each lifetime provided by the ASP.NET Core. The interface is very simple. It contains single method GetID, which must return a unique ID

Creating the Service

Next, let us create a single service, which implements all the three Interfaces.

The service generates a unique id, whenever it is instantiated and returns that id in the GetID method.

Now, let us look at each service lifetime in detail.

Transient

The Transient services are always created new, each time the service is requested.

Register the Transient Service

Now, under ConfigureServices method of the startup class register the SomeServive via ITransientService interface as shown below

Inject it into Controller

Open the HomeController and inject the two instance of the SomeService as shown below

First, We inject the two instance of the service via the interface ITransientService in the constructor of HomeController.

Next, we query the GetID method in each instance and pass it to the view using ViewBag.

View

Open the view and add the following code

Run the application and you should see two different Guid are displayed on the screen. It is evident that we have received two new instances of the Transient service.

Transient Service in ASP.NET Core Dependency Injection

Scoped

The Services with scoped lifetime are created only once per each request (scope). I.e. a new instance is created per request, and the instance is reused within that request.

Now, let us see it with an example

Register the Scoped Service

Under the ConfigureServices method register the SomeService using the AddScoped method & using the IScopedService interface as shown below.

services.AddScoped<IScopedService, SomeService>();

Inject scoped service into Controller

Next, inject the service into the controller. We already have transient service injected into the controller. Let us not change that. The HomeController is now as below

In the action method, message3 & message4 comes from the scoped service.

View

In the view add these lines

Run the application

The instance created only once per request, i.e. why you have same id’s generated.

Now hit the browser refresh button. The id changes i.e. because the new instance is created for every request.

Scoped Service in ASP.NET Core Dependency Injection

Singleton

Single Instance of the service is created when it was requested for the first time. After that for every subsequent request, it will use the same instance. The new request does not create the new instance of the service but reuses the instance already created.

Register the Singleton Service

Singleton services are registered using the AddSingleton method.

Inject Singleton service into Controller

First, we are injecting 6 instances the SomeService. Two instances per each interface. This is done in the constructor of the Controller.

View

Run the application. The ids generated from Singleton services are same and will not change even if you refresh the application. You can see it from the image below

Singleton Service in ASP.NET Core Dependency Injection

Which one to use

Transient services are safest to create, as you always get the new instance. But, since they are created every time they will use more memory & Resources and can have the negative impact on performance if you too many of them.

Use Transient lifetime for the lightweight service with little or no state.

Scoped services service is the better option when you want to maintain state within a request.

Singletons are created only once and not destroyed until the end of the Application. Any memory leaks in these services will build up over time. Hence watch out for the memory leaks. Singletons are also memory efficient as they are created once reused everywhere.

Use Singletons where you need to maintain application wide state. Application configuration or parameters, Logging Service, caching of data is some of the examples where you can use singletons.

Injecting service with different lifetimes into another

Be careful, while injecting service into another service with a different lifetime

Consider the example of Singleton Service, which depends on another Service which is registered with say the transient lifetime.

When the request comes for the first time a new instance of the singleton is created. It also creates a new instance of the transient object and injects into the Singleton service.

When the second request arrives the instance of the singleton is reused. The singleton already contains the instance of the transient service Hence it is not created again. This effectively converts the transient service into the singleton.

The services with the lower lifetime injected into service with higher lifetime would change the lower lifetime service to higher lifetime. This will make the debugging the application very difficult and should be avoided at all costs.

Hence, remember the following rules

  1. Never inject Scoped & Transient services into Singleton service.
  2. Never inject Transient services into scoped service

Summary

In this tutorial, we looked at the lifetime and their consequences of the services that registered with ASP.NET Core dependency injection system.

5 thoughts on “Dependency Injection Lifetime: Transient, Singleton & Scoped”

Leave a Comment

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top