C# 包装Masstransit以实现CQRS是否是一种良好的做法?

C# 包装Masstransit以实现CQRS是否是一种良好的做法?,c#,message-queue,microservices,cqrs,masstransit,C#,Message Queue,Microservices,Cqrs,Masstransit,我希望有一个单独的CommandBus和EventBus以及ICommandHandler和IEventHandler,这样一个OrderEventHandler类看起来像: public class OrderEventHandler : IEventHandler<OrderPlaced>, IEventHandler<OrderRegistrantAssigned>, IEventHandler<OrderTotalsCalculate

我希望有一个单独的
CommandBus
EventBus
以及
ICommandHandler
IEventHandler
,这样一个
OrderEventHandler
类看起来像:

public class OrderEventHandler :
    IEventHandler<OrderPlaced>,
    IEventHandler<OrderRegistrantAssigned>,
    IEventHandler<OrderTotalsCalculated>,
    IEventHandler<OrderConfirmed>,
    IEventHandler<OrderExpired>,
    IEventHandler<SeatAssignmentsCreated>,
    IEventHandler<SeatAssigned>,
    IEventHandler<SeatAssignmentUpdated>,
    IEventHandler<SeatUnassigned>
{ 
    public void Handle(OrderPlaced @event){...}
    .
    .
    .
}
公共类OrderEventHandler: 伊文坦德勒, 伊文坦德勒, 伊文坦德勒, 伊文坦德勒, 伊文坦德勒, 伊文坦德勒, 伊文坦德勒, 伊文坦德勒, 伊文坦德勒 { 公共无效句柄(orderplacted@event){…} . . . } 一个可能的解决方案是在
Masstransit
基础设施和我的
CQR
之间提供一个采用者(比如
ConsumerToHandlerAdopter
,它只公开我通常需要的上下文细节)

但是,由于我是新来的
Masstransit
,我无法思考我以后可能要处理的问题

所以我的问题是:
包装Masstransit以便我处理自己的基础设施是否值得?

我们使用Masstransit广泛实施CRQ,但仅用于命令处理

我们多次讨论了不使用消息传递基础结构来同步写入和读取模型的原因。主要原因是,您有机会保持更改而不发布事件,因为这是两个不同的基础结构。除非使用DTC之类的工具,否则无法保证各型号之间的一致性

此外,在这一点上,我们也更愿意远离“godhandler”类。MassTransit特别擅长通过将每个消费者划分为单独的类别来实施SRP(单一责任原则)

对于一般的基于域事件的集成(反应式事件处理),我们还使用MassTransit

您还可以拥有实现多个消息接口的事件,这样您将拥有更全面的事件处理:

public interface CustomerRegistered
{
    string FullName { get; }
}

public interface OrderPlaced
{
    string Reference { get; }
    List<OrderLine> Lines { get; }
}

public class NewCustomerOrderedStuff : CustomerRegistered, OrderPlaced
{
...
}

public class CustomerRegisteredConsumer : IConsumer<CustomerRegistered>

public class OrderPlacedConsumer : IConsumer<OrderPlaced>
公共接口自定义注册
{
字符串全名{get;}
}
公共接口已放置
{
字符串引用{get;}
列出行{get;}
}
公共类NewCustomerOrderedStuff:CustomerRegistered,OrderPlaced
{
...
}
公共类CustomerRegisteredConsumer:IConsumer
公共类OrderPlacedConsumer:IConsumer

这些消费者中的每一个都有不同的关注点,可以生活在一个单独的有界上下文(服务)中。

非常感谢@Alexey Zimarev,我使用rabbitmq作为传输层。我的目标是在saga中表示我的聚合,每当它们变得一致时,就发布通过调用
aggregate.method()
返回的事件。我不需要在它们达到特定状态后使用聚合,所以我可以删除它们。我有几个项目使用sagas作为聚合。这工作得很好,但它没有单独的读写模型。同时,我为EventStore制作了一个saga持久性,通过使用它,我可以获得事件源saga,使用投影构建读取模型,这些投影通过EventStore追赶订阅连接。是的,在进行事件源时,拥有一个适当的事件存储非常重要。有些人用卡夫卡来达到这个目的,但对此众说纷纭。使用事件源时,发布事件的问题会变得更严重,因为如果来自其他上下文的投影和事件使用者正在侦听同一总线,则会关闭重播事件的选项。这是一种反应。这涉及将域事件转换为集成事件,并将其写入集成流或将这些事件发布到某个消息总线。反应器使用这些事件,并在其自身的有界上下文中生成必要的操作。你也可以称之为“反应性ACL”。是的,这是一个潜在的问题,对此我没有真正的答案。我的观察是RMQ非常可靠。如果更改以事务方式持久化,然后我们将事件发布到总线,那么我们可以非常肯定(尽管不是100%)它发生了。我们运行RMQ多年,每天处理数百万条消息,从未遇到任何问题。这可能是一个网络问题,但在这种情况下,持久性也不起作用,除非它们位于完全不同的网络中。您是否使用消息队列/总线来同步读模型和写模型?你能看看我的问题吗+1.鲍勃叔叔:不要嫁给框架!哦,你可以使用这个框架——只是不要和它耦合。保持一定的距离。将框架视为属于体系结构外围之一的细节。不要让它进入内部圈子。