Проверка ViewModel для списка


у меня есть следующее определение viewmodel

public class AccessRequestViewModel
{
    public Request Request { get; private set; }
    public SelectList Buildings { get; private set; }
    public List<Person> Persons { get; private set; }
}

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

Edit: в настоящее время выполняется эта проверка с FluentValidation (хорошая библиотека!)

RuleFor(vm => vm.Persons)
                .Must((vm, person) => person.Count > 0)
                .WithMessage("At least one person is required");
7 57

7 ответов:

если вы используете аннотации данных для выполнения проверки может потребоваться пользовательских атрибутов:

public class EnsureOneElementAttribute : ValidationAttribute
{
    public override bool IsValid(object value)
    {
        var list = value as IList;
        if (list != null)
        {
            return list.Count > 0;
        }
        return false;
    }
}

и затем:

[EnsureOneElement(ErrorMessage = "At least a person is required")]
public List<Person> Persons { get; private set; }

или сделать его более общим:

public class EnsureMinimumElementsAttribute : ValidationAttribute
{
    private readonly int _minElements;
    public EnsureMinimumElementsAttribute(int minElements)
    {
        _minElements = minElements;
    }

    public override bool IsValid(object value)
    {
        var list = value as IList;
        if (list != null)
        {
            return list.Count >= _minElements;
        }
        return false;
    }
}

и затем:

[EnsureMinimumElements(1, ErrorMessage = "At least a person is required")]
public List<Person> Persons { get; private set; }

лично я использую FluentValidation.NET вместо аннотаций данных для выполнения проверки, потому что я предпочитаю императивную логику проверки вместо декларативной. Я думаю, что он более мощный. Так что мое правило проверки будет просто выглядеть так:

RuleFor(x => x.Persons)
    .Must(x => x.Count > 0)
    .WithMessage("At least a person is required");

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

[Range(minimum: 1, maximum: Int32.MaxValue, ErrorMessage = "At least one item needs to be selected")]
public int ItemCount
{
    get
    {
        return Items != null ? Items.Length : 0;
    }
}

В приведенном выше коде ItemCount является примером вычисляемого свойства для проверяемой модели представления, а Items-примером свойства коллекции элементов, количество которых проверяется. В этом примере, по крайней мере один элемент применяется к элементу коллекции, и максимальное ограничение - это максимальное значение, которое может принимать целое число, которое для большинства практических целей не ограничено. Сообщение об ошибке при сбое проверки также может быть установлено через элемент ErrorMessage атрибута RangeAttribute в приведенном выше примере.

ответ Дарина хорош, но версия ниже автоматически даст вам полезное сообщение об ошибке.

public class MinimumElementsAttribute : ValidationAttribute
{
    private readonly int minElements;

    public MinimumElementsAttribute(int minElements)
    {
        this.minElements = minElements;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var list = value as IList;

        var result = list?.Count >= minElements;

        return result
            ? ValidationResult.Success
            : new ValidationResult($"{validationContext.DisplayName} requires at least {minElements} element" + (minElements > 1 ? "s" : string.Empty));
    }
}

использование:

    [MinimumElements(1)]
    public List<Customer> Customers {get;set}

    [MinimumElements(2)]
    public List<Address> Addresses {get;set}

сообщение об ошибке:

  • клиенты требуют по крайней мере 1 элемент
  • адреса требуют не менее 2 элементов

у вас есть два варианта здесь, либо создать пользовательский атрибут проверки и украсить свойство с ним, или вы можете сделать ваш ViewModel реализовать IValidatableObject интерфейс (который определяет Validate способ)

надеюсь, что это помогает :)

следующий код работает в asp.net ядро 1.1.

[Required, MinLength(1, ErrorMessage = "At least one item required in work order")]
public ICollection<WorkOrderItem> Items { get; set; }

было бы очень чисто и элегантно иметь пользовательскую проверку. Что-то вроде этого:

public class AccessRequestViewModel
{
    public Request Request { get; private set; }
    public SelectList Buildings { get; private set; }
    [AtLeastOneItem]
    public List<Person> Persons { get; private set; }
}

или [MinimumItems(1)].

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

public class AccessRequestViewModel
{
    private AccessRequesetViewModel() { };

    public static GetAccessRequestViewModel (List<Person> persons)
    {
            return new AccessRequestViewModel()
            {
                Persons = persons,
            };
    }

    public Request Request { get; private set; }
    public SelectList Buildings { get; private set; }
    public List<Person> Persons { get; private set; }
}

всегда используя фабрику для создания экземпляра ViewModel, вы можете гарантировать, что всегда будет человек.

Это, вероятно, не идеально подходит для того, что вы хотите, но это, вероятно, будет работать.