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 ...
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()
);
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());
}
}
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."
]
}
}
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));
}
@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;
}
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
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;
}
}
}
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);
}
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
}
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;
}
}
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);
}