ipjohnson / Grace

Grace is a feature rich dependency injection container library

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Automatic registration of open generics can lead to failures

jods4 opened this issue · comments

(I'm creating this issue as a reference for other users that may encounter this. I always disable auto-registration, so I am in no need for a fix or change.)

There are some edge cases where the default configuration of Grace can fail whereas MS DI works.
I will illustrate this with the popular MassTransit library, that just works with MS but fails to start in Grace default configuration.

The problem

The failure happens when MassTransit tries to locate the following service:

services.GetRequiredService(typeof(IEnumerable<Bind<IBus, IBusInstanceSpecification>>));

The catch is that in its basic default configuration, MassTransit does not register a Bind<IBus, IBusInstanceSpecification>>. The call above is expected to return an empty enumerable, which is how it works with MS DI.

This fails with the default Grace configuration, because of the following unfortunate sequence of events:

  • Grace will look for injectable Bind<IBus, IBusInstanceSpecification>;
  • As neither the open generic, nor that specific combination, has been registered, Grace will register it itself;
  • Now Grace tries to instantiate one Bind<IBus, IBusInstanceSpecification> but its ctor takes one IBusInstanceSpecification;
  • As this service is an interface and is not registered, Grace fails with LocateException.

Work-arounds

Disabling auto-registration is one solution: UseGrace(new InjectionScopeConfiguration { AutoRegisterUnknown = false }).

If auto-registration is desirable, then config.ExcludeTypeFromAutoRegistration(pattern) can be used to selectively disable it and accepts wildcards. In the scenario above, it would be advisable to disable auto-registraton of MassTransit.*.

Possible fixes in Grace

Maybe things could be changed to work out of the box with Grace?

Even with GetRequiredServices(), when locating an IEnumerable, failure to locate services may not be an issue, as an empty IEnumerable is an acceptable result.

Now, Grace should be careful to not swallow meaningful exceptions, e.g. when a service is registered (explicitly) but its dependencies can't be satisfied.

It might be a little tricky to code, but I would say somehow Grace should not auto-register a dependency that it then cannot satisfy.

commented

I'm closing this in favor of #315, which is a duplicate but it contains more testing, incl. on .net 8 branch, and a more thorough discussion of possible mitigations.