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?
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?
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
–
Danczyk 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
–
Psychosis Using LINQ:
IEnumerable<ModelError> allErrors = ModelState.Values.SelectMany(v => v.Errors);
List<string> errors = new List<string>()
instead of var errors = new List<string>()
is realy a waste of time, but writing IEnumerable<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) –
Finicky ModelState.Values.SelectMany(v => v.Errors).ToList()[0]
can be easy to peek the error –
Mestizo Exception
rather than ErrorMessage
. –
Genitals 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
–
Danczyk 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
–
Psychosis 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));
ModelState.Values.SelectMany(x => x.Errors.Select(x => x.ErrorMessage))
–
Casey ModelState.SelectMany(x => x.Value.Errors.Select(y => $"{x.Key}: {y.ErrorMessage}"))
–
Greenlet 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 :
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.
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();
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));
Anybody looking for asp.net core 3.1. The answer includes key (field name). Most of other answers include only errors.
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});
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();
}
}
<div class="text-danger" style="direction:rtl" asp-validation-summary="All"></div>
simply use asp-validation-summary Tag Helper
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. –
Calends 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;
}
}
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>)
In addition, ModelState.Values.ErrorMessage
may be empty, but ModelState.Values.Exception.Message
may indicate an error.
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)));
}
get error with Field Name and Error Message
var errors = new List<ErrorDto>();
foreach (KeyValuePair<string, ModelStateEntry> kvp in context.ModelState)
{
if (kvp.Value.Errors.Count > 0)
{
errors.Add(new ErrorDto()
{
FieldName = kvp.Key,
ErrorMessage = string.Join(",", kvp.Value.Errors.Select(v => v.ErrorMessage))
});
}
}
Error Model
public class ErrorDto
{
public string FieldName { get; set; }
public string ErrorMessage { get; set; }
}
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));
© 2022 - 2024 — McMap. All rights reserved.
@Html.ValidationSummary()
is a quick way to display them all in razor. – Kimberelykimberleeforeach (var error in ViewData.ModelState.Values.SelectMany(modelState => modelState.Errors)) { DoSomething(error); }
– PashModelState
variable, you can see some interesting information. – Arnulfoarny