Dependency Injection Lifetime: Transient, Singleton & Scoped

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

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 how we instantiate the dependency. We define the lifetime when we register the service.

We learned how to register services in the article Dependency injection in ASP.NET core. There are three ways, by which you can do that. And it in turn decides how the DI Framework manages the lifecycle of the services.

  1. Transient: creates a new instance of the service, every time you request it.
  2. Scoped: creates a new instance for every scope. (Each request is a Scope). Within the scope, it reuses the existing service.
  3. Singleton: Creates a new Service only once during the application lifetime, and uses it 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 Web Application (use the web application model view controller template) and name it as DependencyInjection. You can follow these tutorials on how to create a new project.

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 a single method GetID, which must return a unique ID

Source Code

Creating the Service

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

Source Code

The service generates a unique id, whenever we instantiate it. The GetID method returns that id.

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

Transient

The Transient services always create a new instance, every time we request for it

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

Source Code

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.

Source Code

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. It creates a new instance per request and reuses that instance 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.

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

Source Code

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 the same IDs generated.

Now hit the browser refresh button. The id changes i.e. because DI creates the new instance of the service and reuses it

Scoped Service in ASP.NET Core Dependency Injection

Singleton

The Singleton scope creates a single instance of the service when the request for it comes 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 existing instance.

Register the Singleton Service

Singleton services are registered using the AddSingleton method.

Inject Singleton service into Controller

Source Code

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

View

Source Code

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 the dependency injection system creates them every time they will use more memory & Resources and can have a 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 a higher lifetime would change the lower lifetime service to a higher lifetime. This will make 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 scopes of the ASP.NET Core DI Framework. Knowing the difference between Scoped Vs Transient Vs Singleton is very important as it will impact the performance of the app.

References

18 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