2011-06-21 21 views
23

¿Es posible poner un atributo [Obligatorio] en una propiedad de lista <>?Atributo requerido en la propiedad de lista genérica

Me enlace a una lista genérica en POST y me preguntaba si podría hacer que ModelState.IsValid() falle si la propiedad tiene 0 elementos en ella?

+0

Si cambia su modelo a utilizar una matriz en lugar de una lista se puede utilizar el [MinLengthAttribute ] (https://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.minlengthattribute%28v=vs.110%29.aspx) – janv8000

Respuesta

27

Agregar el atributo Required a una propiedad de estilo de lista realmente no hace lo que desea. La voluntad se quejará si la lista no se crea, pero no se quejará si la lista existe con 0 elementos en ella.

Sin embargo, debería ser bastante fácil para derivar atribuyen sus propias anotaciones de datos y hacer que compruebe la lista de Count> 0. Algo como esto (no determinado todavía):

[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:

También deberá tener cuidado al vincular su lista en su vista. Por ejemplo, si se enlaza un List<String> a una vista como esta:

<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" /> 

El modelo ligante MVC siempre poner 5 elementos en la lista, todas String.Empty. Si así es como funciona su Vista, su atributo debería ser un poco más complejo, como usar Reflection para extraer el parámetro de tipo genérico y comparar cada elemento de la lista con default(T) o algo así.

Una mejor alternativa es usar jQuery para crear dinámicamente los elementos de entrada.

+0

No creo que puedas [profundizar en esa edición] (https://stackoverflow.com/questions/45201531/cant-force-listint-to-be-required)? – Sinjai

+0

No estoy seguro de qué edición estás preguntando ... tu enlace solo responde a una pregunta. –

+0

Sí, la pregunta es (potencialmente, eso es parcialmente lo que estoy preguntando) relacionado. – Sinjai

20

Para los que estamos buscando ejemplos minimalistas:

[AttributeUsage(AttributeTargets.Property)] 
public sealed class CannotBeEmptyAttribute : RequiredAttribute 
{ 
    public override bool IsValid(object value) 
    { 
     var list = value as IEnumerable; 
     return list != null && list.GetEnumerator().MoveNext(); 
    } 
} 

Esto se modificó el código de la respuesta aceptada. Es adecuado en el caso de la pregunta, y en aún más casos, ya que IEnumerable es más alto en System.Collections hierarchy. Además, hereda el comportamiento de RequiredAttribute, por lo que no es necesario codificarlo explícitamente.

+0

La solución más genérica, ¡Gracias! –

1

Modificado aplicación @moudrick para mi requisito

Obligatorio Validación Atributo de lista y la casilla de verificación Lista

[AttributeUsage(AttributeTargets.Property)] 
public sealed class CustomListRequiredAttribute : RequiredAttribute 
{ 
    public override bool IsValid(object value) 
    { 
     var list = value as IEnumerable; 
     return list != null && list.GetEnumerator().MoveNext(); 
    } 
} 

Si tienes la lista pulsando

[AttributeUsage(AttributeTargets.Property)] 
public sealed class CustomCheckBoxListRequiredAttribute : RequiredAttribute 
{ 
    public override bool IsValid(object value) 
    { 
     bool result = false; 

     var list = value as IEnumerable<CheckBoxViewModel>; 
     if (list != null && list.GetEnumerator().MoveNext()) 
     { 
      foreach (var item in list) 
      { 
       if (item.Checked) 
       { 
        result = true; 
        break; 
       } 
      } 
     } 

     return result; 
    } 
} 

Aquí está mi Ver Modelo

public class CheckBoxViewModel 
{   
    public string Name { get; set; } 
    public bool Checked { get; set; } 
} 

Uso

[CustomListRequiredAttribute(ErrorMessage = "Required.")] 
public IEnumerable<YourClass> YourClassList { get; set; } 

[CustomCheckBoxListRequiredAttribute(ErrorMessage = "Required.")] 
public IEnumerable<CheckBoxViewModel> CheckBoxRequiredList { get; set; } 
2

Para aquellos que utilizan C# 6.0 y que están en busca de una sola línea:

[AttributeUsage(AttributeTargets.Property)] 
public sealed class CannotBeEmptyAttribute : RequiredAttribute 
{ 
    public override bool IsValid(object value) => (value as IEnumerable)?.GetEnumerator().MoveNext() ?? false; 
} 
Cuestiones relacionadas