¿Cómo obtengo la colección de errores de estado del modelo en ASP.NET MVC?

145

¿Cómo obtengo la colección de errores en una vista?

No quiero usar el Resumen de validación de ayuda HTML o el Mensaje de validación. En cambio, quiero verificar si hay errores y, si los hay, mostrarlos en un formato específico. También en los controles de entrada quiero verificar un error de propiedad específico y agregar una clase a la entrada.

PD: Estoy usando el Spark View Engine pero la idea debería ser la misma.

Entonces pensé que podría hacer 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" />

....

O algo así.

ACTUALIZAR

Mi solución final se veía así:

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

Esto solo agrega la clase de error css si esta propiedad tiene un error.

Ryan Montgomery
fuente
1
Posible duplicado de Cómo obtener todos los errores de ASP.Net MVC modelState?
Michael Freidgeim

Respuestas:

210
<% ViewData.ModelState.IsValid %>

o

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

y para una propiedad específica ...

<% ViewData.ModelState["Property"].Errors %> // Note this returns a collection
Chad Moran
fuente
1
la propiedad ModelState es de tipo diccionario para obtener el error de pasar el nombre de clave ViewData.ModelState ["Name"]
con respecto a "ViewData.ModelState [" Propiedad "]. Errores" ¿arrojaría esto una excepción de referencia nula si no hubiera una clave con el nombre "Propiedad"? ¿sería mejor verificar primero si hay valores nulos en ViewData.ModelState ["Propiedad"] antes de leer los Errores?
David Hollowell - MSFT
@DaveH Sí, primero debes verificar por completo la existencia
Alex Lyman
61

Para obtener solo los errores de ModelState, use este Linq:

var modelStateErrors = this.ModelState.Keys.SelectMany(key => this.ModelState[key].Errors);
Chris McKenzie
fuente
2
¿arrojaría esto una excepción de referencia nula si no hubiera una clave con el nombre especificado? ¿sería mejor comprobar primero si hay valores nulos en la [clave] ViewData.ModelState antes de leer los errores?
David Hollowell - MSFT
55
Debido a que comenzamos iterando sobre esto.ModelState.Keys, no veo el potencial para una KeyNotFoundException. Creo que ese cheque sería exagerado.
Chris McKenzie
28

Esto le dará una cadena con todos los errores con separación de comas

string validationErrors = string.Join(",",
                    ModelState.Values.Where(E => E.Errors.Count > 0)
                    .SelectMany(E => E.Errors)
                    .Select(E => E.ErrorMessage)
                    .ToArray());
UshaP
fuente
¡Esto es lo único que encontré en toda esta lista que realmente imprime los errores! Gracias
Jamie
6

Gracias Chad! Para mostrar todos los errores asociados con la clave, esto es lo que se me ocurrió. Por alguna razón, el asistente base Html.ValidationMessage solo muestra el primer error asociado con la clave.

    <%= 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();
    }
Rastrillo36
fuente
6

Al reunir varias respuestas de lo anterior, esto es lo que terminé usando:

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

validationErrorstermina siendo un List<string>mensaje que contiene cada mensaje de error. A partir de ahí, es fácil hacer lo que quieras con esa lista.

ingrese la descripción de la imagen aquí

Casey Crookston
fuente
2

Aquí está el 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
fuente
0

Si no sabe qué propiedad causó el error, puede, usando la reflexión, recorrer todas las propiedades:

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

Donde T es el tipo de su "ViewModel".

Gerard
fuente