Сообщение FluentValidation для вложенных свойств

#c# #asp.net #validation #fluentvalidation

#c# #asp.net #проверка #fluentvalidation

Вопрос:

У меня есть класс со сложным свойством:

 public class A
{
    public B Prop { get; set; }
}

public class B
{
    public int Id { get; set; }
}
  

Я добавил средство проверки:

 public class AValidator : AbstractValidator<A>
{
    public AValidator()
    {
        RuleFor(x => x.A.Id)
            .NotEmpty()
            .WithMessage("Please ensure you have selected the A object");            
    }
}
  

Но во время проверки на стороне клиента A.Id у меня все еще есть сообщение о проверке по умолчанию : 'Id' must not be empty . Как я могу изменить его на свою строку из средства проверки?

Комментарии:

1. Похоже, это не поддерживается . Предлагаемый альтернативный подход заключается в том, чтобы иметь модели плоского представления и избегать вложенности объектов

2. Это поддерживается и зависит от того, где вы хотите использовать свои средства проверки. Проверьте мой ответ ниже.

Ответ №1:

Вы можете добиться этого, используя пользовательский валидатор для вложенного объекта:

 public class AValidator : AbstractValidator<A>
{
    public AValidator()
    {
        RuleFor(x => x.B).NotNull().SetValidator(new BValidator());
    }

    class BValidator : AbstractValidator<B>
    {
        public BValidator()
        {
            RuleFor(x => x.Id).NotEmpty().WithMessage("Please ensure you have selected the B object");
        }
    }
}

public class A
{
    public B B { get; set; }
}

public class B
{
    public int Id { get; set; }
}
  

Ответ №2:

Здесь есть альтернативный вариант. При настройке FluentValidation в вашем Startup классе вы можете установить следующее configuration.ImplicitlyValidateChildProperties = true;

Таким образом, полный код может выглядеть примерно так

 services
    .AddMvc()
    .AddFluentValidation(configuration =>
        {
            ...
            configuration.ImplicitlyValidateChildProperties = true;
            ...
        })
  

Таким образом, у вас все равно будет два валидатора, один для класса A и один для класса B , тогда класс B будет проверен.

В документации говорится:

Следует ли неявно проверять дочерние свойства, если можно найти соответствующий валидатор. По умолчанию это значение равно false, и вам следует подключить дочерние средства проверки с помощью setValidator .

Таким образом, установка этого значения true подразумевает, что дочерние свойства будут проверены.

Комментарии:

1. Это очень интересно, вы случайно не знаете, как можно это протестировать?

2. Мне было бы интересно, как это можно включить в наборы правил. Как вы можете определить допустимый набор правил проверки, когда ваш вложенный объект будет проверен?

Ответ №3:

Довольно старый вопрос, но для будущих поколений — вы можете либо использовать дочерний валидатор, либо определить встроенные дочерние правила, как описано в официальной документации: https://fluentvalidation.net/start#complex-properties

Ответ №4:

Это зависит от того, где вы хотите использовать свои средства проверки:

В обычном сценарии, когда у нас есть приложение с N уровнями, в ASP.net слой, для проверки View Models DTOs или Commands (например, для достижения быстрой проверки без сбоев), просто включите ImplicitlyValidateChildProperties , как сказал @StevenYates:

 services.AddMvc().AddFluentValidation(fv => 
{
    fv.ImplicitlyValidateChildProperties = true;
});
  

Когда это включено, вместо того, чтобы указывать дочерние средства проверки с помощью SetValidator , инфраструктура проверки MVC будет рекурсивно пытаться автоматически находить средства проверки для каждого свойства автоматически.

ИМХО, это здорово, потому что, помимо того, что это практично, это мешает нам забыть некоторые .SetValidator (...) !

Обратите внимание, что если вы включите это поведение, вам не следует использовать setValidator для дочерних свойств, иначе средство проверки будет выполнено дважды.

Документ: https://docs .fluentvalidation.net/en/latest/aspnet.html#implicit-vs-explicit-child-property-validation


Но, в дополнение (или вместо этого) к этому, если вы хотите использовать FluentValidation на других уровнях (например, в домене), вам необходимо использовать SetValidator(...) метод, как сказал @t138, например:

 RuleFor(customer => customer.Address).SetValidator(new AddressValidator());
  

Документ: https://docs .fluentvalidation.net/en/latest/start.html#complex-properties

Ответ №5:

 public class A
{
    public B B { get; set; }
}

public class B
{
    public int Id { get; set; }
}

public class AValidator : AbstractValidator<A>
{
    public AValidator()
    {
        RuleFor(x => x.B).NotNull().SetValidator(new BValidator());
    }

    class BValidator : AbstractValidator<B>
    {
        public BValidator()
        {
            RuleFor(x => x.Id).NotEmpty().WithMessage("message ....");

        }
    }
}

----------------------------------------------------------------------
  public void ConfigureServices(IServiceCollection services)
   {
          
            services.AddControllers().AddFluentValidation(fv =>
            {
                fv.RegisterValidatorsFromAssemblyContaining<Startup>();
                fv.ImplicitlyValidateChildProperties = true;
            });
    }
  

Ответ №6:

Вы можете использовать метод дочерних элементов:

 public class AValidator : AbstractValidator<A>
{
    public AValidator()
    {
        RuleFor(x => x.Prop)
            .ChildRules(x => x.RuleFor(b => b.Id))
            .NotEmpty()
            .WithMessage("Please ensure you have selected the A object");
    }
}