Y a-t-il un moyen d'ignorer certaines propriétés (sur un POCO) lors de la validation d'un formulaire dans ASP.NET MVC3?

j'ai un assistant d'inscription pour l'inscription des nouveaux utilisateurs. Quand j'essaie de passer à la 2ème page, j'obtiens des erreurs de validation parce que mon User l'objet n'a pas encore été entièrement peuplé. Est il possible que je peux dire à chaque ActionMethod pour ignorer certaines propriétés lorsqu'il vérifie l' ModelState.IsValid vérifie?

par exemple. (Simplifié, pseduo code)

public class User
{
   [Required]
   public string Name; // Asked on page 1.
   [Required]
   public int Age; // Asked on page 1.
   [Required]
   public string Avatar;  // Asked on Page 2.
}

il se plaint en disant que L'Avatar est requis/ne peut pas être null. Mais je n'ai pas l'occasion de demander à l'utilisateur de remplir ceci, jusqu'à la prochaine page.

est-il possible de demander d'ignorer ce chèque, en page 1?

19
demandé sur Pure.Krome 2011-03-06 10:20:12

8 réponses

Dans l'action juste supprimer les erreurs pour les éléments non encore vérifiées. Cela rend votre modèle valide pour les éléments déjà vérifiés

foreach (var error in ModelState["Avatar"].Errors)
 {
      ModelState["Avatar"].Errors.Remove(error);
 }

ou

ModelState["Avatar"].Errors.Clear();
19
répondu Darroll 2012-09-20 14:31:34

Ceci est discuté dans le Livre de Steve Sanderson asp.net mvc 2 book, page 486.

créer un attribut personnalisé, ValidateIncomingValuesOnlyAttribute, qui hérite D'ActionFilterAttribute, et l'appliquer à votre classe de controller.

Remplacer le OnActionExecuting méthode:

public override void OnActionExecuting(ActionExecutingContext filterContext)
{

var modelState = filterContext.Controller.ViewData.ModelState;
var incomingValues = filterContext.Controller.ValueProvider;

var keys = modelState.Keys.Where(x => !incomingValues.ContainsPrefix(x));
foreach(var key in keys)
{
modelState[key].Errors.Clear();
}
}

de Cette façon, vous validez les données se rapportant à chaque étape de l'assistant. Vous avez ensuite besoin d'une page de confirmation sans entrée de données pour envoyer les données validées à la serveur.

mais surtout, lisez le livre de Steve Sanderson, il donne une solution de travail à ceci et votre autre problème.

Addendum:

si à la place de ce qui précède vous décidez de faire une map vers un viewmodel, faites attention car vous devrez soit:

A. Ne pas décorer les propriétés de viewmodel avec les attributs de validation dataannotation, auquel cas vous validez seulement une fois que l'Utilisateur a rempli l'Assistant entier et essayer de soumettre à la base de données. Ce serait très naïf du point de vue de l'utilisateur...

B. Sinon, vous devez toujours utiliser la technique décrite par S Sanderson, c'est-à-dire effacer toutes les erreurs de validation qui ne se rapportent pas aux champs de l'étape courante.

Je ne vois pas la réponse acceptée comme répondant à la question telle qu'elle a été posée.

5
répondu awrigley 2011-03-06 14:02:05

Pour ignorer les propriétés de ModelState, voici le code le plus simple.

if (ModelState["PropertyName"] != null) ModelState["PropertyName"].Errors.Clear();
3
répondu Shyam Bhagat 2015-07-10 04:34:26

j'étais juste en train de jouer avec les formulaires de validation et ModelState et trouvé une solution très facile à votre problème sans écrire une nouvelle méthode, des dérogations, etc.

ModelState.Where(m => m.Key == "Avatar").FirstOrDefault().Value.Errors.Clear();
// At  this point ModeState will have an error for that Key,
// by applying Clear it remove the error so modelstate becomes valid again

if (!ModelState.IsValid) {
    return View("User", model);
} else {     
    try  {
        // do something
    } catch {
        TempData["errorMessage"] = "something went wrong";
    }
}
2
répondu Adam Bielecki 2017-08-09 09:37:38

Qu'en est-il IgnoreModelErrors custom class ?

http://mrbigglesworth79.blogspot.in/2011/12/partial-validation-with-data.html


hériter de la classe ActionFilterAttribute, et des erreurs claires[basées sur des noms ou des motifs regex correspondants] dans L'interpréteur Onactionexecute comme démontré dans le lien ci-dessus. Ce sera plus propre.

0
répondu Hoven 2013-03-25 16:34:23

les Modèles de vue qui correspondent exactement aux données postées en arrière est généralement la technique recommandée car il est très prévisible et vous obtenez tous les avantages de la frappe forte, échafaudage, etc.. D'un autre côté, l'utilisation de BindAttribute peut exiger que vous preniez en compte les propriétés qui ne sont pas publiées à nouveau, et peut entraîner une défaillance silencieuse à l'exécution lorsqu'un nom de propriété est modifié mais que les chaînes Include ou Exclude de BindAttribute ne le sont pas. Éviter l'utilisation de la validation les attributs ont de nombreux inconvénients dans MVC et devraient être remplacés par une autre technique de validation comme Ivalidatablobject ou FluentValidation.

malgré tous les avantages des modèles de vue et les mises en garde qui accompagnent la BindAttribute, il peut parfois être préférable d'utiliser la BindAttribute et d'afficher partiellement un modèle/modèle de vue. Cette Contributionactionfilter couvre ce cas précis. Il prend le code @awrigley cité un peu plus loin, mais au lieu d'effacer les erreurs le ValueProvider, il efface les erreurs basées sur l'utilisation de BindAttribute (par exemple Include et Exclude). Cet attribut peut être ajouté en toute sécurité à la collection GlobalFilterCollection parce qu'il ne changera pas le comportement de la validation MVC lorsque la BindAttribute n'a pas été appliquée. Veuillez noter: je n'ai pas fait un usage intensif de cette mais il fonctionne bien pour mon cas.

using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web.Mvc;

/// <summary>
/// When the BindAttribute is in use, validation errors only show for values that 
/// are included or not excluded.
/// </summary>
public class ValidateBindableValuesOnlyAttributes : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var modelState = filterContext.Controller.ViewData.ModelState;
        var includedProperties = filterContext.ActionDescriptor.GetParameters()
            .SelectMany(o => o.BindingInfo.Include.Select(name => (string.IsNullOrWhiteSpace(o.BindingInfo.Prefix) ? "" : o.BindingInfo.Prefix + ".") + name));
        var excludedProperties = filterContext.ActionDescriptor.GetParameters()
            .SelectMany(o => o.BindingInfo.Exclude.Select(name => (string.IsNullOrWhiteSpace(o.BindingInfo.Prefix) ? "" : o.BindingInfo.Prefix + ".") + name));

        var ignoreTheseProperties = new List<KeyValuePair<string, ModelState>>();
        if (includedProperties.Any())
        {
            ignoreTheseProperties.AddRange(modelState.Where(k => !includedProperties.Any(name => Regex.IsMatch(k.Key, "^" + Regex.Escape(name) + @"(\.|\[|$)"))));
        }
        ignoreTheseProperties.AddRange(modelState.Where(k => excludedProperties.Any(name => Regex.IsMatch(k.Key, "^" + Regex.Escape(name) + @"(\.|\[|$)"))));

        foreach (var item in ignoreTheseProperties)
        {
            item.Value.Errors.Clear();
        }
    }
}
0
répondu Jeremy Cook 2013-11-21 21:15:44

j'avais une entité de référence qui n'était pas censée être validée.

Supprimé de validation au début de l'action:

[HttpPost]
public async Task<IActionResult> Post([FromBody] Contact contact)
{
  var skipped = ModelState.Keys.Where(key => key.StartsWith(nameof(Contact.Portfolios)));
  foreach (var key in skipped)
    ModelState.Remove(key);
    //ModelState doesn't include anything about Portfolios which we're not concerned with

  if (!ModelState.IsValid)
    return BadRequest(ModelState);

  //Rest of action
}
0
répondu Shimmy 2017-08-09 09:48:20