You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 17:01:26