-
-
Notifications
You must be signed in to change notification settings - Fork 12
Double initialization when resolving strongly typed singleton registrations using concrete type #138
Comments
After a little more investigation I found that adding builder.Register<ISingleton, WritingSingleton>(c => c
.As<WritingSingleton>()
.With(Lifetimes.PerContainer));
builder.Register(typeof(WritingSingleton), c => c
.As(typeof(ISingleton))
.With(Lifetimes.PerContainer)); I'm not sure if this is by design. Can you please verify @Barsonax?. Also, is there a reason why there aren't any generic constraints in place on the strongly typed |
With the working registrations, we can get a duplicated initialization again when using a child container: using System;
namespace Singularity.DoubleInit
{
public interface ISingleton { }
public class WritingSingleton : ISingleton
{
public WritingSingleton() => Console.WriteLine("Initialized");
}
class Program
{
static void Main(string[] args)
{
var container = new Container(builder =>
{
// Both registrations result in two initializations of WritingSingleton
builder.Register<ISingleton, WritingSingleton>(c => c.As<WritingSingleton>().With(Lifetimes.PerContainer));
//builder.Register(typeof(WritingSingleton), c => c.As(typeof(ISingleton)).With(Lifetimes.PerContainer));
});
var childContainer = container.GetNestedContainer();
var instance1 = childContainer.GetInstance<ISingleton>();
var instance2 = childContainer.GetInstance<ISingleton>();
var instance5 = childContainer.GetInstance<WritingSingleton>();
}
}
} The documentation on So I would interpret this as that there should be an instance created only once, since the child container inherits the very same instance. Am I mistaken or is the implementation mistaken? |
A workaround is to remove builder.ConfigureSettings(settings =>
{
settings.ConfigureServiceBindingGenerators(generators =>
{
generators.Remove(x => x is ConcreteServiceBindingGenerator);
});
}); |
Thanks for making a issue. When you register a type you are registering a mapping from a service type to a implementation type. This means if you use the concrete implementation type to resolve the type it cannot find the mapping and thus Singularity will create a new separate registration as you already found out. This is confusing behavior. Not registering the implementation as a service in the mapping was done on purpose to make things more explicit but that kinda backfired here. Thinking of changing this now. Your childcontainer example is indeed a bug which I will fix. A generic constraints on the As method would be nice but iam afraid C# doesn't support that specific kind of constraint since |
The documentation states "Supports resolving unregistered concrete types". What does that mean then when this is expected behavior (everything needs to be registered explicitly)? Regarding the generic constraint, check again. The ASP.NET Core's default dependency injection does use generic constraints, which are Additionally, registering implementation types that are not assignable from the used dependency type does not result in a runtime error either. |
It means that when Singularity cannot find a registration for a given service type it will create a default one for you. This is what
Thats a different kind of constraint there. Lets view the code of the
Here we don't want TService to derive/implement TInstance but we want TInstance to derive/implement from TService. Such a constraint does not compile in C#. The
Seems a runtime check was missing in the As method. Added it on my branch along with unit tests to verify this. EDIT: prerelease package which should fix your issues: https://www.nuget.org/packages/Singularity/0.17.4-fixlifetimeinchi0008 |
I see, now I understand.
+1. That was my original expectation. That new prerelease package works in my case, thank you 👍 |
Describe the bug
One feature of Singularity is "Supports resolving unregistered concrete types". I may misunderstand how to use it, but I think those two registrations should be equivalent (where
WritingSingleton
implementsISingleton
):However, I find that in the first, strongly typed registration the singleton will be initialized once when resolving
ISingleton
, and another time when resolvingWritingSingleton
.To Reproduce
Expected behavior
Both registrations should result in
Initialized
being written to the console only once.The text was updated successfully, but these errors were encountered: