目录
1.定义领域事件接口
public interface IDomainEvent:INotification
{
}
其中INotification来自MediatR:
namespace MediatR
{
//
// 摘要:
// Marker interface to represent a notification
public interface INotification
{
}
}
所有的领域事件都应该集成该接口。
2.领域事件处理接口
public interface IDomainEventHandler<TDomainEvent>:INotificationHandler<TDomainEvent>
where TDomainEvent:IDomainEvent
{
//这里我们使用了INotificationHandler的Handle方法来作为处理方法的定义
//Task Handle(TDomainEvent domainEvent, CancellationToken cancellationToken);
}
领域事件处理接口是泛型接口,其实例化成员只能处理特定的领域事件。因为基类接口有Handler方法,所有不用再重复定义。
3.领域事件在实体的处理
领域事件是为实体服务的,所以实体里面要有领域事件的处理办法。在抽象类Entity表示如下:
#region
private List<IDomainEvent> _domainEvents=new List<IDomainEvent>();
public IReadOnlyCollection<IDomainEvent> DomainEvents => _domainEvents?.AsReadOnly();
public void AddDomainEvent(IDomainEvent eventItem)
{
_domainEvents = _domainEvents ?? new List<IDomainEvent>();
_domainEvents.Add(eventItem);
}
public void RemoveDomainEvent(IDomainEvent eventItem)
{
_domainEvents?.Remove(eventItem);
}
public void ClearDomainEvents()
{
_domainEvents?.Clear();
}
#endregion
主要是定义了一个领域事件List,并配有三个方法来管理这个集合。
当我们通过 仓储保存实体时:
public class EFContext:DbContext, IUnitOfWork,ITransaction
{
....
public async Task<bool> SaveEntitiesAsync(CancellationToken cancellationToken = default)
{
var result = await base.SaveChangesAsync(cancellationToken);
await _mediator.DispatchDomainEventsAsync(this);
return true;
}
}
会调用DispatchDomainEventAsync,重点关注这个函数:
public static class MediatorExtension
{
public static async Task DispatchDomainEventsAsync(this IMediator mediator, DbContext ctx)
{
var domainEntities = ctx.ChangeTracker
.Entries<Entity>()
.Where(x => x.Entity.DomainEvents != null && x.Entity.DomainEvents.Any());
var domainEvents = domainEntities
.SelectMany(x => x.Entity.DomainEvents)
.ToList();
domainEntities.ToList()
.ForEach(entity => entity.Entity.ClearDomainEvents());
foreach (var domainEvent in domainEvents)
await mediator.Publish(domainEvent);
}
}
这是一个扩展方法,获取所有跟踪的实体对象,然后将所有的实体对象放入list,放入后先清楚原来实体中的领域事件,然后发送出去。这样就会被响应。也就是,在保存实体的时候才会触发事件响应。
4.小结
1.由领域模型内部创建领域事件
2.由专有的领域事件处理类来处理领域事件
3.根据实际情况来决定是否在同一事务中处理