首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >DDD:从域项目引用MediatR接口

DDD:从域项目引用MediatR接口
EN

Stack Overflow用户
提问于 2017-11-14 18:33:17
回答 6查看 8.6K关注 0票数 12

我才刚开始用DDD。我正在将域事件放入CQRS应用程序中,我遇到了一个基本任务:如何在域项目中使用MediatR.INotification标记接口而不创建域依赖于基础设施。

我的解决方案分为以下四个项目:

代码语言:javascript
复制
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.

我目前在UI项目中安装了MediatR和MediatR .net核心DI包,它们使用.AddMediatR()与命令一起添加到DI中。

代码语言:javascript
复制
services.AddMediatR(typeof(MyApp.AppServices.Commands.Command).Assembly);

它从AppServices项目中扫描和注册命令处理程序。

当我想要定义一个事件时,问题就出现了。要让MediatR处理我的域事件,需要用MediatR.INotification接口标记它们。

代码语言:javascript
复制
namespace ObApp.Domain.Events
{
    public class NewUserAdded : INotification
    {
        ...
    }

在这种情况下,如何正确地标记我的事件,以便MediatR可以使用它们?我可以为事件创建自己的标记界面,但是如果没有自动将它们转换为MediatR的方法,MediatR.INotification将无法识别这些事件。

这仅仅是使用多个项目的缺点吗?即使我使用的是单个项目,如果我在域中使用MediatR.INotification,也会在域中放置一个“外部”接口。

当我的用户实体继承自EF的IdentityUser时,我遇到了同样的问题。在这种情况下,网络的共识似乎是务实的,继续前进,让轻微的污染,以节省很多头痛。这又是一个类似的案子吗?我不介意为了实用主义而牺牲纯洁,但不只是为了懒惰。

这是我使用的其他包都会出现的一个基本问题,所以我期待着解决这个问题。

谢谢!

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2017-11-14 20:29:44

最好您的域层不依赖于任何基础设施,但这在CQRS中是很难获得的,因为绑定。根据我的经验我可以告诉你。但是,您可以将这种依赖性降到最低。这样做的一种方法是创建您自己的EventInterface,它扩展了MediatR.INotification,并在整个域代码中使用该接口。这样,如果您想要更改基础结构,您只需要在一个地方进行更改。

票数 11
EN

Stack Overflow用户

发布于 2018-03-12 08:39:23

如果您想要保持域层真正的纯净,而不需要引用MediatR,请为域层中的事件、中介和处理程序创建您自己的接口。然后在基础结构或应用程序层中,创建包装类来包装MediatR并通过包装类传递调用。使用这种方法,您将不需要从MediatR接口派生。确保在您的IoC中也注册包装

下面是一个例子:

在您的域层中:

代码语言:javascript
复制
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));
}

然后,在您的基础结构或应用程序层中,无论哪里有MediatR包:

代码语言:javascript
复制
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);
    }
}

我还没有用管道等测试过它,但它应该能用。干杯!

票数 5
EN

Stack Overflow用户

发布于 2017-11-15 05:43:23

首先尝试在域层中不存在基础设施依赖将是头等大事。

我不知道MediatR,但根据您的描述,它需要在将要在该空间中使用的类上实现一个接口。

创建一个驻留在域之外的包装类可能是一种选择吗?

代码语言:javascript
复制
public class MediatRNotification<T> : INotification
{
    T Instance { get; }

    public MediatRNotification(T instance)
    {
        Instance = instance;
    }
}

您的基础结构甚至可以使用一些反射来从域事件创建这个包装器。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47292941

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档