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

.NET 8中如何在服务层收集并返回多个验证错误而非抛出异常?

.NET 8中如何在服务层收集并返回多个验证错误而非抛出异常?

嘿,我完全懂你想要的效果——就像用FluentValidation处理DTO那样,把所有验证问题一次性攒起来返回给前端,而不是遇到一个错误就抛出异常打断整个流程对吧?在.NET 8里我们可以通过自定义验证结果结构,或者复用FluentValidation的思路来实现,下面给你具体的方案:

方案一:自定义验证结果类,手动收集服务层验证错误

首先我们可以定义一个简单的验证结果类,用来承载所有错误信息:

public class ServiceValidationResult
{
    // 存储所有验证错误的集合
    public List<string> Errors { get; } = new List<string>();
    // 快速判断是否验证通过
    public bool IsValid => Errors.Count == 0;

    // 添加错误的方法
    public void AddError(string errorMessage)
    {
        Errors.Add(errorMessage);
    }
}

接下来改造你的服务层逻辑,不再抛出异常,而是把错误添加到这个结果类里:

// 假设这是你的服务方法
public ServiceValidationResult ProcessCustomerData(Customer customer)
{
    var validationResult = new ServiceValidationResult();

    // 原来的抛异常逻辑改成添加错误
    if (!hasAnyPhoneNumber)
    {
        validationResult.AddError(MessageHelper.GetMessage(ErrorMessageName.NOT_EMPTY));
    }

    // 你可以继续添加其他业务验证逻辑,所有错误都会被收集
    if (string.IsNullOrWhiteSpace(customer.FullName))
    {
        validationResult.AddError("客户姓名不能为空");
    }

    if (!IsValidCustomerType(customer.Type))
    {
        validationResult.AddError("客户类型选择无效");
    }

    return validationResult;
}

然后在调用服务的上层(比如API控制器),根据验证结果做处理:

[HttpPost]
public IActionResult CreateCustomer(CustomerCreateDto dto)
{
    var customer = _mapper.Map<Customer>(dto);
    var validationResult = _customerService.ProcessCustomerData(customer);

    if (!validationResult.IsValid)
    {
        // 把错误集合返回给前端,格式可以根据需求调整
        return BadRequest(new { Code = "VALIDATION_FAILED", Errors = validationResult.Errors });
    }

    // 验证通过,执行后续业务逻辑
    _customerService.SaveCustomer(customer);
    return Ok(new { Message = "客户创建成功" });
}

方案二:复用FluentValidation处理服务层业务验证

如果你的项目已经在使用FluentValidation处理DTO验证,那可以把这套逻辑延伸到服务层的领域对象验证上,保持风格一致。

首先为你的领域对象创建验证器:

public class CustomerValidator : AbstractValidator<Customer>
{
    public CustomerValidator()
    {
        // 基础字段验证
        RuleFor(c => c.PhoneNumber)
            .NotEmpty()
            .WithMessage(MessageHelper.GetMessage(ErrorMessageName.NOT_EMPTY));

        RuleFor(c => c.FullName)
            .NotEmpty()
            .WithMessage("客户姓名不能为空");

        // 还可以添加依赖数据库的业务验证,比如检查手机号是否已存在
        RuleFor(c => c.PhoneNumber)
            .MustAsync(async (phone, cancellation) => await _customerRepo.IsPhoneUniqueAsync(phone))
            .WithMessage("该手机号已被注册");
    }
}

然后在服务层注入这个验证器,调用验证方法并转换为我们需要的结果:

private readonly CustomerValidator _customerValidator;

public CustomerService(CustomerValidator customerValidator)
{
    _customerValidator = customerValidator;
}

public async Task<ServiceValidationResult> ValidateCustomer(Customer customer)
{
    var fluentResult = await _customerValidator.ValidateAsync(customer);
    var serviceResult = new ServiceValidationResult();

    foreach (var error in fluentResult.Errors)
    {
        serviceResult.AddError(error.ErrorMessage);
    }

    return serviceResult;
}

这样不管是DTO还是服务层的领域对象,都用同一种验证方式,维护起来更方便。

小提示

  • 服务层返回验证结果后,上层调用方一定要主动检查IsValid状态,不要忽略验证结果直接执行业务逻辑。
  • 对于复杂的跨字段业务验证,也可以放到验证逻辑里,只要把错误信息添加到结果集合即可,不需要抛出异常。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 10:09:29