web-dev-qa-db-fra.com

Comment gérer les booléens / checkbox dans ASP.NET MVC 2 avec DataAnnotations?

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; }
}

Le code de balisage de vue:

<%= Html.CheckBoxFor(m => m.AgreesWithTerms) %>
<%= Html.LabelFor(m => m.AgreesWithTerms)%>

Le résultat:

Aucune validation n'est exécutée. C'est correct jusqu'à présent car bool est un type de valeur et jamais null. Mais même si je rend AgreesWithTerms nullable, cela ne fonctionnera pas parce que le compilateur crie

"Les modèles ne peuvent être utilisés qu'avec un accès aux champs, un accès aux propriétés, un index de tableau à une dimension ou des expressions d'indexeur personnalisé à paramètre unique."

Alors, quelle est la bonne façon de gérer cela?

46
asp_net

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;
    }
}
18
asp_net

Ma solution est la suivante (ce n'est pas très différent des réponses déjà soumises, mais je pense qu'elle est mieux nommée):

/// <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;
    }
}

Ensuite, 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; }
91
s1mm0t

Je créerais un validateur à la fois côté serveur ET côté client. En utilisant MVC et une validation de formulaire discrète, cela peut être réalisé simplement en procédant comme suit:

Tout d'abord, créez une classe dans votre projet pour effectuer la validation côté serveur comme ceci:

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"
        };
    }
}

Ensuite, annotez la propriété appropriée dans votre modèle:

[EnforceTrue(ErrorMessage=@"Error Message")]
public bool ThisMustBeTrue{ get; set; }

Enfin, activez la validation côté client en ajoutant le script suivant à votre vue:

<script type="text/javascript">
    jQuery.validator.addMethod("enforcetrue", function (value, element, param) {
        return element.checked;
    });
    jQuery.validator.unobtrusive.adapters.addBool("enforcetrue");
</script>

Remarque: Nous avons déjà créé une méthode GetClientValidationRules qui pousse notre annotation vers la vue de notre modèle.

49
dazbradbury
[Compare("Remember", ErrorMessage = "You must accept the terms and conditions")]
public bool Remember { get; set; }
6
Vedat Taylan

Cela peut être un "hack" mais vous pouvez utiliser l'attribut Range intégré:

[Display(Name = "Accepted Terms Of Service")]
[Range(typeof(bool), "true", "true")]
public bool Terms { get; set; }

Le seul problème est que la chaîne "warning" indiquera "Le FIELDNAME doit être entre True et true".

5
ProVega

"Obligatoire" est la mauvaise validation, ici. Vous voulez quelque chose qui ressemble à "Doit avoir la valeur true", qui n'est pas la même chose que "Obligatoire". Qu'en est-il de l'utilisation de quelque chose comme:

[RegularExpression("^true")]

?

4
Craig Stuntz

Je prends simplement le meilleur des solutions existantes et je les rassemble en une seule réponse qui permet la validation côté serveur et côté client.

Le à appliquer pour modéliser une propriété afin de garantir une valeur booléenne doit être vrai:

/// <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 utiliser la validation discrète.

jQuery.validator.addMethod("mustbetrue", function (value, element) {
    return element.checked;
});
jQuery.validator.unobtrusive.adapters.addBool("mustbetrue");
3
James Skimming

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;
    }
}

Ensuite, 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; }
3

Pour les personnes qui ont du mal à faire fonctionner cela pour la validation côté client (anciennement moi): assurez-vous d'avoir également

  1. Inclus <% Html.EnableClientValidation (); %> avant le formulaire dans la vue
  2. Utilisé <% = Html.ValidationMessage ou Html.ValidationMessageFor pour le champ
  3. Création d'un DataAnnotationsModelValidator qui renvoie une règle avec un type de validation personnalisé
  4. Enregistré la classe dérivant de DataAnnotationsModelValidator dans le Global.Application_Start

http://www.highoncoding.com/Articles/729_Creating_Custom_Client_Side_Validation_in_ASP_NET_MVC_2_0.aspx

est un bon tutoriel pour le faire, mais manque l'étape 4.

2
Craig Lebowitz

La bonne façon de le faire est de vérifier le type!

[Range(typeof(bool), "true", "true", ErrorMessage = "You must or else!")]
public bool AgreesWithTerms { get; set; }
2
saj

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

1
user1608132

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; }

Remarque - "True" doit commencer par un T majuscule

1
mvt