TL; DR如何调整现有的一组事件/通知和相关处理程序,以便MediatR可以使用它们,而无需为每个现有类型实现额外的处理程序和通知?
长版: 我们目前有一个调度事件的系统,我们使用总线实现来进行实际的传输。
我目前正在尝试使用进程内变体。
与MediatR INotification
类似,我们有一个标记界面IEvent
同样类似于MediatR的INotificationHandler<in INotification>
,我们有一个IEventHandler<in IEvent>
我们使用Autofac来注册我们的EventHandlers,然后我们在实际消耗总线上的东西时会有一些反思。
我想做的,但无法理解,是实现某种通用适配器/包装器,以便我可以保留现有的事件和事件处理程序,并在从MediatR发送通知时使用它们,基本上减少了我现有代码的变化量围绕设置容器。
就代码而言,我希望以下类的行为就像使用MediatR接口一样。
public class MyHandler : IEventHandler<SampleEvent>
{
public Task Handle(SampleEvent input) => Task.CompletedTask;
}
有什么建议吗?
答案 0 :(得分:2)
现在你的代码看起来像这样:
public class SampleEvent : IEvent
{
}
public class SampleEventHandler : IEventHandler<SampleEvent>
{
public Task Handle(SampleEvent input) => Task.CompletedTask;
}
我们需要有MediatR识别的事件,这意味着他们需要实施INotification
。
执行此操作的第一种方法是使IEvent
接口实现INotification
。关于这一点的好处是代码变化非常小,它使您所有的当前和新事件与MediatR兼容。可能不那么伟大的事情是,当前IEvent
实现的程序集需要依赖于MediatR。
public interface IEvent : INotification
{
}
如果这不可行,我认为这样做的第二种方法是创建新的,特定于MediatR的类,这些类继承现有的类并实现INotification
。这意味着您需要为每个现有类创建一个适配器类,但是您可以从MediatR依赖项中释放现有项目。
// Lives in AssemblyA
public class ExistingEvent : IEvent
{
}
// Lives in AssemblyB that has a dependency on both
// AssemblyA and MediatR
public class MediatrExistingEvent : ExistingEvent, INotification
{
}
无论您在上一步中采用哪种方式,现在都处于这样一种状态,即您拥有同时实现IEvent
和INotification
的类,并且您拥有实现IEventHandler<in T> where T : IEvent
的处理程序}。
我们可以创建一个满足MediatR API的适配器类,并将工作委托给现有的处理程序:
public class MediatrAdapterHandler<T> : INotificationHandler<T>
where T : IEvent, INotification
{
private readonly IEventHandler<T> _inner;
public MediatrAdapterHandler(IEventHandler<T> inner)
{
_inner = inner;
}
public Task Handle(T notification) => _inner.Handle(notification);
}
最后一件事是在Autofac容器中注册这个类。鉴于您现有的处理程序已注册为IEventHandler<T>
,它很容易完成:
builder
.RegisterGeneric(typeof(MediatrAdapterHandler<>))
.As(typeof(INotificationHandler<>));
每当您向容器询问INotificationHandler<T>
的实例时,它将创建MediatrAdapterHandler<T>
的实例,其中将注入IEventHandler<T>
的原始实现。