Jak uzyskać kolekcję błędów stanu modelu w ASP.NET MVC?

145

Jak uzyskać zbiór błędów w widoku?

Nie chcę używać podsumowania walidacji pomocnika HTML lub komunikatu walidacji. Zamiast tego chcę sprawdzić błędy i wyświetlić je w określonym formacie. Również w kontrolkach wejściowych chcę sprawdzić określony błąd właściwości i dodać klasę do danych wejściowych.

PS Używam Spark View Engine, ale pomysł powinien być taki sam.

Pomyślałem, że mógłbym zrobić coś takiego ...

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

....and also...

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

....

Czy jakoś tak.

AKTUALIZACJA

Moje ostateczne rozwiązanie wyglądało następująco:

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

Spowoduje to dodanie klasy CSS błędu tylko wtedy, gdy ta właściwość zawiera błąd.

Ryan Montgomery
źródło
1
Możliwy duplikat Jak pobrać wszystkie błędy z ASP.Net MVC modelState?
Michael Freidgeim

Odpowiedzi:

210
<% ViewData.ModelState.IsValid %>

lub

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

i dla konkretnej nieruchomości ...

<% ViewData.ModelState["Property"].Errors %> // Note this returns a collection
Chad Moran
źródło
1
właściwość ModelState jest typu słownikowego, aby uzyskać błąd podczas przekazywania nazwy klucza ViewData.ModelState ["Name"]
dotyczące „ViewData.ModelState [„ Property ”]. Errors” czy spowodowałoby to zgłoszenie zerowego wyjątku odwołania, gdyby nie było klucza o nazwie „Property”? czy lepiej byłoby najpierw sprawdzić wartość null w ViewData.ModelState ["Property"] przed odczytaniem w Errors?
David Hollowell - MSFT
@DaveH Tak, najpierw powinieneś całkowicie sprawdzić istnienie
Alex Lyman,
61

Aby po prostu pobrać błędy z ModelState, użyj tego Linq:

var modelStateErrors = this.ModelState.Keys.SelectMany(key => this.ModelState[key].Errors);
Chris McKenzie
źródło
2
czy spowoduje to zgłoszenie zerowego wyjątku odwołania, jeśli nie ma klucza o określonej nazwie? czy lepiej byłoby najpierw sprawdzić wartość null w ViewData.ModelState [klucz] przed odczytaniem w Errors?
David Hollowell - MSFT
5
Ponieważ zaczynamy od iteracji po this.ModelState.Keys, nie widzę potencjału dla KeyNotFoundException. Myślę, że ten czek byłby przesadą.
Chris McKenzie
30

Skrócona wersja odpowiedzi @ ChrisMcKenzie :

var modelStateErrors = this.ModelState.Values.SelectMany(m => m.Errors);
Todd Menier
źródło
28

W ten sposób otrzymasz jeden ciąg ze wszystkimi błędami oddzielonymi przecinkami

string validationErrors = string.Join(",",
                    ModelState.Values.Where(E => E.Errors.Count > 0)
                    .SelectMany(E => E.Errors)
                    .Select(E => E.ErrorMessage)
                    .ToArray());
UshaP
źródło
To jedyna rzecz, jaką znalazłem na całej liście, która faktycznie wyświetla błędy! Dzięki
Jamie
6

Dzięki Chad! Aby pokazać wszystkie błędy związane z kluczem, oto co wymyśliłem. Z jakiegoś powodu podstawowy helper Html.ValidationMessage pokazuje tylko pierwszy błąd związany z kluczem.

    <%= 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
źródło
6

Zestawiając kilka odpowiedzi z góry, oto co ostatecznie użyłem:

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

validationErrorskończy się jako List<string>zawierająca każdy komunikat o błędzie. Stamtąd łatwo jest robić, co chcesz z tą listą.

wprowadź opis obrazu tutaj

Casey Crookston
źródło
2

Oto 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
źródło
0

Jeśli nie wiesz, jaka właściwość spowodowała błąd, możesz za pomocą odbicia zapętlić wszystkie właściwości:

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

Gdzie T jest typem Twojego „ViewModel”.

Gerard
źródło