域对象不应该有任何依赖项,因此也没有依赖项注入。但是,当从域对象内调度域事件时,我可能希望使用集中的EventDispatcher
. 我怎么能抓住一个?
我不想将事件列表返回给调用者,因为我希望它们保持不透明并保证它们的调度。这些事件应该只被需要强制执行最终一致约束的其他域对象和服务使用。
我正忙着在最近的一个项目中实现事件.
我已经验证了structuremap正在扫描正确的汇编和添加EventHandler
Scan(cfg =>
{
cfg.TheCallingAssembly();
cfg.IncludeNamespace("ABC.EventHandler");
cfg.ConnectImplementationsToTypesClosing(typeof(IHandle<>));
});
public class StructureMapEventDispatcher : IEventDispatcher
{
public void Dispatch<TEvent>(TEvent eventToDispatch) where TEvent : IDomainEvent
{
foreach (var handler in ObjectFactory.GetAllInstances<IHandle<TEvent>>())
{
handler.Handle(eventToDispatch);
}
}
}
Run Code Online (Sandbox Code Playgroud)
之前我曾经从域中触发事件.有点像Dispatcher.RaiseEvent(new [domainEvent class](x,y,z));
而事件将被激起.我不得不改变设计,我现在收集集合中的collectiong事件
_domainEvents = new Collection<IDomainEvent>();
Run Code Online (Sandbox Code Playgroud)
我将域保存到存储库后再将其提升
public static void Raise(ICollection<IDomainEvent> domainEvents)
{
foreach (var domainEvent in domainEvents)
{
DomainEventDispatcher.Raise(domainEvent);
}
}
Run Code Online (Sandbox Code Playgroud)
但现在
ObjectFactory.GetAllInstances<IHandle<TEvent>>()
返回0个处理程序计数
如果我注意的话
ObjectFactory.GetAllInstances<IHandle<DomainEventClass>>()
它正确返回处理程序集合(目前我有2个,它显示2个计数)
...我假设这与事件被提出类型IDomainEvent
而不是实际类型有关,这使得结构图很难解决它.
我该如何解决这个问题?
问候,
三月
-
编辑1:
我已经确定struturemap容器包含从程序集扫描的所有事件处理程序.
编辑2
我不知道如何让这个问题引起更多关注.我正在为获得所需结果的解决方案添加赏金.如果问题不明确,请询问.
基本上我想ObjectFactory.GetAllInstances<IHandle<TEvent>>()
返回处理程序TEvent …
嗨,我有以下senario,我不明白如何获得最终的一致性:
如果我们在事件中传递聚合的版本,那么在13中会出现乐观的并发错误吗?
如果是,则将消息1新应用于其他上下文中的对象.我们如何保持一致性?
这是阻止我在我的域中应用事件的问题.欢迎所有帮助.
基本思想是在另一个上下文中更新另一个聚合.我只是坚持这个并发技术.
我们不是在命令处理程序和命令推送总线的意义上使用事件源或CQRS.只有事件处理我们想要异步发生,因为我们有一个我们不希望改变的现有设计.
布莱尔
domain-driven-design event-handling eventual-consistency optimistic-locking domain-events
我想在我的项目中使用CQRS模式的元素.我想知道我是否使用Command and Events做得对.我不确定的是事件是否可以调用命令.为了更好地展示我想做什么,我将使用图表和示例.
这是一个例子:
用户调用TripCreateCommand.TripCreateCommandHandler完成他的工作,并在成功发布TripCreatedEvent之后.
现在我们有两个TripCreatedEvent监听器(监听器执行顺序无关紧要)
第一个监听器(可以在第二个监听器之后执行):
对于trip.author.friends中的每个用户调用两个命令(命令的顺序很重要)
第二个监听器(可以在第一个监听器之前执行):
这是示例图:
这是一个好方法吗?EventListener可以调用Command,或者我应该以其他方式执行它吗?
我已经按照Udi Dahan 的领域事件 - 救赎文章中的规定实现了领域事件。
据我了解,域事件可以异步运行到引发它的线程(通常来自域模型或服务)。
不需要任何类型的“共享”工作单元或存储库实现,也不需要事务一致性。
问:为什么 Udi 没有在单独的线程中实现领域事件的处理?
例如,我添加了 a 的创建Task
来异步处理事件:
public static void Raise<T>(T domainEvent) where T : IDomainEvent
{
if (Container != null)
{
foreach (var handler in Container.ResolveAll<IDomainEventHandler<T>>())
{
Task.Factory.StartNew(() =>
{
handler.Handle(domainEvent);
}).ContinueWith(t => {
// Log exception
}, TaskContinuationOptions.OnlyOnFaulted);
}
}
}
Run Code Online (Sandbox Code Playgroud)
由此可能产生任何多线程问题吗?
编辑: 请注意,虽然这些域事件是轻量级的,但它们仍将在 IIS 上运行,因为这是一个 MVC Web 项目。
multithreading domain-driven-design dependency-injection onion-architecture domain-events
我正在研究领域事件,特别是有两种可能性:
A.使用这样的"通用"事件:
public class OrderStateChangedEvent : IEvent
{
public Guid OrderId { get; }
public OrderState NewState { get; }
}
Run Code Online (Sandbox Code Playgroud)
那么消费者就会想出新的状态并做点什么.由于我使用的是Rx,这并不是那么难(并且比开关/情况更好):
var subscription = DomainEvents
.AsObservable<OrderStateChangedEvent>()
.Where(e => e.NewState == OrderState.OrderCompleted)
.Subscribe(OnOrderCompleted);
Run Code Online (Sandbox Code Playgroud)
B.使用特定事件:
public class OrderCompletedEvent : IEvent
{
public Guid OrderId { get; }
}
Run Code Online (Sandbox Code Playgroud)
这会导致更多的事件类,一方面可能会得到太多,另一方面事件类名称包含语言,这可能是一个加分点.
你有什么建议?我对域事件没有经验,也不能在这里做出合格的决定(两者似乎没有任何重大缺点)
I am trying to further my understanding of DDD. More specifically, how to handle domain events via a message bus for asynchronous processing.
Lets say I have some architecture ->
_____________________
| |
| Client |
|_____________________|
|
__________|__________
| |
| Application Service |
|_____________________|
|
__________|__________
| |
| Domain |
|_____________________|
Run Code Online (Sandbox Code Playgroud)
When my domain raises some domain event, how do I get that event to a messaging service such as RabbitMQ?
My first thought is to inject …
在 DDD 文献中,返回域事件模式被描述为管理域事件的一种方式。从概念上讲,聚合根保留了一个域事件列表,当您对其进行某些操作时会填充该列表。
当对聚合根的操作完成后,DB 事务在应用服务层完成,然后应用服务对域事件进行迭代,调用事件调度器来处理这些消息。
我的问题是关于我们现在应该如何处理交易。Event Dispatcher 是否应该负责为它处理的每个事件管理一个新事务?或者应用程序服务应该在它调用域事件调度器的域事件迭代中管理事务?当调度程序使用像 RabbitMQ 这样的基础设施机制时,问题是无关紧要的,但是当域事件在进程中处理时,问题就无关紧要了。
与我的问题相关的子问题。您对使用 ORM 钩子(即:NHibernate 的 IPostInsertEventListener、IPostDeleteEventListener、IPostUpdateEventListener)在聚合根上启动域事件迭代而不是在应用程序服务中手动执行此操作有何看法?它是否增加了太多的耦合?是否更好,因为它不需要在每个用例中编写相同的代码(域事件在聚合上循环,如果它不在调度程序内部,则可能创建新事务)?
我想澄清一下在实现 DDD(领域驱动设计)的 EDA 系统(具有事件驱动架构的系统)中实现不同类型事件的方式。假设我们没有使用事件溯源。
更具体地说,阅读相关文章后,似乎有 3 种事件:
"type": "paycheck-generated",
"event-id": "537ec7c2-d1a1-2005-8654-96aee1116b72",
"delivery-id": "05011927-a328-4860-a106-737b2929db4e",
"timestamp": 1615726445,
"payload": {
"employee-id": "456123",
"link": "/paychecks/456123/2021/01" }
}
Run Code Online (Sandbox Code Playgroud)
{
"type": "customer-updated",
"event-id": "6b7ce6c6-8587-4e4f-924a-cec028000ce6",
"customer-id": "01b18d56-b79a-4873-ac99-3d9f767dbe61",
"timestamp": 1615728520,
"payload": {
"first-name": "Carolyn",
"last-name": "Hayes",
"phone": "555-1022",
"status": "follow-up-set",
"follow-up-date": "2021/05/08",
"birthday": "1982/04/05",
"version": 7
}
}
Run Code Online (Sandbox Code Playgroud)
{
"type": "customer-updated",
"event-id": "6b7ce6c6-8587-4e4f-924a-cec028000ce6",
"customer-id": "01b18d56-b79a-4873-ac99-3d9f767dbe61",
"timestamp": 1615728520,
"payload": {
"status": "follow-up-set",
"follow-up-date": "2021/05/10",
"version": 8
}
}
Run Code Online (Sandbox Code Playgroud)
上面的每个示例都来自 Khononov 的书(学习领域驱动设计:调整软件架构和业务策略)
说了前面的陈述,我想澄清以下问题:
(1)与其他有界上下文通信时,事件携带状态转移 …
architecture events domain-driven-design event-driven domain-events
我在这里提出一个问题:为多个订阅者提升域事件,答案让我得到以下模式,我可以像这样拥有一个IEventPublisher:
public interface IEventPublisher<T>
{
void Publish(T data);
}
Run Code Online (Sandbox Code Playgroud)
和像这样的IEventSubscriber:
public interface IEventSubscriber<T>
{
void Handle(T data);
}
Run Code Online (Sandbox Code Playgroud)
这个问题是我需要将每个发布者的实例传递给构造函数,如下所示:
public Service(IEventPublisher<ThingyChangedEvent> publisherThingyChanged)
{
// Set publisher to local variable
}
// then call this in a method
_publisherThingyChanged.Publish(new ThingyChangedEvent { ThingyId = model.Id});
Run Code Online (Sandbox Code Playgroud)
理想情况下,我希望能够拥有一个包含任何IEventPublishers的通用发布者,所以我可以调用类似的东西:
_genericPublisher.Publish(new ThingyChangedEvent { ThingyId = model.Id});
Run Code Online (Sandbox Code Playgroud)
我无法弄清楚如何做到这一点,因为我无法传递IEventPublisher的集合而没有像在ThingyChangedEvent中那样定义T,而我想要的是根据传递给通用发布者的类型来确定发布者.
任何建议非常感谢.
编辑:
好的,使用下面的答案和来自这里的一些信息:http://www.udidahan.com/2009/06/14/domain-events-salvation/我想出了以下内容,但它并不完全存在:
public interface IEventManager
{
void Publish<T>(T args) where T : IEvent;
}
Run Code Online (Sandbox Code Playgroud)
public class EventManager:IEventManager {Autofac.ILifetimeScope _container;
public EventManager(Autofac.ILifetimeScope container) …
Run Code Online (Sandbox Code Playgroud) domain-events ×10
c# ×3
architecture ×1
cqrs ×1
event-driven ×1
events ×1
generics ×1
structuremap ×1