源码及系列文章目录
Git 源码 :https://github.com/tangsong1995/TS.Microservices
CSDN 资源 :https://download.csdn.net/download/qq_33649351/34675095
系列文章目录 :https://blog.csdn.net/qq_33649351/article/details/120998558
使用 MediatR 实现 CQRS
MediatR:.NET中的简单中介者模式实现,一种进程内消息传递机制(无其他外部依赖)。 支持以同步或异步的形式进行请求/响应,命令,查询,通知和事件的消息传递,并通过C#泛型支持消息的智能调度。
CQRS:命令查询职责分离模式,将查询与命令(增、删、改)分离。
MediatR 核心对象
- IMediator
- IRequest、 IRequest<T>
- IRequestHandler<in TRequest, TResponse>
- INotificationHandler<in TNotification>
IMediator:负责Send和Publish。
IRequest:定义入参出参。
IRequestHandler:负责处理命令。
INotificationHandler:负责处理命令。
IMediator 有两个方法 Send 和 Publish ,Send是1:1,只能发送一个命令对象,后面的后覆盖前面的。Publish是1:*,只要实现了INotificationHandler接口的类都能接受到消息。
MediatR 实现 CQRS
继承 IRequest 定义入参出参:
class MyCommand : IRequest<long>
{
public string CommandName { get; set; }
}
继承 IRequestHandler 创建处理程序:
class MyCommandHandler : IRequestHandler<MyCommand, long>
{
public Task<long> Handle(MyCommand request, CancellationToken cancellationToken)
{
Console.WriteLine($"MyCommandHandler执行命令:{request.CommandName}");
return Task.FromResult(10L);
}
}
引用包 MediatR.Extensions.Microsoft.DependencyInjection ,注册 MediatR :
services.AddMediatR(typeof(Program).Assembly);
使用:
await mediator.Send(new MyCommand { CommandName = "cmd" });
使用 MediatR 处理领域事件
在 EFContext 定义领域事件的发送:
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);
}
public class EFContext : DbContext, IUnitOfWork, ITransaction
{
protected IMediator _mediator;
public EFContext(DbContextOptions options, IMediator mediator) : base(options)
{
_mediator = mediator;
}
#region IUnitOfWork
public async Task<bool> SaveEntitiesAsync(CancellationToken cancellationToken = default)
{
var result = await base.SaveChangesAsync(cancellationToken);
//实现领域事件的发送
await _mediator.DispatchDomainEventsAsync(this);
return true;
}
}
定义领域事件 Handler :
public interface IDomainEventHandler<TDomainEvent> : INotificationHandler<TDomainEvent>
where TDomainEvent : IDomainEvent
{
}
public class OrderCreatedDomainEventHandler : IDomainEventHandler<OrderCreatedDomainEvent>
{
ICapPublisher _capPublisher;
public OrderCreatedDomainEventHandler(ICapPublisher capPublisher)
{
_capPublisher = capPublisher;
}
public async Task Handle(OrderCreatedDomainEvent notification, CancellationToken cancellationToken)
{
await _capPublisher.PublishAsync("OrderCreated", new OrderCreatedIntegrationEvent(notification.Order.Id));
}
}
使用 IPipelineBehavior 实现配置请求管道进行消息处理(需要注意的是:IPipeLineBehavior只能用于处理IRequestHandler,不能用于处理INotificationHandler):
public class TransactionBehavior<TDbContext, TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TDbContext : EFContext
{
ILogger _logger;
TDbContext _dbContext;
ICapPublisher _capBus;
public TransactionBehavior(TDbContext dbContext, ILogger logger, ICapPublisher capBus)
{
_dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_capBus = capBus ?? throw new ArgumentNullException(nameof(capBus));
}
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
var response = default(TResponse);
var typeName = request.GetGenericTypeName();
try
{
if (_dbContext.HasActiveTransaction)
{
return await next();
}
// 定义数据路操作执行的策略
var strategy = _dbContext.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
Guid transactionId;
using (var transaction = await _dbContext.BeginTransactionAsync(_capBus))
using (_logger.BeginScope("TransactionContext:{TransactionId}", transaction.TransactionId))
{
_logger.LogInformation("----- 开始事务 {TransactionId} ({@Command})", transaction.TransactionId, typeName, request);
response = await next();
_logger.LogInformation("----- 提交事务 {TransactionId} {CommandName}", transaction.TransactionId, typeName);
await _dbContext.CommitTransactionAsync(transaction);
transactionId = transaction.TransactionId;
}
});
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "处理事务出错 {CommandName} ({@Command})", typeName, request);
throw;
}
}
}
public class OrderingContextTransactionBehavior<TRequest, TResponse> : TransactionBehavior<OrderingContext, TRequest, TResponse>
{
public OrderingContextTransactionBehavior(OrderingContext dbContext, ILogger<OrderingContextTransactionBehavior<TRequest, TResponse>> logger, ICapPublisher capBus) : base(dbContext, logger,capBus)
{
}
}
注册:
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(OrderingContextTransactionBehavior<,>));
services.AddMediatR(typeof(Order).Assembly, typeof(Program).Assembly);