535

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?

wonea
  • 4,783
  • 17
  • 86
  • 139
chobo2
  • 83,322
  • 195
  • 530
  • 832
  • 6
    If you're just displaying the errors, then `@Html.ValidationSummary()` is a quick way to display them all in razor. – levininja Jan 20 '14 at 20:23
  • 15
    `foreach (var error in ViewData.ModelState.Values.SelectMany(modelState => modelState.Errors)) { DoSomething(error); }` – Razvan Dumitru Oct 17 '14 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() – user3590235 Nov 12 '20 at 18:10
  • A side note: If you debug just `ModelState` variable, you can see some interesting information. – carloswm85 Mar 03 '22 at 14:04
  • answer for a similar question https://stackoverflow.com/a/68022337/6741585 – Ali May 06 '22 at 15:03
  • @user3590235 the answer that includes key is below from Jivan Bhandari stackoverflow.com/a/65676216/52277 – Michael Freidgeim Apr 05 '23 at 20:40

21 Answers21

645

Using LINQ:

IEnumerable<ModelError> allErrors = ModelState.Values.SelectMany(v => v.Errors);
Hakan Fıstık
  • 16,800
  • 14
  • 110
  • 131
mmutilva
  • 18,688
  • 22
  • 59
  • 82
  • 101
    Modified to return IEnumerable with just the error message:: var allErrors = ModelState.Values.SelectMany(v => v.Errors.Select(b => b.ErrorMessage)); – Kieran Feb 19 '14 at 00:30
  • 7
    This is great, but unfortunately Watch/Immediate windows don't support lambda's :( – AaronLS Mar 31 '14 at 23:02
  • Does not work for me. Values does not contain a definition for Select many. Do I have to include anything, any library, LINQ or something? – Estevez Nov 19 '14 at 15:28
  • 3
    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. – Estevez Nov 19 '14 at 15:30
  • 1
    @AaronLS Visual Studio 2015 does. – irfandar Jun 10 '16 at 07:39
  • @HakamFostok why in the hell not? – Dave Van den Eynde Jun 15 '16 at 08:49
  • 1
    @HakamFostok If you are typing out all of your variable types instead of using var, you are wasting your time. – JB06 Jun 15 '16 at 17:03
  • 1
    @DaveVandenEynde because one thing "Readability" – Hakan Fıstık Jun 16 '16 at 06:22
  • 2
    @JB06 typing out all of variable types will save the person's time who read our code, so it is saving time. – Hakan Fıstık Jun 16 '16 at 06:29
  • 7
    @hakam-fostok @jb06 you're both right. Typing `List errors = new List()` instead of `var errors = new List()` is realy a waste of time, but writing `IEnumerable 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) – aprovent Jul 18 '16 at 15:46
  • I was using this, until I encountered a: modified enumeration operation may not execute [Error](http://stackoverflow.com/questions/604831/collection-was-modified-enumeration-operation-may-not-execute) This isn't safe if used with a foreach() that subsequently appends a message to the ModelStateDictionary (for validation error output in view), and additionally doesn't handle the situation where the message is empty but the Exception object is not. This is certainly not a valid solution, it just looks pretty. – Barry Apr 05 '17 at 17:00
  • Some things like `ModelState.Values.SelectMany(v => v.Errors).ToList()[0]` can be easy to peek the error – code4j Feb 21 '18 at 07:52
  • 1
    It's worth noting that you may need to look at `Exception` rather than `ErrorMessage`. – Sinjai Nov 01 '18 at 15:51
  • ModelState.Values do not include keys, that are important to understand errors. the answer that includes key is below from Jivan Bhandari https://stackoverflow.com/a/70242034/52277 – Michael Freidgeim Apr 05 '23 at 20:52
588
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?.

Community
  • 1
  • 1
Oren Trutner
  • 23,752
  • 8
  • 54
  • 55
  • 28
    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` – AaronLS Sep 16 '14 at 01:12
  • 9
    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 kvp in htmlHelper.ViewData.ModelState) {` and insert this line below it: `var modelState = kvp.Value;`. You can get the key from `kvp.Key` – viggity Apr 11 '18 at 19:07
  • @viggity, the answer that includes key is below from Jivan Bhandari https://stackoverflow.com/a/65676216/52277 – Michael Freidgeim Apr 05 '23 at 20:35
232

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));
Dunc
  • 18,404
  • 6
  • 86
  • 103
  • 8
    The other option is to do the following: ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage).JoinString("; "); – Tod Thomson Feb 15 '13 at 02:06
  • 3
    @Tod, is IEnumerable.JoinString() your own extension method? See http://stackoverflow.com/q/4382034/188926 – Dunc Feb 15 '13 at 09:32
  • 2
    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 :( – Tod Thomson Feb 17 '13 at 04:55
  • 5
    or ... ModelState.Values.SelectMany(O => O.Errors).Select(O => O.ErrorMessage).Aggregate((U, V) => U + ", " + V) – fordareh Aug 14 '13 at 00:35
  • you can also do the select on the errors :) Not sure if it matters: `ModelState.Values.SelectMany(x => x.Errors.Select(x => x.ErrorMessage))` – DLeh Oct 23 '14 at 17:46
  • 2
    This works great when you are using web api and returning an IHttpActionResult result. So, you can just do: return BadRequest(messages); Thanks, Dunc! – Rich Ward Aug 24 '16 at 15:21
  • 1
    How would also add the Key name? I would assume this is the name of the input control that was missing or failed IsValid. – JustJohn Oct 14 '19 at 02:04
  • 2
    @JustJohn With Key name: `ModelState.SelectMany(x => x.Value.Errors.Select(y => $"{x.Key}: {y.ErrorMessage}"))` – Dunc Oct 14 '19 at 09:23
  • 1
    Thanks Dunc! I came up with this: string messages = string.Join(Environment.NewLine, ModelState .SelectMany(x => x.Value.Errors.Select(y => $"{x.Key}: {y.ErrorMessage}"))); Boy, that syntax makes my eyes cross. I am very grateful. – JustJohn Oct 15 '19 at 20:27
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

jerone
  • 16,206
  • 4
  • 39
  • 57
Yasser Shaikh
  • 46,934
  • 46
  • 204
  • 281
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>
alexsuslin
  • 4,130
  • 1
  • 20
  • 30
Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689
16

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

}
Alan Macdonald
  • 1,872
  • 20
  • 36
  • 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 – Daniël Tulp Oct 22 '13 at 08:07
  • 1
    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 – Alan Macdonald Oct 22 '13 at 17:40
  • BTW you did realise the second extension method returns IEnumerable and not just a big single string? – Alan Macdonald Oct 22 '13 at 17:52
11

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.

Mariusz Jamro
  • 30,615
  • 24
  • 120
  • 162
james31rock
  • 2,615
  • 2
  • 20
  • 25
8

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

r_piramoon
  • 141
  • 1
  • 6
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));
Josh Sutterfield
  • 1,943
  • 2
  • 16
  • 25
  • 1
    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. – Josh Sutterfield Mar 09 '17 at 21:50
7

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});
Michael Freidgeim
  • 26,542
  • 16
  • 152
  • 170
Jivan Bhandari
  • 860
  • 1
  • 10
  • 32
6

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();
    }
}
CodeArtist
  • 5,534
  • 8
  • 40
  • 65
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...
amiry jd
  • 27,021
  • 30
  • 116
  • 215
4

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();
Steve Lydford
  • 428
  • 5
  • 7
4

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;            
    }
}
Chris Marisic
  • 32,487
  • 24
  • 164
  • 258
4

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

simply use asp-validation-summary Tag Helper

4

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

dpricop
  • 91
  • 2
3

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

Taryn
  • 242,637
  • 56
  • 362
  • 405
Jason Dufair
  • 671
  • 8
  • 15
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,599
  • 12
  • 30
  • 49
0

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

-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 });
}
Alfred Severo
  • 496
  • 5
  • 15
-1

var result = string.Join(',',ModelState.Values.SelectMany(v => v.Errors).Select(a=>a.ErrorMessage));

mostafa kazemi
  • 514
  • 6
  • 7