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

schreiben
War es hilfreich?

Lö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
}

JSON Ergebnis wird

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;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top