代码编织梦想


前言

1.什么是CQRS模式

CQRS 是一种与领域驱动设计 (DDD) 和事件溯源相关的架构模式,本质上是一种读写逻辑分离的机制。

CQRS可以有两种实现方式。

1、CQ两端数据库共享,只是在上层代码上分离。

这样做的好处是可以让我们的代码读写分离,更容易维护,而且不存在CQ两端的数据一致性问题, 因为是共享一个数据库的。

2、CQ两端不仅代码分离,数据库也分离,然后Q端数据由C端同步过来。

同步方式有两种:同步或异步,如果需要CQ两端的强一致性,则需要用同步;如果能接受CQ两端数据的最终一致性,则可以使用异步。

C端可以采用EventSourcing(简称ES)模式,所有C端的最新数据全部用DomainEvent表达即可。

而要查询显示用的数据,则从Q端的ReadDB(关系型数据库)查询即可。

在这里插入图片描述

2.中介者模式

中介者模式属于行为型模式,它包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用,从而使它们可以松散耦合。

当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用,保证这些作用可以彼此独立的变化。

具体二十三种设计模式可以查看这个专题:https://blog.csdn.net/aa2528877987/article/details/108290229

在这里插入图片描述

3.MediatR

MediatR是一个实现中介者模式的类库,可以帮我们轻松的实现CQRS 。

MediatR有两种功能,一种是单播消息传播(请求/响应消息),就是一对一消息传递,这个就比较适合CQRS模式;另一种是多播消息传递(发布通知),消息分发给多个应用,这种适用于消息订阅。下面简单介绍一下这两种方式的使用。

一、基于MediatR的CQRS模式

1.添加包

dotnet add package MediatR
dotnet add package MediatR.Extensions.Microsoft.DependencyInjection

在这里插入图片描述

2.MediatR单播消息模式使用

2.1 创建消息对象

1、请求对象

命令对象

//命令对象,也就是增加或者修改传入的模型,正常情况下可以增加验证的功能
//请求需要继承IRequest<ResponseModel>,泛型里面是相应类
public class MakeCustomerRequestModel : IRequest<MakeCustomerResponseModel>
{
    public Guid CustomerId { get; set; }
    public string CustomerName { get; set; }
    public Guid BlongId { get; set; }
    public int Quantity { get; set; }
    public double Amount { get; set; }
    public string Phone { get; set; }
    public DateTime CreatTime { get; set; }
}

在这里插入图片描述

查询对象

//查询对象,可以通过id等去查询
//请求需要继承IRequest<ResponseModel>,泛型里面是相应类
public class GetCustomerByIdRequestModel : IRequest<GetCustomerByIdResponseModel>
{
    public Guid CustomerId { get; set; }
}

在这里插入图片描述

2、响应对象

命令对象

//命令对象,返回主键ID,和是否查询成功
public class MakeCustomerResponseModel
{
    public bool IsSuccess { get; set; }
    public Guid CustomerId { get; set; }
}

在这里插入图片描述

查询对象

//查询对象,返回查询的数据,刚好与前面相反
public class GetCustomerByIdResponseModel
{
    public Guid CustomerId { get; set; }
    public string CustomerName { get; set; }
    public Guid BlongId { get; set; }
    public int Quantity { get; set; }
    public double Amount { get; set; }
    public string Phone { get; set; }
    public DateTime CreatTime { get; set; }
}

在这里插入图片描述

2.2 创建消息处理器Handlers

命令对象

//命令处理,需要继承IRequestHandler泛型,和实现Handle方法,如下
public class MakeCustomerCommandHandler : IRequestHandler<MakeCustomerRequestModel, MakeCustomerResponseModel>
{
    public Task<MakeCustomerResponseModel> Handle(MakeCustomerRequestModel request, CancellationToken cancellationToken)
    {
        var result = new MakeCustomerResponseModel
        {
            IsSuccess = true,
            CustomerId = new Guid("4ED8843E-7718-40D1-B8E0-B813FE4E0A68")
        };
        // 业务逻辑
        return Task.FromResult(result);
    }
}

在这里插入图片描述

查询对象

//命令处理,需要继承IRequestHandler泛型,和实现Handle方法,如下
public class GetCustomerByIdQueryHandlers : IRequestHandler<GetCustomerByIdRequestModel, GetCustomerByIdResponseModel>
{
    public Task<GetCustomerByIdResponseModel> Handle(GetCustomerByIdRequestModel request, CancellationToken cancellationToken)
    {
        var orderDetails = new GetCustomerByIdResponseModel();
        // 业务逻辑
        return Task.FromResult(orderDetails);
    }
}

在这里插入图片描述

2.3 注入使用

1、注入

#region 添加MediatR
builder.Services.AddMediatR(Assembly.GetExecutingAssembly());
#endregion

在这里插入图片描述
2、使用

[Route("[controller]/[action]")]
[ApiController]
public class CustomerController : ControllerBase
{
    private readonly IMediator _mediator;
    public CustomerController(IMediator mediator)
    {
        _mediator = mediator;
    }

    [HttpPost]
    public IActionResult MakeCustomer([FromBody] MakeCustomerRequestModel requestModel)
    {
        var response = _mediator.Send(requestModel).Result;
        return Ok(response);
    }

    [HttpGet]
    public IActionResult CustomerDetails(Guid id)
    {
        var response = _mediator.Send(new GetCustomerByIdRequestModel { CustomerId = id }).Result;
        return Ok(response);
    }
}

在这里插入图片描述
2、效果

命令对象
在这里插入图片描述
查询对象
在这里插入图片描述

3.MediatR多消息模式使用

3.1 创建消息对象

public class GeneralNotificationModel : INotification
{
    public string Title { get; set; }
    public string Content { get; set; }

    public GeneralNotificationModel(string title, string content)
    {
        Title = title;
        Content = content;
    }
}

3.2 创建消息处理器Handlers

public class GeneralNotificationHandler : INotificationHandler<GeneralNotificationModel>
{
    public Task Handle(GeneralNotificationModel notification, CancellationToken cancellationToken)
    {
        Console.WriteLine($"{notification.Title}:{notification.Content}");
        return Task.CompletedTask;
    }
}
public class LogHandler : INotificationHandler<GeneralNotificationModel>
{
    private readonly ILogger<LogHandler> _logger;

    public LogHandler(ILogger<LogHandler> logger)
    {
        _logger = logger;
    }

    public Task Handle(GeneralNotificationModel notification, CancellationToken cancellationToken)
    {
        _logger.LogInformation($"{notification.Title}:{notification.Content}");
        return Task.CompletedTask;
    }
}

3.3 注入使用

public class MakeOrderCommandHandler : IRequestHandler<MakeOrderRequestModel,MakeOrderResponseModel>
{
    private readonly IMediator _mediator;

    public MakeOrderCommandHandler(IMediator mediator)
    {
        _mediator = mediator;
    }

    public Task<MakeOrderResponseModel> Handle(MakeOrderRequestModel request, CancellationToken cancellationToken)
    {
        var result = new MakeOrderResponseModel
        {
            IsSuccess = true,
            OrderId = new Guid("53d26807-ad70-4449-8479-024c54eb2020")
        };
        //发布
        _mediator.Publish(new GeneralNotificationModel("已下单", result.OrderId.ToString()), cancellationToken);

        return Task.FromResult(result);
    }
}

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/aa2528877987/article/details/128748768

【愚公系列】2022年12月 .net core工具案例-爱代码爱编程

文章目录 前言1.事件总线概念2.发布-订阅概念 一、.NET Core使用事件总线(进程内事件总线)1.安装包2.基本使用 二、进阶用法(参数校验)1.安装nueget包2.注册管道3.自定义验证