Ich möchte alle Fehlermeldungen aus dem modelState erhalten, ohne die Schlüsselwerte zu kennen. Durchsuchen, um alle Fehlernachrichten zu erfassen, die der ModelState enthält.
Wie kann ich das machen?
foreach (ModelState modelState in ViewData.ModelState.Values) {
foreach (ModelError error in modelState.Errors) {
DoSomethingWith(error);
}
}
Siehe auch Wie erhalte ich die Auflistung von Modellstatusfehlern in ASP.NET MVC? .
Verwenden von LINQ :
IEnumerable<ModelError> allErrors = ModelState.Values.SelectMany(v => v.Errors);
Aufbauend auf der LINQ-Version, wenn Sie alle Fehlermeldungen in einer Zeichenfolge zusammenfassen möchten:
string messages = string.Join("; ", ModelState.Values
.SelectMany(x => x.Errors)
.Select(x => x.ErrorMessage));
Ich konnte dies mit einem kleinen LINQ tun,
public static List<string> GetErrorListFromModelState
(ModelStateDictionary modelState)
{
var query = from state in modelState.Values
from error in state.Errors
select error.ErrorMessage;
var errorList = query.ToList();
return errorList;
}
Die obige Methode gibt eine Liste von Validierungsfehlern zurück.
Weiterführende Literatur:
Beim Debuggen finde ich es nützlich, eine Tabelle am Ende jeder meiner Seiten zu platzieren, um alle ModelState-Fehler anzuzeigen.
<table class="model-state">
@foreach (var item in ViewContext.ViewData.ModelState)
{
if (item.Value.Errors.Any())
{
<tr>
<td><b>@item.Key</b></td>
<td>@((item.Value == null || item.Value.Value == null) ? "<null>" : item.Value.Value.RawValue)</td>
<td>@(string.Join("; ", item.Value.Errors.Select(x => x.ErrorMessage)))</td>
</tr>
}
}
</table>
<style>
table.model-state
{
border-color: #600;
border-width: 0 0 1px 1px;
border-style: solid;
border-collapse: collapse;
font-size: .8em;
font-family: arial;
}
table.model-state td
{
border-color: #600;
border-width: 1px 1px 0 0;
border-style: solid;
margin: 0;
padding: .25em .75em;
background-color: #FFC;
}
</style>
Wie ich herausgefunden habe, die Ratschläge in den bisherigen Antworten befolgt zu haben, kann es zu Ausnahmen kommen, ohne dass Fehlermeldungen gesetzt werden. Um alle Probleme zu beheben, die Sie wirklich benötigen, um sowohl die Fehlernachricht als auch die Ausnahme zu erhalten.
String messages = String.Join(Environment.NewLine, ModelState.Values.SelectMany(v => v.Errors)
.Select( v => v.ErrorMessage + " " + v.Exception));
oder als Erweiterungsmethode
public static IEnumerable<String> GetErrors(this ModelStateDictionary modelState)
{
return modelState.Values.SelectMany(v => v.Errors)
.Select( v => v.ErrorMessage + " " + v.Exception).ToList();
}
Falls jemand den Namen der Model-Eigenschaft zum Binden der Fehlermeldung in einer stark typisierten Ansicht zurückgeben möchte.
List<ErrorResult> Errors = new List<ErrorResult>();
foreach (KeyValuePair<string, ModelState> modelStateDD in ViewData.ModelState)
{
string key = modelStateDD.Key;
ModelState modelState = modelStateDD.Value;
foreach (ModelError error in modelState.Errors)
{
ErrorResult er = new ErrorResult();
er.ErrorMessage = error.ErrorMessage;
er.Field = key;
Errors.Add(er);
}
}
Auf diese Weise können Sie den Fehler tatsächlich mit dem Feld verknüpfen, das den Fehler ausgelöst hat.
Dies erweitert die Antwort von @Dunc. Siehe XML-Dokumentkommentare
// ReSharper disable CheckNamespace
using System.Linq;
using System.Web.Mvc;
public static class Debugg
{
/// <summary>
/// This class is for debugging ModelState errors either in the quick watch
/// window or the immediate window.
/// When the model state contains dozens and dozens of properties,
/// it is impossible to inspect why a model state is invalid.
/// This method will pull up the errors
/// </summary>
/// <param name="modelState">modelState</param>
/// <returns></returns>
public static ModelError[] It(ModelStateDictionary modelState)
{
var errors = modelState.Values.SelectMany(x => x.Errors).ToArray();
return errors;
}
}
Für den Fall, dass jemand es braucht, habe ich folgende statische Klasse in meinen Projekten verwendet
Verwendungsbeispiel:
if (!ModelState.IsValid)
{
var errors = ModelState.GetModelErrors();
return Json(new { errors });
}
Verwendungen:
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using WebGrease.Css.Extensions;
Klasse:
public static class ModelStateErrorHandler
{
/// <summary>
/// Returns a Key/Value pair with all the errors in the model
/// according to the data annotation properties.
/// </summary>
/// <param name="errDictionary"></param>
/// <returns>
/// Key: Name of the property
/// Value: The error message returned from data annotation
/// </returns>
public static Dictionary<string, string> GetModelErrors(this ModelStateDictionary errDictionary)
{
var errors = new Dictionary<string, string>();
errDictionary.Where(k => k.Value.Errors.Count > 0).ForEach(i =>
{
var er = string.Join(", ", i.Value.Errors.Select(e => e.ErrorMessage).ToArray());
errors.Add(i.Key, er);
});
return errors;
}
public static string StringifyModelErrors(this ModelStateDictionary errDictionary)
{
var errorsBuilder = new StringBuilder();
var errors = errDictionary.GetModelErrors();
errors.ForEach(key => errorsBuilder.AppendFormat("{0}: {1} -", key.Key,key.Value));
return errorsBuilder.ToString();
}
}
Nur die Fehlermeldungen selbst auszugeben, war für mich nicht ausreichend, aber das gelang.
var modelQuery = (from kvp in ModelState
let field = kvp.Key
let state = kvp.Value
where state.Errors.Count > 0
let val = state.Value.AttemptedValue ?? "[NULL]"
let errors = string.Join(";", state.Errors.Select(err => err.ErrorMessage))
select string.Format("{0}:[{1}] (ERRORS: {2})", field, val, errors));
Trace.WriteLine(string.Join(Environment.NewLine, modelQuery));
Und das funktioniert auch:
var query = from state in ModelState.Values
from error in state.Errors
select error.ErrorMessage;
var errors = query.ToArray(); // ToList() and so on...
Nützlich für die Übergabe von Fehlernachrichten an View, möglicherweise über Json:
messageArray = this.ViewData.ModelState.Values.SelectMany(modelState => modelState.Errors, (modelState, error) => error.ErrorMessage).ToArray();
Außerdem kann ModelState.Values.ErrorMessage
leer sein, ModelState.Values.Exception.Message
kann jedoch einen Fehler anzeigen.
Ich weiß nicht, dass dies das Problem in meinem Fall ist, manchmal erhalte ich eine Nachricht im ErrorMessage-Abschnitt von ModelState und manchmal in der Ausnahmemeldung des ModelState-Fehlers.
Daher habe ich eine Methode erstellt, die mit beiden Szenarien umgehen kann. Hoffe, das hilft jedem hier.
public static string GetErrorMessageFromModelState(ModelStateDictionary modelState)
{
string errorMessage = string.Empty;
try
{
string[] errorMessageList = (from m in modelState
where m.Value.Errors.Count > 0
select string.Join(", ", m.Value.Errors.Select(x =>
!string.IsNullOrEmpty(x.ErrorMessage) ? x.ErrorMessage : !string.IsNullOrEmpty(x.Exception.Message) ?
x.Exception.Message.Split('\'').Length > 0 ? x.Exception.Message.Split('\'')[1].ToString() : m.Key.Split('.').Length > 1 ?
m.Key.Split('.')[1] : m.Key.Split('.')[0] : m.Key.Split('.')[0]))).ToArray();
errorMessage = string.Format("Error in Field(s): " + string.Join(", ", errorMessageList) + " {0} required.", (errorMessageList.Count() > 1 ? "are" : "is"));
}
catch (Exception ex)
{
errorMessage = ex.Message;
if (ex.InnerException != null)
errorMessage += Environment.NewLine + ex.InnerException;
}
return errorMessage;
}
In Ihrer Implementierung fehlt die statische Klasse.
if (!ModelState.IsValid)
{
var errors = ModelStateErrorHandler.GetModelErrors(this.ModelState);
return Json(new { errors });
}
lieber
if (!ModelState.IsValid)
{
var errors = ModelState.GetModelErrors();
return Json(new { errors });
}