webentwicklung-frage-antwort-db.com.de

ASP.NET MVC Konvertieren von ModelState-Fehlern in Json

Wie erhalten Sie eine Liste aller ModelState-Fehlermeldungen? Ich habe diesen Code gefunden, um alle Schlüssel zu erhalten: ( Eine Liste der Schlüssel mit ModelState-Fehlern zurückgeben )

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

Aber wie bekomme ich die Fehlermeldungen als IList oder IQueryable?

Ich könnte gehen:

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

Aber das machen Sie manuell - sicherlich gibt es eine Möglichkeit, dies mit LINQ zu tun? Die .ErrorMessage-Eigenschaft ist so weit in der Kette, dass ich nicht weiß, wie man LINQ schreibt ...

116
JK.

Sie können alles in die select-Klausel einfügen:

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

EDIT: Sie können mehrere Fehler in separate Listenelemente extrahieren, indem Sie eine from-Klausel wie folgt hinzufügen:

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

Oder:

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

2nd EDIT : Sie suchen einen Dictionary<string, string[]>:

var errorList = ModelState.ToDictionary(
    kvp => kvp.Key,
    kvp => kvp.Value.Errors.Select(e => e.ErrorMessage).ToArray()
);
172
SLaks

Hier ist die vollständige Implementierung mit allen zusammengestellten Elementen: 

Erstellen Sie zuerst eine Erweiterungsmethode:

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

Rufen Sie dann diese Erweiterungsmethode auf und geben Sie die Fehler von der Controller-Aktion (falls vorhanden) als json zurück:

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

Und schließlich zeigen Sie diese Fehler auf der Clientseite (in jquery.validation style, können jedoch problemlos in einen anderen Stil geändert werden)

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());
    }
}
71
JK.

Ich benutze hier gerne Hashtable, damit ich ein JSON-Objekt mit Eigenschaften als Schlüssel und Fehler als Wert in Form eines String-Arrays erhalte.

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

Auf diese Weise erhalten Sie folgende Antwort:

{
   "success":false,
   "errors":{
      "Phone":[
         "The Phone field is required."
      ]
   }
}
21
Jovica Zaric

Dafür gibt es viele verschiedene Möglichkeiten, die alle funktionieren. Hier mache ich es jetzt ...

if (ModelState.IsValid)
{
    return Json("Success");
}
else
{
    return Json(ModelState.Values.SelectMany(x => x.Errors));
}
7
Dean North

@JK es hat mir sehr geholfen, aber warum nicht: 

 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
h45d6f7d4f6f

Am einfachsten ist es, eine BadRequest mit dem ModelState selbst zurückzugeben:

Zum Beispiel bei einer PUT:

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

    // perform the update

    return StatusCode(HttpStatusCode.NoContent);
}

Wenn wir Datenanmerkungen verwenden, z. eine Handynummer wie diese in der Klasse Update:

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

Dies wird bei einer ungültigen Anfrage Folgendes zurückgeben:

{
  "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."
    ]
  }
}

Schauen Sie sich System.Web.Http.Results.OkNegotiatedContentResult an.

Es wandelt alles, was Sie hineinwerfen, in JSON um.

Also habe ich das gemacht

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

return Ok(errorList);

Dies führte zu:

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

Ich muss noch prüfen, was passiert, wenn mehr als ein Fehler für jedes Feld vorliegt, aber der Punkt ist, dass das OkNegoriatedContentResult brillant ist!

Bekam die Linq/Lambda-Idee von @SLaks

3
ozzy432836

ToDictionary ist eine erweiterbare Erweiterung, die in System.Linq enthalten ist und in der System.Web.Extensions-DLL http://msdn.Microsoft.com/de-de/library/system.linq.enumerable.todictionary.aspx enthalten ist. So sieht die gesamte Klasse für mich aus.

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
philrabin

Warum nicht das ursprüngliche ModelState-Objekt an den Client zurückgeben und dann die Werte mit jQuery lesen. Für mich sieht es viel einfacher aus und verwendet die allgemeine Datenstruktur (.nets ModelState)

um die ModelState als Json zurückzugeben, übergeben Sie sie einfach an den Json-Klassenkonstruktor (funktioniert mit jedem Objekt).

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
d.popov

Dies kann auf einfache Weise durch die Verwendung integrierter Funktionen erreicht werden

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

    //do something
}

JSON-Ergebnis wird sein

2
Nisfan

Variation mit Rückgabetyp statt IEnumerable zurückzugeben 

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
Jeff Circeo

Ich habe eine Erweiterung erstellt, die String mit Trennzeichen "" zurückgibt (Sie können Ihren eigenen verwenden): 

   public static string GetFullErrorMessage(this ModelStateDictionary modelState) {
        var messages = new List<string>();

        foreach (var entry in modelState) {
            foreach (var error in entry.Value.Errors)
                messages.Add(error.ErrorMessage);
        }

        return String.Join(" ", messages);
    }
0