2009-08-30 3 views
324

Я хочу получить все сообщения об ошибках из modelState, не зная значений ключей. Прокрутка, чтобы захватить все сообщения об ошибках, содержащиеся в ModelState.Как получить все ошибки из ASP.Net MVC modelState?

Как это сделать?

+4

Если вы просто показываете ошибки, то '@ Html.ValidationSummary()' - это быстрый способ отобразить их все в бритве. – levininja

+5

'foreach (ошибка var в ViewData.ModelState.Values.SelectMany (modelState => modelState.Errors)) {DoSomething (ошибка); } ' –

ответ

403
foreach (ModelState modelState in ViewData.ModelState.Values) { 
    foreach (ModelError error in modelState.Errors) { 
     DoSomethingWith(error); 
    } 
} 

См. Также How do I get the collection of Model State Errors in ASP.NET MVC?.

+13

Очень полезно. Обратите внимание, что в некоторых сценариях, таких как сбои привязки и неудачные запросы, будут записи ModelState с пустой строкой для 'Value.ErrorMessage' и вместо этого значение Value.Exception.Message' – AaronLS

397

Использование LINQ:

IEnumerable<ModelError> allErrors = ModelState.Values.SelectMany(v => v.Errors); 
+39

Изменено для возврата IEnumerable с указанием только сообщения об ошибке :: var allErrors = ModelState.Values.SelectMany (v => v.Errors.Select (b => b.ErrorMessage)); – Kieran

+5

Это замечательно, но, к сожалению, Watch/Immediate windows не поддерживают lambda's :( – AaronLS

+0

Не работает для меня. Значения не содержат определения для Select many. Должен ли я включать что-либо, любую библиотеку, LINQ или что-то еще? – Estevez

144

Опираясь на verison LINQ, если вы хотите присоединиться все сообщения об ошибках в одну строку:

string messages = string.Join("; ", ModelState.Values 
             .SelectMany(x => x.Errors) 
             .Select(x => x.ErrorMessage)); 
+4

Другой вариант - сделать следующее: ModelState.Values.SelectMany (x => x.Errors) .Выберите (x => x.ErrorMessage) .JoinString (";"); –

+2

@Tod, IEnumerable.JoinString() ваш собственный метод расширения? См. Http://stackoverflow.com/q/4382034/188926 – Dunc

+1

Эй, Dunc - да, я подозреваю, что добавил этот метод расширения к моей базе кода и забыл об этом, а затем подумал, что это был метод структуры LOL :( –

4

И это тоже работает:

var query = from state in ModelState.Values 
    from error in state.Errors 
    select error.ErrorMessage; 
var errors = query.ToArray(); // ToList() and so on... 
+0

@Yasser Вы видели ответ Тото? –

+0

@ TheMuffinMan да есть. Что насчет этого ? – Yasser

+0

@ Yasser Это лучший ответ. Ничего плохого в этом нет, но не стоит использовать его, когда доступно 'SelectMany'. –

1

Кроме того, ModelState.Values.ErrorMessage может быть пустым, но ModelState.Values.Exception.Message может указывать ели ошибку.

23

я был в состоянии сделать это, используя немного 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; 
} 

выше метод возвращает список ошибок проверки.

Дополнительная литература:

How to read all errors from ModelState in ASP.NET MVC

+5

+1 для того, чтобы быть более полезным во время отладки, поскольку это метод расширения –

12

Во время отладки я считаю полезным, чтобы поместить таблицу в нижней части каждого из моих страниц, чтобы показать все ошибки 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> 
+0

, если есть какие-либо случаи края здесь, где это не удается, просто отредактируйте ответ, чтобы исправить его. –

9

Как я обнаружил последовав совет в ответах до сих пор, вы можете получить исключения, происходящие без сообщений об ошибках быть установлены, так, чтобы охватить все проблемы, которые действительно нужны, чтобы получить как 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(); 

} 
+0

Почему вы хотите строку со всеми ошибками в ней? не имеет смысла, когда вы хотите что-то сделать с ним в представлении, массив списка лучше, чем imho. –

+1

Отладка. Моя первая проблема заключалась в том, чтобы выяснить, что не так с моим приложением. Я не пытался сказать, что пользователь просто узнает, что происходит не так. Кроме того, тривиально преобразовать этот пример из создания перечисления строк в перечисление чего-то другого, например. сообщение об ошибке и исключение, поэтому действительно полезно знать, что вам нужны оба бита информации. –

+0

Кстати, вы поняли, что второй метод расширения возвращает IEnumerable , а не только одну большую строку? –

2

полезное для передачи массива сообщений об ошибках для просмотра, возможно, через Json:

messageArray = this.ViewData.ModelState.Values.SelectMany(modelState => modelState.Errors, (modelState, error) => error.ErrorMessage).ToArray(); 
4

Это расширяет на ответ от @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;    
    } 
} 
4

Для только в случае, если кто-то это нужно я сделал и использовать следующий статический класс в моих проектах

Пример использования:

if (!ModelState.IsValid) 
{ 
    var errors = ModelState.GetModelErrors(); 
    return Json(new { errors }); 
} 

Usings:

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

Спасибо CodeArtist !! Я сделал небольшое изменение в коде ниже его реализации. –

0

В вашей реализации вам не хватает статического класса, это должно быть.

if (!ModelState.IsValid) 
{ 
    var errors = ModelStateErrorHandler.GetModelErrors(this.ModelState); 
    return Json(new { errors }); 
} 

довольно

if (!ModelState.IsValid) 
{ 
    var errors = ModelState.GetModelErrors(); 
    return Json(new { errors }); 
} 
3

В случае, если кто хочет вернуть имя свойства модели для связывания сообщения об ошибке в сильно типизированной.

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

Таким образом, вы действительно можете связать ошибку с полем, в котором была ошибка.

4

Вывод только сообщений об ошибках сам по себе был недостаточным для меня, но это сделало трюк.

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)); 
+0

В качестве предупреждения пары ключевых значений в ModelState могут включать значения NULL, поэтому исходный код здесь включает в себя некоторые симпатичные операции C# 6 с оператором null-coalesce (?.), Следовательно, currying to the ?? в конце выражения. Исходным выражением, которое должно защищать от нулевых ошибок, было: state.Value.?AttemptedValue ?? "[НОЛЬ]". Насколько мне известно, код в его текущем состоянии, без скрытой обработки случаев, когда state.Value == null, находится под угрозой. –

Смежные вопросы