getting all of registered services of a generic type

Oct 15, 2013 at 9:47 PM
I'm trying to retrieve a list of generic handlers from my container but getting nothing. Yet if I Get the handler instead I get one back. I'm sure this has something to do with my registration.

Registration looks like this

container.RegisterManyForOpenGeneric(typeof(IHandleEvent<>), typeof(IHandleEvent<>).Assembly);

this returns a single value (expected)
var handler = Container.GetInstance<IHandleEvent<MyEvent>>();

but this returns nothing (though I know there is one in there)
var handlers = Container.GetAllInstances(typeof(IHandleEvent<TEvent>));

I'm sure it has something to do with TEvent but the answer is not screaming at me. Can you help?

Thanks,

Steven
Oct 15, 2013 at 10:03 PM
I also verified that the following returns an instance
var handler = Container.GetInstance<IHandleEvent<TEvent>>();
it seems that only the GetAllInstances returns nothing.
Coordinator
Oct 15, 2013 at 10:39 PM
> it seems that only the GetAllInstances returns nothing.

That's correct. Simple Injector explicitly separates one-type registrations from registrations of collections. One-type registrations are done using the Register methods, while registering a collection is done using the _RegisterAll methods. For instance:
container.Register<ILogger, DbLogger>();

container.RegisterAll<ILogger>(typeof(DbLogger), typeof(FileLogger), typeof(EventLogger));
This distinction is made explicitly, since you would usually either depend on an IEnumerable<ILogger> or on ILogger, but not mix them. And when register multiple ILogger implementations, what would it mean to resolve a single ILogger? Which logger should the framework return? To prevent this ambiguity, Simple Injector forces the user to make this extinction explicitly.

The RegisterManyForOpenGeneric uses the _Register under the covers. It always registers one closed-generic interface with one closed-generic implementation. It will throw an exception when you have multiple non-generic implementations that implement the same closed-generic interface. In other words, RegisterManyForOpenGeneric is a handy short cut for doing the following registrations by hand:
container.Register<IHandleEvent<MyEvent>, MyEventHandler>();
container.Register<IHandleEvent<YourEvent>, YourEventHandler>();
container.Register<IHandleEvent<HisEvent>, HisEventHandler>();
container.Register<IHandleEvent<CoolEvent>, CoolEventHandler>();
Since the RegisterManyForOpenGeneric simply calls container.Register(Type, Type) under the covers, you can't resolve the registered implementations using GetAllInstances. That would simply return an empty collection.

In your case, you want to resolve a collection, and this indicates that your application could contain multiple implementations of the same closed-generic interface. Calling the default RegisterManyForOpenGeneric overload in that case will result in an exception. What you need to do is call the overload that takes a callback delegate and register found types using RegisterAll. Here's an example:
container.RegisterManyForOpenGeneric(typeof(IHandleEvent<>), 
    container.RegisterAll, // this is the callback delegate
    typeof(IHandleEvent<>).Assembly);
When you made the previous registration, the following statement will throw an exception:
var handler = Container.GetInstance<IHandleEvent<MyEvent>>(); 
That's because only collections are registered, no non-collection registrations. The following will succeed:
var handlers = Container.GetAllInstances<IHandleEvent<MyEvent>>(); 
Still, you might want to resolve a whole collection as if it was a single event handler. This is useful when there are many consumers that depend on that IEnumerable<IHandleEvent<T>> abstraction. When you inject an IEnumerable, each consumer has to loop through the collection manually and this results in a lot of duplicate, boilerplate code. Besides, if you decide that the way the collection should be processed must change, you have to change a lot of code throughout the application.

So in that case, you want to create a generic composite event handler (implementing the Composite pattern) that wraps the collection. This might look like this:
public class CompositeEventHandler<TEvent> : IHandleEvent<TEvent>
{
    private readonly IEnumerable<IHandleEvent<TEvent>> handlers;

    public CompositeEventHandler(IEnumerable<IHandleEvent<TEvent>> handlers)
    {
        this.handlers = handlers;
    }

    public void Handle(TEvent @event)
    {
        foreach (var handler in this.handlers)
        {
            handler.Handle(@event);
        }
    }
}
Since this class is generic, we can register it using the RegisterOpenGeneric extension method alongside the RegisterManyForOpenGeneric registration:
container.RegisterManyForOpenGeneric(typeof(IHandleEvent<>), 
    container.RegisterAll, // this is the callback delegate
    typeof(IHandleEvent<>).Assembly);

container.RegisterOpenGeneric(typeof(IHandleEvent<>), typeof(CompositeEventHandler<>));
This registration will ensure that every time an IHandleEvent<T> is requested, a CompositeEventHandler<T> is returned. And since the CompositeEventHandler<T> depends on IEnumerable<IHandleEvent<T>>, the registrations made using the RegisterManyForOpenGeneric are injected. When no registrations are made for a certain TEvent, Simple Injector will inject an empty collection (that's the behavior you're currently seeing). This allows you to define events in the application, for which no event handlers exist (yet), and still allow the application to fire those events.

With this registration a consumer could look as follows:
public class SomeConsumer
{
    private IHandleEvent<MyEvent> handler;

    public SomeConsumer(IHandleEvent<MyEvent> handler) { this.handler = handler; }

    public DoSomeStuff()
    {
        this.handler.Handle(new MyEvent());
    }
}
With the previous registration, an CompositeEventHandler<MyEvent> will get injected into SomeConsumer and calling Handle on it, will ensure that all registered event handlers for MyEvent get fired.

I hope this makes sense.

For more information see the following wiki pages:
Marked as answer by StevenReachSoft on 11/2/2013 at 8:25 PM
Oct 16, 2013 at 12:18 AM
Awesome! Thank you for both the education AND the answer. I really like how well you've thought through the scenarios.

Thank you again!

Steven
Nov 3, 2013 at 3:53 AM
I have a follow up question to this please.

In addition to handlers of specific events, I also want to handle all events that implement the interface IDomainEvent. Registering the below works for specific handlers of type IHandleEvent<T> but not one with the below mygenerichandler below
container.RegisterManyForOpenGeneric(typeof(IHandleEvent<>), 
    container.RegisterAll, // this is the callback delegate
    typeof(IHandleEvent<>).Assembly);
This one doesn't return in the GetAllInstances<IDomainEventSubscriber<TEvent>>
    public class mygenerichandler : IDomainEventSubscriber<IDomainEvent>
    {

        public void HandleEvent(IDomainEvent domainEvent)
        {
            Console.WriteLine("");
        }

    }
  1. Is there a way to run the registration differently to get all handlers of the TEvent? TEvent is enforced to be IDomainEvent at the interface level (where clause)
  2. The way I've made it work for now is by using the composite pattern as you've described above. It works fine and suits my purpose, but I'm not sure I like it 100%. It seems I should be able to say "Give me all the handlers of this event, even generic ones".
Thoughts?
Coordinator
Nov 3, 2013 at 8:52 AM
I'm not sure I follow. Can you describe the relationship between IHandleEvent<T> and IDomainEventSubscriber<T>? Does one inherit from the other? Can you give an example of what you're trying to achieve?
Nov 3, 2013 at 12:03 PM
Edited Nov 3, 2013 at 12:17 PM
ok. here goes.

when a domain event occurs I sometimes need to handle the specific event in the application, think notify the user perhaps via SignalR. In all cases I want to handle the event generically by sending it as a message on a service bus, think notifications going outside the system like email or an audit queue. I don't want a make a handler for each and every event just to send on the service bus when all events implement IDomainEvent.

The way the Composite pattern works as you mentioned above I do get an instance of every DomainEvent. I loop through the IEnumerable then as a last step send it on the bus. I guess the problem that I have is that the IEnumerable<myevent> is empty for those events I haven't specifically handled. It makes zero technical difference and perhaps it is the correct way to handle it. It just seems 'odd' because there is always at least one handler (Generic) so I wanted your thoughts.
Coordinator
Nov 3, 2013 at 12:42 PM
Ahh. okay. There are multiple path to walk here. For instance, you might be able to solve the issue by making the IHandleEvent<T> contravariant and allowo Simple Injector to resolve all assignable types, as you can read here. Another option is to add an open generic handler to the registered collection, as can be seen in the following stackoverflow Q/A.

Although there are even other options, using a mix of RegisterManyForOpenGeneric and RegisterAllOpenGeneric (as explained in the stackoverflow answer) would probably be your best bet. In your situation this might look like this:
    Type[] openGenericHandlers = new[]
    { 
        // "class GenericEventToBusHandler<TEvent> where TEvent : IDomainEvent"
        typeof(GenericEventToBusHandler<>) 
    };

    var nonGenericHandlers = OpenGenericBatchRegistrationExtensions
        .GetTypesToRegister(container,
            typeof(IHandleEvent<>),
            typeof(IHandleEvent<>).Assembly);

    container.RegisterManyForOpenGeneric(typeof(IHandleEvent<>),
        container.RegisterAll,
        nonGenericHandlers.Concat(openGenericHandlers));

    container.RegisterAllOpenGeneric(typeof(IHandleEvent<>), 
        openGenericHandlers);
Nov 3, 2013 at 6:30 PM
First to answer the question I missed earlier. IHandleEVent and IDomainEventSubscriber are the same. I started to make the change and got caught in transition. Sorry for the confusion.

Secondly, I'm sure I'm doing something fundamentally wrong here. My GenericEventToBusHandler<> looks like
    public class GenericEventToBusHandler<TEvent> where TEvent : IDomainEvent,
        IDomainEventSubscriber<IDomainEvent>
    {

        public void HandleEvent(IDomainEvent domainEvent)
        {
        }
    }
using that I get
The supplied type GenericEventToBusHandler<TEvent> does not implement IDomainEventSubscriber<T>.
my interfaces are here just in case it's something I'm doing there
    public interface IDomainEventSubscriber<in T> where T : IDomainEvent
    {
        void HandleEvent(T domainEvent);
    }

    public interface IDomainEvent
    {
        int EventVersion { get; set; }
        DateTime OccurredOn { get; set; }
    }
I confess I'm still reading the links you've included, but I'd appreciate some additional guidance. I'm sure I'm missing something really simple and fundamental.
Nov 3, 2013 at 6:44 PM
D'OH! my mistake. changing the genericbus handler to
    public class GenericEventToBusHandler<TEvent> : IDomainEventSubscriber<TEvent> where TEvent : IDomainEvent
was the problem. While I like this way better, I'll continue reading what you wrote to see what I like better. Your dispatcher approach in the blog post looks very intriguing.