【问题标题】:Get error message if ModelState.IsValid fails?如果 ModelState.IsValid 失败,获取错误消息?
【发布时间】:2011-03-06 17:50:56
【问题描述】:

我的控制器中有这个功能。

[HttpPost]
public ActionResult Edit(EmployeesViewModel viewModel)
{
    Employee employee = GetEmployee(viewModel.EmployeeId);
    TryUpdateModel(employee);

    if (ModelState.IsValid)
    {
        SaveEmployee(employee);
        TempData["message"] = "Employee has been saved.";
        return RedirectToAction("Details", new { id = employee.EmployeeID });
    }

    return View(viewModel); // validation error, so redisplay same view
}

它不断失败,ModelState.IsValid 不断返回 false 并重新显示视图。但我不知道错误是什么。

有没有办法获取错误并将其重新显示给用户?

【问题讨论】:

标签: c# asp.net asp.net-mvc


【解决方案1】:

试试这个

if (ModelState.IsValid)
{
    //go on as normal
}
else
{
    var errors = ModelState.Select(x => x.Value.Errors)
                           .Where(y=>y.Count>0)
                           .ToList();
}

errors 将是所有错误的列表。

如果您想向用户显示错误,您只需将模型返回到视图,如果您没有删除 Razor @Html.ValidationFor() 表达式,它就会显示出来。

if (ModelState.IsValid)
{
    //go on as normal
}
else
{
    return View(model);
}

视图将在每个字段旁边和/或在 ValidationSummary 中显示任何验证错误(如果存在)。

【讨论】:

    【解决方案2】:

    如果您希望生成包含 ModelState 错误消息的单个错误消息字符串,您可以使用 SelectMany 将错误平展为单个列表:

    if (!ModelState.IsValid)
    {
        var message = string.Join(" | ", ModelState.Values
            .SelectMany(v => v.Errors)
            .Select(e => e.ErrorMessage));
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest, message);
    }
    

    【讨论】:

    • 有时不提供ErrorMessage,例如如果未设置必需的 DateTime 字段。在这种情况下,请查找异常消息,例如e.Exception.Message.
    • 有时也没有提供!我有一个 ModelState 有 5 个错误,每个错误都有一个空 ExceptionErrorMessage 的空字符串,而 ModelState 上的其他条目根本没有与它们关联的 Errors
    【解决方案3】:

    您可以在视图中执行此操作,而无需在操作中执行任何特殊操作,方法是使用 Html.ValidationSummary() 显示所有错误消息,或使用 Html.ValidationMessageFor() 显示模型特定属性的消息。

    如果您仍需要从您的操作或控制器中查看错误,请查看ModelState.Errors 属性

    【讨论】:

    • 没有 ModelState.Errors 属性?!
    • @niico 我认为他的意思是“ModelState”类型的属性,而 Controller.ModelState 属性的类型是 ModelStateDictionary。
    • @niico ModelState.Errors 只存在于 MVC,不存在于 WebAPI
    【解决方案4】:

    如果模态状态无效并且由于您的控件处于折叠的手风琴中而无法在屏幕上看到错误,那么您可以返回 HttpStatusCode 以便在您执行 F12 时显示实际的错误消息。您也可以将此错误记录到 ELMAH 错误日志中。下面是代码

    if (!ModelState.IsValid)
    {
                  var message = string.Join(" | ", ModelState.Values
                                                .SelectMany(v => v.Errors)
                                                .Select(e => e.ErrorMessage));
    
                    //Log This exception to ELMAH:
                    Exception exception = new Exception(message.ToString());
                    Elmah.ErrorSignal.FromCurrentContext().Raise(exception);
    
                    //Return Status Code:
                    return new HttpStatusCodeResult(HttpStatusCode.BadRequest, message);
    }
    

    但请注意,此代码将记录所有验证错误。因此,只有在出现您无法在屏幕上看到错误的情况时才应使用此选项。

    【讨论】:

    • 是否可以获得名称/消息对,以便我们知道哪个字段有错误?
    【解决方案5】:

    如果有人在这里使用 WebApi(不是 MVC),您只需返回 ModelState 对象:

    return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);

    【讨论】:

      【解决方案6】:
      ModelState.Values.SelectMany(v => v.Errors).ToList().ForEach(x => _logger.Error($"{x.ErrorMessage}\n"));
      

      【讨论】:

        【解决方案7】:

        这是一个有用的 sn-p,我可以将其复制/粘贴到我的 OnPostASync() 处理程序中,以快速识别失败的验证项:

        public async Task<IActionResult> OnPostAsync(string editButton)
            {
                if (!ModelState.IsValid)
                {
                    var errors = 
                        from value in ModelState.Values
                        where value.ValidationState == ModelValidationState.Invalid
                        select value;  
                    return Page();  // <-- I set a breakpoint here, and examine "errors"
                }
                ...
        

        与上面的其他一些解决方案不同,我可以看到两者

        1. 错误消息文本 (ErrorMessage) ... 和 ...
        2. 导致错误的特定字段

        【讨论】:

          【解决方案8】:

          确定并添加到观看:

          1. 在代码中的 ModelState 行设置断点
          2. 将模型状态添加到手表
          3. 扩展 ModelState“值”
          4. 扩展值“结果视图”

          现在您可以看到所有 SubKey 的列表及其在值末尾的验证状态。

          所以搜索无效值

          【讨论】:

            【解决方案9】:

            这是示例扩展

            public class GetModelErrors
            {
                //Usage return Json to View :
                //return Json(new { state = false, message = new GetModelErrors(ModelState).MessagesWithKeys() });
                public class KeyMessages
                {
                    public string Key { get; set; }
                    public string Message { get; set; }
                }
                private readonly ModelStateDictionary _entry;
                public GetModelErrors(ModelStateDictionary entry)
                {
                    _entry = entry;
                }
            
                public int Count()
                {
                    return _entry.ErrorCount;
                }
                public string Exceptions(string sp = "\n")
                {
                    return string.Join(sp, _entry.Values
                        .SelectMany(v => v.Errors)
                        .Select(e => e.Exception));
                }
                public string Messages(string sp = "\n")
                {
                    string msg = string.Empty;
                    foreach (var item in _entry)
                    {
                        if (item.Value.ValidationState == ModelValidationState.Invalid)
                        {
                            msg += string.Join(sp, string.Join(",", item.Value.Errors.Select(i => i.ErrorMessage)));
                        }
                    }
                    return msg;
                }
            
                public List<KeyMessages> MessagesWithKeys(string sp = "<p> ● ")
                {
                    List<KeyMessages> list = new List<KeyMessages>();
                    foreach (var item in _entry)
                    {
                        if (item.Value.ValidationState == ModelValidationState.Invalid)
                        {
                            list.Add(new KeyMessages
                            {
                                Key = item.Key,
                                Message = string.Join(null, item.Value.Errors.Select(i => sp + i.ErrorMessage))
                            });
                        }
                    }
                    return list;
                }
            }
            

            【讨论】:

              【解决方案10】:

              我不知道这是否是您的问题,但是如果您添加用户然后更改应用程序的名称,该用户将保留在数据库中(当然),但将无效(这是正确的行为) .但是,不会为此类故障添加错误。错误列表为空,但 M​​odelState.IsValid 会为登录返回 false。

              【讨论】:

                【解决方案11】:
                publicIHttpActionResultPost(Productproduct) {  
                    if (ModelState.IsValid) {  
                        //Dosomethingwiththeproduct(notshown).  
                        returnOk();  
                    } else {  
                        returnBadRequest();  
                    }  
                }
                

                public HttpResponseMessage Post(Product product)
                        {
                            if (ModelState.IsValid)
                            {
                                // Do something with the product (not shown).
                
                                return new HttpResponseMessage(HttpStatusCode.OK);
                            }
                            else
                            {
                                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
                            }
                        }
                

                【讨论】:

                  【解决方案12】:

                  我将此方法用作获取错误的通用方法

                   public static List<string> GetModelErrros(ModelStateDictionary modelState)
                          {
                              var errors = modelState.Values.Where(E => E.Errors.Count > 0)
                                           .SelectMany(E => E.Errors)
                                           .Select(E => E.ErrorMessage)
                                           .ToList();
                  
                              return errors;
                          }
                  

                  你可以使用它

                  logger.LogInformation("ID {0} input Error  ", string.Join(",", SiteUtils.GetModelErrros(ModelState)));
                  

                  【讨论】:

                    【解决方案13】:

                    试试

                    ModelState.Values.First().Errors[0].ErrorMessage
                    

                    【讨论】:

                    • 这只会获取第一个字段的第一个错误。试试看上面的@johnnyHK 答案。
                    猜你喜欢
                    • 2022-01-04
                    • 2013-06-24
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2011-11-07
                    • 2015-11-21
                    • 1970-01-01
                    • 2014-05-28
                    相关资源
                    最近更新 更多