在閱讀本文章以前,你能夠先閱讀:數據庫
領域事件是在領域中發生的事,你但願同一個領域(進程)的其餘部分了解它。 通知部分一般以某種方式對事件做出反應。框架
重點強調領域事件發佈/訂閱是使用 MediatR 同步實現的。dom
首先,定義待辦事項已更新的領域事件this
public class TodoUpdatedDomainEvent : INotification { public Todo Todo { get; } public TodoUpdatedDomainEvent(Todo todo) { Todo = todo; } }
而後,引起領域事件,將域事件添加到集合,而後在提交事務以前或以後當即調度這些域事件,而不是當即調度到域事件處理程序 。spa
public abstract class Entity { //... private List<INotification> domainEvents; public IReadOnlyCollection<INotification> DomainEvents => domainEvents?.AsReadOnly(); public void AddDomainEvent(INotification eventItem) { domainEvents = domainEvents ?? new List<INotification>(); domainEvents.Add(eventItem); } public void RemoveDomainEvent(INotification eventItem) { domainEvents?.Remove(eventItem); } public void ClearDomainEvents() { domainEvents?.Clear(); } //... 其餘代碼 }
要引起事件時,只需將其在聚合根實體的方法處添加到代碼中的事件集合。設計
public class Todo : AggregateRoot { //... public void Update( string name) { Name = name; AddDomainEvent(new TodoUpdatedDomainEvent(this)); } //... 其餘代碼 }
請注意 AddDomainEvent 方法的惟一功能是將事件添加到列表。 還沒有調度任何事件,還沒有調用任何事件處理程序。你須要在稍後將事務提交到數據庫時調度事件。code
public class Repository : IDisposable, IRepository { //... private readonly IMediator mediator; private readonly DbContext context; public Repository(DbContext context, IMediator mediator) { this.context = context ?? throw new ArgumentNullException(nameof(context)); this.mediator = mediator ?? throw new ArgumentNullException(nameof(mediator)); } public void Save() { mediator.DispatchDomainEvents(context); context.SaveChanges(); } public static void DispatchDomainEvents(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) mediator.Publish(domainEvent); } //... 其餘代碼 }
最後,訂閱並處理領域事件對象
public class TodoUpdatedDomainEventHandler : INotificationHandler<TodoUpdatedDomainEvent> { private readonly ILoggerFactory logger; public TodoUpdatedDomainEventHandler(ILoggerFactory logger) { this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); } public Task Handle(TodoUpdatedDomainEvent todoUpdatedDomainEvent, CancellationToken cancellationToken) { logger.CreateLogger<TodoUpdatedDomainEvent>().LogDebug("Todo with Id: {TodoId} has been successfully updated", todoUpdatedDomainEvent.Todo.Id); return Task.CompletedTask; } }