.NET Core 5 Web API 400 Bad Request 处理更优实现模式咨询
.NET Core 5 Web API 400请求校验优化方案
方案1:使用内置数据注解+自动模型验证(无第三方依赖,无需修改模型继承结构)
ASP.NET Core Web API 自带模型校验能力,仅需给模型属性添加对应校验特性即可,无需调整现有模型的继承关系,对API调用方完全无感知,不会造成破坏性变更。
- 给模型属性添加校验特性
public class Customer { [Required(ErrorMessage = "First name is required")] public string FirstName { get; set; } [Required(ErrorMessage = "Last name is required")] public string LastName { get; set; } [Required(ErrorMessage = "Email address is required")] public string EmailAddress { get; set; } [Required(ErrorMessage = "At least one role is required")] [MinLength(1, ErrorMessage = "At least one role is required")] public List<string> Roles { get; set; } // 其他Customer专属属性 }
Employee模型同理,直接给对应需要校验的属性添加相同的[Required]等特性即可,不需要和Customer做任何继承关联。
2. 开启自动校验
确认控制器类上添加了[ApiController]特性,.NET Core 3.0+版本默认会对加了该特性的控制器自动执行模型校验,校验失败直接返回400响应,不需要在Action中写任何判断逻辑。
如果需要统一自定义400响应格式,可在Startup.cs的ConfigureServices方法中添加如下配置:
services.Configure<ApiBehaviorOptions>(options => { options.InvalidModelStateResponseFactory = context => { // 提取所有校验错误信息 var errorList = context.ModelState .Where(m => m.Value.Errors.Any()) .SelectMany(m => m.Value.Errors.Select(e => e.ErrorMessage)) .ToList(); // 返回自定义格式的400响应 return new BadRequestObjectResult(new { Code = 400, Msg = "参数校验失败", Errors = errorList }); }; });
- 简化后的Action代码
所有的参数校验if语句都可以直接删除:
[HttpPost("register-customer")] [Produces("application/json")] [MapToApiVersion("1")] public async Task<ActionResult<IRegistrationStatus>> RegisterCustomer([FromBody] Customer customer) { try { // 到此处已经自动完成所有必填项校验,直接调用业务逻辑即可 var registrationStatus = await _registerService.Register(customer); return Ok(registrationStatus); } catch (Exception ex) { return StatusCode(500, ex.ToString()); } }
如果需要实现更复杂的跨字段关联校验,可以让模型实现IValidatableObject接口,在Validate方法中编写自定义校验逻辑,自动校验流程也会触发该方法的执行。
方案2:使用FluentValidation实现更高复用性的校验逻辑
如果公共校验规则较多,想要避免重复编写相同的校验特性,可以使用FluentValidation库实现校验逻辑和模型的完全解耦,同样不需要修改现有模型的任何结构。
- 安装Nuget包
Install-Package FluentValidation.AspNetCore
- 注册服务
在Startup.cs的ConfigureServices方法中添加:
services.AddFluentValidationAutoValidation(); // 扫描当前程序集中所有校验器自动注册 services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
- 封装公共校验逻辑
// 公共校验基类,复用所有人名、邮箱等通用校验规则 public abstract class PersonValidator<T> : AbstractValidator<T> where T : class { protected PersonValidator() { RuleFor("FirstName").NotEmpty().WithMessage("First name is required") .MaximumLength(50).WithMessage("First name不能超过50个字符"); RuleFor("LastName").NotEmpty().WithMessage("Last name is required"); RuleFor("EmailAddress").NotEmpty().EmailAddress().WithMessage("邮箱格式不正确"); } }
- 编写各自模型的校验器
// Customer专属校验器 public class CustomerValidator : PersonValidator<Customer> { public CustomerValidator() { RuleFor(x => x.Roles).NotEmpty().WithMessage("At least one role is required"); // 其他Customer专属校验规则 } } // Employee专属校验器 public class EmployeeValidator : PersonValidator<Employee> { public EmployeeValidator() { RuleFor(x => x.EmployeeNo).NotEmpty().WithMessage("工号不能为空"); // 其他Employee专属校验规则 } }
所有校验逻辑完全独立于模型之外,现有模型不需要做任何修改,不会对API契约产生任何影响,公共校验规则仅需编写一次即可复用给所有符合条件的模型。
内容的提问来源于stack exchange,提问作者Ctrl_Alt_Defeat
相关产品推荐
相关产品推荐

