150

How do I get the collection of errors in a view?

I don't want to use the Html Helper Validation Summary or Validation Message. Instead I want to check for errors and if any display them in specific format. Also on the input controls I want to check for a specific property error and add a class to the input.

P.S. I'm using the Spark View Engine but the idea should be the same.

So I figured I could do something like...

<if condition="${ModelState.Errors.Count > 0}">
  DisplayErrorSummary()
</if>

....and also...

<input type="text" value="${Model.Name}" 
       class="?{ModelState.Errors["Name"] != string.empty} error" />

....

Or something like that.

UPDATE

My final solution looked like this:

<input type="text" value="${ViewData.Model.Name}" 
       class="text error?{!ViewData.ModelState.IsValid && 
                           ViewData.ModelState["Name"].Errors.Count() > 0}" 
       id="Name" name="Name" />

This only adds the error css class if this property has an error.

AGuyCalledGerald
  • 7,452
  • 16
  • 69
  • 113
rmontgomery429
  • 14,410
  • 16
  • 55
  • 64
  • 1
    Possible duplicate of [How to get all Errors from ASP.Net MVC modelState?](https://stackoverflow.com/questions/1352948/how-to-get-all-errors-from-asp-net-mvc-modelstate) – Michael Freidgeim Nov 16 '17 at 06:59

9 Answers9

216
<% ViewData.ModelState.IsValid %>

or

<% ViewData.ModelState.Values.Any(x => x.Errors.Count >= 1) %>

and for a specific property...

<% ViewData.ModelState["Property"].Errors %> // Note this returns a collection
Chris Kooken
  • 31,984
  • 14
  • 81
  • 117
Chad Moran
  • 12,774
  • 2
  • 47
  • 71
  • 1
    the ModelState property is of dictionary type to get the error for pass the key name ViewData.ModelState["Name"] –  Feb 21 '09 at 16:29
  • regarding "ViewData.ModelState["Property"].Errors" would this throw a null reference exception if there was no key with the name "Property"? would it be better to first check for null on the ViewData.ModelState["Property"] prior to reading in Errors? – David Hollowell - MSFT Nov 06 '12 at 18:16
  • @DaveH Yep, you should totally check for existence first – Alex Lyman Dec 04 '13 at 20:03
63

To just get the errors from the ModelState, use this Linq:

var modelStateErrors = this.ModelState.Keys.SelectMany(key => this.ModelState[key].Errors);
Chris McKenzie
  • 3,391
  • 1
  • 26
  • 34
  • 2
    would this throw a null reference exception if there was no key with the specified name? would it be better to first check for null on the ViewData.ModelState[key] prior to reading in Errors? – David Hollowell - MSFT Nov 06 '12 at 18:16
  • 5
    Because we start by iterating over this.ModelState.Keys, I don't see the potential for a KeyNotFoundException. I think that check would be overkill. – Chris McKenzie Nov 06 '12 at 22:09
31

Condensed version of @ChrisMcKenzie's answer:

var modelStateErrors = this.ModelState.Values.SelectMany(m => m.Errors);
Community
  • 1
  • 1
Todd Menier
  • 35,101
  • 14
  • 140
  • 163
30

This will give you one string with all the errors with comma separating

string validationErrors = string.Join(",",
                    ModelState.Values.Where(E => E.Errors.Count > 0)
                    .SelectMany(E => E.Errors)
                    .Select(E => E.ErrorMessage)
                    .ToArray());
UshaP
  • 1,251
  • 2
  • 18
  • 32
  • This is the only thing I found in this entire list that actually prints out the errors! Thanks – Jamie Jun 27 '19 at 16:02
7

Putting together several answers from above, this is what I ended up using:

var validationErrors = ModelState.Values.Where(E => E.Errors.Count > 0)
    .SelectMany(E => E.Errors)
    .Select(E => E.ErrorMessage)
    .ToList();

validationErrors ends up being a List<string> that contains each error message. From there, it's easy to do what you want with that list.

enter image description here

Casey Crookston
  • 11,730
  • 21
  • 92
  • 169
6

Thanks Chad! To show all the errors associated with the key, here's what I came up with. For some reason the base Html.ValidationMessage helper only shows the first error associated with the key.

    <%= Html.ShowAllErrors(mykey) %>

HtmlHelper:

    public static String ShowAllErrors(this HtmlHelper helper, String key) {
        StringBuilder sb = new StringBuilder();
        if (helper.ViewData.ModelState[key] != null) {
            foreach (var e in helper.ViewData.ModelState[key].Errors) {
                TagBuilder div = new TagBuilder("div");
                div.MergeAttribute("class", "field-validation-error");
                div.SetInnerText(e.ErrorMessage);
                sb.Append(div.ToString());
            }
        }
        return sb.ToString();
    }
Rake36
  • 982
  • 2
  • 10
  • 17
2

Here is the VB.

Dim validationErrors As String = String.Join(",", ModelState.Values.Where(Function(E) E.Errors.Count > 0).SelectMany(Function(E) E.Errors).[Select](Function(E) E.ErrorMessage).ToArray())
MaylorTaylor
  • 4,031
  • 14
  • 43
  • 72
0

If you don't know what property caused the error, you can, using reflection, loop over all properties:

public static String ShowAllErrors<T>(this HtmlHelper helper) {
    StringBuilder sb = new StringBuilder();
    Type myType = typeof(T);
    PropertyInfo[] propInfo = myType.GetProperties();

    foreach (PropertyInfo prop in propInfo) {
        foreach (var e in helper.ViewData.ModelState[prop.Name].Errors) {
            TagBuilder div = new TagBuilder("div");
            div.MergeAttribute("class", "field-validation-error");
            div.SetInnerText(e.ErrorMessage);
            sb.Append(div.ToString());
        }
    }
    return sb.ToString();
}

Where T is the type of your "ViewModel".

Gerard
  • 2,501
  • 1
  • 26
  • 38
0

Got this from BrockAllen's answer that worked for me, it displays the keys that have errors:

    var errors =
    from item in ModelState
    where item.Value.Errors.Count > 0
    select item.Key;
    var keys = errors.ToArray();

Source: https://forums.asp.net/t/1805163.aspx?Get+the+Key+value+of+the+Model+error