.NET Core 3.1 自定义模型验证与 fluentvalidation
.NET Core 3.1 custom model validation with fluentvalidation
我正在尝试通过构建一个小型测试 webapi 来学习 .net 3.1,目前我的 objective 是使用 fluentvalidation 验证 dtos,如果失败,请向调用者提供自定义 json。我发现但无法克服的问题有两个;
- 我似乎无法通过 fluentvalidation 获得我写的消息(它们总是 - 我假设 .net 核心默认的)
- 我似乎无法修改 json 化的对象类型,然后输出给调用者。
我的代码如下:
1.控制器
[ApiController]
[Route("[controller]")]
public class AdminController : ControllerBase
{
[HttpPost]
[ProducesResponseType(StatusCodes.Status409Conflict)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status202Accepted)]
public async Task<IActionResult> RegisterAccount(NewAccountInput dto)
{
return Ok();
}
}
2。 Dto 和自定义验证器
public class NewAccountInput
{
public string Username { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public AccountType Type { get; set; }
}
public class NewAccountInputValidator : AbstractValidator<NewAccountInput>
{
public NewAccountInputValidator()
{
RuleFor(o => o.Email).NotNull().NotEmpty().WithMessage("Email vazio");
RuleFor(o => o.Username).NotNull().NotEmpty().WithMessage("Username vazio");
}
}
3。用于验证的过滤器
public class ApiValidationFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
//the only output i want are the error descriptions, nothing else
var data = context.ModelState
.Values
.SelectMany(v => v.Errors.Select(b => b.ErrorMessage))
.ToList();
context.Result = new JsonResult(data) { StatusCode = 400 };
}
//base.OnActionExecuting(context);
}
}
最后,我的配置服务
public void ConfigureServices(IServiceCollection services)
{
services
//tried both lines and it doesnt seem to work either way
.AddScoped<ApiValidationFilter>()
.AddControllers(//config=>
//config.Filters.Add(new ApiValidationFilter())
)
.AddFluentValidation(fv => {
fv.RunDefaultMvcValidationAfterFluentValidationExecutes = false;//i was hoping this did the trick
fv.RegisterValidatorsFromAssemblyContaining<NewAccountInputValidator>();
});
}
现在,用邮递员尝试这个我得到了结果
这突出了我拥有 atm 的两个问题
这是使用 asp.net core 3.15 和 visualstudio 16.6.3
完成的
您看到的消息实际上来自 FluentValidation - see the source。
您看不到您提供的自定义消息的原因是 FluentValidation 将显示来自链中第一个失败验证器的验证消息,在本例中为 NotNull
。
此 提供了一些选项,用于为整个验证器链指定单个自定义验证消息。
在这种情况下,您描述的操作过滤器永远不会被命中,因为验证首先失败。为防止这种情况,您可以使用:
services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressModelStateInvalidFilter = true;
});
这将停止对无效模型的 BadRequest 自动 return。此 提供了一些替代解决方案,包括配置 InvalidModelStateResponseFactory
来执行您需要的操作。
我正在尝试通过构建一个小型测试 webapi 来学习 .net 3.1,目前我的 objective 是使用 fluentvalidation 验证 dtos,如果失败,请向调用者提供自定义 json。我发现但无法克服的问题有两个;
- 我似乎无法通过 fluentvalidation 获得我写的消息(它们总是 - 我假设 .net 核心默认的)
- 我似乎无法修改 json 化的对象类型,然后输出给调用者。
我的代码如下:
1.控制器
[ApiController]
[Route("[controller]")]
public class AdminController : ControllerBase
{
[HttpPost]
[ProducesResponseType(StatusCodes.Status409Conflict)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status202Accepted)]
public async Task<IActionResult> RegisterAccount(NewAccountInput dto)
{
return Ok();
}
}
2。 Dto 和自定义验证器
public class NewAccountInput
{
public string Username { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public AccountType Type { get; set; }
}
public class NewAccountInputValidator : AbstractValidator<NewAccountInput>
{
public NewAccountInputValidator()
{
RuleFor(o => o.Email).NotNull().NotEmpty().WithMessage("Email vazio");
RuleFor(o => o.Username).NotNull().NotEmpty().WithMessage("Username vazio");
}
}
3。用于验证的过滤器
public class ApiValidationFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
//the only output i want are the error descriptions, nothing else
var data = context.ModelState
.Values
.SelectMany(v => v.Errors.Select(b => b.ErrorMessage))
.ToList();
context.Result = new JsonResult(data) { StatusCode = 400 };
}
//base.OnActionExecuting(context);
}
}
最后,我的配置服务
public void ConfigureServices(IServiceCollection services)
{
services
//tried both lines and it doesnt seem to work either way
.AddScoped<ApiValidationFilter>()
.AddControllers(//config=>
//config.Filters.Add(new ApiValidationFilter())
)
.AddFluentValidation(fv => {
fv.RunDefaultMvcValidationAfterFluentValidationExecutes = false;//i was hoping this did the trick
fv.RegisterValidatorsFromAssemblyContaining<NewAccountInputValidator>();
});
}
现在,用邮递员尝试这个我得到了结果
这突出了我拥有 atm 的两个问题
这是使用 asp.net core 3.15 和 visualstudio 16.6.3
完成的您看到的消息实际上来自 FluentValidation - see the source。
您看不到您提供的自定义消息的原因是 FluentValidation 将显示来自链中第一个失败验证器的验证消息,在本例中为 NotNull
。
此
在这种情况下,您描述的操作过滤器永远不会被命中,因为验证首先失败。为防止这种情况,您可以使用:
services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressModelStateInvalidFilter = true;
});
这将停止对无效模型的 BadRequest 自动 return。此 InvalidModelStateResponseFactory
来执行您需要的操作。