Обложка канала

.NET Разработчик

Опытный разработчик не так давно зашёл в .Net и поставил цель получить сертификат Microsoft. Свой ежедневный прогресс он описывает на канале .Net Разработчик. Заметки об изученном материале, советы по повышению производительности и поддержке мотивации, ин

.NET Разработчик

3 года назад
Открыть в
День 1637. #DDD Использование Доменных Событий для Построения Слабосвязанных Систем. Окончание Начало Публикация с помощью EF Core Поскольку EF Core использует паттерн Единица Работы, вы можете использовать его для сбора всех доменных событий в текущей транзакции и их публикации. Можно либо переопределить метод SaveChangesAsync, либо использовать перехватчик:
public class ApplicationDbContext : DbContext
{
  public override async Task<int> SaveChangesAsync(
    CancellationToken ct = default)
  {
    var result = await 
     base.SaveChangesAsync(ct);

    await PublishDomainEventsAsync();

    return result;
  }
}

Важное решение: публиковать доменные события до или после вызова SaveChangesAsync (сохранения данных в БД)? До: - события являются частью той же транзакции, - немедленная согласованность данных. После: - события – отдельная транзакция, - конечная согласованность, т.к. сообщения обрабатываются после исходной транзакции, - риск несогласованности БД, т.к. обработка события может привести к сбою. Можно решить эту проблему с помощью паттерна исходящих сообщений (Outbox), когда изменения в БД и изменения, сделанные в доменном событии сохраняются (в виде исходящих сообщений) в одной транзакции. Метода PublishDomainEventsAsync:
private async Task PublishDomainEventsAsync()
{
  var events = ChangeTracker
   .Entries<Entity>()
   .Select(e => e.Entity)
   .SelectMany(ent =>
   {
     var evnts = ent.GetDomainEvents();
     ent.ClearDomainEvents();
     return evnts;
   })
   .ToList();

   foreach (var ev in events)
     await _mediator.Publish(ev);
}

Обработка Нужно определить класс, реализующий INotificationHandler<T>, где T – тип доменного события. Обработчик доменного события CourseCompleted ниже публикует CourseCompletedIntegrationEvent для уведомления других систем.
public class CourseCompletedDomainEventHandler
 : INotificationHandler<CourseCompleted>
{
  private readonly IBus _bus;

  public CourseCompletedDomainEventHandler(IBus bus)
  {
    _bus = bus;
  }

  public async Task Handle(
   CourseCompleted de,
   CancellationToken ct)
  {
    await _bus.Publish(
     new CourseCompletedIntegrationEvent(de.CourseId),
     ct);
  }
}

Итого - Доменные события могут помочь построить слабосвязанную систему, отделяя основную логику домена от побочных эффектов, которые можно обрабатывать асинхронно. - Для реализации доменных событий, можно использовать библиотеки EF Core и MediatR. - Нужно решить, когда публиковать доменные события: до или после сохранения изменений в БД. - Публикация доменных событий после сохранения изменений в БД и паттерн Outbox для добавления транзакционных гарантий обеспечивают окончательную согласованность, но также бОльшую надёжность. Источник: https://www.milanjovanovic.tech/blog/using-domain-events-to-build-loosely-coupled-systems