547

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?

Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
asked Aug 30, 2009 at 2:41
6
  • 6
    If you're just displaying the errors, then @Html.ValidationSummary() is a quick way to display them all in razor. Commented Jan 20, 2014 at 20:23
  • 19
    foreach (var error in ViewData.ModelState.Values.SelectMany(modelState => modelState.Errors)) { DoSomething(error); } Commented Oct 17, 2014 at 13:41
  • 1
    Thanks everyone for pointing me in the right direction. Like @viggity said, Keys are important and this did it for me: ModelState.Where(e=>e.Value.Errors.Count > 0).ToList() Commented Nov 12, 2020 at 18:10
  • A side note: If you debug just ModelState variable, you can see some interesting information. Commented Mar 3, 2022 at 14:04
  • answer for a similar question stackoverflow.com/a/68022337/6741585 Commented May 6, 2022 at 15:03

22 Answers 22

655

Using LINQ:

IEnumerable<ModelError> allErrors = ModelState.Values.SelectMany(v => v.Errors);
Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
answered Feb 8, 2011 at 15:07
Sign up to request clarification or add additional context in comments.

14 Comments

Modified to return IEnumerable<string> with just the error message:: var allErrors = ModelState.Values.SelectMany(v => v.Errors.Select(b => b.ErrorMessage));
This is great, but unfortunately Watch/Immediate windows don't support lambda's :(
Yes! I (you, anyone) needs "using System.Linq;" in the top. Otherwise you got the message 'Values does not contain a definition for Select many'. It was missing in my case.
@JB06 typing out all of variable types will save the person's time who read our code, so it is saving time.
@hakam-fostok @jb06 you're both right. Typing 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)
|
591

Use:

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

Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
answered Aug 30, 2009 at 4:41

3 Comments

Very helpful. Note in some scenarios, such as binding failures and bad requests, there will be ModelState entries with empty string for Value.ErrorMessage and instead a Value.Exception.Message
Errors are nice but sometimes you want the key of the modelstate too (i.e. the name of the field). you can get that by changing the first line to this: 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
@viggity, the answer that includes key is below from Jivan Bhandari stackoverflow.com/a/65676216/52277
237

Building on the LINQ version, 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));
Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
answered Oct 22, 2011 at 17:05

9 Comments

The other option is to do the following: ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage).JoinString("; ");
@Tod, is IEnumerable.JoinString() your own extension method? See stackoverflow.com/q/4382034/188926
Hey Dunc - yes I suspect I have added that extension method to my code base and have forgotten about it and then thought it was a framework method LOL :(
or ... ModelState.Values.SelectMany(O => O.Errors).Select(O => O.ErrorMessage).Aggregate((U, V) => U + ", " + V)
This works great when you are using web api and returning an IHttpActionResult result. So, you can just do: return BadRequest(messages); Thanks, Dunc!
|
39

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

Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
answered Dec 1, 2012 at 16:01

Comments

21

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>
Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
answered Dec 15, 2012 at 2:41

Comments

16

As I discovered having followed the advice in the answers given so far, you can get exceptions occurring 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();
}
Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
answered Jan 16, 2013 at 16:24

3 Comments

why would you want a string with all the errors in it? doesn't make sense when you want to do something with it in the view, an array of list is way better imho
To debug. My first problem was to find out what was going wrong with my app. I wasn't trying to tell the user just find out what was going wrong. Besides it's trivial to convert that example from creating an enumeration of strings to an enumeration of something else, e.g. error message and exception so the really useful thing is knowing that you need both bits of information
BTW you did realise the second extension method returns IEnumerable<String> and not just a big single string?
12

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.

Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
answered Apr 22, 2016 at 14:38

Comments

10

This code snippet is useful too and gives you a List<string> that contains the error messages.

var errors = ModelState.Values.SelectMany(x => x.Errors.Select(c => c.ErrorMessage)).ToList();
Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
answered Dec 6, 2021 at 7:23

Comments

7

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));
Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
answered Sep 8, 2016 at 22:54

1 Comment

As a warning, the key value pairs in ModelState may include NULL values, which is why the original code here included some cute C# 6 business with a null-coalesce operator (?.), hence the currying to the ?? at the end of the expression. The original expression which should protect from null errors was: state.Value.?AttemptedValue ?? "[NULL]". As far as I know, the code in its current state, without the sneaky handling of cases where state.Value == null, is at risk.
7

If anybody is 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});
Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
answered Jan 12, 2021 at 0:00

Comments

6

For just in case someone needs it, I made and used the following static class in my projects.

Usage example:

if (!ModelState.IsValid)
{
 var errors = ModelState.GetModelErrors();
 return Json(new { errors });
}

Usage:

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();
 }
}
Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
answered Jun 17, 2015 at 21:20

Comments

5

Use:

<div class="text-danger" style="direction:rtl" asp-validation-summary="All"></div>

Simply use the asp-validation-summary tag helper:

<div class="text-danger" asp-validation-summary="All">
</div>
Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
answered Mar 24, 2020 at 15:45

Comments

5

For an Ajax request, a better solution is:

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 });
}

The response format will be:

{"formValid":0,
 "formErrors":[{
 "fieldName":"name of field from object",
 "fieldValue":"value from browser",
 "fieldMessage":null /* The error message from model annotations. If the field is valid, the value will be null */
 }]
}

For more details about Func<>, check this page: Func<TSource, Int32, TResult>)

Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
answered Nov 3, 2021 at 9:13

Comments

4

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...```
Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
answered Jul 31, 2012 at 0:36

Comments

4

Useful for passing an array of error messages to View, perhaps via JSON:

messageArray = this.ViewData.ModelState.Values.SelectMany(modelState => modelState.Errors, (modelState, error) => error.ErrorMessage).ToArray();
Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
answered Mar 25, 2013 at 10:19

Comments

4

This is expanding upon the answer from Dunc. See the XML document 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;
 }
}
Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
answered Oct 11, 2013 at 21:08

Comments

3

In addition, ModelState.Values.ErrorMessage may be empty, but ModelState.Values.Exception.Message may indicate an error.

Taryn
249k57 gold badges375 silver badges409 bronze badges
answered Oct 1, 2012 at 18:26

Comments

1

Get the error with a 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; }
}
Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
answered Dec 1, 2022 at 19:36

Comments

0
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)));
}
Matt Ke
3,78912 gold badges35 silver badges53 bronze badges
answered Jun 29, 2020 at 17:36

1 Comment

0

With fieldName...

if (!this.ModelState.IsValid)
{
 foreach (var modelState in this.ModelState)
 {
 foreach (var error in modelState.Value.Errors)
 {
 rModel.AddError(error.ErrorMessage, ErrorType.Error, modelState.Key);
 }
 }
 rModel.Message = "Invalid Data";
 return false;
}
Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
answered Apr 26, 2024 at 18:14

1 Comment

-1

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 });
}
Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
answered Jun 22, 2015 at 2:18

Comments

-2

Use:

var result = string.Join(',', ModelState.Values.SelectMany(v => v.Errors).Select(a => a.ErrorMessage));
Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
answered Apr 21, 2021 at 10:20

1 Comment

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.