Web开发:使用MediatR包实现中介者模式,避免组件之间直接通信

文章目录

一、简介

MediatR 基于中介者模式,是轻量消息中介库,适配 CQRS:拆分 Command(写)/Query(读),通过 Handler 解耦业务逻辑,无需组件直接通信。

二、Program主程序

csharp 复制代码
using WebApplication2.BLL;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();

// 注册 MediatR(核心)
builder.Services.AddMediatR(cfg =>
{
    cfg.RegisterServicesFromAssembly(typeof(Program).Assembly);
});

// 添加 Swagger/OpenAPI 服务(核心配置)
//builder.Services.AddEndpointsApiExplorer(); // 启用端点探索
builder.Services.AddSwaggerGen(options =>
{
    // 可选:配置 Swagger 文档信息(标题、版本、描述)
    options.SwaggerDoc("v1", new Microsoft.OpenApi.OpenApiInfo
    {
        Title = "MediatR WebAPI Demo",
        Version = "v1",
        Description = "集成 MediatR + Swagger 的 WebAPI 示例"
    });
});

var app = builder.Build();

// 配置 Swagger 中间件(开发环境启用,生产环境可关闭)
if (app.Environment.IsDevelopment())
{
    // 启用 Swagger UI
    app.UseSwagger();
    // 配置 Swagger UI 访问路径(默认:/swagger)
    app.UseSwaggerUI(options =>
    {
        options.SwaggerEndpoint("/swagger/v1/swagger.json", "MediatR Demo API v1");
        // 可选:设置 Swagger UI 为默认首页
        options.RoutePrefix = string.Empty; // 访问根路径直接打开 Swagger
    });
}

app.UseAuthorization();

app.MapControllers();

app.Run();

三、两个模式的定义

请求 - 处理者:一对一,有返回值,用于核心业务逻辑;发布 - 订阅:一对多,无返回值,用于事件联动逻辑。

csharp 复制代码
namespace WebApplication2.BLL
{
    #region 请求-处理者模式入参、出参实体
	//入参:CreateOrderCommand,出参:CreateOrderResponse
    public class CreateOrderCommand : IRequest<CreateOrderResponse>
    {
        [Required(ErrorMessage = "订单编号不能为空")]
        public string OrderNo { get; set; } = string.Empty;

        [Range(0.01, int.MaxValue, ErrorMessage = "订单金额必须大于0")]
        public int Amount { get; set; }
    }

    // 出参:CreateOrderResponse
    public class CreateOrderResponse
    {
        public Guid OrderId { get; set; }
        public string OrderNo { get; set; } = string.Empty;
        public bool Success { get; set; }
    }
    #endregion

    #region 发布-订阅模式事件实体
    // 定义「事件」(发布-订阅,一对多)
    public class OrderCreatedEvent : INotification
    {
        public string OrderNo { get; set; } = string.Empty;
        public int Amount { get; set; }
    }
    #endregion

    #region 处理者
	// IRequestHandler内部写两个实体,一个是入参实体,一个是出参实体
    public class CreateOrderCommandHandler : IRequestHandler<CreateOrderCommand, CreateOrderResponse>
    {
        // Handle 方法:实现具体业务逻辑
        public async Task<CreateOrderResponse> Handle(CreateOrderCommand request, CancellationToken cancellationToken)
        {
            // 模拟业务逻辑:比如写入数据库、调用支付接口等
            Console.WriteLine("【1】开始创建订单:{0},金额:{1}", request.OrderNo, request.Amount);

            // 返回结果
            return new CreateOrderResponse
            {
                OrderId = Guid.NewGuid(),
                OrderNo = request.OrderNo,
                Success = true
            };
        }
    }
    #endregion

    #region 多个订阅者
    // 5. 订阅者1(监听 OrderCreatedEvent)
    public class OrderCreatedHandler1 : INotificationHandler<OrderCreatedEvent>
    {
        public async Task Handle(OrderCreatedEvent notification, CancellationToken cancellationToken)
        {
            Console.WriteLine("【订阅者1】处理订单后续逻辑:{0},金额:{1}", notification.OrderNo, notification.Amount);
            await Task.CompletedTask; // 模拟异步操作
        }
    }

    // 6. 订阅者2(监听 OrderCreatedEvent)
    public class OrderCreatedHandler2 : INotificationHandler<OrderCreatedEvent>
    {
        public async Task Handle(OrderCreatedEvent notification, CancellationToken cancellationToken)
        {
            Console.WriteLine("【订阅者2】处理订单后续逻辑:{0},金额:{1}", notification.OrderNo, notification.Amount);
            await Task.CompletedTask; // 模拟异步操作
        }
    }
    #endregion
}

四、高层服务(控制器)

csharp 复制代码
namespace WebApplication2.Controllers
{
    [Route("api/[controller]")]
    [ApiController] // 自动做模型验证
    public class OrdersController : ControllerBase
    {
        // 注入 IMediator(ASP.NET Core 自动管理)
        private readonly IMediator _mediator;

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

		//请求-处理者
        [Route(nameof(CreateOrder))]
        [HttpPost]
        public async Task<CreateOrderResponse> CreateOrder(CreateOrderCommand command)
        {
            var response = await _mediator.Send(command);
            return response;
        }

		//发布-订阅
        [Route(nameof(PublishOrder))]
        [HttpPost]
        public async Task<Task> PublishOrder(OrderCreatedEvent command)
        {
             await _mediator.Publish(new OrderCreatedEvent
            {
                OrderNo = command.OrderNo,
                Amount = command.Amount
            });
            return Task.CompletedTask;
        }
    }
}
相关推荐
索西引擎2 分钟前
【React】Immer.js 在现代 Redux 生态中的角色:不可变性保障的工程化实现与开发体验优化
前端·javascript·react.js
大卫陈14 分钟前
微信小程序虚拟支付实战:从「支付能力被限制」到沙箱调通的全过程
前端·后端
武子康14 分钟前
vLLM 0.25.1:服务没有报错,为什么仍会生成垃圾 Token(5 级正确性门禁 + 自动回滚条件)
前端·人工智能·后端
jyp2012110718 分钟前
Vue3 Diff 算法
前端·vue.js
胡萝卜术22 分钟前
抽象的三级跳:从原生 DOM 到 React 组件树,我们到底在解决什么问题?
前端·javascript·面试
黄敬峰25 分钟前
从零理解React:事件、组件与响应式——一个WebGPU Demo的前端笔记
前端·面试
weedsfly39 分钟前
从类继承到自定义 Hook:模板方法模式的前端演进
前端·javascript·面试
Quz40 分钟前
QML 线性布局:Row/RowLayout 与 Column/ColumnLayout
前端·qt
你为她披上外套时我正站在窗外44 分钟前
用 Rust + WebAssembly 写了个字幕工具,文件全程不离开浏览器
前端
帅帅哥的兜兜44 分钟前
AI模型初了解
前端