使用RegisterInitializer连接事件处理程序

我有一个WCF服务,它使用Simple Injector进行dependency injection。 我想在容器引导程序中连接一些事件处理程序。 我创建了一个接口IStatusChangeNotification

 public interface IStatusChangeNotification { event EventHandler JobStatusChange; } 

我的CommandHandler实现了IStatusChangeNotification并且有两个事件处理程序类EmailNotificationMmrNotification ,每个类定义一个Notify()方法。 然后在我的引导代码中,我有以下内容:

 container.Register(); container.Register(); container.RegisterManyForOpenGeneric(typeof(ICommandHandler), Assembly.GetExecutingAssembly()); container.RegisterInitializer(scn => { scn.JobStatusChange += container.GetInstance().Notify; scn.JobStatusChange += container.GetInstance().Notify; }); 

这有效,并收到通知。 我的问题是,这是否是连接事件处理程序的正确/最佳方法? 如何在请求结束时删除处理程序并且无法删除它们会导致内存泄漏?

虽然您的方法可能有用,但我认为您的系统设计的这一部分可能应该得到与命令处理程序相同的注意力。 命令处理程序触发事件的最常见原因是发布描述某些业务相关操作的事件。 因此,不是使用.NET事件,而是以与建模命令相同的方式对这些域事件进行建模:

 // Abstractions public interface IEventHandler where TEvent : IDomainEvent { void Handle(TEvent e); } public interface IEventPublisher { void Publish(TEvent e) where TEvent : IDomainEvent; } // Events public class JobStatusChanged : IDomainEvent { public readonly int JobId; public JobStatusChanged(int jobId) { this.JobId = jobId; } } // Container-specific Event Publisher implementation public class SimpleInjectorEventPublisher : IEventPublisher { private readonly Container container; public SimpleInjectorEventPublisher(Container container) { this.container = container; } public void Publish(TEvent e) { var handlers = container.GetAllInstances>(); foreach (var handler in handlers) { hanlder.Handle(e); } } } 

使用以前的基础结构,您可以创建以下事件和命令处理程序:

 // Event Handlers public class EmailNotificationJobStatusChangedHandler : IEventHandler { public void Handle(JobStatusChanged e) { // TODO: Implementation } } public class MmrNotificationJobStatusChangedHandler : IEventHandler { public void Handle(JobStatusChanged e) { // TODO: Implementation } } // Command Handler that publishes public class ChangeJobStatusCommandHandler : ICommandHandler { private readonly IEventPublisher publisher; public ChangeJobStatusCommandHandler(IEventPublisher publisher) { this.publisher = publisher; } public void Handle(ChangeJobStatus command) { // change job status this.publisher.Publish(new JobStatusChanged(command.JobId)); } } 

现在,您可以注册命令处理程序和事件处理程序,如下所示:

 container.RegisterManyForOpenGeneric(typeof(ICommandHandler<>), Assembly.GetExecutingAssembly()); // This registers a collection of eventhandlers with RegisterAll, // since there can be multiple implementations for the same event. container.RegisterManyForOpenGeneric(typeof(IEventHandler<>), container.RegisterAll, Assembly.GetExecutingAssembly()); 

这样就无需单独注册每个事件处理程序类,因为它们只是IEventHandler实现,并且都可以在一行代码中进行批量注册。 也没有必要使用RegisterInitializer来使用自定义接口挂钩任何事件。

其他优点是:

  • 命令处理程序和IEventPublisher接口之间的依赖关系使得该命令非常清楚地发布事件。
  • 该设计具有更高的可扩展性,因为当新的命令和事件添加到系统时,组合根不太可能必须更改。
  • 它使您的域非常好,因为每个事件在系统中都有自己的实体。
  • 更改事件处理方式会容易得多,因为现在它是SimpleInjectorEventProcessor的实现细节。 例如,您可以希望并行运行它们,在它们自己的事务中运行它们,稍后处理它们(通过将它们存储在事件存储中)。