正如其他人所提到的,共识似乎是 wrap MediatR.INotification
。我发现这篇 2020 年的帖子非常有用。
我们确实必须处理我们的领域事件不是有效的 MediatR INotification 的小问题。我们将通过创建一个通用的 INotification 来包装我们的领域事件来克服这个问题。
创建自定义通用 INotification。
using System;
using MediatR;
using DomainEventsMediatR.Domain;
namespace DomainEventsMediatR.Application
{
public class DomainEventNotification<TDomainEvent> : INotification where TDomainEvent : IDomainEvent
{
public TDomainEvent DomainEvent { get; }
public DomainEventNotification(TDomainEvent domainEvent)
{
DomainEvent = domainEvent;
}
}
}
创建一个 Dispatcher,在 MediatR 通知中包装域事件并发布它们:
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using MediatR;
using DomainEventsMediatR.Domain;
namespace DomainEventsMediatR.Application
{
public class MediatrDomainEventDispatcher : IDomainEventDispatcher
{
private readonly IMediator _mediator;
private readonly ILogger<MediatrDomainEventDispatcher> _log;
public MediatrDomainEventDispatcher(IMediator mediator, ILogger<MediatrDomainEventDispatcher> log)
{
_mediator = mediator;
_log = log;
}
public async Task Dispatch(IDomainEvent devent)
{
var domainEventNotification = _createDomainEventNotification(devent);
_log.LogDebug("Dispatching Domain Event as MediatR notification. EventType: {eventType}", devent.GetType());
await _mediator.Publish(domainEventNotification);
}
private INotification _createDomainEventNotification(IDomainEvent domainEvent)
{
var genericDispatcherType = typeof(DomainEventNotification<>).MakeGenericType(domainEvent.GetType());
return (INotification)Activator.CreateInstance(genericDispatcherType, domainEvent);
}
}
}
微软的方法
请注意,在其CQRS 完整示例中,Microsoft建议在域实体中简单地引用 MediatR 接口:
在 C# 中,域事件只是一个数据保存结构或类,如 DTO,其中包含与域中刚刚发生的事情相关的所有信息,如下例所示:
public class OrderStartedDomainEvent : INotification
{
public string UserId { get; }
public string UserName { get; }
public int CardTypeId { get; }
public string CardNumber { get; }
public string CardSecurityNumber { get; }
public string CardHolderName { get; }
public DateTime CardExpiration { get; }
public Order Order { get; }
public OrderStartedDomainEvent(Order order, string userId, string userName,
int cardTypeId, string cardNumber,
string cardSecurityNumber, string cardHolderName,
DateTime cardExpiration)
{
Order = order;
UserId = userId;
UserName = userName;
CardTypeId = cardTypeId;
CardNumber = cardNumber;
CardSecurityNumber = cardSecurityNumber;
CardHolderName = cardHolderName;
CardExpiration = cardExpiration;
}
}
首先,您将实体中发生的事件添加到每个实体的事件集合或列表中。该列表应该是实体对象的一部分,或者更好的是,您的基实体类的一部分,如以下 Entity 基类示例所示:
public abstract class Entity
{
//...
private List<INotification> _domainEvents;
public List<INotification> DomainEvents => _domainEvents;
public void AddDomainEvent(INotification eventItem)
{
_domainEvents = _domainEvents ?? new List<INotification>();
_domainEvents.Add(eventItem);
}
public void RemoveDomainEvent(INotification eventItem)
{
_domainEvents?.Remove(eventItem);
}
//... Additional code
}