48 votes

Comment fournir des avertissements lors de la validation dans ASP.NET MVC?

Parfois la saisie de l'utilisateur n'est pas strictement non valide, mais peut être considérée comme problématique.

Par exemple:

  • Un utilisateur entre dans une longue phrase en une seule ligne, Name champ. Il devrait probablement ont utilisé l' Description champ à la place.
  • Un utilisateur entre un Name qui est très similaire à celui d'une entité existante. Peut-être qu'il est de la saisie de la même entité, mais ne réalisent pas qu'il existe déjà, ou certains simultanées utilisateur a entré.

Certains de ces effets peuvent facilement être vérifiés côté client, certains exigent côté serveur vérifie.

Quel est le meilleur moyen, peut-être quelque chose de similaire DataAnnotations de validation, de fournir des mises en garde de l'utilisateur dans de tels cas? La clé ici est que l'utilisateur doit être en mesure de remplacer l'avertissement et encore soumettre le formulaire (ou re-soumettez le formulaire, en fonction de la mise en œuvre).

La solution la plus viable qui vient à l'esprit est de créer un attribut, semblable à un CustomValidationAttribute, que peut faire un appel AJAX et affiche un avertissement de texte, mais n'affecte pas l' ModelState. L'utilisation prévue est ceci:

[WarningOnFieldLength(MaxLength = 150)]
[WarningOnPossibleDuplicate()]
public string Name { get; set; }

Dans la vue:

@Html.EditorFor(model => model.Name)
@Html.WarningMessageFor(model => model.Name)
@Html.ValidationMessageFor(model => model.Name)

Alors, des idées?

49voto

Serge Belov Points 3401

Conception Globale

Pour commencer, je crois que vous auriez à suivre en quelque sorte, si l'utilisateur choisit de les ignorer. Un simple et transparente façon de le faire est d'avoir un Ignorer les Avertissements case, l'utilisateur qui aura à vérifier avant de soumettre. Une autre option est un ont leur soumettre le formulaire à deux reprises et d'ignorer les mises en garde sur la deuxième soumettre; puis vous auriez probablement besoin d'une IgnoreWarnings champ caché. Il pourrait y avoir d'autres motifs, mais par souci de simplicité, je vais aller avec la première option.

En bref, l'approche est de créer

  • Une coutume annotation de données d'attribut pour tous les modèles de vue de soutenir l'avertissement type de validation;
  • Connu de la classe de base dont le point de vue des modèles va hériter d';
  • Nous allons dupliquer le logique en JavaScript pour chaque attribut personnalisé.

Veuillez noter que le code ci-dessous illustre la démarche et je suppose beaucoup de choses sans en connaître le contexte.

Modèle De Vue

Dans ce scénario, il est préférable de se séparer d'un modèle de vue à partir d'un modèle réel qui est une bonne idée de toute façon. Une approche possible est d'avoir une classe de base pour tous les modèles de vue qui soutien mises en garde:

public abstract class BaseViewModel
{
    public bool IgnoreWarnings { get; set; }
}

La clé raison pour laquelle un modèle doit être distincte est qu'il n'y a que peu de sens dans le stockage de l' IgnoreWarnings propriété dans votre base de données.

Votre dérivé du modèle de vue seront ensuite comme suit:

public class YourViewModel : BaseViewModel
{
    [Required]
    [StringLengthWarning(MaximumLength = 5, ErrorMessage = "Your Warning Message")]
    public string YourProperty { get; set; }
}

StringLengthWarning est une coutume annotation de données d'attribut pour le serveur et la validation côté client. Il soutient tout le maximum de longueur et peut être facilement étendue à toutes les autres propriétés.

Annotation De Données De L'Attribut

Le noyau de l'attribut est - IsValid(value, validationContext méthode.

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
public class StringLengthWarningAttribute : ValidationAttribute, IClientValidatable 
{
    public int MaximumLength { get; set; }

    public override bool IsValid(object value)
    {
        return true;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var model = validationContext.ObjectInstance as BaseViewModel;
        var str = value as string;
        if (!model.IgnoreWarnings && (string.IsNullOrWhiteSpace(str) || str.Length > MaximumLength))
            return new ValidationResult(ErrorMessage);
        return base.IsValid(value, validationContext);
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        yield return new StringLengthWarningValidationRule(MaximumLength, ErrorMessage);
    }
}

L'attribut implémente IClientValidatable et utilise un client personnalisé règle de validation:

public class StringLengthWarningValidationRule : ModelClientValidationRule
{
    public StringLengthWarningValidationRule(int maximumLength, string errorMessage)
    {
        ErrorMessage = errorMessage;
        ValidationType = "stringlengthwarning";
        ValidationParameters.Add("maximumlength", maximumLength);
        ValidationParameters.Add("ignorewarningsfield", "IgnoreWarnings");
    }
}

JavaScript côté Client

Enfin, pour le faire fonctionner, vous aurez besoin de JavaScript référencé à partir de votre point de vue:

$(function () {
    $.validator.addMethod('stringlengthwarning', function (value, element, params) {
        var maximumlength = params['maximumlength'];
        var ignorewarningsfield = params['ignorewarningsfield'];

        var ctl = $("#" + ignorewarningsfield);
        if (ctl == null || ctl.is(':checked'))
            return true;
        return value.length <= maximumlength;
    });

    $.validator.unobtrusive.adapters.add("stringlengthwarning", ["maximumlength", "ignorewarningsfield"], function (options) {
        var value = {
            maximumlength: options.params.maximumlength,
            ignorewarningsfield: options.params.ignorewarningsfield
        };
        options.rules["stringlengthwarning"] = value;
        if (options.message) {
            options.messages["stringlengthwarning"] = options.message;
        }
    });

}(jQuery));

Le JavaScript fait quelques hypothèses que vous souhaiterez revoir (la case nom, etc).

Mise à JOUR: HTML Helpers

Pour afficher les messages de validation séparément pour les erreurs et les avertissements, un couple d'assistants seront nécessaires. La classe suivante fournit un exemple:

public static class  MessageHelpers
{
    public static MvcHtmlString WarningMessageFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
    {
        if (htmlHelper.ViewData.ModelState["IgnoreWarnings"] != null)
            return htmlHelper.ValidationMessageFor(expression);
        return MvcHtmlString.Empty;
    }

    public static MvcHtmlString ErrorMessageFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
    {
        if (htmlHelper.ViewData.ModelState["IgnoreWarnings"] == null)
            return htmlHelper.ValidationMessageFor(expression);
        return MvcHtmlString.Empty;
    }
}

Dans la vue, ils peuvent être utilisés comme d'habitude:

        @Html.EditorFor(model => model.YourProperty)
        @Html.ErrorMessageFor(model => model.YourProperty)
        @Html.WarningMessageFor(model => model.YourProperty)

4voto

Mark Points 12663

Vous pouvez utiliser la fonction depends de validation jQuery pour vous simplifier la vie.

Ex.

 @Html.LabelFor(m => m.UserName)
@Html.TextBoxFor(m => m.UserName)
@Html.ValidationMessageFor(m => m.UserName)

<label>Ignore Warnings</label>
<input id="ignore-warnings" type="checkbox" />

<script>
  $(function () {
    $("#UserName").rules("add", {
      minlength: {
        param: 6,
        depends: function (element) {
          return !$("#ignore-warnings").attr('checked');
        }
      },

      // server side remote validation for duplicate check
      remote: {
        param: '/account/duplicate',
        depends: function (element) {
          return !$("#ignore-warnings").attr('checked');
        }
      }
    });
  });
</script>
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X