【问题标题】:ValidationMessage - Handle multiple errors for the same propertyValidationMessage - 处理同一属性的多个错误
【发布时间】:2010-10-31 17:00:55
【问题描述】:

我在 MVC 中使用 ValidationMessage 控件。验证每个属性时,可能会显示多个错误消息,但 ValidationMessage 仅显示列表中的第一条错误消息。

这是一个例子:

ModelState["Key"] = new ModelState();
ModelState["Key"].Errors.Add("Error 1");
ModelState["Key"].Errors.Add("Error 2");

在 html 中我有:<%= Html.ValidationMessage("Key")%>

其中显示:"Error 1"

我想查看页面上的所有错误消息"Error 1 Error 2"

知道怎么做吗?

【问题讨论】:

    标签: asp.net-mvc


    【解决方案1】:

    由于ModelState 遵循字典模式来查找错误,看来最终我们需要将所有错误连接到单个ModelState 键中:

       ModelState["Key"].Errors.Add("Error 1. " + "Error 2");
    

    如果您使用IValidatableObject convention 执行自定义验证,您可以将验证结果失败转换为ModelState 条目,如下所示:

    var resultsGroupedByMembers = validationResults
        .SelectMany(_ => _.MemberNames.Select(
             x => new {MemberName = x ?? "", 
                       Error = _.ErrorMessage}))
        .GroupBy(_ => _.MemberName);
    
    foreach (var member in resultsGroupedByMembers)
    {
        ModelState.AddModelError(
            member.Key,
            string.Join(". ", member.Select(_ => _.Error)));
    }
    

    需要交叉连接,注意每个验证结果可能有多个MemberName。未绑定的结果绑定到“”,并且应该可用于ValidationSummary

    【讨论】:

      【解决方案2】:

      更直接的方法:

      控制器:

      ModelState.AddModelError("other", "error 1");
      ModelState.AddModelError("other", "error 2");
      ModelState.AddModelError("other", "error 3");
      

      查看:

      <ul>
          @foreach (var error in Html.ViewData.ModelState["other"].Errors)
          {
              <li>@error.ErrorMessage</li>
          }
      </ul>
      

      【讨论】:

        【解决方案3】:

        基于此处和How to display multiple validation errors with @Html.ValidationMessageFor? 中提供的解决方案,我为属性创建了自己的多行验证消息。它的行为有点像 ValidationSummary,但可以按字段使用。我使用它为模型的集合字段提供验证消息。这使我可以为集合提供摘要消息,并且仅针对集合。

        public static MvcHtmlString MultilineValidationMessageFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes = null)
        {
            var propertyName = ExpressionHelper.GetExpressionText(expression);
            var modelState = htmlHelper.ViewData.ModelState;
        
            // If we have multiple (server-side) validation errors, collect and present them.
            if (modelState.ContainsKey(propertyName) && modelState[propertyName].Errors.Count > 1)
            {
                var msgs = new StringBuilder();
                foreach (ModelError error in modelState[propertyName].Errors)
                {
                    msgs.AppendLine(error.ErrorMessage + "<br />");
                }
        
                // Return standard ValidationMessageFor, overriding the message with our concatenated list of messages.
                var msgSpan = htmlHelper.ValidationMessageFor(expression, "{0}", htmlAttributes as IDictionary<string, object> ?? htmlAttributes);
                var msgDiv = msgSpan.ToHtmlString().Replace("span", "div");
        
                return new MvcHtmlString(string.Format(msgDiv, msgs.ToString()));
            }
        
            // Revert to default behaviour.
            return htmlHelper.ValidationMessageFor(expression, null, htmlAttributes as IDictionary<string, object> ?? htmlAttributes);
        }
        

        【讨论】:

          【解决方案4】:

          我遇到了完全相同的问题,因此我为 HtmlHelper 创建了一个扩展方法来替代 MVC ValidationMessage 方法。

          与 ValidationSummary 方法相比,它的好处是它显示每个字段的错误消息,因此您可以将它放在每个字段旁边(与 ValidationMessage 方法相同)。

          public static string AllValidationMessage(this HtmlHelper helper, string modelName)
          {
              StringBuilder builder = new StringBuilder();
              TagBuilder ulTag = new TagBuilder("ul");
              ulTag.AddCssClass("u-error-list");
          
              builder.Append(ulTag.ToString(TagRenderMode.StartTag));
              if (helper.ViewData.ModelState.ContainsKey(modelName) &&
                  helper.ViewData.ModelState[modelName].Errors.Count > 0)
              {
                  foreach (var err in helper.ViewData.ModelState[modelName].Errors)
                  {
                      TagBuilder liTag = new TagBuilder("li") { InnerHtml = HttpUtility.HtmlEncode(err.ErrorMessage) };
                      liTag.AddCssClass("u-error-item");
                      builder.Append(liTag.ToString());
                  }
              }
              builder.Append(ulTag.ToString(TagRenderMode.EndTag));
          
              var msgSpan = helper.ValidationMessage(modelName, "{placeholder}");
          
              if (msgSpan == null)
                  return string.Empty;
          
              return msgSpan.ToHtmlString().Replace("{placeholder}", builder.ToString());
          }
          
          public static string AllValidationMessageFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression)
          {
              return HtmlHelperExtensions.AllValidationMessage(helper, ExpressionHelper.GetExpressionText(expression));
          }
          

          编辑:添加 AllValidationMessageFor 方法
          编辑:添加对 msgSpan 的空检查

          【讨论】:

            【解决方案5】:

            您也可以在控制器操作中检查

            ModelState.IsValid

            如果它为 false,则只返回 View,ValidationSumary 将被填充。

            【讨论】:

              【解决方案6】:

              使用开箱即用的 MVC,您必须添加一个 ValidationSummary:

              <%= Html.ValidationSummary() %>
              

              这将显示所有 ModelErrors。

              【讨论】:

                猜你喜欢
                • 2012-09-09
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2017-08-16
                • 2010-12-24
                • 1970-01-01
                • 1970-01-01
                • 2021-10-19
                相关资源
                最近更新 更多