.Net Core 微服务实战 - MediatR

源码及系列文章目录

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);
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值