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 oneIBusInstanceSpecification
; - 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.