Как получить все ошибки от ASP.Net MVC modelState?
Я хочу получить все сообщения об ошибках из modelState не зная ключевых значений. Зацикливание, чтобы захватить все сообщения об ошибках, которые содержит ModelState.
Как я могу это сделать?
14 ответов:
foreach (ModelState modelState in ViewData.ModelState.Values) { foreach (ModelError error in modelState.Errors) { DoSomethingWith(error); } }
см. также Как получить коллекцию ошибок состояния модели в ASP.NET MVC?.
С помощью LINQ:
IEnumerable<ModelError> allErrors = ModelState.Values.SelectMany(v => v.Errors);
основываясь на версии LINQ, если вы хотите объединить все сообщения об ошибках в одну строку:
string messages = string.Join("; ", ModelState.Values .SelectMany(x => x.Errors) .Select(x => x.ErrorMessage));
я смог сделать это с помощью небольшого 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; }
выше метод возвращает список ошибок валидации.
Читайте Далее :
во время отладки я считаю полезным поместить таблицу в нижней части каждой страницы, чтобы показать все 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>
Как я обнаружил, следуя советам в ответах, приведенных до сих пор, вы можете получить исключения, происходящие без сообщений об ошибках, поэтому, чтобы поймать все проблемы, вам действительно нужно получить как ErrorMessage, так и исключение.
String messages = String.Join(Environment.NewLine, ModelState.Values.SelectMany(v => v.Errors) .Select( v => v.ErrorMessage + " " + v.Exception));
или как метод расширения
public static IEnumerable<String> GetErrors(this ModelStateDictionary modelState) { return modelState.Values.SelectMany(v => v.Errors) .Select( v => v.ErrorMessage + " " + v.Exception).ToList(); }
и это тоже работает:
var query = from state in ModelState.Values from error in state.Errors select error.ErrorMessage; var errors = query.ToArray(); // ToList() and so on...
это расширяется на ответ от @Dunc . См. комментарии XML-документации
// 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; } }
на всякий случай, если кому-то это нужно, я сделал и использую следующий статический класс в своих проектах
пример использования:
if (!ModelState.IsValid) { var errors = ModelState.GetModelErrors(); return Json(new { errors }); }
директивы:
using System.Collections.Generic; using System.Linq; using System.Text; using System.Web.Mvc; using WebGrease.Css.Extensions;
класс:
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(); } }
вывод только самих сообщений об ошибках было недостаточно для меня, но это сделало трюк.
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));
в случае, если кто-то хочет вернуть имя свойства модели для привязки сообщения об ошибке в строго типизированном представлении.
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); } }
таким образом, вы можете фактически связать ошибку с полем, которое вызвало ошибку.
полезно для передачи массива сообщений об ошибках для просмотра, возможно, через Json:
messageArray = this.ViewData.ModelState.Values.SelectMany(modelState => modelState.Errors, (modelState, error) => error.ErrorMessage).ToArray();
кроме того,
ModelState.Values.ErrorMessage
может быть пустым, ноModelState.Values.Exception.Message
может указывать на ошибку.
в вашем реализации вам не хватает статического класса, это должно быть.
if (!ModelState.IsValid) { var errors = ModelStateErrorHandler.GetModelErrors(this.ModelState); return Json(new { errors }); }
, а
if (!ModelState.IsValid) { var errors = ModelState.GetModelErrors(); return Json(new { errors }); }