pla*_*sjh 8 .net c# domain-driven-design mediatr
我刚刚开始使用DDD.我将域事件放入CQRS应用程序中,我遇到了一项基本任务:如何在域项目中使用MediatR.INotification标记接口,而不会在基础结构上创建域依赖项.
我的解决方案分为以下四个项目:
MyApp.Domain
- Domain events
- Aggregates
- Interfaces (IRepository, etc), etc.
MyApp.ApplicationServices
- Commands
- Command Handlers, etc.
MyApp.Infrastructure
- Repository
- Emailer, etc.
MyApp.Web
- Startup
- MediatR NuGet packages and DI here
- UI, etc.
Run Code Online (Sandbox Code Playgroud)
我目前在UI项目中安装了MediatR和MediatR .net Core DI软件包,并使用.AddMediatR()将它们添加到DI中
services.AddMediatR(typeof(MyApp.AppServices.Commands.Command).Assembly);
Run Code Online (Sandbox Code Playgroud)
它从AppServices项目中扫描并注册命令处理程序.
当我想要定义一个事件时,就会出现问题.要使MediatR使用我的域事件,需要使用MediatR.INotification接口进行标记.
namespace ObApp.Domain.Events
{
public class NewUserAdded : INotification
{
...
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下标记我的事件的正确方法是什么,以便MediatR可以使用它们?我可以为事件创建自己的标记界面,但MediatR将无法识别那些没有某种方法自动将它们转换为MediatR.INotification的标记.
这只是使用多个项目的缺点吗?即使我使用的是单个项目,如果我在域部分中使用MediatR.INotification,我会在域中放置一个"外部"接口.
当我的用户实体从EF的IdentityUser继承时,我遇到了同样的问题.在这种情况下,网络共识似乎是务实的,并继续允许轻微的污染,以节省许多麻烦.这是另一个类似的案例吗?我不介意为了实用主义而牺牲纯洁,而不仅仅是为了懒惰.
这是我使用的其他软件包会出现的一个基本问题,所以我期待着解决这个问题.
谢谢!
如果您想让域层保持真正的纯粹,而不引用 MediatR,请在域层中为事件、中介器和处理程序创建您自己的接口。然后在基础设施或应用程序层中,创建包装类来包装 MediatR 并通过包装类传递调用。使用这种方法,您不需要从 MediatR 接口派生。确保也在 IoC 中注册包装器
这是一个例子:
在您的域层中:
public interface IDomainMediator
{
Task Publish<TNotification>(TNotification notification,
CancellationToken cancellationToken = default(CancellationToken))
where TNotification : IDomainNotification;
}
public interface IDomainNotification
{}
public interface IDomainNotificationHandler<in TNotification>
where TNotification : IDomainNotification
{
Task Handle(TNotification notification,
CancellationToken cancellationToken=default(CancellationToken));
}
Run Code Online (Sandbox Code Playgroud)
然后在您的基础设施或应用程序层中,无论您在哪里有 MediatR 包:
public class MediatRWrapper : IDomainMediator
{
private readonly MediatR.IMediator _mediator;
public MediatRWrapper(MediatR.IMediator mediator)
{
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
}
public Task Publish<TNotification>(TNotification notification,
CancellationToken cancellationToken = default(CancellationToken))
where TNotification : IDomainNotification
{
var notification2 = new NotificationWrapper<TNotification>(notification);
return _mediator.Publish(notification2, cancellationToken);
}
}
public class NotificationWrapper<T> : MediatR.INotification
{
public T Notification { get; }
public NotificationWrapper(T notification)
{
Notification = notification;
}
}
public class NotificationHandlerWrapper<T1, T2> : MediatR.INotificationHandler<T1>
where T1 : NotificationWrapper<T2>
where T2 : IDomainNotification
{
private readonly IEnumerable<IDomainNotificationHandler<T2>> _handlers;
//the IoC should inject all domain handlers here
public NotificationHandlerWrapper(
IEnumerable<IDomainNotificationHandler<T2>> handlers)
{
_handlers = handlers ?? throw new ArgumentNullException(nameof(handlers));
}
public Task Handle(T1 notification, CancellationToken cancellationToken)
{
var handlingTasks = _handlers.Select(h =>
h.Handle(notification.Notification, cancellationToken));
return Task.WhenAll(handlingTasks);
}
}
Run Code Online (Sandbox Code Playgroud)
我还没有用管道等对其进行测试,但它应该可以工作。干杯!
最好您的域层不依赖于任何基础结构,但是由于绑定而很难在CQRS中获得。我可以根据我的经验告诉你。但是,您可以最小化这种依赖性。一种方法是使自己的EventInterface扩展MediatR.INotification并在整个域代码中使用该接口。这样,如果您想更改基础架构,则只需在一个地方进行更改。
| 归档时间: |
|
| 查看次数: |
2489 次 |
| 最近记录: |