FluentValidation как создать общую часть - PullRequest
0 голосов
/ 24 августа 2018

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

public abstract class CarrierAbstractFormAPI
{
    public string Name { get; set; }
    public string Fein { get; set; }
    public string McNumber { get; set; }
    public string DotNumber { get; set; }

    public AddressCreateAPI Address { get; set; }
}

и класс AddressCreateAPI:

public class AddressCreateAPI
{
    public string Street { get; set; }
    public string City { get; set; }
    public string ZipPostalCode { get; set; }
    public int StateProvinceId { get; set; }
    public string ContactName { get; set; }
    public string ContactPhone { get; set; }
    public string ContactFaxNumber { get; set; }
    public string ContactEmail { get; set; }
}

Мой валидатор:

public abstract class CarrierAbstractFluentValidation<T> : AbstractValidator<T> where T : CarrierAbstractFormAPI
{
    public CarrierAbstractFluentValidation()
    {
        RuleFor(d => d.Name)
            .NotEmpty().WithMessage("Name is required");

        RuleFor(d => d.Fein)
            .NotEmpty().WithMessage("Fein is required");

        RuleFor(d => d.McNumber)
            .NotEmpty().WithMessage("McNumber is required");

        RuleFor(d => d.DotNumber)
            .NotEmpty().WithMessage("DotNumber is required");

        RuleFor(d => d.Address.Street)
            .NotEmpty().WithMessage("Address Street is required");

        RuleFor(d => d.Address.City)
            .NotEmpty().WithMessage("Address City is required");

        RuleFor(d => d.Address.StateProvinceId)
            .InclusiveBetween(0, int.MaxValue).WithMessage("Address State is required");

    }
}

Работает нормально. Но у меня есть несколько дополнительных классов, которые могут иметь

public AddressCreateAPI Address { get; set; }

недвижимость. Я хочу переместить деталь:

        RuleFor(d => d.Address.Street)
            .NotEmpty().WithMessage("Address Street is required");

        RuleFor(d => d.Address.City)
            .NotEmpty().WithMessage("Address City is required");

        RuleFor(d => d.Address.StateProvinceId)
            .InclusiveBetween(0, int.MaxValue).WithMessage("Address State is required");

к общему классу и применить его в каждом свободном валидаторе, который имеет свойство Address. Как это сделать?

Ответы [ 2 ]

0 голосов
/ 25 августа 2018

Подумайте об этом, все что вам нужно сделать, это повторно использовать класс валидатора.

class AddressCreateAPIValidator : AbstractValidator<AddressCreateAPI>
{
    public AddressCreateAPIValidator()
    {
        RuleFor(d => d.Street)
        .NotEmpty().WithMessage("Address Street is required");

        RuleFor(d => d.City)
            .NotEmpty().WithMessage("Address City is required");

        RuleFor(d => d.StateProvinceId)
            .InclusiveBetween(0, int.MaxValue).WithMessage("Address State is required");
    }
}

class SomeClass
{
    public AddressCreateAPI Prop { get; set; }
}

class SomeClassValidator : AbstractValidator<SomeClass>
{
    public SomeClassValidator()
    {
        RuleFor(d => d.Prop).SetValidator(new AddressCreateAPIValidator());
    }
}

Обратите внимание, как AddressCreateAPIValidator извлекает общую логику для проверки классов AddressCreateAPI и затем повторно используется для свойствиспользуя вызов SetValidator.

Вы можете смешивать и сопоставлять это с подходом, основанным на отражении, из другого ответа, если вы хотите создать универсальный валидатор.

0 голосов
/ 24 августа 2018

Вы можете использовать следующий метод расширения, который проверяет переданный тип посредством отражения и применяет указанные правила проверки:

public static bool Apply<T, TProperty>(this AbstractValidator<T> validator, string propertyName, Action<IRuleBuilderInitial<T, TProperty>> rule)
{
    var property = typeof(T).GetProperty(propertyName);

    if (property == null)
    {
        Console.WriteLine($"{typeof(T).Name} does not expose property {propertyName}!");
        return false;
    }

    if (!typeof(TProperty).IsAssignableFrom(property.PropertyType))
    {
        Console.WriteLine($"Property {typeof(T).Name}.{propertyName} is of type {property.PropertyType.Name} which is not (derived from) {typeof(TProperty).Name}!");
        return false;
    }

    rule(validator.RuleFor(t => (TProperty)property.GetValue(t)));

    return true;
}

Пример использования:

class a
{
    public string Prop { get; set; }
}

class b
{
    public DateTime Prop { get; set; }
}

class c
{
    public string Prop2 { get; set; }
}

class Validator<T> : AbstractValidator<T>
{
    public Validator()
    {
        this.Apply<T, string>("Prop", r => r.NotEmpty().WithMessage("Prop is required"));
    }
}

Console.WriteLine(new Validator<a>().Validate(new a { Prop = "AAA" }));
Console.WriteLine(new Validator<a>().Validate(new a()));
Console.WriteLine(new Validator<b>().Validate(new b { Prop = DateTime.Now }));
Console.WriteLine(new Validator<c>().Validate(new c { Prop2 = "AAA" }));
Console.WriteLine(new Validator<c>().Validate(new c { Prop2 = "AAA" }));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...