Required Attribute on Generic List Property

Nick Reeve picture Nick Reeve · Jun 21, 2011 · Viewed 15.7k times · Source

Is it possible to put a [Required] attribute onto a List<> property?

I bind to a generic list on POST and was wondering if I could make ModelState.IsValid() fail if the property has 0 items in it?

Answer

Michael Edenfield picture Michael Edenfield · Jun 21, 2011

Adding the Required attribute to a list-style property doesn't really do what you want. The will complain if the list isn't created, but won't complain if the list exists with 0 item in it.

However, it should be easy enough to derive your own data annotations attribute and make it check the list for Count > 0. Something like this (not tested yet):

[AttributeUsage(AttributeTargets.Property)]
public sealed class CannotBeEmptyAttribute : ValidationAttribute
{
    private const string defaultError = "'{0}' must have at least one element.";
    public CannotBeEmptyAttribute ( ) : base(defaultError) //
    { 
    }

    public override bool IsValid ( object value )
    {
      IList list = value as IList;
      return ( list != null && list.Count > 0 );
    }

    public override string FormatErrorMessage ( string name )
    {
        return String.Format(this.ErrorMessageString, name);
    }
}

EDIT:

You'll also have to be careful how you bind your list in your view. For example, if you bind a List<String> to a view like this:

<input name="ListName[0]" type="text" />
<input name="ListName[1]" type="text" />
<input name="ListName[2]" type="text" />
<input name="ListName[3]" type="text" />
<input name="ListName[4]" type="text" />

The MVC model binder will always put 5 elements in your list, all String.Empty. If this is how your View works, your attribute would need to get a bit more complex, such as using Reflection to pull the generic type parameter and comparing each list element with default(T) or something.

A better alternative is to use jQuery to create the input elements dynamically.