Checking the layout of the ViewModel for a list

I have the following viewport definition

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

So, in my application there must be at least 1 person to request access. What approach can be used for verification? I do not want this check to be performed in my controller, which would be easy to do. Is the only custom attribute attribute selection?

Edit: Performing this check with FluentValidation (good library!)

 RuleFor(vm => vm.Persons) .Must((vm, person) => person.Count > 0) .WithMessage("At least one person is required"); 
+43
c # asp.net-mvc-3 fluentvalidation model-validation
Feb 28 '11 at 19:40
source share
6 answers

If you use data annotations to perform validation, you may need a custom attribute:

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

and then:

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

or make it more general:

 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; } } 

and then:

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

Personally, I use FluentValidation.NET instead of data annotations to perform validation, because I prefer the logic of correct validation over declarative. I think he is more powerful. So my validation rule would look something like this:

 RuleFor(x => x.Persons) .Must(x => x.Count > 0) .WithMessage("At least a person is required"); 
+111
Feb 28 '11 at 19:44
source share

Another possible way to handle counting checks for items in a collection of view model objects is to have a computed property that returns the count of the collection or list. The RangeAttribute attribute can be used, as in the code below, to ensure that the account is validated:

 [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; } } 

In the above code, ItemCount is an exemplary computed property for a validated view model, and elements is a property of an example member that is being verified. In this example, at least one element is applied to a member of the collection, and the maximum limit is the maximum value that an integer can take, which for most practical purposes is unlimited. The error message when validation fails can also be set via the RangeAttribute ErrorMessage member in the above example.

+5
Aug 14 '15 at 14:33
source share

One approach may be to use a private constructor and a static method to return an instance of an object.

 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; } } 

By always using factory to create an instance of ViewModel, you can guarantee that there will always be a person.

This is probably not ideal for what you want, but most likely it will work.

0
Feb 28 '11 at 19:45
source share

It would be very clean and elegant to have a custom check. Something like that:

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

Or [MinimumItems(1)] .

0
Feb 28 '11 at 19:48
source share

Here you have two options: create a custom validation attribute and decorate it with this property, or you can force your ViewModel to implement the IValidatableObject interface (which defines the Validate method)

Hope this helps :)

0
Feb 28 '11 at 19:52
source share

The following code works in asp.net core 1.1.

 [Required, MinLength(1, ErrorMessage = "At least one item required in work order")] public ICollection<WorkOrderItem> Items { get; set; } 
0
Aug 31 '17 at 19:37
source share



All Articles