Como obtenho a coleção de erros de estado do modelo no ASP.NET MVC?

145

Como obtenho a coleção de erros em uma exibição?

Não quero usar o Resumo de validação do auxiliar de HTML nem a Mensagem de validação. Em vez disso, quero verificar se há erros e se algum os exibe em formato específico. Também nos controles de entrada, desejo verificar um erro de propriedade específico e adicionar uma classe à entrada.

PS: Estou usando o Spark View Engine, mas a ideia deve ser a mesma.

Então achei que poderia fazer algo como ...

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

....and also...

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

....

Ou algo assim.

ATUALIZAR

Minha solução final ficou assim:

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

Isso adiciona apenas a classe css de erro se esta propriedade tiver um erro.

Ryan Montgomery
fonte
1
Possível duplicata de Como obter todos os erros do ASP.Net MVC modelState?
Michael Freidgeim

Respostas:

210
<% ViewData.ModelState.IsValid %>

ou

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

e para uma propriedade específica ...

<% ViewData.ModelState["Property"].Errors %> // Note this returns a collection
Chad Moran
fonte
1
a propriedade ModelState é do tipo de dicionário para obter o erro de passar o nome da chave ViewData.ModelState ["Name"]
em relação a "ViewData.ModelState [" Propriedade "]. Erros" isso lançaria uma exceção de referência nula se não houvesse uma chave com o nome "Propriedade"? seria melhor primeiro verificar nulo no ViewData.ModelState ["Property"] antes de ler em Erros?
precisa
@DaveH Sim, você deve verificar totalmente a existência primeiro #
Alex Lyman
61

Para obter apenas os erros do ModelState, use este Linq:

var modelStateErrors = this.ModelState.Keys.SelectMany(key => this.ModelState[key].Errors);
Chris McKenzie
fonte
2
isso lançaria uma exceção de referência nula se não houvesse chave com o nome especificado? seria melhor primeiro verificar nulo na ViewData.ModelState [chave] antes de ler em Erros?
precisa
5
Como começamos iterando sobre this.ModelState.Keys, não vejo o potencial de uma KeyNotFoundException. Eu acho que esse cheque seria um exagero.
22420 Chris McKenzie #:
28

Isso fornecerá uma sequência com todos os erros com vírgula separando

string validationErrors = string.Join(",",
                    ModelState.Values.Where(E => E.Errors.Count > 0)
                    .SelectMany(E => E.Errors)
                    .Select(E => E.ErrorMessage)
                    .ToArray());
UshaP
fonte
Esta é a única coisa que encontrei em toda a lista que realmente imprime os erros! Obrigado
Jamie
6

Obrigado Chad! Para mostrar todos os erros associados à chave, eis o que eu criei. Por algum motivo, o auxiliar Html.ValidationMessage base mostra apenas o primeiro erro associado à chave.

    <%= 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
fonte
6

Reunindo várias respostas acima, é isso que acabei usando:

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

validationErrorsacaba sendo um List<string>que contém cada mensagem de erro. A partir daí, é fácil fazer o que quiser com essa lista.

insira a descrição da imagem aqui

Casey Crookston
fonte
2

Aqui está o 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
fonte
0

Se você não souber qual propriedade causou o erro, é possível, usando a reflexão, fazer um loop sobre todas as propriedades:

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

Onde T é o tipo do seu "ViewModel".

Gerard
fonte