Проверка 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 ответов:
если вы используете аннотации данных для выполнения проверки может потребоваться пользовательских атрибутов:
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, вы можете гарантировать, что всегда будет человек.
Это, вероятно, не идеально подходит для того, что вы хотите, но это, вероятно, будет работать.