If you register a type as a singleton then you expect just 1 instance of this type in your whole application. What you may not know is that ASP.NET Core is creating 2 instances of IServiceProvider during building of the IWebHost that may lead to 2 instance of your "singleton".

This is the case if you register a type, say MySingleton, when configuring the web host ...

WebHost
 .CreateDefaultBuilder()
 .UseStartup<Startup>()
 .ConfigureServices(services => services.AddSingleton<MySingleton>())
 .Build()
 .Run();

 ..., e.g. so that is available in the constructor of your Startup

public class Startup
{
  private readonly MySingleton _mySingletonFromHostingServiceProvider;

  public Startup(MySingleton mySingletonFromHostingServiceProvider)
  {
    _mySingletonFromHostingServiceProvider = mySingletonFromHostingServiceProvider;
  } 
  ...
}

Now, if we resolve MySingleton during normal web request we get a whole new instance instead the same instance as in constructor of the Startup class. 

public void Configure(IApplicationBuilder app)
{
  app.Use((ctx, next) =>
  {
    var mySingleton = ctx.RequestServices.GetRequiredService<MySingleton>();
    
    // the comparison of 2 instances yields "false"
    var areEqual = _mySingletonFromHostingServiceProvider == mySingleton;

    Console.WriteLine($"==> {nameof(_mySingletonFromHostingServiceProvider)} == {nameof(mySingleton)}: {areEqual}");
         return next();
    });
}

 There are at least two ways to fix this problem.

Either pass an instance of MySingleton to method AddSingleton instead of passing just the type

var mySingleton = new MySingleton();
WebHost
 .CreateDefaultBuilder()
 .UseStartup<Startup>()
 .ConfigureServices(services => services.AddSingleton(mySingleton))
 .Build()
 .Run();

 or by replacing the previous registration with a new one in ConfigureServices 

public class Startup
{
  private readonly MySingleton _mySingletonFromHostingServiceProvider;

  public Startup(MySingleton mySingletonFromHostingServiceProvider)
  {
     _mySingletonFromHostingServiceProvider = mySingletonFromHostingServiceProvider;
  }

  public void ConfigureServices(IServiceCollection services)
  {
    services.Replace(new ServiceDescriptor(typeof(MySingleton), _mySingletonFromHostingServiceProvider));
    // alternative way 
    //services.AddSingleton(_mySingletonFromHostingServiceProvider);
 }
  ...
}

According to @davidfowl the ASP.NET team will address this problem in the future. 

PS: There is at least another one solution to fix this problem and gaining back the control over your web app but that's for another time ... :)

Kostenloses Cheat Sheet zu ASP.NET Core API-Dokumentation mit Swagger

Sebastian Gingter zeigt Ihnen auf wenigen Seiten übersichtlich zusammengefasst, was Sie bei der Dokumentation Ihrer ASP.NET Core API wissen sollten.

Melden Sie sich kostenlos zu unserem Newsletter an, um das Cheat Sheet per E-Mail zu erhalten.

Related Articles

 | Pawel Gerr

If you are using Autofac in your ASP.NET Core application then I recommend to update Autofac to version 4.6.1. This bugfix release brought a change how child scope handle additional registrations so that some errors like just disappear. With additional registrations I mean the…

Read article
 | Pawel Gerr

After several years of using the same Dependency Injection (DI) framework like Autofac you may have a good understanding how your components, implementing the interface IDisposable, are going to be disposed. With the nuget package Microsoft.Extensions.DependencyInjection the new…

Read article
 | Pawel Gerr

With the introduction of ASP.NET Core 3.0 the default JSON serializer has been changed from Newtonsoft.Json to System.Text.Json. For projects and libraries switching to the new JSON serializer this change means more performance and the opportunity to rewrite our . Serialization…

Read article