container icon indicating copy to clipboard operation
container copied to clipboard

Child container fails to resolve registered open generic interface after parent container fails to resolve it

Open rjgotten opened this issue 3 years ago • 3 comments

Description

Assume a root container and a child container where the child has an open generic interface->type mapping registered.

  • Resolving the interface from the child container works. This is expected, since it has the mapping.
  • Resolving the interface from the parent container throws a ResolutionFailedException. This is expected, since it does not have the mapping.
  • Resolving the interface from the child container after having attempted to resolve it from the parent container will cause the child container to also throw a ResolutionFailedException because the interface is not mapped. This is unexpected (and wrong: it clearly is mapped).

Reproduction

An NUnit unit test project that illustrates the above is available at https://github.com/NetMatch/unity-358-repro

Versions

NuGet Unity package 5.11.7

rjgotten avatar Nov 09 '20 11:11 rjgotten

I wonder if this is a variant of https://github.com/unitycontainer/microsoft-dependency-injection/issues/14 which was resolved in 2018, and if it's not basically the same problem:

  1. Child container doesn't have open-to-closed mapping;
  2. Child container looks up at parent container;
  3. Parent container does have open-to-closed type mapping (which previously failed)
  4. Closed type resolves on parent container;
  5. But parent container doesn't have interface actually mapped; so we always get ResolutionFailedException

rjgotten avatar Nov 09 '20 13:11 rjgotten

Unity creates a registration and a pipeline for each type. If type can not be created, the pipeline throws an exception. When you resolve in child, the container will check registrations from that child to the root container and if registration is found it will be using it.

So, in your case faulty registration is being picked up by the child.

You could override registration in child to prevent the exception.

ENikS avatar Nov 17 '20 01:11 ENikS

You could override registration in child to prevent the exception.

The open generic registration is done on the child container.

The problem starts when you attempt to resolve a closed instance of that generic type in the parent container, before you attempt to resolve that same closed instance in the child container.

At that point something caches the broken resolve in the parent container, and attempting to then resolve the same type in the child container -- where it should succeed -- is broken as well, presumably because the child container sees the cached broken resolve for the closed generic type on the parent, before it runs through the open generic on the child.


I guess the issue boils down to open generic type registrations on child containers not overruling closed generic type resolves and/or registrations on parents, which I think -- if this is indeed the case -- would be an architectural flaw.

If you specify an open generic type mapping, that means you're specifying you'll be handling all closed generic forms of that type and thus should be overriding all closed forms on parent containers as well.

rjgotten avatar Nov 17 '20 11:11 rjgotten