Adapt/Wrap 现有框架中的 MediatR 通知
Adapt/Wrap MediatR notifications in existing framework
TL;DR 如何调整现有的一组 events/notifications 和相关处理程序,以便 MediatR 使用它们而不必为每个现有类型实施额外的处理程序和通知?
长版:
我们目前有一个用于调度事件的系统,我们在其中使用总线实现来进行实际传输。
我目前正在试验一个进行中的变体。
与 MediatR 的 INotification
非常相似,我们有一个标记界面 IEvent
同样类似于 MediatR 的 INotificationHandler<in INotification>
我们有一个 IEventHandler<in IEvent>
我们使用 Autofac 来注册我们的 EventHandlers,然后我们在实际从总线上消费时进行一些反射。
我想做但又无法理解的是,实现某种通用的 adapter/wrapper 以便我可以保留现有的事件和事件处理程序,并在从 MediatR 发送通知时使用它们,基本上减少了我现有代码围绕设置容器的更改量。
就代码而言,我想让以下 class 表现得好像它在使用 MediatR 接口一样。
public class MyHandler : IEventHandler<SampleEvent>
{
public Task Handle(SampleEvent input) => Task.CompletedTask;
}
有什么建议吗?
现状
所以现在您的代码如下所示:
public class SampleEvent : IEvent
{
}
public class SampleEventHandler : IEventHandler<SampleEvent>
{
public Task Handle(SampleEvent input) => Task.CompletedTask;
}
使事件与 MediatR 兼容
我们需要 MediatR 识别的事件,这意味着他们需要实施 INotification
。
第一种方法是让您的 IEvent
接口实现 INotification
。这样做的好处是几乎没有代码更改,它使您所有当前和新的事件都与 MediatR 兼容。可能不太好的事情是,您当前的 IEvent
实现所在的程序集需要依赖 MediatR。
public interface IEvent : INotification
{
}
如果这不可行,我看到的第二种方法是创建新的、特定于 MediatR 的 classes,它们继承现有的并实现 INotification
。这意味着您需要为每个现有 class 创建一个适配器 class,但您可以从 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
{
}
连接处理程序
无论您在上一步中采用哪种方式,您现在所处的状态是您有 class 实现了 IEvent
和 INotification
,并且您有处理程序实施 IEventHandler<in T> where T : IEvent
.
我们可以创建一个适配器 class 来满足 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容器中注册这个class。鉴于您现有的处理程序已注册为 IEventHandler<T>
,这很容易完成:
builder
.RegisterGeneric(typeof(MediatrAdapterHandler<>))
.As(typeof(INotificationHandler<>));
现在每次您向容器请求 INotificationHandler<T>
的实例时,它都会创建一个 MediatrAdapterHandler<T>
的实例,其中将注入您对 IEventHandler<T>
的原始实现。
TL;DR 如何调整现有的一组 events/notifications 和相关处理程序,以便 MediatR 使用它们而不必为每个现有类型实施额外的处理程序和通知?
长版: 我们目前有一个用于调度事件的系统,我们在其中使用总线实现来进行实际传输。
我目前正在试验一个进行中的变体。
与 MediatR 的 INotification
非常相似,我们有一个标记界面 IEvent
同样类似于 MediatR 的 INotificationHandler<in INotification>
我们有一个 IEventHandler<in IEvent>
我们使用 Autofac 来注册我们的 EventHandlers,然后我们在实际从总线上消费时进行一些反射。
我想做但又无法理解的是,实现某种通用的 adapter/wrapper 以便我可以保留现有的事件和事件处理程序,并在从 MediatR 发送通知时使用它们,基本上减少了我现有代码围绕设置容器的更改量。
就代码而言,我想让以下 class 表现得好像它在使用 MediatR 接口一样。
public class MyHandler : IEventHandler<SampleEvent>
{
public Task Handle(SampleEvent input) => Task.CompletedTask;
}
有什么建议吗?
现状
所以现在您的代码如下所示:
public class SampleEvent : IEvent
{
}
public class SampleEventHandler : IEventHandler<SampleEvent>
{
public Task Handle(SampleEvent input) => Task.CompletedTask;
}
使事件与 MediatR 兼容
我们需要 MediatR 识别的事件,这意味着他们需要实施 INotification
。
第一种方法是让您的 IEvent
接口实现 INotification
。这样做的好处是几乎没有代码更改,它使您所有当前和新的事件都与 MediatR 兼容。可能不太好的事情是,您当前的 IEvent
实现所在的程序集需要依赖 MediatR。
public interface IEvent : INotification
{
}
如果这不可行,我看到的第二种方法是创建新的、特定于 MediatR 的 classes,它们继承现有的并实现 INotification
。这意味着您需要为每个现有 class 创建一个适配器 class,但您可以从 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
{
}
连接处理程序
无论您在上一步中采用哪种方式,您现在所处的状态是您有 class 实现了 IEvent
和 INotification
,并且您有处理程序实施 IEventHandler<in T> where T : IEvent
.
我们可以创建一个适配器 class 来满足 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容器中注册这个class。鉴于您现有的处理程序已注册为 IEventHandler<T>
,这很容易完成:
builder
.RegisterGeneric(typeof(MediatrAdapterHandler<>))
.As(typeof(INotificationHandler<>));
现在每次您向容器请求 INotificationHandler<T>
的实例时,它都会创建一个 MediatrAdapterHandler<T>
的实例,其中将注入您对 IEventHandler<T>
的原始实现。