在MVC中如何在视图显示错误而非抛出验证异常?
如何在视图中展示MediatR验证行为的错误信息
你的问题出在当前的ValidationBehavior直接抛出了ValidationException,这个异常会被调试器捕获,而没有被上层处理后传递到视图层。要让用户在视图中看到错误,需要修改异常处理逻辑或者调整验证行为的返回方式,以下是两种可行方案:
方案1:全局捕获验证异常并映射到ModelState(适合ASP.NET MVC/Razor Pages)
通过全局异常过滤器捕获ValidationException,将错误信息注入到ModelState中,再返回当前视图展示错误:
1. 创建异常过滤器
public class ValidationExceptionFilter : IExceptionFilter { public void OnException(ExceptionContext context) { if (context.Exception is ValidationException validationEx) { // 将每个验证错误添加到ModelState foreach (var failure in validationEx.Errors) { context.ModelState.AddModelError(failure.PropertyName, failure.ErrorMessage); } // 标记异常已处理,返回当前视图 context.ExceptionHandled = true; context.Result = new ViewResult { ViewData = context.Controller.ViewData }; } } }
2. 注册过滤器
在Program.cs(或Startup.cs)中注册这个全局过滤器:
builder.Services.AddControllersWithViews(options => { options.Filters.Add<ValidationExceptionFilter>(); });
方案2:修改ValidationBehavior返回带错误的响应(适合CQRS模式)
如果你的命令/查询响应设计为包含执行状态,可调整验证行为不抛出异常,而是返回包含错误信息的响应对象:
1. 定义基础响应类
public class BaseResponse { public bool IsSuccess { get; set; } = true; public List<string> Errors { get; set; } = new(); }
2. 让命令响应继承基础类
public class SaveXResponse : BaseResponse { public int Id { get; set; } // 示例响应数据 }
3. 修改ValidationBehavior
public class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse> where TResponse : BaseResponse, new() { private readonly IEnumerable<IValidator<TRequest>> _validators; public ValidationBehavior(IEnumerable<IValidator<TRequest>> validators) { _validators = validators; } public Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next) { var context = new ValidationContext<TRequest>(request); var failures = _validators .Select(x => x.Validate(context)) .SelectMany(x => x.Errors) .Where(x => x != null) .ToList(); if (failures.Any()) { // 返回带错误的响应,而非抛出异常 var response = new TResponse { IsSuccess = false, Errors = failures.Select(f => $"{f.PropertyName}: {f.ErrorMessage}").ToList() }; return Task.FromResult(response); } return next(); } }
4. 控制器中处理响应
public async Task<IActionResult> Save(SaveXCommand command) { var response = await _mediator.Send(command); if (!response.IsSuccess) { // 将错误信息注入ModelState foreach (var error in response.Errors) { var errorParts = error.Split(':'); if (errorParts.Length == 2) { ModelState.AddModelError(errorParts[0].Trim(), errorParts[1].Trim()); } else { ModelState.AddModelError(string.Empty, error); } } // 返回视图并保留用户输入 return View(command); } // 验证成功,跳转至目标页面 return RedirectToAction(nameof(Details), new { id = response.Id }); }
视图中显示错误
无论采用哪种方案,都可以使用ASP.NET MVC的验证辅助方法在视图中展示错误:
<!-- 显示所有错误的摘要 --> @Html.ValidationSummary(true, "", new { @class = "text-danger" }) <!-- 单个属性的错误提示 --> <div class="form-group"> @Html.LabelFor(m => m.ImageUrl) @Html.TextBoxFor(m => m.ImageUrl, new { @class = "form-control" }) @Html.ValidationMessageFor(m => m.ImageUrl, "", new { @class = "text-danger" }) </div> <div class="form-group"> @Html.LabelFor(m => m.StartDate) @Html.TextBoxFor(m => m.StartDate, new { @class = "form-control" }) @Html.ValidationMessageFor(m => m.StartDate, "", new { @class = "text-danger" }) </div>
内容的提问来源于stack exchange,提问作者user17847724
相关产品推荐
相关产品推荐

