Swimburger

Change the ServiceLifetime after the service has been added to the .NET ServiceCollection

Niels Swimberghe

Niels Swimberghe - - .NET

Follow me on Twitter, buy me a coffee

ASP.NET Core has a built-in dependency injection container that many libraries provide helpers for to conveniently integrate the libraries. In some cases, though, the ServiceLifetime of the added services is not the lifetime you want to use. To change the lifetime, you could look at the source code and replicate how the library adds the service to the ServiceCollection while specifying a different ServiceLifetime. However, the library may change over time and now your replica is out of date.

While the dependency injection container is built into ASP.NET Core, you can also use it in any other type of .NET app, and this blog post applies in those cases too.

Instead, what you could do is grab the ServiceDescriptor and copy its properties to a new ServiceDescriptor with a different ServiceLifetime, then remove the old descriptor and add the new one.

Here's a method that does that:

private static void ChangeServiceLifetime(
    IServiceCollection services,
    Type serviceType,
    ServiceLifetime lifetime
)
{
    var servicesToReplace = services.Where(service => service.ServiceType == serviceType).ToList();
    foreach (var service in servicesToReplace)
    {
        services.Remove(service);
        if (service.ImplementationInstance != null) 
                throw new Exception("Services with an implementation instance their lifetime cannot be changed.");
        if (service.ImplementationFactory == null)
        {
            services.Add(new ServiceDescriptor(
                service.ServiceType,
                service.ImplementationType!,
                lifetime
            ));
        }
        else
        {
            services.Add(new ServiceDescriptor(
                service.ServiceType,
                service.ImplementationFactory,
                lifetime
            ));
        }
    }
}

The ChangeServiceLifetime method accepts the service collection to update, the serviceType which is the type of the service you want to update, and the desired ServiceLifetime.

ChangeServiceLifetime then finds each ServiceDescriptor in the service collection, removes it from the collection, makes a copy of the descriptor with the desired lifetime, and adds the new descriptor to the service collection.

You can use the method like this:

var builder = WebApplication.CreateBuilder();

builder.Services.AddTwilioClient();
ChangeServiceLifetime(builder.Services, typeof(ITwilioRestClient), ServiceLifetime.Singleton);
ChangeServiceLifetime(builder.Services, typeof(TwilioRestClient), ServiceLifetime.Singleton);

var webApplication = builder.Build();

In this case I'm changing the lifetime of the ITwilioRestClient and TwilioRestClient from scoped to singleton. The Twilio helper library for ASP.NET Core assumes scoped is the desired lifetime, but sometimes I'm using the library in test or console applications in which case I want it to be a transient or singleton service.

Be careful when doing this. The library may rely on the lifetime they have chosen and have unexpected results when you change it.

Related Posts

Related Posts