与 ASP.NET Core 深度集成
🌐 在 Web 应用中充分发挥 MediatR 的优势
📖 概述
ASP.NET Core 是 MediatR 最主要的应用场景。本章讲解如何在 Web API、MVC、Razor Pages 等应用中深度集成 MediatR。
🔧 自动扫描与注册
基础配置
csharp
// Program.cs
var builder = WebApplication.CreateBuilder(args);
// 添加控制器支持
builder.Services.AddControllers();
// 注册 MediatR(自动扫描当前程序集)
builder.Services.AddMediatR(cfg =>
cfg.RegisterServicesFromAssembly(typeof(Program).Assembly));
var app = builder.Build();
app.MapControllers();
app.Run();多程序集扫描
csharp
builder.Services.AddMediatR(cfg => {
// 扫描多个程序集
cfg.RegisterServicesFromAssembly(typeof(Program).Assembly);
cfg.RegisterServicesFromAssembly(typeof(SharedLibraryMarker).Assembly);
cfg.RegisterServicesFromAssembly(typeof(OrderHandlersMarker).Assembly);
});自定义服务生命周期
csharp
builder.Services.AddMediatR(cfg => {
cfg.RegisterServicesFromAssembly(typeof(Program).Assembly);
cfg.Lifetime = ServiceLifetime.Scoped; // 默认 Transient
});🎮 在控制器中使用 IMediator
RESTful API
csharp
[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
private readonly IMediator _mediator;
public OrdersController(IMediator mediator)
{
_mediator = mediator;
}
// GET: api/orders/{id}
[HttpGet("{id}")]
public async Task<ActionResult<OrderDto>> GetOrder(Guid id)
{
var query = new GetOrderQuery { OrderId = id };
var order = await _mediator.Send(query);
if (order == null)
return NotFound();
return Ok(order);
}
// POST: api/orders
[HttpPost]
public async Task<ActionResult<OrderResult>> CreateOrder([FromBody] CreateOrderCommand command)
{
var result = await _mediator.Send(command);
return CreatedAtAction(nameof(GetOrder), new { id = result.OrderId }, result);
}
// PUT: api/orders/{id}
[HttpPut("{id}")]
public async Task<IActionResult> UpdateOrder(Guid id, [FromBody] UpdateOrderCommand command)
{
if (id != command.OrderId)
return BadRequest();
await _mediator.Send(command);
return NoContent();
}
// DELETE: api/orders/{id}
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteOrder(Guid id)
{
await _mediator.Send(new DeleteOrderCommand { OrderId = id });
return NoContent();
}
}MVC 控制器
csharp
public class HomeController : Controller
{
private readonly IMediator _mediator;
public HomeController(IMediator mediator)
{
_mediator = mediator;
}
public async Task<IActionResult> Index()
{
var orders = await _mediator.Send(new ListOrdersQuery());
return View(orders);
}
[HttpPost]
public async Task<IActionResult> Create(CreateOrderViewModel model)
{
if (!ModelState.IsValid)
return View(model);
var command = new CreateOrderCommand
{
ProductName = model.ProductName,
Quantity = model.Quantity
};
await _mediator.Send(command);
return RedirectToAction("Index");
}
}🛠️ 在中间件中使用 MediatR
请求日志中间件
csharp
public class RequestLoggingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<RequestLoggingMiddleware> _logger;
public RequestLoggingMiddleware(RequestDelegate next, ILogger<RequestLoggingMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context, IMediator mediator)
{
var requestId = Guid.NewGuid();
_logger.LogInformation("请求开始: {Method} {Path} [{RequestId}]",
context.Request.Method,
context.Request.Path,
requestId);
try
{
await _next(context);
_logger.LogInformation("请求完成: {StatusCode} [{RequestId}]",
context.Response.StatusCode,
requestId);
}
catch (Exception ex)
{
_logger.LogError(ex, "请求失败: [{RequestId}]", requestId);
throw;
}
}
}
// 注册中间件
app.UseMiddleware<RequestLoggingMiddleware>();全局异常处理中间件
csharp
public class ExceptionHandlingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<ExceptionHandlingMiddleware> _logger;
public ExceptionHandlingMiddleware(RequestDelegate next, ILogger<ExceptionHandlingMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context, IMediator mediator)
{
try
{
await _next(context);
}
catch (ValidationException ex)
{
_logger.LogWarning("验证失败: {Errors}", ex.Errors);
context.Response.StatusCode = 400;
await context.Response.WriteAsJsonAsync(new
{
errors = ex.Errors.Select(e => new
{
field = e.PropertyName,
message = e.ErrorMessage
})
});
}
catch (NotFoundException ex)
{
_logger.LogWarning("资源未找到: {Message}", ex.Message);
context.Response.StatusCode = 404;
await context.Response.WriteAsJsonAsync(new { error = ex.Message });
}
catch (Exception ex)
{
_logger.LogError(ex, "未处理的异常");
context.Response.StatusCode = 500;
await context.Response.WriteAsJsonAsync(new { error = "服务器内部错误" });
}
}
}
// 注册(放在管道前面)
app.UseMiddleware<ExceptionHandlingMiddleware>();📄 在 Razor Pages 中使用
csharp
// Pages/Orders/Index.cshtml.cs
public class IndexModel : PageModel
{
private readonly IMediator _mediator;
public List<OrderDto> Orders { get; set; }
public IndexModel(IMediator mediator)
{
_mediator = mediator;
}
public async Task OnGetAsync()
{
Orders = await _mediator.Send(new ListOrdersQuery());
}
}
// Pages/Orders/Create.cshtml.cs
public class CreateModel : PageModel
{
private readonly IMediator _mediator;
[BindProperty]
public CreateOrderViewModel Order { get; set; }
public CreateModel(IMediator mediator)
{
_mediator = mediator;
}
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
return Page();
var command = new CreateOrderCommand
{
ProductName = Order.ProductName,
Quantity = Order.Quantity
};
await _mediator.Send(command);
return RedirectToPage("./Index");
}
}📚 结合 Swagger/OpenAPI 文档
安装 NuGet 包
bash
dotnet add package Swashbuckle.AspNetCore配置 Swagger
csharp
// Program.cs
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Title = "订单 API",
Version = "v1",
Description = "基于 MediatR 的订单管理系统 API"
});
// 包含 XML 注释
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath);
});
// 启用 Swagger UI
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "订单 API v1");
c.RoutePrefix = string.Empty; // 在根路径显示
});
}为命令添加文档注释
csharp
/// <summary>
/// 创建订单命令
/// </summary>
public class CreateOrderCommand : IRequest<OrderResult>
{
/// <summary>
/// 产品名称
/// </summary>
/// <example>iPhone 15 Pro</example>
public string ProductName { get; set; }
/// <summary>
/// 数量
/// </summary>
/// <example>2</example>
public int Quantity { get; set; }
/// <summary>
/// 单价
/// </summary>
/// <example>7999.00</example>
public decimal Price { get; set; }
}🔐 身份验证与授权
在 Handler 中获取用户信息
csharp
public class CreateOrderHandler : IRequestHandler<CreateOrderCommand, OrderResult>
{
private readonly IHttpContextAccessor _httpContextAccessor;
public CreateOrderHandler(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public async Task<OrderResult> Handle(CreateOrderCommand request, CancellationToken ct)
{
// 获取当前用户
var userId = _httpContextAccessor.HttpContext?.User.FindFirstValue(ClaimTypes.NameIdentifier);
var userEmail = _httpContextAccessor.HttpContext?.User.FindFirstValue(ClaimTypes.Email);
// 使用用户信息
var order = new Order
{
ProductName = request.ProductName,
CreatedBy = userId,
CustomerEmail = userEmail
};
await _dbContext.Orders.AddAsync(order, ct);
await _dbContext.SaveChangesAsync(ct);
return new OrderResult { OrderId = order.Id };
}
}
// 注册 HttpContextAccessor
builder.Services.AddHttpContextAccessor();基于角色的授权
csharp
[Authorize(Roles = "Admin,Manager")]
[HttpPost]
public async Task<ActionResult<OrderResult>> CreateOrder([FromBody] CreateOrderCommand command)
{
var result = await _mediator.Send(command);
return Ok(result);
}🎯 最佳实践
✅ 推荐做法
csharp
// 1. 控制器保持简洁,只负责 HTTP 层面
[HttpPost]
public async Task<ActionResult<OrderResult>> CreateOrder([FromBody] CreateOrderCommand command)
{
var result = await _mediator.Send(command);
return CreatedAtAction(nameof(GetOrder), new { id = result.OrderId }, result);
}
// 2. 业务逻辑在 Handler 中
public class CreateOrderHandler : IRequestHandler<CreateOrderCommand, OrderResult>
{
public async Task<OrderResult> Handle(CreateOrderCommand request, CancellationToken ct)
{
// 所有业务逻辑在这里
}
}
// 3. 使用管道行为处理横切关注点
builder.Services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
builder.Services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
// 4. 全局异常处理中间件
app.UseMiddleware<ExceptionHandlingMiddleware>();❌ 避免的做法
csharp
// 1. 不要在控制器中包含业务逻辑
[HttpPost]
public async Task<ActionResult> CreateOrder([FromBody] CreateOrderCommand command)
{
// ❌ 错误:业务逻辑应该在 Handler 中
var order = new Order { /* ... */ };
await _dbContext.Orders.AddAsync(order);
await _emailService.SendConfirmation(order);
return Ok();
}
// 2. 不要直接注入 Repository 到控制器
public class OrdersController : ControllerBase
{
private readonly IOrderRepository _repo; // ❌ 应该通过 Handler
public OrdersController(IOrderRepository repo)
{
_repo = repo;
}
}
// 3. 不要忘记异步
[HttpPost]
public ActionResult<OrderResult> CreateOrder([FromBody] CreateOrderCommand command) // ❌ 缺少 async
{
return _mediator.Send(command); // ❌ 应该 await
}📊 性能优化
1. 启用响应缓存
csharp
[HttpGet("{id}")]
[ResponseCache(Duration = 60)] // 缓存 60 秒
public async Task<ActionResult<OrderDto>> GetOrder(Guid id)
{
var query = new GetOrderQuery { OrderId = id };
var order = await _mediator.Send(query);
return Ok(order);
}2. 使用输出缓存(.NET 7+)
csharp
app.UseOutputCache();
[HttpGet]
[OutputCache(Duration = 60)]
public async Task<ActionResult<List<OrderDto>>> ListOrders()
{
var orders = await _mediator.Send(new ListOrdersQuery());
return Ok(orders);
}3. 最小 API(.NET 6+)
csharp
// 更轻量的 API 定义
app.MapGet("/api/orders/{id}", async (Guid id, IMediator mediator) =>
{
var order = await mediator.Send(new GetOrderQuery { OrderId = id });
return order is null ? Results.NotFound() : Results.Ok(order);
});
app.MapPost("/api/orders", async (CreateOrderCommand command, IMediator mediator) =>
{
var result = await mediator.Send(command);
return Results.Created($"/api/orders/{result.OrderId}", result);
});🎓 总结
核心价值
✅ 解耦: 控制器不依赖具体服务
✅ 测试友好: Handler 易于单元测试
✅ 一致性: 统一的请求处理模式
✅ 扩展性: 管道行为自动应用
关键要点
- 控制器只负责 HTTP 层面
- 业务逻辑在 Handler 中
- 使用管道行为处理横切关注点
- 全局异常处理中间件
- 集成 Swagger 提供 API 文档
💡 提示: ASP.NET Core + MediatR 是企业级应用的最佳组合!