ASP.NET Core MVC中如何使用FluentValidation验证CQRS查询并在验证失败时跳转404错误页
解决方案:ASP.NET Core MVC中CQRS查询的FluentValidation验证与错误重定向
我来帮你一步步解决这两个问题,这在结合CQRS和FluentValidation的ASP.NET Core项目里是很典型的场景。
问题1:使用FluentValidation在CQRS查询执行前验证参数
要实现查询参数的前置验证,我们可以借助FluentValidation的验证器,配合MediatR的管道行为来实现自动化验证,这样能让Handler只专注于业务逻辑,不用关心参数校验。
步骤1:安装必要的NuGet包
首先确保你已经安装了以下包:
Install-Package FluentValidation Install-Package FluentValidation.AspNetCore
步骤2:为查询创建验证器
为GetTagByIdQuery编写对应的验证器类,定义参数规则(比如ID必须大于0):
using FluentValidation; public class GetTagByIdQueryValidator : AbstractValidator<GetTagByIdQuery> { public GetTagByIdQueryValidator() { // 规则:ID必须大于0,否则抛出验证错误 RuleFor(query => query.Id) .GreaterThan(0) .WithMessage("标签ID必须是有效的正整数"); } }
步骤3:添加MediatR验证管道行为
创建一个管道行为类,让MediatR在执行Handler之前自动触发验证:
using FluentValidation; using MediatR; public class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse> { private readonly IEnumerable<IValidator<TRequest>> _validators; public ValidationBehavior(IEnumerable<IValidator<TRequest>> validators) { _validators = validators; } public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken) { // 执行所有针对当前请求的验证 if (_validators.Any()) { var validationContext = new ValidationContext<TRequest>(request); var validationResults = await Task.WhenAll( _validators.Select(validator => validator.ValidateAsync(validationContext, cancellationToken)) ); // 收集所有验证失败的错误 var validationFailures = validationResults .SelectMany(result => result.Errors) .Where(error => error != null) .ToList(); if (validationFailures.Any()) { throw new ValidationException(validationFailures); } } // 验证通过,继续执行Handler return await next(); } }
步骤4:注册服务到DI容器
在Program.cs中注册验证器和管道行为,让框架能自动发现和使用它们:
// 注册当前程序集中所有的FluentValidation验证器 builder.Services.AddValidatorsFromAssemblyContaining<GetTagByIdQueryValidator>(); // 注册MediatR的验证管道行为 builder.Services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
这样一来,当你调用_mediator.Send(new GetTagByIdQuery { Id = id })时,系统会先自动执行验证,如果ID不符合规则(比如小于等于0),就会抛出ValidationException,不会进入Handler执行查询。
问题2:验证失败/查询结果为空时重定向到404页面
这里分两种场景:参数验证失败和查询结果为空,我们可以通过全局异常处理或者Action内捕获的方式来实现重定向。
方案1:全局异常过滤器(推荐)
创建一个全局异常过滤器,统一处理验证异常和资源未找到的情况:
第一步:定义自定义NotFoundException(可选)
为了区分"资源不存在"的场景,我们可以自定义一个异常类:
public class NotFoundException : Exception { public NotFoundException(string message) : base(message) { } }
第二步:修改Query Handler,资源不存在时抛异常
修改GetTagByIdQueryHandler,当查询不到标签时抛出自定义的NotFoundException:
public async Task<Tag> Handle(GetTagByIdQuery request, CancellationToken cancellationToken) { var tag = await _unitOfWork.Tags.GetAsync(request.Id); if (tag == null) { throw new NotFoundException($"ID为{request.Id}的标签不存在"); } return tag; }
第三步:创建全局异常过滤器
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; public class CustomExceptionFilter : IExceptionFilter { public void OnException(ExceptionContext context) { // 处理验证异常或资源未找到异常 if (context.Exception is ValidationException || context.Exception is NotFoundException) { // 重定向到自定义的404页面(假设你有Error控制器的NotFound方法) context.Result = new RedirectToActionResult("NotFound", "Error", null); context.ExceptionHandled = true; } } }
第四步:注册过滤器到MVC
在Program.cs中添加这个过滤器:
builder.Services.AddControllersWithViews(options => { options.Filters.Add<CustomExceptionFilter>(); });
方案2:在Action内手动捕获异常
如果你不想用全局过滤器,也可以在Action里直接捕获异常并处理:
public async Task<IActionResult> Edit(int id) { try { var tag = await _mediator.Send(new GetTagByIdQuery { Id = id }); return View(tag); } catch (ValidationException) { // 参数验证失败,重定向到404 return RedirectToAction("NotFound", "Error"); } catch (NotFoundException) { // 资源不存在,返回内置的NotFound结果或重定向 return RedirectToAction("NotFound", "Error"); // 或者直接返回内置404:return NotFound(); } }
内容的提问来源于stack exchange,提问作者AmRo
相关产品推荐
相关产品推荐

