首页 > 解决方案 > .NET Core 3.1 自定义模型验证与 fluentvalidation

问题描述

我试图通过构建一个小型测试 webapi 来学习 .net 3.1,目前我的目标是使用 fluentvalidation 验证 dtos,如果它失败,则向调用者提供一个自定义 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>();
                    
                });

        }

现在,与邮递员一起尝试,我得到了结果

图像

这突出了我拥有自动取款机的两个问题

这是使用 asp.net core 3.15 和 visualstudio 16.6.3 完成的

标签: c#asp.net-core-3.1fluentvalidationmodel-validation

解决方案


您看到的消息实际上来自 FluentValidation -请参阅源代码

您没有看到您提供的自定义消息的原因是 FluentValidation 将显示来自链中第一个失败的验证器的验证消息,在这种情况下NotNull

这个问题提供了一些选项,用于为整个验证器链指定单个自定义验证消息。

在这种情况下,您描述的操作过滤器永远不会被击中,因为验证首先失败。为了防止这种情况,您可以使用:

services.Configure<ApiBehaviorOptions>(options =>
{
    options.SuppressModelStateInvalidFilter = true;
});

这将停止为无效模型自动返回 BadRequest。这个问题提供了一些替代解决方案,包括配置一个InvalidModelStateResponseFactory来做你需要的。


推荐阅读