Grace icon indicating copy to clipboard operation
Grace copied to clipboard

ExcludeTypeFromAutoRegistration dosn't do anything for ChildContainers

Open Warstone opened this issue 2 years ago • 5 comments

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.

Warstone avatar Nov 10 '22 15:11 Warstone

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.

ipjohnson avatar Nov 11 '22 11:11 ipjohnson

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 avatar Nov 11 '22 14:11 Warstone

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 avatar Nov 22 '22 10:11 Warstone

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.

Warstone avatar Nov 22 '22 14:11 Warstone

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.

ipjohnson avatar Nov 22 '22 23:11 ipjohnson