Comment manipuler booléens / cases à cocher ASP.NET MVC 2 avec des annotations de données?
j'ai un modèle de vue comme celui-ci:
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; }
}
afficher le code de balisage:
<%= Html.CheckBoxFor(m => m.AgreesWithTerms) %>
<%= Html.LabelFor(m => m.AgreesWithTerms)%>
le résultat:
aucune validation n'est exécutée. C'est bon pour l'instant parce que bool est un type de valeur et jamais null. Mais même si je rends les accords nulles, cela ne marchera pas car le compilateur crie
Modèles "peut être utilisé uniquement avec accès sur le terrain, l'accès à la propriété, à une seule dimension du tableau d'index, ou expressions indexeuses personnalisées à un seul paramètre."
alors, quelle est la bonne façon de gérer ça?
12 réponses
ma Solution est la suivante (ce n'est pas très différent des réponses déjà soumises, mais je crois que c'est mieux nommé):
/// <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;
}
}
, Alors vous pouvez l'utiliser comme ceci dans votre modèle:
[MustBeTrue(ErrorMessage = "You must accept the terms and conditions")]
[DisplayName("Accept terms and conditions")]
public bool AcceptsTerms { get; set; }
je créerais un validateur pour le côté serveur et le côté Client. En utilisant MVC et la validation discrète du formulaire, ceci peut être réalisé simplement en faisant ce qui suit:
tout d'abord, créez une classe dans votre projet pour effectuer la validation côté serveur comme suit:
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"
};
}
}
à la suite de cela, annoter la propriété appropriée dans votre modèle:
[EnforceTrue(ErrorMessage=@"Error Message")]
public bool ThisMustBeTrue{ get; set; }
et enfin, activez la validation côté client en ajoutant ce qui suit: script à votre vue:
<script type="text/javascript">
jQuery.validator.addMethod("enforcetrue", function (value, element, param) {
return element.checked;
});
jQuery.validator.unobtrusive.adapters.addBool("enforcetrue");
</script>
Note: Nous avons déjà créé une méthode GetClientValidationRules
qui pousse notre annotation à la vue de notre modèle.
Je l'ai obtenu en créant un attribut personnalisé:
public class BooleanRequiredAttribute : RequiredAttribute
{
public override bool IsValid(object value)
{
return value != null && (bool) value;
}
}
[Compare("Remember", ErrorMessage = "You must accept the terms and conditions")]
public bool Remember { get; set; }
c'est peut-être un "hack" mais vous pouvez utiliser l'attribut de portée intégré:
[Display(Name = "Accepted Terms Of Service")]
[Range(typeof(bool), "true", "true")]
public bool Terms { get; set; }
le seul problème est la chaîne de caractères" warning "qui dit"The FIELDNAME must be between True and true".
"Nécessaire" est la bonne validation, ici. Vous voulez quelque chose de semblable à "Doit avoir la valeur true," qui n'est pas le même que "Nécessaire". Que diriez-vous d'utiliser quelque chose comme:
[RegularExpression("^true")]
?
ma solution est cet attribut personnalisé simple pour les valeurs booléennes:
public class BooleanAttribute : ValidationAttribute
{
public bool Value
{
get;
set;
}
public override bool IsValid(object value)
{
return value != null && value is bool && (bool)value == Value;
}
}
, Alors vous pouvez l'utiliser comme ceci dans votre modèle:
[Required]
[Boolean(Value = true, ErrorMessage = "You must accept the terms and conditions")]
[DisplayName("Accept terms and conditions")]
public bool AcceptsTerms { get; set; }
Je ne fais que prendre le meilleur des solutions existantes et le rassembler en une seule réponse qui permet à la fois la validation côté serveur et côté client.
la valeur à appliquer aux propriétés du modèle a pour garantir une valeur de bool doit être vraie:
/// <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",
};
}
}
le JavaScript à inclure pour faire usage de validation discrète.
jQuery.validator.addMethod("mustbetrue", function (value, element) {
return element.checked;
});
jQuery.validator.unobtrusive.adapters.addBool("mustbetrue");
pour les personnes qui ont de la difficulté à obtenir ce travail de validation du côté du client (anciennement moi): assurez-vous que vous avez aussi
- Inclus <% Html.Validation valide (); % > avant le formulaire dans la vue
- Utilisé <%= Html.ValidationMessage ou Html.ValidationMessageFor pour le champ
- a créé un DataAnnotationsModelValidator qui renvoie une règle avec un type de validation personnalisé
- a enregistré la classe dérivant de DataAnnotationsModelValidator dans le Global.Application_Start
est un bon tutoriel sur ce sujet, mais manque l'étape 4.
la bonne façon de faire ceci est de vérifier le type!
[Range(typeof(bool), "true", "true", ErrorMessage = "You must or else!")]
public bool AgreesWithTerms { get; set; }
a trouvé une solution plus complète ici (validation côté serveur et côté client):
http://blog.degree.no/2012/03/validation-of-required-checkbox-in-asp-net-mvc/#comments
il suffit d'ajouter [RegularExpression]:
[DisplayName("I accept terms and conditions")]
[RegularExpression("True", ErrorMessage = "You must accept the terms and conditions")]
public bool AgreesWithTerms { get; set; }
Note - "vrai" doit commencer par le capital t