web-dev-qa-db-fra.com

Comment obtenir toutes les erreurs de ASP.Net MVC modelState?

Je souhaite obtenir tous les messages d'erreur de modelState sans connaître les valeurs clés. En boucle pour récupérer tous les messages d'erreur que contient ModelState.

Comment puis-je faire ceci?

376
chobo2
foreach (ModelState modelState in ViewData.ModelState.Values) {
    foreach (ModelError error in modelState.Errors) {
        DoSomethingWith(error);
    }
}

Voir aussi Comment obtenir la collection d'erreurs d'état de modèle dans ASP.NET MVC? .

455
Oren Trutner

Utilisation de LINQ :

IEnumerable<ModelError> allErrors = ModelState.Values.SelectMany(v => v.Errors);
452
mmutilva

En vous appuyant sur la version de LINQ, si vous souhaitez réunir tous les messages d'erreur en une seule chaîne:

string messages = string.Join("; ", ModelState.Values
                                        .SelectMany(x => x.Errors)
                                        .Select(x => x.ErrorMessage));
165
Dunc

J'ai pu faire cela en utilisant un peu LINQ, 

public static List<string> GetErrorListFromModelState
                                              (ModelStateDictionary modelState)
{
      var query = from state in modelState.Values
                  from error in state.Errors
                  select error.ErrorMessage;

      var errorList = query.ToList();
      return errorList;
}

La méthode ci-dessus renvoie une liste d'erreurs de validation. 

Lectures supplémentaires:

Comment lire toutes les erreurs de ModelState dans ASP.NET MVC

24
Yasser

Lors du débogage, il est utile de placer un tableau au bas de chacune de mes pages pour afficher toutes les erreurs ModelState.

<table class="model-state">
    @foreach (var item in ViewContext.ViewData.ModelState) 
    {
        if (item.Value.Errors.Any())
        { 
        <tr>
            <td><b>@item.Key</b></td>
            <td>@((item.Value == null || item.Value.Value == null) ? "<null>" : item.Value.Value.RawValue)</td>
            <td>@(string.Join("; ", item.Value.Errors.Select(x => x.ErrorMessage)))</td>
        </tr>
        }
    }
</table>

<style>
    table.model-state
    {
        border-color: #600;
        border-width: 0 0 1px 1px;
        border-style: solid;
        border-collapse: collapse;
        font-size: .8em;
        font-family: arial;
    }

    table.model-state td
    {
        border-color: #600;
        border-width: 1px 1px 0 0;
        border-style: solid;
        margin: 0;
        padding: .25em .75em;
        background-color: #FFC;
    }
 </style>
13
Simon_Weaver

Comme j'ai découvert après avoir suivi les conseils donnés dans les réponses données jusqu'à présent, vous pouvez obtenir des exceptions sans définir de message d'erreur. Par conséquent, pour résoudre tous les problèmes, vous devez obtenir à la fois le message ErrorMessage et l'exception.

String messages = String.Join(Environment.NewLine, ModelState.Values.SelectMany(v => v.Errors)
                                                           .Select( v => v.ErrorMessage + " " + v.Exception));

ou comme méthode d'extension

public static IEnumerable<String> GetErrors(this ModelStateDictionary modelState)
{
      return modelState.Values.SelectMany(v => v.Errors)
                              .Select( v => v.ErrorMessage + " " + v.Exception).ToList();

}
11
Alan Macdonald

Si quelqu'un souhaite renvoyer la propriété Name of the Model pour lier le message d'erreur dans une vue fortement typée.

List<ErrorResult> Errors = new List<ErrorResult>();
foreach (KeyValuePair<string, ModelState> modelStateDD in ViewData.ModelState)
{
    string key = modelStateDD.Key;
    ModelState modelState = modelStateDD.Value;

    foreach (ModelError error in modelState.Errors)
    {
        ErrorResult er = new ErrorResult();
        er.ErrorMessage = error.ErrorMessage;
        er.Field = key;
        Errors.Add(er);
    }
}

De cette façon, vous pouvez réellement lier l’erreur au champ qui l’a renvoyée. 

5
james31rock

Ceci s'étend sur la réponse de @Dunc. Voir les commentaires de la doc xml

// ReSharper disable CheckNamespace
using System.Linq;
using System.Web.Mvc;


public static class Debugg
{
    /// <summary>
    /// This class is for debugging ModelState errors either in the quick watch 
    /// window or the immediate window.
    /// When the model state contains dozens and dozens of properties, 
    /// it is impossible to inspect why a model state is invalid.
    /// This method will pull up the errors
    /// </summary>
    /// <param name="modelState">modelState</param>
    /// <returns></returns>
    public static ModelError[]  It(ModelStateDictionary modelState)
    {
        var errors = modelState.Values.SelectMany(x => x.Errors).ToArray();
        return errors;            
    }
}
4
Chris Marisic

Pour juste au cas où quelqu'un en aurait besoin, j'ai créé et utilisé la classe statique suivante dans mes projets

Exemple d'utilisation:

if (!ModelState.IsValid)
{
    var errors = ModelState.GetModelErrors();
    return Json(new { errors });
}

Usings:

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using WebGrease.Css.Extensions;

Classe:

public static class ModelStateErrorHandler
{
    /// <summary>
    /// Returns a Key/Value pair with all the errors in the model
    /// according to the data annotation properties.
    /// </summary>
    /// <param name="errDictionary"></param>
    /// <returns>
    /// Key: Name of the property
    /// Value: The error message returned from data annotation
    /// </returns>
    public static Dictionary<string, string> GetModelErrors(this ModelStateDictionary errDictionary)
    {
        var errors = new Dictionary<string, string>();
        errDictionary.Where(k => k.Value.Errors.Count > 0).ForEach(i =>
        {
            var er = string.Join(", ", i.Value.Errors.Select(e => e.ErrorMessage).ToArray());
            errors.Add(i.Key, er);
        });
        return errors;
    }

    public static string StringifyModelErrors(this ModelStateDictionary errDictionary)
    {
        var errorsBuilder = new StringBuilder();
        var errors = errDictionary.GetModelErrors();
        errors.ForEach(key => errorsBuilder.AppendFormat("{0}: {1} -", key.Key,key.Value));
        return errorsBuilder.ToString();
    }
}
4
CodeArtist

Afficher uniquement les messages d'erreur eux-mêmes ne me suffisait pas, mais cela a suffi. 

var modelQuery = (from kvp in ModelState
                  let field = kvp.Key
                  let state = kvp.Value
                  where state.Errors.Count > 0
                  let val = state.Value.AttemptedValue ?? "[NULL]"

                  let errors = string.Join(";", state.Errors.Select(err => err.ErrorMessage))
                  select string.Format("{0}:[{1}] (ERRORS: {2})", field, val, errors));

Trace.WriteLine(string.Join(Environment.NewLine, modelQuery));
4
Josh Sutterfield

Et ça marche aussi:

var query = from state in ModelState.Values
    from error in state.Errors
    select error.ErrorMessage;
var errors = query.ToArray(); // ToList() and so on...
4
javad amiry

Utile pour passer un tableau de messages d'erreur à View, peut-être via Json:

messageArray = this.ViewData.ModelState.Values.SelectMany(modelState => modelState.Errors, (modelState, error) => error.ErrorMessage).ToArray();
2
Steve Lydford

De plus, ModelState.Values.ErrorMessage peut être vide, mais ModelState.Values.Exception.Message peut indiquer une erreur.

2
Jason Dufair

Je ne sais pas que c'est le problème dans mon cas, parfois je reçois un message dans la section ErrorMessage de ModelState et parfois dans le message d'exception de l'erreur ModelState.

Par conséquent, j'ai créé une méthode qui peut traiter les deux scénarios. J'espère que cela aidera tout le monde ici ..

public static string GetErrorMessageFromModelState(ModelStateDictionary modelState)
    {
        string errorMessage = string.Empty;

        try
        {
            string[] errorMessageList = (from m in modelState
                                         where m.Value.Errors.Count > 0
                                         select string.Join(", ", m.Value.Errors.Select(x =>
                                         !string.IsNullOrEmpty(x.ErrorMessage) ? x.ErrorMessage : !string.IsNullOrEmpty(x.Exception.Message) ?
                                         x.Exception.Message.Split('\'').Length > 0 ? x.Exception.Message.Split('\'')[1].ToString() : m.Key.Split('.').Length > 1 ?
                                         m.Key.Split('.')[1] : m.Key.Split('.')[0] : m.Key.Split('.')[0]))).ToArray();

            errorMessage = string.Format("Error in Field(s): " + string.Join(", ", errorMessageList) + " {0} required.", (errorMessageList.Count() > 1 ? "are" : "is"));
        }
        catch (Exception ex)
        {
            errorMessage = ex.Message;
            if (ex.InnerException != null)
                errorMessage += Environment.NewLine + ex.InnerException;
        }

        return errorMessage;
    }
0
Yagnesh Khamar

Dans votre implémentation, il vous manque Classe statique, cela devrait être.

if (!ModelState.IsValid)
{
    var errors =  ModelStateErrorHandler.GetModelErrors(this.ModelState);
    return Json(new { errors });
}

plutôt

if (!ModelState.IsValid)
{
    var errors = ModelState.GetModelErrors();
    return Json(new { errors });
}
0
Alfred Severo