Please feel free to suggest a better title for the question. I can't figure out a good name for describing the problem.
I was in the need to make an class accessible via the dependency injection on startup. The class should not only be available via it's concrete implementation but also via the interface it implements. And I need to ensure it is the same object instance returned via both injections.
The real worlds scenario that led me to the singleton case was a nuget for abstractions providing the interface (IStore), multiple nugets holding concrete implementations (DBStore, RedisStore). When I tried to implement the health checks for each store implementation I could get IStore injected but not the concrete implementation. And I wanted to use some variables that were initialized and modified in the concrete implementation (thats why I need the same instance for both injections). Since the stores are (hopefully) used as singletons it worked. I am not saying there is a real world scenario for the scoped and transient way. I am just curious if that would be possible if they are not singletons.
The following codes describe how I managed to do this with singletons.
The way that led me to the singleton solution:
Having this interface:
public interface ITestInterface
{
string ReturnAString();
int ReturnAnInt();
}
and this concrete implementation
public class TestImplementation : ITestInterface
{
private int counter = 0;
public string ReturnAString() {return "a string"; }
public int ReturnAnInt() { return counter++; }
}
They are used in two (let's say) services. One wants the interface injected in the constructor and the other needs the concrete implementation.
Trial and errors in the Startup.ConfigureServices method for making the same instance injected in both cases:
Try 1:
// only ITestInterface is injected but not TestImplemenation
services.AddSingleton<ITestInterface, TestImplementation>();
Try 2:
//only TestImplementation is injected (DI does not recognize it implements the Interface)
services.AddSingleton<TestImplementation>();
Try 3:
// both are injected but they are not singleton any more (counters increment independently)
services.AddSingleton<ITestInterface, TestImplementation>();
services.AddSingleton<TestImplementation, TestImplementation>();
Try 4:
TestImplementation instance = new TestImplementation();
services.AddSingleton<ITestInterface>(instance);
services.AddSingleton(instance);
//services.AddSingleton<TestImplementation>(instance);
Well, at try 4 I have the same instance for both injections.
Now lets assume the TestImplementation needs some (e.g. connection) settings injected.
I can write an extension method for getting the settings from the Configuration and pass it to the singleton instance.
TestImplementation instance = new TestImplementation(Configuration.GetTestSettings());
services.AddSingleton<ITestInterface>(instance);
services.AddSingleton(instance);
So how would I achieve that both injections are the same instance using the same settings with scoped or transient? Since I don't think I can create the instance by hand/code there.