ASP.NET MVC comment convertir les erreurs ModelState en json

Comment obtenir une liste de tous les messages D'erreur ModelState? J'ai trouvé ce code pour obtenir toutes les clés: ( Retour d'une liste de clés avec ModelState erreurs )

var errorKeys = (from item in ModelState
        where item.Value.Errors.Any() 
        select item.Key).ToList();

mais comment recevrais-je les messages d'erreur comme IList ou IQueryable?

je pourrais aller:

foreach (var key in errorKeys)
{
    string msg = ModelState[error].Errors[0].ErrorMessage;
    errorList.Add(msg);
}

mais cela le fait manuellement - il y a sûrement un moyen de le faire en utilisant LINQ? Le. La propriété ErrorMessage est si loin chaîne que je ne sais pas écrire le LINQ...

113
demandé sur Community 2010-05-17 03:09:00

12 réponses

vous pouvez mettre n'importe quoi vous voulez à l'intérieur de la select clause:

var errorList = (from item in ModelState
        where item.Value.Errors.Any() 
        select item.Value.Errors[0].ErrorMessage).ToList();

EDIT : vous pouvez extraire plusieurs erreurs dans des éléments de liste séparés en ajoutant une from clause, comme ceci:

var errorList = (from item in ModelState.Values
        from error in item.Errors
        select error.ErrorMessage).ToList();

Ou:

var errorList = ModelState.Values.SelectMany(m => m.Errors)
                                 .Select(e => e.ErrorMessage)
                                 .ToList();

2 nd EDIT : Vous cherchez un Dictionary<string, string[]> :

var errorList = ModelState.ToDictionary(
    kvp => kvp.Key,
    kvp => kvp.Value.Errors.Select(e => e.ErrorMessage).ToArray()
);
168
répondu SLaks 2010-05-16 23:32:12

Voici la mise en œuvre complète avec tous les morceaux réunis:

créer D'abord une méthode d'extension:

public static class ModelStateHelper
{
    public static IEnumerable Errors(this ModelStateDictionary modelState)
    {
        if (!modelState.IsValid)
        {
            return modelState.ToDictionary(kvp => kvp.Key,
                kvp => kvp.Value.Errors
                                .Select(e => e.ErrorMessage).ToArray())
                                .Where(m => m.Value.Any());
        }
        return null;
    }
}

ensuite appeler cette méthode d'extension et retourner les erreurs de l'action du contrôleur (s'il y en a) comme json:

if (!ModelState.IsValid)
{
    return Json(new { Errors = ModelState.Errors() }, JsonRequestBehavior.AllowGet);
}

et enfin, montrer ces erreurs du côté du client (en jquery.la validation de style, mais peut facilement être changé à n'importe quel autre style)

function DisplayErrors(errors) {
    for (var i = 0; i < errors.length; i++) {
        $("<label for='" + errors[i].Key + "' class='error'></label>")
        .html(errors[i].Value[0]).appendTo($("input#" + errors[i].Key).parent());
    }
}
68
répondu JK. 2018-06-05 13:33:30

j'aime utiliser Hashtable ici, pour obtenir un objet JSON avec des propriétés comme clés et des erreurs comme valeur sous forme de tableau de chaînes de caractères.

var errors = new Hashtable();
foreach (var pair in ModelState)
{
    if (pair.Value.Errors.Count > 0)
    {
        errors[pair.Key] = pair.Value.Errors.Select(error => error.ErrorMessage).ToList();
    }
}
return Json(new { success = false, errors });

de cette façon vous obtenez la réponse suivante:

{
   "success":false,
   "errors":{
      "Phone":[
         "The Phone field is required."
      ]
   }
}
20
répondu Jovica Zaric 2013-09-04 21:09:27

il y a beaucoup de façons différentes de faire cela qui fonctionnent toutes. Voici maintenant, je le fais...

if (ModelState.IsValid)
{
    return Json("Success");
}
else
{
    return Json(ModelState.Values.SelectMany(x => x.Errors));
}
7
répondu Dean North 2013-11-29 12:11:25

@JK cela m'a beaucoup aidé mais pourquoi pas:

 public class ErrorDetail {

        public string fieldName = "";
        public string[] messageList = null;
 }

        if (!modelState.IsValid)
        {
            var errorListAux = (from m in modelState 
                     where m.Value.Errors.Count() > 0 
                     select
                        new ErrorDetail
                        { 
                                fieldName = m.Key, 
                                errorList = (from msg in m.Value.Errors 
                                             select msg.ErrorMessage).ToArray() 
                        })
                     .AsEnumerable()
                     .ToDictionary(v => v.fieldName, v => v);
            return errorListAux;
        }
5
répondu h45d6f7d4f6f 2012-11-25 04:47:51

regardez le système.Web.Http.Résultat.OkNegotiatedContentResult.

il convertit tout ce qu'on y jette en JSON.

alors j'ai fait ça

var errorList = ModelState.ToDictionary(kvp => kvp.Key.Replace("model.", ""), kvp => kvp.Value.Errors[0].ErrorMessage);

return Ok(errorList);

résultat:

{
  "Email":"The Email field is not a valid e-mail address."
}

je suis encore à vérifier ce qui se passe quand il ya plus d'une erreur pour chaque champ, mais le point est le OkNegoriatedContentResult est brillant!

a obtenu l'idée de linq/lambda de @SLaks

3
répondu ozzy432836 2015-10-14 09:01:25

la façon la plus simple de faire cela est de simplement retourner un BadRequest avec le ModelState lui-même:

par exemple sur un PUT :

[HttpPut]
public async Task<IHttpActionResult> UpdateAsync(Update update)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    // perform the update

    return StatusCode(HttpStatusCode.NoContent);
}

si nous utilisons des annotations de données sur par exemple un numéro mobile, comme celui-ci, dans la classe Update :

public class Update {
    [StringLength(22, MinimumLength = 8)]
    [RegularExpression(@"^\d{8}$|^00\d{6,20}$|^\+\d{6,20}$")]
    public string MobileNumber { get; set; }
}

ceci retournera ce qui suit sur une demande invalide:

{
  "Message": "The request is invalid.",
  "ModelState": {
    "update.MobileNumber": [
      "The field MobileNumber must match the regular expression '^\d{8}$|^00\d{6,20}$|^\+\d{6,20}$'.",
      "The field MobileNumber must be a string with a minimum length of 8 and a maximum length of 22."
    ]
  }
}
3
répondu Erik A. Brandstadmoen 2015-11-24 08:24:52

ToDictionary est une extension énumérable trouvée dans le système.Linq emballé dans le système.Web.DLL http://msdn.microsoft.com/en-us/library/system.linq.enumerable.todictionary.aspx . Voici à quoi ressemble le cours complet pour moi.

using System.Collections;
using System.Web.Mvc;
using System.Linq;

namespace MyNamespace
{
    public static class ModelStateExtensions
    {
        public static IEnumerable Errors(this ModelStateDictionary modelState)
        {
            if (!modelState.IsValid)
            {
                return modelState.ToDictionary(kvp => kvp.Key,
                    kvp => kvp.Value.Errors.Select(e => e.ErrorMessage).ToArray()).Where(m => m.Value.Count() > 0);
            }
            return null;
        }

    }

}
2
répondu philrabin 2010-09-10 18:31:01

pourquoi ne pas retourner l'objet original ModelState au client, puis utiliser jQuery pour lire les valeurs. Pour moi, il semble beaucoup plus simple, et utilise la structure de données commune (.net ModelState )

pour retourner le ModelState comme Json, passez-le simplement au constructeur de classe Json (fonctionne avec N'importe quel objet)

C#:

return Json(ModelState);

js:

        var message = "";
        if (e.response.length > 0) {
            $.each(e.response, function(i, fieldItem) {
                $.each(fieldItem.Value.Errors, function(j, errItem) {
                    message += errItem.ErrorMessage;
                });
                message += "\n";
            });
            alert(message);
        }
2
répondu d.popov 2014-04-10 20:53:44

moyen Simple d'y parvenir en utilisant une fonctionnalité intégrée

[HttpPost]
public IActionResult Post([FromBody]CreateDoctorInput createDoctorInput) {
    if (!ModelState.IsValid) {
        return BadRequest(ModelState);
    }

    //do something
}

JSON résultat sera

2
répondu Nisfan 2018-08-24 18:50:18

Variation avec le type de retour au lieu de retourner IEnumerable

public static class ModelStateHelper
{
    public static IEnumerable<KeyValuePair<string, string[]>> Errors(this ModelStateDictionary modelState)
    {
        if (!modelState.IsValid)
        {
            return modelState
                .ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Errors.Select(e => e.ErrorMessage).ToArray())
                .Where(m => m.Value.Any());
        }

        return null;
    }
}
1
répondu Jeff Circeo 2013-01-31 16:41:52
  List<ErrorList> Errors = new List<ErrorList>(); 


        //test errors.
        var modelStateErrors = this.ModelState.Keys.SelectMany(key => this.ModelState[key].Errors);

        foreach (var x in modelStateErrors)
        {
            var errorInfo = new ErrorList()
            {
                ErrorMessage = x.ErrorMessage
            };
            Errors.Add(errorInfo);

        }

si vous utilisez jsonresult alors retourner""

return Json(Errors);

ou vous pouvez simplement retourner les modelStateErrors, Je ne l'ai pas essayé. Ce que j'ai fait, c'est assigner la collection D'erreurs à mon modèle de vue et ensuite la boucle.dans ce cas, je peux retourner mes erreurs via json. J'ai une classe/modèle, je voulais obtenir la source/clé mais j'essaye toujours de comprendre.

    public class ErrorList
{
    public string ErrorMessage;
}
-1
répondu CyberNinja 2017-02-09 13:24:43