asp.net - regulares - Anotaciones de datos para la validación, ¿al menos un campo obligatorio?
validar campos formulario mvc (4)
Si tengo un objeto de búsqueda con una lista de campos, ¿puedo, mediante el espacio de nombres System.ComponentModel.DataAnnotations, configurarlo para validar que al menos uno de los campos en la búsqueda no es nulo o está vacío? es decir, todos los campos son opcionales, pero al menos uno siempre debe ingresarse.
Creé un validador personalizado para esto, no le dará validación del lado del cliente, solo del lado del servidor.
Tenga en cuenta que para que esto funcione, deberá usar tipos que nullable
valores nullable
, ya que los tipos de valores tendrán como valor predeterminado 0
o false
.
Primero crea un nuevo validador:
using System.ComponentModel.DataAnnotations;
using System.Reflection;
// This is a class-level attribute, doesn''t make sense at the property level
[AttributeUsage(AttributeTargets.Class)]
public class AtLeastOnePropertyAttribute : ValidationAttribute
{
// Have to override IsValid
public override bool IsValid(object value)
{
// Need to use reflection to get properties of "value"...
var typeInfo = value.GetType();
var propertyInfo = typeInfo.GetProperties();
foreach (var property in propertyInfo)
{
if (null != property.GetValue(value, null))
{
// We''ve found a property with a value
return true;
}
}
// All properties were null.
return false;
}
}
A continuación, puede decorar sus modelos con esto:
[AtLeastOneProperty(ErrorMessage="You must supply at least one value")]
public class SimpleTest
{
public string StringProp { get; set; }
public int? Id { get; set; }
public bool? BoolProp { get; set; }
}
Luego, cuando llame a ModelState.IsValid
se llamará a su validador y su mensaje se agregará a ValidationSummary en su vista.
Tenga en cuenta que puede extender esto para verificar el tipo de propiedad que regresa, o buscar atributos en ellos para incluir / excluir de la validación si lo desea, esto es asumiendo un validador genérico que no sabe nada sobre el tipo que está validando .
Si desea realizar una validación compleja en contra de cualquier clase .Net, sin litrar con anotaciones, consulte FluentValidation o .Net 2.0, FluentValidation for 2.0
He extendido la respuesta de Zhaph para admitir la agrupación de propiedades.
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class AtLeastOnePropertyAttribute : ValidationAttribute
{
private string[] PropertyList { get; set; }
public AtLeastOnePropertyAttribute(params string[] propertyList)
{
this.PropertyList = propertyList;
}
//See http://.com/a/1365669
public override object TypeId
{
get
{
return this;
}
}
public override bool IsValid(object value)
{
PropertyInfo propertyInfo;
foreach (string propertyName in PropertyList)
{
propertyInfo = value.GetType().GetProperty(propertyName);
if (propertyInfo != null && propertyInfo.GetValue(value, null) != null)
{
return true;
}
}
return false;
}
}
Uso:
[AtLeastOneProperty("StringProp", "Id", "BoolProp", ErrorMessage="You must supply at least one value")]
public class SimpleTest
{
public string StringProp { get; set; }
public int? Id { get; set; }
public bool? BoolProp { get; set; }
}
Y si quieres tener 2 grupos (o más):
[AtLeastOneProperty("StringProp", "Id", ErrorMessage="You must supply at least one value")]
[AtLeastOneProperty("BoolProp", "BoolPropNew", ErrorMessage="You must supply at least one value")]
public class SimpleTest
{
public string StringProp { get; set; }
public int? Id { get; set; }
public bool? BoolProp { get; set; }
public bool? BoolPropNew { get; set; }
}
Esta pregunta es bastante antigua, pero a partir de .NET 3.5 (creo), IValidatableObject puede ayudar con situaciones difíciles de validación. Puede implementarlo para validar reglas comerciales arbitrarias. En este caso, algo así como:
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (string.IsNullOrWhiteSpace(FieldOne) && string.IsNullOrWhiteSpace(FieldTwo))
yield return new ValidationResult("Must provide value for either FieldOne or FieldTwo.", new string[] { "FieldOne", "FieldTwo" });
}