Cómo manejar booleanos / Casillas de verificación en ASP.NET MVC 2 con anotaciones de datos?
Tengo un modelo de vista como este:
public class SignUpViewModel
{
[Required(ErrorMessage = "Bitte lesen und akzeptieren Sie die AGB.")]
[DisplayName("Ich habe die AGB gelesen und akzeptiere diese.")]
public bool AgreesWithTerms { get; set; }
}
El código de marcado de la vista:
<%= Html.CheckBoxFor(m => m.AgreesWithTerms) %>
<%= Html.LabelFor(m => m.AgreesWithTerms)%>
El resultado:
No se ejecuta ninguna validación. Eso está bien hasta ahora porque bool es un tipo de valor y nunca nulo. Pero incluso si hago que AgreesWithTerms sea nullable, no funcionará porque el compilador grita
"Las plantillas solo se pueden usar con acceso a campos, acceso a propiedades, índice de matriz de una sola dimensión o expresiones de indexador personalizado de un solo parámetro."
Entonces, ¿cuál es la forma correcta de manejar esto?
12 answers
Mi solución es la siguiente (no es muy diferente a las respuestas ya presentadas, pero creo que se llama mejor):
/// <summary>
/// Validation attribute that demands that a boolean value must be true.
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class MustBeTrueAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
return value != null && value is bool && (bool)value;
}
}
Entonces puedes usarlo así en tu modelo:
[MustBeTrue(ErrorMessage = "You must accept the terms and conditions")]
[DisplayName("Accept terms and conditions")]
public bool AcceptsTerms { get; set; }
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-25 23:31:46
Crearía un validador tanto para el Servidor COMO para EL Cliente. Usando MVC y validación discreta de formularios, esto se puede lograr simplemente haciendo lo siguiente:
En primer lugar, cree una clase en su proyecto para realizar la validación del lado del servidor de la siguiente manera:
public class EnforceTrueAttribute : ValidationAttribute, IClientValidatable
{
public override bool IsValid(object value)
{
if (value == null) return false;
if (value.GetType() != typeof(bool)) throw new InvalidOperationException("can only be used on boolean properties.");
return (bool)value == true;
}
public override string FormatErrorMessage(string name)
{
return "The " + name + " field must be checked in order to continue.";
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
yield return new ModelClientValidationRule
{
ErrorMessage = String.IsNullOrEmpty(ErrorMessage) ? FormatErrorMessage(metadata.DisplayName) : ErrorMessage,
ValidationType = "enforcetrue"
};
}
}
Después de esto, anote la propiedad apropiada en su modelo:
[EnforceTrue(ErrorMessage=@"Error Message")]
public bool ThisMustBeTrue{ get; set; }
Y Finalmente, habilite la validación del lado del cliente agregando el siguiente script a su vista:
<script type="text/javascript">
jQuery.validator.addMethod("enforcetrue", function (value, element, param) {
return element.checked;
});
jQuery.validator.unobtrusive.adapters.addBool("enforcetrue");
</script>
Nota: Ya hemos creado un método GetClientValidationRules
que empuja nuestra anotación a la vista desde nuestro modelo.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-27 17:56:55
Lo conseguí creando un atributo personalizado:
public class BooleanRequiredAttribute : RequiredAttribute
{
public override bool IsValid(object value)
{
return value != null && (bool) value;
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-11 15:17:14
[Compare("Remember", ErrorMessage = "You must accept the terms and conditions")]
public bool Remember { get; set; }
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-20 08:03:26
Esto podría ser un "hackeo", pero puede usar el atributo de rango incorporado:
[Display(Name = "Accepted Terms Of Service")]
[Range(typeof(bool), "true", "true")]
public bool Terms { get; set; }
El único problema es que la cadena "warning" dirá "El FIELDNAME debe estar entre True y true".
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-03 22:02:28
"Requerido" es la validación incorrecta, aquí. Desea algo similar a "Debe tener el valor verdadero", que no es lo mismo que "Requerido". ¿Qué hay de usar algo como:
[RegularExpression("^true")]
?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-11 15:06:25
Mi solución es este atributo personalizado simple para valores booleanos:
public class BooleanAttribute : ValidationAttribute
{
public bool Value
{
get;
set;
}
public override bool IsValid(object value)
{
return value != null && value is bool && (bool)value == Value;
}
}
Entonces puedes usarlo así en tu modelo:
[Required]
[Boolean(Value = true, ErrorMessage = "You must accept the terms and conditions")]
[DisplayName("Accept terms and conditions")]
public bool AcceptsTerms { get; set; }
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-06 17:54:41
Solo estoy tomando lo mejor de las soluciones existentes y poniéndolas juntas en una sola respuesta que permite la validación tanto del lado del servidor como del lado del cliente.
Las propiedades a aplicar al modelo a para asegurar que un valor bool debe ser true:
/// <summary>
/// Validation attribute that demands that a <see cref="bool"/> value must be true.
/// </summary>
/// <remarks>Thank you <c>http://stackoverflow.com/a/22511718</c></remarks>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class MustBeTrueAttribute : ValidationAttribute, IClientValidatable
{
/// <summary>
/// Initializes a new instance of the <see cref="MustBeTrueAttribute" /> class.
/// </summary>
public MustBeTrueAttribute()
: base(() => "The field {0} must be checked.")
{
}
/// <summary>
/// Checks to see if the given object in <paramref name="value"/> is <c>true</c>.
/// </summary>
/// <param name="value">The value to check.</param>
/// <returns><c>true</c> if the object is a <see cref="bool"/> and <c>true</c>; otherwise <c>false</c>.</returns>
public override bool IsValid(object value)
{
return (value as bool?).GetValueOrDefault();
}
/// <summary>
/// Returns client validation rules for <see cref="bool"/> values that must be true.
/// </summary>
/// <param name="metadata">The model metadata.</param>
/// <param name="context">The controller context.</param>
/// <returns>The client validation rules for this validator.</returns>
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
if (metadata == null)
throw new ArgumentNullException("metadata");
if (context == null)
throw new ArgumentNullException("context");
yield return new ModelClientValidationRule
{
ErrorMessage = FormatErrorMessage(metadata.DisplayName),
ValidationType = "mustbetrue",
};
}
}
El JavaScript a incluir para hacer uso de la validación discreta.
jQuery.validator.addMethod("mustbetrue", function (value, element) {
return element.checked;
});
jQuery.validator.unobtrusive.adapters.addBool("mustbetrue");
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-20 14:56:53
Para las personas que tienen problemas para que esto funcione para la validación en el lado del cliente (anteriormente yo): asegúrese de tener también
- Incluido antes del formulario en la vista
- Usado
- Se creó un DataAnnotationsModelValidator que devuelve una regla con un tipo de validación personalizado
- Registró la clase derivada de DataAnnotationsModelValidator en el Global.Application_Start
Es un buen tutorial para hacer esto, pero falla el paso 4.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-28 17:17:37
La forma correcta de hacer esto es comprobar el tipo!
[Range(typeof(bool), "true", "true", ErrorMessage = "You must or else!")]
public bool AgreesWithTerms { get; set; }
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-18 20:28:03
Encontré una solución más completa aquí (validación del lado del servidor y del cliente):
Http://blog.degree.no/2012/03/validation-of-required-checkbox-in-asp-net-mvc/#comments
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-10 18:59:39
Basta con añadir [RegularExpression]:
[DisplayName("I accept terms and conditions")]
[RegularExpression("True", ErrorMessage = "You must accept the terms and conditions")]
public bool AgreesWithTerms { get; set; }
Nota - "True" debe comenzar con mayúscula T
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-07 11:57:37