Как вернуть указанное свойство c в сообщении проверки RuleForEach, используя Fluent Validator? - PullRequest
0 голосов
/ 27 марта 2020

Допустим, у меня есть тестовый класс, подобный этому:

public class TestClass
{
    public Properties[] TestProperties { get; set; }
    public Guid Id { get; set; }

    public TestClass(Properties[] testProperties)
    {
        Id = Guid.NewGuid();
        TestProperties = testProperties;
    }
}

, и класс свойств следующим образом:

 public class Properties
{
    public Guid Id { get; set; }
    public string Name { get; set; }

    public Properties(string name)
    {
        Name = name;
        Id = Guid.NewGuid();
    }
}

Мне нужно проверить, что ни одно из моих свойств Name в массиве TestProperties имеет значение null, например:

public class TestValidator : AbstractValidator<TestClass>
{
    public TestValidator()
    {
        RuleForEach(x => x.TestProperties)
            .Must(y => y.Name != string.Empty && y.Name != null)
            .WithMessage("TestPropertie at {CollectionIndex}, can't be null or empty");
    }
}

Но вместо того, чтобы возвращать позицию свойства с ошибкой, в сообщении проверки я хотел бы вернуть его Id, как я могу сделать так?

Ответы [ 2 ]

1 голос
/ 29 марта 2020

Да, используя валидаторы по умолчанию, можно добавить другие значения свойств из объектов в сообщение.

Это можно сделать, используя перегрузку WithMessage, которая принимает лямбда-выражение, а затем Передача значений в строку. Формат или с помощью строковой интерполяции.

Источник

Есть несколько способов сделать это. Во-первых, согласно вашей текущей реализации, использующей Must:

public class TestClassValidator : AbstractValidator<TestClass>
{
    public TestClassValidator()
    {
        RuleForEach(x => x.TestProperties)
            .Must(y => !string.IsNullOrEmpty(y.Name))
            .WithMessage((testClass, testProperty) => $"TestProperty {testProperty.Id} name can't be null or empty");
    }
}

Я стараюсь по возможности избегать использования Must, если вы придерживаетесь встроенных валидаторов, у вас больше шансов на проверка стороны работает из коробки (если вы используете ее в веб-приложении). Использование ChildRules позволяет вам использовать встроенные валидаторы, а также получить преимущество от использования свободного интерфейса:

public class TestClassValidator : AbstractValidator<TestClass>
{
    public TestClassValidator()
    {
        RuleForEach(x => x.TestProperties)
            .ChildRules(testProperties =>
            {
                testProperties.RuleFor(testProperty => testProperty.Name)
                    .NotNull()
                    .NotEmpty()
                    .WithMessage(testProperty => $"TestProperty {testProperty.Id} name can't be null or empty");
            });
    }
}

ChildRules doco

У меня есть включил валидатор NotNull () для многословия / выравнивания с пользовательским сообщением об ошибке, однако это не требуется, поскольку NotEmpty () будет охватывать пустой или пустой регистр.

Наконец, если бы это был я, я, вероятно, создал бы отдельный валидатор для типа Properties (это должно быть Property?) и используйте SetValidator для его включения. Разбивает вопросы валидации, определяет валидацию для типа один раз, делает правила многократно используемыми и облегчает тестирование валидаторов. Я не буду описывать это здесь, поскольку это выходит за рамки этого вопроса, но ссылки ниже дают примеры того, как это сделать.

дочерний валидатор doco (SetValidator использование) здесь и здесь

Рабочие образцы вышеуказанных, включая тесты, можно найти здесь .

0 голосов
/ 15 апреля 2020

Я подошел к этому немного по-другому, потому что хотел более многоразового решения. (Я проверяю много разных классов похожими способами). Помещение идентификации сообщения в расширение с помощью Must <> привязывает вас к типу и может привести к копированию и вставке. Вместо этого я передаю в качестве аргумента валидации Fun c, который возвращает идентифицирующую строку и позволяет вызывающей стороне решить, как идентифицировать проверяемый объект.

    public static IRuleBuilderOptions<T, string> IsValidStringEnumAllowNullable<T>(this IRuleBuilder<T, string> ruleBuilder, IList<string> validValues, Func<T,string> identifierLookup)
    {
        return ruleBuilder.Must((rootObject, testValue, context) =>
        {
            context.MessageFormatter.AppendArgument("AllowableValues", string.Join(", ", validValues));
            context.MessageFormatter.AppendArgument("Identifier", identifierLookup(rootObject));
            return string.IsNullOrEmpty(testValue) || validValues.Contains(testValue, StringComparer.Ordinal);

        }).WithMessage("{Identifier}{PropertyName} with value {PropertyValue} must be one of the allowable values: {AllowableValues}, or null or empty string");
    }

А затем вызывающий код, где я сообщите указанному c сообщению проверки «как» идентифицировать объект для обмена сообщениями:

base.RuleForEach(rq => rq.Thingies).ChildRules(x =>
{
    x.RuleFor(f => f.MyProperty).IsValidStringEnumAllowNullable(ValidationStrings.AnArrayOfAllowedValues, f => $"Thing[{f.Id}] ");
});

Результат этого кода

Thing[1234] My Property with value asdf must be one of the allowable values: Value1, ValidValue2, Somethingelse, or null or empty string
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...