ipjohnson / Grace

Grace is a feature rich dependency injection container library
MIT License
336 stars 33 forks source link

ExcludeTypeFromAutoRegistration dosn't do anything for ChildContainers #299

Open Warstone opened 1 year ago

Warstone commented 1 year ago
public class B
{
    public B(A a)
    {
        A = a;
    }

    public A A;
}
public class A
{
    public int Value;
}

public static class Program
{
    public static void Main()
    {
        var container = new DependencyInjectionContainer();
        container.Configure(c =>
        {
            // c.ExcludeTypeFromAutoRegistration(typeof(A)); // Uncomment this line for correct answer
        });

        var origA = new A() { Value = 5 };
        var subContainer = container.CreateChildScope();
        subContainer.Configure(c =>
        {
            c.ExcludeTypeFromAutoRegistration(typeof(A)); // This line is useless
        });

        B obj = subContainer.Locate<B>(new {
            a = origA
        });

        Console.Write($"obj A val = {obj.A.Value}"); // This will write "obj A val = 0", expected result: "obj A val = 5"
    }
}

Here is the code illustrating example. If I exclude AutoRegistration in child container (I want to override parent behaviour) it won't work. I need to exclude it in parent container.

So Excluding in child containers dosn't do anything.

ipjohnson commented 1 year ago

I'll take a look this weekend but ultimately I believe what you're seeing is that auto registration is independent between container & child container. So the request bubble up to the root container where the auto registration resolves.

Warstone commented 1 year ago

I think same, but it's not expected behavior for me. Nested container must block such things and I've expected to see 5 in result

Warstone commented 1 year ago

If you want to make it works as I expect, than in subContainer you could register factory like this:

c.ExportFactory<IInjectionContext, B>(scope => new B((A)scope.GetExtraData("a")));

But it still wired that something dosn't work as intended

Warstone commented 1 year ago
public class B
{
    public B(IA a)
    {
        A = a;
    }

    public IA A;
}

public interface IA
{
    public int Value {get; set; }
}
public class A: IA
{
    public int Value { get; set; }
}

...

        var container = new DependencyInjectionContainer();
        container.Configure(c =>
        {
            c.Export<A>().As<IA>();
        });

        var origA = new A() { Value = 5 };
        var subContainer = container.CreateChildScope();
        subContainer.Configure(c =>
        {
            c.ExportInstance(origA).As<IA>().Lifestyle.Singleton();
            // c.Export<B>().As<B>(); // This line will fix this and give same Values
        });

        B obj = subContainer.Locate<B>();
        IA obj2 = subContainer.Locate<IA>();

        Console.Write($"B.A.Value = {obj.A.Value}, IA.Value = {obj2.Value}"); // B.A.Value = 0, IA.Value = 5

It looks like childContainers broken completely.

ipjohnson commented 1 year ago

Essentially what you're seeing is that auto registration is done in the root container. I'll say up front that the child container support is not 100% compatible with what you'll see in other containers like Unity or AutoFac. Most of these decisions are rooted in the fact Grace use Linq expressions to build factories for performance but they don't take dynamic exports into consideration like child containers.