Dependency Injection: Singleton, Scoped and Transient

The three lifetime registrations for the out of the box DI functionality:

  • singleton (one and only forever)
  • scoped (one in every request)
  • transient (new everytime).

In the code below three objects are added to the DI container, a singleton, a scoped and a transient item.

When you run this code you can observe that the singleton is always the same date (even on different browser tabs). The scoped object will have the same date during the request, even when retrieved multiple times from the DI container it will have the same date and time. The transient object however will have a different date and time each time it is retrieved from the DI container.

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;

var builder = WebApplication.CreateBuilder();

builder.Services.AddSingleton(x => new SingletonDate());
builder.Services.AddTransient(x => new TransientDate());
builder.Services.AddScoped(x => new ScopedDate());

var app = builder.Build();

app.Use(async (context, next) =>
{
    var single = context.RequestServices.GetService<SingletonDate>();
    var scoped = context.RequestServices.GetService<ScopedDate>();
    var transient = context.RequestServices.GetService<TransientDate>();

    await context.Response.WriteAsync("Open this page in two tabs \n");
    await context.Response.WriteAsync("Keep refreshing and you will see the three different DI behaviors\n");
    await context.Response.WriteAsync("----------------------------------\n");
    await context.Response.WriteAsync($"Singleton : {single.Date.ToString("MM/dd/yyyy hh:mm:ss.fff tt")}\n");
    await context.Response.WriteAsync($"Scoped: {scoped.Date.ToString("MM/dd/yyyy hh:mm:ss.fff tt")}\n");
    await context.Response.WriteAsync($"Transient: {transient.Date.ToString("MM/dd/yyyy hh:mm:ss.fff tt")}\n");
    await next.Invoke();
});

app.Run(async (context) =>
{
    await Task.Delay(3000);//delay for 100 ms

    var single = context.RequestServices.GetService<SingletonDate>();
    var scoped = context.RequestServices.GetService<ScopedDate>();
    var transient = context.RequestServices.GetService<TransientDate>();

    await context.Response.WriteAsync("----------------------------------\n");
    await context.Response.WriteAsync($"Singleton : {single.Date.ToString("MM/dd/yyyy hh:mm:ss.fff tt")}\n");
    await context.Response.WriteAsync($"Scoped: {scoped.Date.ToString("MM/dd/yyyy hh:mm:ss.fff tt")}\n");
    await context.Response.WriteAsync($"Transient: {transient.Date.ToString("MM/dd/yyyy hh:mm:ss.fff tt")}\n");
});

app.Run();

public class SingletonDate
{
    public DateTime Date { get; set; } = DateTime.Now;
}

public class TransientDate
{
    public DateTime Date { get; set; } = DateTime.Now;
}

public class ScopedDate
{
    public DateTime Date { get; set; } = DateTime.Now;
}
Share

Leave a Reply

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