简单注入器:如何将事件处理程序实例注册到事件调度程序

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

我有一个接口。

// 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
}

然后在我的 ASP MVC 5 项目上,我有事件的事件处理程序。

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);
        }
    }

关于我的启动 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>();

这样,我怎样才能得到 event dispatcher 并将所有事件处理程序注册到其中?

我试过了

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

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

但是它不起作用。 GetAllInstances 方法未返回任何内容。

Things to note: IEventDispatcher 依赖于我的 EF DbContext 构造函数,我(现在)有两个上下文。 MembershipContextIdentityAccessContext 都派生自 EventDipatchingContext,派生自 DbContext。 基本上是 EventDispatchingContext : DbContext 然后是 MembershipContext : EventDispatchingContext

EventDispatchingContext 负责将事件委托给事件调度程序 after its Commit() method is invoked。他们不会在我的域实体上立即被解雇。我从 Jimmy Bogard 的博客中得到了这个架构

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

在这种情况下,我需要将 IEventDispatcher 设为单例吗?为什么?

如何正确地将处理程序注册到事件调度程序?

阻止 'registering' 事件调度程序中的事件处理程序。相反,您应该将事件调度程序实现作为 Composition Root 的一部分。这样您就可以安全地从调度程序中依赖容器,如下所示:

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);
        }
    }
}

请注意 IEventDispatcher 接口现在只包含一个 Dispatch 方法。

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

您不必将事件调度程序实现设为单例,但由于它没有依赖项也没有状态,因此将其设为单例是明智的。这样它的消费者也可以成为单身人士。 more singletons the merrier.