【问题标题】:How to get all Errors from ASP.Net MVC modelState?如何从 ASP.Net MVC modelState 中获取所有错误?
【发布时间】:2010-11-24 02:07:23
【问题描述】:

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

我该怎么做?

【问题讨论】:

  • 如果您只是显示错误,那么@Html.ValidationSummary() 是一种快速显示它们的方式。
  • foreach (var error in ViewData.ModelState.Values.SelectMany(modelState => modelState.Errors)) { DoSomething(error); }
  • 感谢大家为我指明正确的方向。就像@viggity 说的那样,键很重要,这对我来说是这样的:ModelState.Where(e=>e.Value.Errors.Count > 0).ToList()

标签: asp.net-mvc modelstate


【解决方案1】:

使用LINQ

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

【讨论】:

  • 修改为仅返回错误消息的 IEnumerable:: var allErrors = ModelState.Values.SelectMany(v => v.Errors.Select(b => b.ErrorMessage));
  • 这很好,但不幸的是 Watch/Immediate 窗口不支持 lambda :(
  • 是的!我(你,任何人)需要“使用 System.Linq;”前几名。否则,您会收到消息“值不包含 Select many 的定义”。在我的情况下它丢失了。
  • @AaronLS Visual Studio 2015 可以。
  • @hakam-fostok @jb06 你是对的。键入List&lt;string&gt; errors = new List&lt;string&gt;() 而不是var errors = new List&lt;string&gt;() 确实是在浪费时间,但是在返回类型不是很清楚的情况下编写IEnumerable&lt;ModelError&gt; allErrors = ModelState.Values.SelectMany(v =&gt; v.Errors); 在可读性方面确实更好。 (即使 Visual Studio 可以在鼠标悬停时将其提供给您)
【解决方案2】:
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?

【讨论】:

  • 非常有帮助。请注意,在某些情况下,例如绑定失败和错误请求,Value.ErrorMessage 会出现带有空字符串的 ModelState 条目,而不是 Value.Exception.Message
  • 错误很好,但有时您也需要模型状态的键(即字段的名称)。您可以通过将第一行更改为:foreach (KeyValuePair&lt;string, ModelState&gt; kvp in htmlHelper.ViewData.ModelState) { 并在其下方插入此行:var modelState = kvp.Value;。您可以从kvp.Key获取密钥
【解决方案3】:

在 LINQ 版本的基础上,如果您想将所有错误消息合并到一个字符串中:

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

【讨论】:

  • 另一个选项是执行以下操作:ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage).JoinString("; ");跨度>
  • @Tod,IEnumerable.JoinString() 是您自己的扩展方法吗?见stackoverflow.com/q/4382034/188926
  • 嘿 Dunc - 是的,我怀疑我已经将该扩展方法添加到我的代码库中并且忘记了它,然后认为它是一个框架方法 LOL :(
  • 或 ... ModelState.Values.SelectMany(O => O.Errors).Select(O => O.ErrorMessage).Aggregate((U, V) => U + ", " + V)
  • 这在您使用 web api 并返回 IHttpActionResult 结果时非常有用。所以,你可以这样做: return BadRequest(messages);谢谢,邓克!
【解决方案4】:

我可以使用一点 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】:

    在调试过程中,我发现在每个页面的底部放置一个表格来显示所有 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>
    

    【讨论】:

    • 如果这里有任何失败的边缘情况,请编辑答案以修复它
    【解决方案6】:

    正如我发现到目前为止给出的答案中的建议一样,您可以在不设置错误消息的情况下发生异常,因此要捕获所有问题,您确实需要同时获取 ErrorMessage 和 Exception。

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

    【讨论】:

    • 为什么要一个包含所有错误的字符串?当您想在视图中对其执行某些操作时没有意义,列表数组更好恕我直言
    • 调试。我的第一个问题是找出我的应用程序出了什么问题。我并没有试图告诉用户只是找出问题所在。此外,将该示例从创建字符串枚举转换为其他事物的枚举是微不足道的,例如错误消息和异常,所以真正有用的是知道您需要这两种信息
    • 顺便说一句,您确实意识到第二个扩展方法返回 IEnumerable 而不仅仅是一个大字符串?
    【解决方案7】:

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

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

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

    【讨论】:

      【解决方案8】:

      仅输出错误消息本身对我来说是不够的,但这成功了。

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

      【讨论】:

      • 作为警告,ModelState 中的键值对可能包含 NULL 值,这就是为什么这里的原始代码包含一些带有 null-coalesce 运算符 (?.) 的可爱 C# 6 业务,因此柯里化到??在表达式的末尾。应该防止空错误的原始表达式是: state.Value.?AttemptedValue ?? “[空值]”。据我所知,处于当前状态的代码,如果没有对 state.Value == null 的情况进行偷偷摸摸的处理,就会面临风险。
      【解决方案9】:

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

      用法示例:

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

      【讨论】:

      • 感谢 CodeArtist !!我在其实现下面的代码中做了一个小改动。
      【解决方案10】:

      这也有效:

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

      【讨论】:

      • @Yasser 你看到托托的回答了吗?
      • @TheMuffinMan 是的,我有。怎么样?
      • @Yasser 这是最好的答案。这个没什么问题,但是当SelectMany可用时使用它没有意义。
      【解决方案11】:

      对于将错误消息数组传递给 View 很有用,可能通过 Json:

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

      【讨论】:

        【解决方案12】:

        这是对@Dunc 的回答的扩展。见 xml doc cmets

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

        【讨论】:

          【解决方案13】:

          任何人都在寻找 asp.net core 3.1。比上述答案略有更新。我发现这是 [ApiController] 返回的内容

           Dictionary<string, List<string>> errors = new Dictionary<string, List<string>>();
          
                          foreach (KeyValuePair<string, ModelStateEntry> kvp in ViewData.ModelState)
                          {
                              string key = kvp.Key;
                              ModelStateEntry entry = kvp.Value;
          
                              if (entry.Errors.Count > 0)
                              {
                                  List<string> errorList = new List<string>();
                                  foreach (ModelError error in entry.Errors)
                                  {
                                      errorList.Add(error.ErrorMessage);
                                  }
          
                                  errors[key] = errorList;
                              }
                          }
          
                          return  new JsonResult(new {Errors = errors});
          

          【讨论】:

            【解决方案14】:

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

            【讨论】:

              【解决方案15】:

              &lt;div class="text-danger" style="direction:rtl" asp-validation-summary="All"&gt;&lt;/div&gt;

              只需使用 asp-validation-summary Tag Helper

              【讨论】:

                【解决方案16】:

                对于 AJAX 请求更好的解决方案:

                    public IActionResult Demo(DemoInfo formData)
                    {
                        if (!ModelState.IsValid)
                        {
                            IEnumerable<object> formErrors = ModelState.Select((s) => new { 
                                fieldName = s.Key, 
                                fieldValue = s.Value.RawValue,
                                fieldMessage = s.Value.Errors.FirstOrDefault()?.ErrorMessage
                            });
                            return Json(new { formValid = 0, formErrors });
                        }
                        return Json(new { formValid = 1 });
                    }
                

                回复格式为:

                {"formValid":0,
                 "formErrors":[{
                     "fieldName":"name of field from object",
                     "fieldValue":"value from browser",
                     "fieldMessage":null /*Error message from model annotations if field is valid the value will be null */
                 }]
                }
                

                有关 Func 的更多详细信息请查看此页面:Func<TSource,Int32,TResult>)

                【讨论】:

                  【解决方案17】:
                  var x = new Dictionary<string,string>();
                  for (var b = 0; b < ViewData.ModelState.Values.Count(); b++)
                  {
                      if (ViewData.ModelState.Values.ElementAt(b).Errors.Count() > 0)
                          x.Add(ViewData.ModelState.Keys.ElementAt(b), String.Join(",", ViewData
                              .ModelState.Values.ElementAt(b).Errors.Select(c => c.ErrorMessage)));
                  }
                  

                  【讨论】:

                  • @GuilhermeSilva 是贡献者
                  【解决方案18】:

                  这段代码 sn-p 也很有用,它给你一个包含错误消息的列表。

                  var errors = ModelState.Values.SelectMany(x =&gt; x.Errors.Select(c =&gt; c.ErrorMessage)).ToList();

                  【讨论】:

                    【解决方案19】:

                    在你的实现中你缺少静态类,这应该是。

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

                    相当

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

                    【讨论】:

                      【解决方案20】:

                      var result = string.Join(',',ModelState.Values.SelectMany(v => v.Errors).Select(a=>a.ErrorMessage));

                      【讨论】:

                        猜你喜欢
                        • 2020-11-19
                        • 1970-01-01
                        • 2011-03-09
                        • 2011-06-06
                        • 1970-01-01
                        • 1970-01-01
                        • 2011-02-20
                        • 2019-10-21
                        • 2018-06-21
                        相关资源
                        最近更新 更多