如何从ASP.Net MVC modelState获取所有错误?

How to get all Errors from ASP.Net MVC modelState?

我想在不知道键值的情况下从modelState中获取所有错误消息。 遍历以获取ModelState包含的所有错误消息。

我怎样才能做到这一点?


1
2
3
4
5
foreach (ModelState modelState in ViewData.ModelState.Values) {
    foreach (ModelError error in modelState.Errors) {
        DoSomethingWith(error);
    }
}

另请参见如何在ASP.NET MVC中收集模型状态错误?


使用LINQ:

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


如果您想将所有错误消息连接到一个字符串中,则以LINQ版本为基础:

1
2
3
string messages = string.Join(";", ModelState.Values
                                        .SelectMany(x => x.Errors)
                                        .Select(x => x.ErrorMessage));


我可以使用LINQ做到这一点,

1
2
3
4
5
6
7
8
9
10
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;
}

上面的方法返回验证错误列表。

进一步阅读:

如何从ASP.NET MVC中的ModelState读取所有错误


在调试期间,我发现在每个页面的底部放置一个表格以显示所有ModelState错误很有用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<table class="model-state">
    @foreach (var item in ViewContext.ViewData.ModelState)
    {
        if (item.Value.Errors.Any())
        {
        <tr>
            <td>@item.Key</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和Exception的问题。

1
2
String messages = String.Join(Environment.NewLine, ModelState.Values.SelectMany(v => v.Errors)
                                                           .Select( v => v.ErrorMessage +"" + v.Exception));

或作为扩展方法

1
2
3
4
5
6
public static IEnumerable<String> GetErrors(this ModelStateDictionary modelState)
{
      return modelState.Values.SelectMany(v => v.Errors)
                              .Select( v => v.ErrorMessage +"" + v.Exception).ToList();

}


如果有人想返回Model属性的名称,以便在强类型视图中绑定错误消息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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);
    }
}

这样,您实际上可以将错误与引发错误的字段联系在一起。


仅输出错误消息本身对我来说还不够,但这确实可以解决问题。

1
2
3
4
5
6
7
8
9
10
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));


以防万一有人需要它,我在我的项目中使用了以下静态类

用法示例:

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

Usings:

1
2
3
4
5
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using WebGrease.Css.Extensions;

类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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();
    }
}


这扩展了@Dunc的答案。查看xml文档注释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 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;            
    }
}

这也有效:

1
2
3
4
var query = from state in ModelState.Values
    from error in state.Errors
    select error.ErrorMessage;
var errors = query.ToArray(); // ToList() and so on...


有助于通过Json将错误消息数组传递给View:

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

此外,ModelState.Values.ErrorMessage可能为空,但ModelState.Values.Exception.Message可能表示错误。


我不知道这是我的问题,有时我在ModelState的ErrorMessage部分中收到消息,有时在ModelState错误的异常消息中得到消息。

因此,我创建了一个可以同时处理这两种情况的方法。希望这对这里的每个人都有帮助。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static string GetErrorMessageFromModelState(ModelStateDictionary modelState)
    {
        string errorMessage = string.Empty;

        try
        {
            string[] errorMessageList = (from m in modelState
                                         where m.Value.Errors.Count > 0
                                         select string.Join(",", m.Value.Errors.Select(x =>
                                         !string.IsNullOrEmpty(x.ErrorMessage) ? x.ErrorMessage : !string.IsNullOrEmpty(x.Exception.Message) ?
                                         x.Exception.Message.Split('\'').Length > 0 ? x.Exception.Message.Split('\'')[1].ToString() : m.Key.Split('.').Length > 1 ?
                                         m.Key.Split('.')[1] : m.Key.Split('.')[0] : m.Key.Split('.')[0]))).ToArray();

            errorMessage = string.Format("Error in Field(s):" + string.Join(",", errorMessageList) +" {0} required.", (errorMessageList.Count() > 1 ?"are" :"is"));
        }
        catch (Exception ex)
        {
            errorMessage = ex.Message;
            if (ex.InnerException != null)
                errorMessage += Environment.NewLine + ex.InnerException;
        }

        return errorMessage;
    }


在您的实现中,您应该缺少静态类。

1
2
3
4
5
if (!ModelState.IsValid)
{
    var errors =  ModelStateErrorHandler.GetModelErrors(this.ModelState);
    return Json(new { errors });
}

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