I want to get all the error messages out of the modelState without knowing the key values. Looping through to grab all the error messages that the ModelState contains.
How can I do this?
@Html.ValidationSummary()
is a quick way to display them all in razor.
foreach (var error in ViewData.ModelState.Values.SelectMany(modelState => modelState.Errors)) { DoSomething(error); }
ModelState
variable, you can see some interesting information.
foreach (ModelState modelState in ViewData.ModelState.Values) {
foreach (ModelError error in modelState.Errors) {
DoSomethingWith(error);
}
}
See also How do I get the collection of Model State Errors in ASP.NET MVC?.
Value.ErrorMessage
and instead a Value.Exception.Message
foreach (KeyValuePair<string, ModelState> kvp in htmlHelper.ViewData.ModelState) {
and insert this line below it: var modelState = kvp.Value;
. You can get the key from kvp.Key
Building on the LINQ verison, if you want to join all the error messages into one string:
string messages = string.Join("; ", ModelState.Values
.SelectMany(x => x.Errors)
.Select(x => x.ErrorMessage));
I was able to do this using a little LINQ,
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;
}
The above method returns a list of validation errors.
Further Reading :
How to read all errors from ModelState in ASP.NET MVC
During debugging I find it useful to put a table at the bottom of each of my pages to show all ModelState errors.
<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>
As I discovered having followed the advice in the answers given so far, you can get exceptions occuring without error messages being set, so to catch all problems you really need to get both the ErrorMessage and the Exception.
String messages = String.Join(Environment.NewLine, ModelState.Values.SelectMany(v => v.Errors)
.Select( v => v.ErrorMessage + " " + v.Exception));
or as an extension method
public static IEnumerable<String> GetErrors(this ModelStateDictionary modelState)
{
return modelState.Values.SelectMany(v => v.Errors)
.Select( v => v.ErrorMessage + " " + v.Exception).ToList();
}
In case anyone wants to return the Name of the Model property for binding the error message in a strongly typed view.
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);
}
}
This way you can actually tie the error in with the field that threw the error.
Outputting just the Error messages themselves wasn't sufficient for me, but this did the trick.
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));
For just in case someone need it i made and use the following static class in my projects
Usage example:
if (!ModelState.IsValid)
{
var errors = ModelState.GetModelErrors();
return Json(new { errors });
}
Usings:
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using WebGrease.Css.Extensions;
Class:
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();
}
}
And this works too:
var query = from state in ModelState.Values
from error in state.Errors
select error.ErrorMessage;
var errors = query.ToArray(); // ToList() and so on...
SelectMany
is available.
Useful for passing array of error messages to View, perhaps via Json:
messageArray = this.ViewData.ModelState.Values.SelectMany(modelState => modelState.Errors, (modelState, error) => error.ErrorMessage).ToArray();
This is expanding upon the answer from @Dunc . See xml doc comments
// 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;
}
}
Anybody looking for asp.net core 3.1. Slightly updated than the above answer. I found that this is what [ApiController] returns
Dictionary<string, List<string>> errors = new Dictionary<string, List<string>>();
foreach (KeyValuePair<string, ModelStateEntry> kvp in ViewData.ModelState)
{
string key = kvp.Key;
ModelStateEntry entry = kvp.Value;
if (entry.Errors.Count > 0)
{
List<string> errorList = new List<string>();
foreach (ModelError error in entry.Errors)
{
errorList.Add(error.ErrorMessage);
}
errors[key] = errorList;
}
}
return new JsonResult(new {Errors = errors});
This code snippet is useful too and give you a List that contains of Error Messges.
var errors = ModelState.Values.SelectMany(x => x.Errors.Select(c => c.ErrorMessage)).ToList();
In addition, ModelState.Values.ErrorMessage
may be empty, but ModelState.Values.Exception.Message
may indicate an error.
simply use asp-validation-summary Tag Helper
For AJAX Request better solution:
public IActionResult Demo(DemoInfo formData)
{
if (!ModelState.IsValid)
{
IEnumerable<object> formErrors = ModelState.Select((s) => new {
fieldName = s.Key,
fieldValue = s.Value.RawValue,
fieldMessage = s.Value.Errors.FirstOrDefault()?.ErrorMessage
});
return Json(new { formValid = 0, formErrors });
}
return Json(new { formValid = 1 });
}
Response format will be:
{"formValid":0,
"formErrors":[{
"fieldName":"name of field from object",
"fieldValue":"value from browser",
"fieldMessage":null /*Error message from model annotations if field is valid the value will be null */
}]
}
For more details about Func<> check this page : Func<TSource,Int32,TResult>)
var x = new Dictionary<string,string>();
for (var b = 0; b < ViewData.ModelState.Values.Count(); b++)
{
if (ViewData.ModelState.Values.ElementAt(b).Errors.Count() > 0)
x.Add(ViewData.ModelState.Keys.ElementAt(b), String.Join(",", ViewData
.ModelState.Values.ElementAt(b).Errors.Select(c => c.ErrorMessage)));
}
In your implementation you are missing static Class, this should be.
if (!ModelState.IsValid)
{
var errors = ModelStateErrorHandler.GetModelErrors(this.ModelState);
return Json(new { errors });
}
rather
if (!ModelState.IsValid)
{
var errors = ModelState.GetModelErrors();
return Json(new { errors });
}
var result = string.Join(',',ModelState.Values.SelectMany(v => v.Errors).Select(a=>a.ErrorMessage));
Success story sharing
List<string> errors = new List<string>()
instead ofvar errors = new List<string>()
is realy a waste of time, but writingIEnumerable<ModelError> allErrors = ModelState.Values.SelectMany(v => v.Errors);
, where the return type is not really clear, is really greater in term of readability. (even if visual studio can give it to you on mouse hover)