Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple Injector: How to register event handlers instances to the event dispatcher

I have an interface.

// Assembly: Common
public interface IEventHandler<TEvent> where TEvent : IDomainEvent
{
    void HandleEvent(TEvent theEvent);
}

// Assembly: Common
public interface IDomainEvent
{
}

// Assembly: Common
public interface IEventDispatcher
{
    void Register(IEventHandler<IDomainEvent> handler);
    void Dispatch(IDomainEvent theEvent);
}

// Assembly: Membership
public sealed class MemberRegistered : IDomainEvent
{
    // event properties
}

Then on my ASP MVC 5 project I have event handler for the events.

public sealed class MemberRegisteredHandler : IEventHandler<MemberRegistered>
    {
        public MemberRegisteredHandler(ApplicationUserManager userManager)
        {
            this.userManager = userManager;
        }

        private ApplicationUserManager userManager;

        public void HandleEvent(MemberRegistered theEvent)
        {
            User user = new User(
                theEvent.MemberId.ToString(),
                theEvent.Username,
                theEvent.PersonalInformation.Email);

            this.userManager.CreateUserWithRandomPassword(user);
        }
    }

On my Startup class

var container = new Container();

// TIP: For Simple Injector >= v4.3, instead use container.Collection.Register. 
container.RegisterManyForOpenGeneric(
               typeof(IEventHandler<>),
               container.RegisterAll,
               Assembly.GetExecutingAssembly());

container.Register<IEventDispatcher, SimpleEventDispatcher>();

With that, how can I get the event dispatcher and register all the event handlers into it?

I've tried

var eventDispatcher = container.GetInstance<IEventDispatcher>();

foreach (var handler in container.GetAllInstances<IEventHandler<IDomainEvent>>())
{
    eventDispatcher.Register(handler);
}

But its not working. the GetAllInstances method is not returning anything.

Things to note: The IEventDispatcher is a dependency on my EF DbContext constructor and I have(right now) two contexts. MembershipContext and IdentityAccessContext which both derived from EventDipatchingContext that derives from DbContext. Basically its EventDispatchingContext : DbContext then MembershipContext : EventDispatchingContext

The EventDispatchingContext is responsible for delegating the events to the event dispatcher after its Commit() method is invoked. They are not get fired instantly on my Domain Entites. I got this architecture from Jimmy Bogard's blog

https://lostechies.com/jimmybogard/2014/05/13/a-better-domain-events-pattern/

Do I need to make IEventDispatcher a singleton in this case? Why?

How to properly regsiter the handlers to the event dispatcher?

like image 327
Jaime Sangcap Avatar asked Feb 09 '23 08:02

Jaime Sangcap


1 Answers

Prevent 'registering' the event handlers in your event dispatcher. Instead you should make the event dispatcher implementation part of your Composition Root. This way you can safely take a dependency upon the container from within the dispatcher as follows:

public class SimpleInjectorEventDispatcher : IEventDispatcher
{
    private readonly Container container;
    
    public SimpleInjectorEventDispatcher(Container container)
    {
        this.container = container;
    }

    public void Dispatch(IDomainEvent theEvent)
    {
        var handlerType =
            typeof(IEventHandler<>).MakeGenericType(theEvent.GetType());
        
        var handlers = this.container.GetAllInstances(handlerType);
        
        foreach (dynamic handler in handlers)
        {
            handler.HandleEvent((dynamic)theEvent);
        }
    }
}

Do note that the IEventDispatcher interface now only contains a Dispatch method.

Do I need to make IEventDispatcher a singleton in this case? Why?

You don't have to make the event dispatcher implementation a singleton, but since it has no dependencies and no state, it's wise to make it a singleton. This way its consumers can become singletons as well. The more singletons the merrier.

like image 113
Steven Avatar answered Feb 12 '23 11:02

Steven