FluentValidation 失败不返回 BadRequest

问题描述

我已经按照说明连接了 FluentValidation,在调试测试时,我可以看到基于测试设置的模型无效,但没有抛出异常,而是正在执行控制器上的方法。这是在启用端点路由的 3.1 上。还有什么需要做的才能让它工作并抛出。发生的事情是验证显然在运行;它显示为 ModelState 无效且正确的 InstallmentId 无效,但它继续在 Controller 中处理而不是抛出异常。

services.AddMvc(
                    options =>
                    {
                         options.EnableEndpointRouting = true;
                         //// options.Filters.Add<ExceptionFilter>();
                         //// options.Filters.Add<CustomerRequestFilter>();
                     })
                    .AddFluentValidation(
                         config =>
                         {
                            config.RegisterValidatorsFromAssemblyContaining<Startup>();
                         })

命令和验证器

     public class ProcessManualPayment
        {
            public class Command
                : CustomerRequest<Result?>
            {
                public Guid PaymentPlanId { get; set; }
    
                public Guid InstallmentId { get; set; }
    
                public Guid PaymentCardId { get; set; }
            }
    
          
            public class Validator : AbstractValidator<Command>
            {
                public Validator()
                {
                    this.RuleFor(x => x.CustomerId)
                        .IsValidGuid();
    
                    this.RuleFor(x => x.PaymentPlanId)
                        .IsValidGuid();
    
                    this.RuleFor(x => x.InstallmentId)
                        .IsValidGuid();
    
                    this.RuleFor(x => x.PaymentCardId)
                        .IsValidGuid();
                }
            }

控制器

    [Authorize]
    [HttpPost]
    [Route("payments")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task<IActionResult> ProcessManualPayment(
           [FromBody]
            ProcessManualPayment.Command command)
    {

测试

            [Fact]
            public async Task When_Command_Has_Invalid_Payload_Should_Fail()
            {
                var client = this.factory.CreateClient();

                // Arrange
                var validCmd = new ProcessManualPayment.Command()
                {
                    CustomerId = Guid.NewGuid(),PaymentPlanId = Guid.NewGuid(),InstallmentId = Guid.NewGuid(),PaymentCardId = Guid.NewGuid(),};

                var validCmdJson = JsonConvert.SerializeObject(validCmd,Formatting.None);

                var jObject = JObject.Parse(validCmdJson);

                jObject["installmentId"] = "asdf";

                var payload = jObject.ToString(Formatting.None);

                // Act
                var content = new StringContent(payload,Encoding.UTF8,MediaTypeNames.Application.Json);

                var response = await client.PostAsync(MakePaymentUrl,content);

                var returned = await response.Content.ReadAsstringAsync();

                response.StatusCode.ShouldBe(HttpStatusCode.BadRequest);
            }

            [Fact]
            public async Task When_Payload_Is_Null_Should_Fail()
            {
                // Arrange
                var client = this.factory.CreateClient();

                // Act
                var response = await client.PostAsJsonAsync(MakePaymentUrl,null);

                // Assert
                response.StatusCode.ShouldBe(HttpStatusCode.BadRequest);
            }

GuidValidator

    public class GuidValidator : PropertyValidator
    {
        public GuidValidator()
            : base("'{PropertyName}' value {AttemptedValue} is not a valid Guid.")
        {
        }

        protected override bool IsValid(PropertyValidatorContext context)
        {
            context.messageformatter.AppendArgument("AttemptedValue",context.PropertyValue ?? "'null'");

            if (context.PropertyValue == null)
            {
                return false;
            }

            Guid.TryParse(context.PropertyValue.ToString(),out var value);

            return IsValid(value);
        }

        private static bool IsValid(Guid? value) =>
            value.HasValue
            && !value.Equals(Guid.Empty);
    }

解决方法

谜团解决了,我在控制器上缺少 [ApiController] 属性。