Search code examples
c#.netsingletoninversion-of-control.net-5

.NET Core 5 - Registering a class as singleton with strings in its constructor


I have a .NET 5 web application, in which I am attempting to register a particular class as a singleton instance.

I know that .NET 5 is out of support now, and there are plans to upgrade this app in the near future, but due to some unfortunate design constraints, I have to keep the app in .NET 5 for the time being.

I am using the boilerplate .NET Core DI/IoC service registration.

This particular class accepts two strings as parameters, corresponding to a few app/environment config variables.

Because of these parameters, I know I can't just do this:

services.AddSingleton<ISingletonService, SingletonService>();

The runtime doesn't know what strings to use in the Service constructor. Makes sense.

So, in my Startup.cs, I've tried a few different things.

I've tried initializing a new instance of SingletonService, with the strings being set from a spec class, and registering the instance as a singleton of the interface (this is the way the app was meant to work):

var singletonService = new SingletonService(spec.EnvVariable, spec.AppVariable);
services.AddSingleton<ISingletonService>(singletonService);

I've also tried registering this instance as the concrete type (even though the app only ever refers to the interface):

var singletonService = new SingletonService(spec.EnvVariable, spec.AppVariable);
services.AddSingleton(singletonService);

I've also tried registering the instance as both the interface and the concrete type.

Thinking that maybe there was a problem with the spec, I tried replacing the spec references in the instance constructor call with their respective constants:

var singletonService = new SingletonService("envVariable", "appVariable");
services.AddSingleton<ISingletonService>(singletonService);

I've also tried registering the singleton with an implementation factory:

services.AddSingleton<ISingletonService>(provider =>
{
    var spec = provider.GetService<RegistrySpec>();
    return new SingletonService(spec.EnvVariable, spec.AppVariable);
});

Knowing that the app builder is sometimes finicky about where things are placed in the ConfigureServices() and Configure() methods, I've also tried moving the singleton registration call around to different places in the ConfigureServices() method.

When I inspected the IServiceCollection before the app host is actually built, I can see that both ISingletonService and SingletonService are registered in the collection, with the instance that I initialized listed as their ImplementationInstance property.

However, in all the above cases, the application errors out when IHostBuilder.Build() is called, with the Exception Unable to resolve service for type 'System.String' while attempting to activate SingletonService.

It seems like I've tried everything I've seen in either the Microsoft docs, or other related SO questions, and nothing has worked thus far.

What am I doing wrong?

Thanks!


Solution

  • Sorry for the late follow-up here.

    I found that the problem was actually being caused by a third-party library I was using later in the startup code to scan the application dependencies for classes to register in the container.

    This scanner was registering an extra instance of SingletonService behind the scenes, which was the instance that IHostBuilder.Build() was complaining about.

    Once I excluded SingletonService from the third-party scan, the code worked as expected.