This question originates from the fact that I'm trying to create a Simple Injector implementation for MediatR: https://github.com/jbogard/MediatR/pull/14.
I'm having trouble while trying to resolve implementations of a generic handler interface. Consider the following notification handler interface:
public interface INotificationHandler<in TNotification>
where TNotification : INotification
{
void Handle(TNotification notification);
}
INotifcation
is just an empty marker interface.
I defined the following handlers for the Pinged
(which implements INotification
) event:
public class PingedHandler : INotificationHandler<Pinged>
{
public void Handle(Pinged notification) { }
}
public class PingedHandler2 : INotificationHandler<Pinged>
{
public void Handle(Pinged notification) { }
}
And also a generic handler (notice this should handle every INotification
):
public class GenericHandler : INotificationHandler<INotification>
{
public void Handle(INotification notification) { }
}
With the following registration:
var container = new Container();
container.RegisterManyForOpenGeneric(
typeof (INotificationHandler<>),
(service, impls) => container.RegisterAll(service, impls),
AppDomain.CurrentDomain.GetAssemblies());
Now I expect:
GetAllInstances<INotificationHandler<Pinged>>();
to resolve both PingedHandler
and PingedHandler2
which it does. But it doesn't resolve the GenericHandler
since it implements INotificationHandler<INotification>
and not INotificationHandler<Pinged>
. I wonder if there is a way to let Simple Injector search up the whole object graph and resolve anything that is Pinged
too.
I've found a blog post from Steven about co-variance and contra-variance, but I'm unable to get it working for my example.
tl;dr: it was a bug/shortcoming in Simple Injector v2.6.0, which is fixed in v2.7.0. The configuration in the question (and shown below) does work now.
To summarize @qujck's answer and @Steven's comment: I was able to get it working by installing Simple Injector v2.7.0-beta2 with the following configuration (actually the same as in the question):
// Simple Injector v3.x
container.RegisterCollection(typeof(INotificationHandler<>),
AppDomain.CurrentDomain.GetAssemblies());
// Simple Injector v2.x
container.RegisterManyForOpenGeneric(
typeof(INotificationHandler<>),
container.RegisterAll,
AppDomain.CurrentDomain.GetAssemblies());
Now Simple Injector is able to resolve PingedHandler
, PingedHandler2
and the GenericHandler
when requesting:
container.GetAllInstances<INotificationHandler<Pinged>>();