ASP.NET MVC Wie Model Fehler json konvertieren
-
27-09-2019 - |
Frage
Wie bekommt man eine Liste aller Modelfehlermeldungen? Ich fand diesen Code, um alle Schlüssel zu erhalten: ( Rückgabe einer Liste von Schlüsseln mit Model Fehler )
var errorKeys = (from item in ModelState
where item.Value.Errors.Any()
select item.Key).ToList();
Aber wie würde ich die Fehlermeldungen als IList oder IQueryable bekommen?
Ich könnte:
foreach (var key in errorKeys)
{
string msg = ModelState[error].Errors[0].ErrorMessage;
errorList.Add(msg);
}
Aber das ist es manuell zu tun - sicher gibt einen Weg, es zu tun ist, mithilfe von LINQ? Die .ErrorMessage Eigenschaft ist so weit unten in der Kette, dass ich weiß nicht, wie die LINQ ...
schreibenLösung
Sie können put alles Sie wollen innerhalb der select
-Klausel:
var errorList = (from item in ModelState
where item.Value.Errors.Any()
select item.Value.Errors[0].ErrorMessage).ToList();
Bearbeiten : Sie können mehrere Fehler in separate Listenelemente extrahieren, indem eine from
Klausel hinzufügen, wie folgt aus:
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();
2 nd EDIT :
Sie suchen nach einem Dictionary<string, string[]>
:
var errorList = ModelState.ToDictionary(
kvp => kvp.Key,
kvp => kvp.Value.Errors.Select(e => e.ErrorMessage).ToArray()
);
Andere Tipps
Hier ist die vollständige Umsetzung mit allen Stücken zusammen:
Zuerst eine Erweiterungsmethode erstellen:
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;
}
}
rufe dann die Erweiterungsmethode und zurück um die Fehler von der Steuerung Aktion (falls vorhanden) als json:
if (!ModelState.IsValid)
{
return Json(new { Errors = ModelState.Errors() }, JsonRequestBehavior.AllowGet);
}
Und dann endlich, zeigt diese Fehler auf dem Clientside (in jquery.validation Stil, kann aber leicht auf andere Art 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());
}
}
Ich mag die Verwendung Hashtable
hier, so dass ich JSON-Objekt mit Eigenschaften als Schlüssel und Fehler als Wert in Form von String-Array.
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 können folgende Antwort erhalten:
{
"success":false,
"errors":{
"Phone":[
"The Phone field is required."
]
}
}
Es gibt viele verschiedene Wege, dies zu tun, dass alle Arbeiten. Hier ist jetzt mache ich es ...
if (ModelState.IsValid)
{
return Json("Success");
}
else
{
return Json(ModelState.Values.SelectMany(x => x.Errors));
}
@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;
}
Der einfachste Weg dies zu tun ist, zurückzukehren nur BadRequest
mit dem Model selbst:
Zum Beispiel auf einem PUT
:
[HttpPut]
public async Task<IHttpActionResult> UpdateAsync(Update update)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// perform the update
return StatusCode(HttpStatusCode.NoContent);
}
Wenn wir Daten verwenden Anmerkungen auf z.B. eine Handy-Nummer, wie dies in der Update
Klasse:
public class Update {
[StringLength(22, MinimumLength = 8)]
[RegularExpression(@"^\d{8}$|^00\d{6,20}$|^\+\d{6,20}$")]
public string MobileNumber { get; set; }
}
Dies wird die folgende auf eine ungültige Anfrage zurück:
{
"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."
]
}
}
Hier finden Sie aktuelle System.Web.Http.Results.OkNegotiatedContentResult.
Es wandelt, was man in sie zu JSON werfen.
Also ich habe diese
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 bin noch zu prüfen, was passiert, wenn es mehr als ein Fehler für jedes Feld ist aber der Punkt ist die OkNegoriatedContentResult brillant!
Haben Sie die Linq / Lambda-Idee von @SLaks
Einfache Art und Weise erreicht dies durch die Verwendung integrierte Funktionalität
[HttpPost]
public IActionResult Post([FromBody]CreateDoctorInput createDoctorInput) {
if (!ModelState.IsValid) {
return BadRequest(ModelState);
}
//do something
}
ToDictionary ist eine Enumerable Erweiterung in System.Linq gefunden in der System.Web.Extensions verpackt dll http://msdn.microsoft.com/en-us/library/system.linq.enumerable.todictionary.aspx . Hier ist, was die komplette Klasse sieht aus wie für mich.
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;
}
}
}
Warum nicht das Original ModelState
Objekt an den Client zurück, und dann jQuery verwenden, um die Werte zu lesen. Für mich sieht es viel einfacher, und nutzt die gemeinsame Datenstruktur (.net des ModelState
)
die ModelState
als Json zurückzukehren, einfach übergibt es an Json Klassenkonstruktors (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);
}
Variation mit Rückgabetyp anstelle IEnumerable der Rückkehr
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;
}
}
Ich habe und Erweiterung, dass die Renditen Zeichenfolge mit Trennzeichen „“ (Sie Ihre 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);
}
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);
}
Wenn Sie JsonResult dann verwenden zurückkehren
return Json(Errors);
oder Sie können einfach die modelStateErrors zurückkehren, ich habe es versucht. Was ich getan habe ist assign der Errors Sammlung meiner Ansichtsmodell und dann Schleife it..In diesem Fall habe ich meine Fehler über Json zurückgeben kann. Ich habe eine Klasse / Modell, wollte ich die Quelle / Schlüssel bekommen, aber ich bin immer noch versuchen, es herauszufinden.
public class ErrorList
{
public string ErrorMessage;
}