What is the difference between transient, singleton and scoped in C#?

ยท

3 min read

Definition

Transient, scoped and singleton are different methods for declaring and configuring the lifetime of objects in the dependency injection design pattern.

In software development, it is common to use design patterns to solve recurring problems in a consistent and efficient manner. One such design pattern is the Dependency Injection pattern, which allows for the separation of concerns by injecting dependencies into an object rather than hardcoding them. In this article, we will discuss three common types of Dependency Injection scopes: transient, singleton, and scoped.

Transient Dependency Injection

Transient Dependency Injection refers to the creation of a new instance of a dependency every time it is requested. This means that if an object is dependent on a transient dependency, a new instance of that dependency will be created every time the object is constructed. Transient Dependency Injection is useful for scenarios where the dependencies are stateless and do not need to be shared.

Singleton Dependency Injection

Singleton Dependency Injection refers to the creation of a single instance of a dependency that is shared among all objects that depend on it. This means that if an object is dependent on a singleton dependency, it will always receive the same instance of that dependency. Singleton Dependency Injection is useful for scenarios where the dependencies are stateful and need to be shared among multiple objects.

Scoped Dependency Injection

Scoped Dependency Injection refers to the creation of a single instance of a dependency within a specific scope. This means that if an object is dependent on a scoped dependency, it will receive the same instance of that dependency within the same scope, but a different instance may be created in a different scope. Scoped Dependency Injection is useful for scenarios where the dependencies are stateful and need to be shared within a specific context, such as a request or a user session.

Let's get into a few examples.

Initial Setup

Let's say we have the following interfaces:

public interface IBaseInterface
{
  int DemoId { get; set; }
}

public interface ITransientInterface : IBaseInterface 
{
}

public interface IScopedInterface : IBaseInterface 
{
}

public interface ISingletonInterface : IBaseInterface 
{
}

Implement the interfaces

We have three interfaces called transient, scoped and signleton that are all inheriting from the base interface. These interfaces are implemented in our demo class below:

public class DemoClass : ITransientInterface, IScopedInterface, ISingletonInterface 
{
  public int DemoId { get; set; }
}

We can then use dependency injection in a service with these interfaces. For example:

Create Services

public interfaces IDemoService 
{
}

public class DemoService : IDemoService
{
    private readonly ITransientInterface _transientInterface;
    private readonly IScopedInterface _scopedInterface;
    private readonly ISingletonInterface _singletonInterface;

    public DemoService(ITransientInterface transientInterface, IScopedInterface scopedInterface, ISingletonInterface singletonInterface)     {
transientInterface = _transientInterface;
scopedInterface = _scopedInterface;
singletonInterface = _singletonInterface;
}

....

}

Add To Startup.cs

Once we have those in place we can register the interfaces in the startup.cs within the ConfigureServices method:

services.AddTransient<ITransientInterface, DemoClass>()
            .AddScoped<IScopedInterface, DemoClass>()
            .AddSingleton<ISingletonInterface, DemoClass>()
            .AddTransient<IDemoService, DemoService>()

Conclusion

In conclusion, Transient, Singleton, and Scoped Dependency Injection are three common types of Dependency Injection scopes that can be used to manage the dependencies of an object in a consistent and efficient manner. The appropriate scope to use will depend on the nature of the dependencies and the needs of the project. If you want a new instance of your object to be created with each request then use transient. If you want different object instances across each request then use scoped and finally if you want to use the same object instance for the lifetime of the app then use singleton.

If you found this helpful then please comment below.

Until next time, happy coding! ๐Ÿ™‹โ€โ™‚๏ธ

Did you find this article valuable?

Support Simplifying Code by becoming a sponsor. Any amount is appreciated!

ย