使用RegisterInitializer连接事件处理程序
我有一个WCF服务,它使用Simple Injector进行dependency injection。 我想在容器引导程序中连接一些事件处理程序。 我创建了一个接口IStatusChangeNotification
:
public interface IStatusChangeNotification { event EventHandler JobStatusChange; }
我的CommandHandler
实现了IStatusChangeNotification
并且有两个事件处理程序类EmailNotification
和MmrNotification
,每个类定义一个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
的实现细节。 例如,您可以希望并行运行它们,在它们自己的事务中运行它们,稍后处理它们(通过将它们存储在事件存储中)。
- 运行批处理文件的C#代码在控制台应用程序中工作,但相同的代码在WCF服务中不起作用
- 使用UserNameOverTransport绑定时,如何让WCF以摘要模式发送密码? (将WSE3.0代码转换为WCF)
- 如何从工作线程中调用UI线程上的方法?
- 从异步WCF双工调用更新asp.net页面 – 对象范围 – ASP.NET
- 使用与WCF的接口
- “不要在Design中使用Abstract Base类; 但在建模/分析中“
- 使用自定义WCF正文反序列化而不更改URI模板反序列化
- WCF:运行服务器项目时的PlatformNotSupportedException
- WCF DataContract DataMember订单?