¿Hay alguna manera de que las anotaciones de datos requieran que una propiedad booleana se establezca en verdadera?
public class MyAwesomeObj{
public bool ThisMustBeTrue{get;set;}
}
¿Hay alguna manera de que las anotaciones de datos requieran que una propiedad booleana se establezca en verdadera?
public class MyAwesomeObj{
public bool ThisMustBeTrue{get;set;}
}
Respuestas:
Podrías crear tu propio validador:
public class IsTrueAttribute : ValidationAttribute
{
#region Overrides of ValidationAttribute
/// <summary>
/// Determines whether the specified value of the object is valid.
/// </summary>
/// <returns>
/// true if the specified value is valid; otherwise, false.
/// </returns>
/// <param name="value">The value of the specified validation object on which the <see cref="T:System.ComponentModel.DataAnnotations.ValidationAttribute"/> is declared.
/// </param>
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;
}
#endregion
}
return (bool) value == true;
esta es una comparación redundante
Crearía un validador tanto para el servidor como para el cliente. Usando MVC y la validación de formularios discretos, 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 así:
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 creamos un método GetClientValidationRules
que empuja nuestra anotación a la vista desde nuestro modelo.
Si usa archivos de recursos para proporcionar el mensaje de error para la internacionalización, elimine la FormatErrorMessage
llamada (o simplemente llame a la base) y modifique el GetClientValidationRules
método así:
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
string errorMessage = String.Empty;
if(String.IsNullOrWhiteSpace(ErrorMessage))
{
// Check if they supplied an error message resource
if(ErrorMessageResourceType != null && !String.IsNullOrWhiteSpace(ErrorMessageResourceName))
{
var resMan = new ResourceManager(ErrorMessageResourceType.FullName, ErrorMessageResourceType.Assembly);
errorMessage = resMan.GetString(ErrorMessageResourceName);
}
}
else
{
errorMessage = ErrorMessage;
}
yield return new ModelClientValidationRule
{
ErrorMessage = errorMessage,
ValidationType = "enforcetrue"
};
}
Sé que esta es una publicación anterior, pero quería compartir una forma simple del lado del servidor para hacer esto. Usted crea una propiedad pública establecida en true y compara su bool con esa propiedad. Si su bool no está marcado (por defecto es falso), el formulario no se validará.
public bool isTrue
{ get { return true; } }
[Required]
[Display(Name = "I agree to the terms and conditions")]
[Compare("isTrue", ErrorMessage = "Please agree to Terms and Conditions")]
public bool AgreeTerms { get; set; }
Código de la maquinilla de afeitar
@Html.CheckBoxFor(m => Model.AgreeTerms, new { id = "AgreeTerms", @checked = "checked" })
<label asp-for="AgreeTerms" class="control-label"></label>
<a target="_blank" href="/Terms">Read</a>
<br />
@Html.ValidationMessageFor(model => model.AgreeTerms, "", new { @class = "text-danger" })
@Html.HiddenFor(x => Model.isTrue)
Probé varias soluciones, pero ninguna funcionó completamente para mí para obtener la validación del lado del cliente y del servidor. Entonces, lo que hice en mi aplicación MVC 5 para que funcione:
En su ViewModel (para la validación del lado del servidor):
public bool IsTrue => true;
[Required]
[Display(Name = "I agree to the terms and conditions")]
[Compare(nameof(IsTrue), ErrorMessage = "Please agree to Terms and Conditions")]
public bool HasAcceptedTermsAndConditions { get; set; }
En su página de Razor (para la validación del lado del cliente):
<div class="form-group">
@Html.CheckBoxFor(m => m.HasAcceptedTermsAndConditions)
@Html.LabelFor(m => m.HasAcceptedTermsAndConditions)
@Html.ValidationMessageFor(m => m.HasAcceptedTermsAndConditions)
@Html.Hidden(nameof(Model.IsTrue), "true")
</div>
Solo me gustaría dirigir a las personas al siguiente Fiddle: https://dotnetfiddle.net/JbPh0X
El usuario agregó
[Range(typeof(bool), "true", "true", ErrorMessage = "You gotta tick the box!")]
a su propiedad booleana que hace que funcione la validación del lado del servidor.
Para que también funcione la validación del lado del cliente, agregaron el siguiente script:
// extend jquery range validator to work for required checkboxes
var defaultRangeValidator = $.validator.methods.range;
$.validator.methods.range = function(value, element, param) {
if(element.type === 'checkbox') {
// if it's a checkbox return true if it is checked
return element.checked;
} else {
// otherwise run the default validation function
return defaultRangeValidator.call(this, value, element, param);
}
}
Simplemente verifique si su representación de cadena es igual a True
:
[RegularExpression("True")]
public bool TermsAndConditions { get; set; }
RegularExpressionAttribute
utiliza internamente Convert.ToString
para obtener la representación de cadena del valor de la propiedad (que se le entrega como un object
).
Puede crear su propio atributo o utilizar CustomValidationAttribute .
Así es como usaría CustomValidationAttribute:
[CustomValidation(typeof(BoolValidation), "ValidateBool")]
donde BoolValidation se define como:
public class BoolValidation
{
public static ValidationResult ValidateBool(bool boolToBeTrue)
{
if (boolToBeTrue)
{
return ValidationResult.Success;
}
else
{
return new ValidationResult(
"Bool must be true.");
}
}
[Required]
atributo significa que requiere cualquier valor, puede ser verdadero o falso. Tendría que usar otra validación para eso.
Continuando con la publicación de ta.speot.is y el comentario de Jerad Rose:
La publicación dada no funcionará del lado del cliente con una validación discreta. Esto debería funcionar en ambos campos (cliente y servidor):
[RegularExpression("(True|true)")]
public bool TermsAndConditions { get; set; }
regex
método discreto define primero verifica si la casilla de verificación es opcional antes de validar la expresión regular, lo cual tiene sentido, excepto que jquery.validate parece considerar cualquier casilla de verificación no marcada como opcional. tl; dr Solo ejecuta la expresión regular en las casillas de verificación marcadas. Podemos agregar una corrección para el regex
validator
método o simplemente crear un validador personalizado.
.NET Core MVC: casilla de verificación obligatoria con anotaciones de datos
public class MyModel
{
[Display(Name = "Confirmation")]
[Range(typeof(bool), "true", "true", ErrorMessage = "Please check the Confirmation checkbox.")]
public bool IsConfirmed { get; set; }
}
<div class="custom-control custom-checkbox col-10">
<input type="checkbox" asp-for="IsConfirmed" class="custom-control-input" />
<label class="custom-control-label" for="IsConfirmed">
"By clicking 'submit', I confirm."
</label>
<span asp-validation-for="IsConfirmed" class="text-danger"></span>
</div>
<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
<script type="text/javascript">
$(document).ready(function () {
// extend range validator method to treat checkboxes differently
var defaultRangeValidator = $.validator.methods.range;
$.validator.methods.range = function (value, element, param) {
if (element.type === 'checkbox') {
// if it's a checkbox return true if it is checked
return element.checked;
} else {
// otherwise run the default validation function
return defaultRangeValidator.call(this, value, element, param);
}
}
});
</script>
No conozco una forma de realizar anotaciones de datos, pero esto se hace fácilmente en su controlador.
public ActionResult Add(Domain.Something model)
{
if (!model.MyCheckBox)
ModelState.AddModelError("MyCheckBox", "You forgot to click accept");
if (ModelState.IsValid) {
//'# do your stuff
}
}
La única otra opción sería construir un validador personalizado para el lado del servidor y un validador remoto para el lado del cliente (la validación remota solo está disponible en MVC3 +)
¿Tiene los elementos adecuados configurados en web.config ?
Eso podría hacer que la validación no funcione.
También puede intentar crear un atributo de validación personalizado (ya que [Required]
solo le importa si existe o no, y a usted le importa el valor):
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
sealed public class RequiredTrueAttribute : ValidationAttribute
{
// Internal field to hold the mask value.
readonly bool accepted;
public bool Accepted
{
get { return accepted; }
}
public RequiredTrueAttribute(bool accepted)
{
this.accepted = accepted;
}
public override bool IsValid(object value)
{
bool isAccepted = (bool)value;
return (isAccepted == true);
}
public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentCulture,
ErrorMessageString, name, this.Accepted);
}
}
Entonces, uso:
[RequiredTrue(ErrorMessage="{0} requires acceptance to continue.")]
public bool Agreement {get; set;}
De aqui .
Esto es lo que funcionó para mí. Nada más hizo. MVC 5:
Modelo
public string True
{
get
{
return "true";
}
}
[Required]
[Compare("True", ErrorMessage = "Please agree to the Acknowlegement")]
public bool Acknowlegement { get; set; }
Ver
@Html.HiddenFor(m => m.True)
@Html.EditorFor(model => model.Acknowlegement, new { htmlAttributes = Model.Attributes })
@Html.ValidationMessageFor(model => model.Acknowlegement, "", new { @class = "text-danger" })
Para ASP.NET Core MVC, aquí está la validación de cliente y servidor, basada en la solución de dazbradbury
public class EnforceTrueAttribute : ValidationAttribute, IClientModelValidator
{
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;
}
public void AddValidation(ClientModelValidationContext context)
{
MergeAttribute(context.Attributes, "data-val", "true");
var errorMessage = ErrorMessage ??
$"The value for field {context.ModelMetadata.GetDisplayName()} must be true.";
MergeAttribute(context.Attributes, "data-val-enforcetrue", errorMessage);
}
private void MergeAttribute(IDictionary<string, string> attributes,
string key,
string value)
{
if (attributes.ContainsKey(key))
{
return;
}
attributes.Add(key, value);
}
}
Y luego sobre el cliente:
$.validator.addMethod("enforcetrue", function (value, element, param) {
return element.checked;
});
$.validator.unobtrusive.adapters.addBool("enforcetrue");
Entonces el uso es:
[EnforceTrue(ErrorMessage = "Please tick the checkbox")]
public bool IsAccepted { get; set; }
Intenté usar la respuesta de fields.cage y no funcionó del todo para mí, pero algo más simple sí lo hizo, y no estoy seguro exactamente por qué (¿una versión diferente de Razor, tal vez?), Pero todo lo que tenía que hacer era esto:
[Required]
[Range(typeof(bool), "true", "true", ErrorMessage = "Agreement required.")]
[Display(Name = "By clicking here, I agree that my firstborn child will etc etc...")]
public bool Agreement1Checked { get; set; }
Y en el archivo .cshtml:
@Html.CheckBoxFor(m => m.Agreement1Checked)
@Html.LabelFor(m => m.Agreement1Checked)
@Html.ValidationMessageFor(m => m.Agreement1Checked)
[NaN, NaN]
donde debería estar[true, true]
Creo que la mejor manera de manejar esto es simplemente verificar en su controlador si la casilla es verdadera; de lo contrario, simplemente agregue un error a su modelo y haga que vuelva a mostrar su vista.
Como se indicó anteriormente, lo único que hace [Obligatorio] es asegurarse de que haya un valor y, en su caso, si no se marca, seguirá siendo falso.
/// <summary>
/// Summary : -CheckBox for or input type check required validation is not working the root cause and solution as follows
///
/// Problem :
/// The key to this problem lies in interpretation of jQuery validation 'required' rule. I digged a little and find a specific code inside a jquery.validate.unobtrusive.js file:
/// adapters.add("required", function (options) {
/// if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
/// setValidationValues(options, "required", true);
/// }
/// });
///
/// Fix: (Jquery script fix at page level added in to check box required area)
/// jQuery.validator.unobtrusive.adapters.add("brequired", function (options) {
/// if (options.element.tagName.toUpperCase() == "INPUT" && options.element.type.toUpperCase() == "CHECKBOX") {
/// options.rules["required"] = true;
/// if (options.message) {
/// options.messages["required"] = options.message;
/// }
/// Fix : (C# Code for MVC validation)
/// You can see it inherits from common RequiredAttribute. Moreover it implements IClientValidateable. This is to make assure that rule will be propagated to client side (jQuery validation) as well.
///
/// Annotation example :
/// [BooleanRequired]
/// public bool iAgree { get; set' }
/// </summary>
public class BooleanRequired : RequiredAttribute, IClientValidatable
{
public BooleanRequired()
{
}
public override bool IsValid(object value)
{
return value != null && (bool)value == true;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
return new ModelClientValidationRule[] { new ModelClientValidationRule() { ValidationType = "brequired", ErrorMessage = this.ErrorMessage } };
}
}