asp.net-mvc - mvc - show modelstate errors in view
¿Cómo obtener todos los errores de ASP.Net MVC modelState? (14)
Útil para pasar una serie de mensajes de error a la Vista, quizás a través de Json:
messageArray = this.ViewData.ModelState.Values.SelectMany(modelState => modelState.Errors, (modelState, error) => error.ErrorMessage).ToArray();
Quiero eliminar todos los mensajes de error de modelState sin conocer los valores clave. Recorriendo para capturar todos los mensajes de error que contiene ModelState.
¿Cómo puedo hacer esto?
Además, ModelState.Values.ErrorMessage
puede estar vacío, pero ModelState.Values.Exception.Message
puede indicar un error.
Basándose en la versión LINQ, si desea unir todos los mensajes de error en una cadena:
string messages = string.Join("; ", ModelState.Values
.SelectMany(x => x.Errors)
.Select(x => x.ErrorMessage));
Como descubrí que seguí los consejos de las respuestas proporcionadas hasta ahora, puede obtener excepciones sin que se establezcan mensajes de error, por lo que para detectar todos los problemas que realmente necesita para obtener tanto el ErrorMessage como la Excepción.
String messages = String.Join(Environment.NewLine, ModelState.Values.SelectMany(v => v.Errors)
.Select( v => v.ErrorMessage + " " + v.Exception));
o como método de extensión
public static IEnumerable<String> GetErrors(this ModelStateDictionary modelState)
{
return modelState.Values.SelectMany(v => v.Errors)
.Select( v => v.ErrorMessage + " " + v.Exception).ToList();
}
Durante la depuración me parece útil colocar una tabla en la parte inferior de cada una de mis páginas para mostrar todos los errores de ModelState.
<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>
En caso de que alguien quiera devolver el nombre de la propiedad del modelo para vincular el mensaje de error en una vista fuertemente tipada.
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);
}
}
De esta manera, realmente puede vincular el error con el campo que lanzó el error.
Esto está ampliando la respuesta de @Dunc. Ver comentarios xml doc.
// 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;
}
}
La salida de solo los mensajes de error en sí no fue suficiente para mí, pero esto resultó ser el truco.
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));
Por si acaso alguien lo necesita, hice y uso la siguiente clase estática en mis proyectos.
Ejemplo de uso:
if (!ModelState.IsValid)
{
var errors = ModelState.GetModelErrors();
return Json(new { errors });
}
Usos:
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using WebGrease.Css.Extensions;
Clase:
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();
}
}
Pude hacer esto usando un poco de 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;
}
El método anterior devuelve una lista de errores de validación.
Otras lecturas :
Utilizando LINQ :
IEnumerable<ModelError> allErrors = ModelState.Values.SelectMany(v => v.Errors);
Y esto funciona también:
var query = from state in ModelState.Values
from error in state.Errors
select error.ErrorMessage;
var errors = query.ToArray(); // ToList() and so on...
En tu implementación faltan clases estáticas, esto debería ser.
if (!ModelState.IsValid)
{
var errors = ModelStateErrorHandler.GetModelErrors(this.ModelState);
return Json(new { errors });
}
más bien
if (!ModelState.IsValid)
{
var errors = ModelState.GetModelErrors();
return Json(new { errors });
}
foreach (ModelState modelState in ViewData.ModelState.Values) {
foreach (ModelError error in modelState.Errors) {
DoSomethingWith(error);
}
}
Consulte también ¿Cómo obtengo la colección de errores de estado de modelo en ASP.NET MVC? .