asp.net mvc - side - Atributo requerido en la propiedad de lista genérica
validate model c# (4)
Implementación modificada de @moudrick para mi requerimiento
Atributo de validación requerido para Lista y casilla de verificación
[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 tiene lista de casillas de verificación
[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 modelo de vista
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; }
¿Es posible poner un atributo [Required] en una propiedad List <>?
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.
Para aquellos que buscan 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();
}
}
Este es un código modificado 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.
Para aquellos que usan C # 6.0 (y superior) y que buscan soluciones únicas:
[AttributeUsage(AttributeTargets.Property)]
public sealed class CannotBeEmptyAttribute : RequiredAttribute
{
public override bool IsValid(object value) => (value as IEnumerable)?.GetEnumerator().MoveNext() ?? false;
}
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 derivar su propio atributo de anotación de datos y hacer que verifique la lista para Count
> 0. Algo así (no probado aún):
[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);
}
}
EDITAR:
También tendrás que tener cuidado de cómo unir tu lista en tu vista. Por ejemplo, si enlaza una 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 archivador modelo MVC siempre pondrá 5 elementos en su lista, todos 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 el default(T)
o algo así.
Una mejor alternativa es usar jQuery para crear los elementos de entrada dinámicamente.