Search code examples
c#.net.net-coreconsole-application

What's the difference between AddScoped and AddSingleton in .NET Core Console Application?


The scope of an AddScoped in an ASP.NET context is understood, i.e., at the request level. When it comes to a console application, it does not have a request context, right? How will it behave?

services.AddScoped<SomeServiceClass>(); services.AddSingleton<SomeServiceClass>();


Solution

  • at the request level. When it comes to a console application, it do not have a request context, right?

    Yes, in ASP.NET Core framework will create a scope per request. In console application there is no "request" concept out of the box but you can create scopes manually when needed (which can be beneficial when you have some iterative and/or long running processing for example involving EF Core DbContext's which by default are scoped and due to change tracking used for DML operations can result in memory-leak like behavior even with disabled change tracking):

    var services = new ServiceCollection();
    // services.Add...
    var serviceProvider = services.BuildServiceProvider();
    
    while (some_condition)
    {
        using var scope = serviceProvider.CreateScope();
    
        var service = scope.ServiceProvider.GetRequiredService<ISomeService>();
        service.DoSomething();
    }
    

    The main difference that with scope validation enabled scoped services can't be resolved from the root scope (this is done to prevent negative effects similar to ones "introduced" by captive dependencies):

    var services = new ServiceCollection();
    // services.Add...
    services.AddScoped<object>();
    var serviceProvider = services.BuildServiceProvider(new ServiceProviderOptions
    {
        ValidateScopes = true, // can be detrimental for perf, disable on Prod
        // ValidateOnBuild = true
    });
    
    // InvalidOperationException: Cannot resolve scoped service 'System.Object' from root provider:
    var service = serviceProvider.GetRequiredService<object>();
    

    From the .NET dependency injection: Service lifetimes doc:

    Scoped

    • For web applications, a scoped lifetime indicates that services are created once per client request (connection). Register scoped services with AddScoped.
    • In apps that process requests, scoped services are disposed at the end of the request.
    • When using Entity Framework Core, the AddDbContext extension method registers DbContext types with a scoped lifetime by default.

    Singleton
    Singleton lifetime services are created either:

    • The first time they're requested.
    • By the developer, when providing an implementation instance directly to the container.

    Every subsequent request of the service implementation from the dependency injection container uses the same instance.

    Singleton services must be thread safe and are often used in stateless services.

    In apps that process requests, singleton services are disposed when the ServiceProvider is disposed on application shutdown. Because memory is not released until the app is shut down, consider memory use with a singleton service.