ChatGPT解决这个技术问题 Extra ChatGPT

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

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

我怎样才能做到这一点?

如果您只是显示错误,那么 @Html.ValidationSummary() 是一种将它们全部显示在 razor 中的快速方法。
foreach (var error in ViewData.ModelState.Values.SelectMany(modelState => modelState.Errors)) { DoSomething(error); }
感谢大家为我指出正确的方向。就像@viggity 说的那样,键很重要,这对我来说是这样的:ModelState.Where(e=>e.Value.Errors.Count > 0).ToList()
附注:如果您只调试 ModelState 变量,您可以看到一些有趣的信息。

H
Hakan Fıstık

使用 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<string> errors = new List<string>() 而不是 var errors = new List<string>() 确实是在浪费时间,但是在返回类型不是很清楚的情况下编写 IEnumerable<ModelError> allErrors = ModelState.Values.SelectMany(v => v.Errors); 在可读性方面确实更好。 (即使视觉工作室可以在鼠标悬停时将其提供给您)
C
Community
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<string, ModelState> kvp in htmlHelper.ViewData.ModelState) { 并在其下方插入此行:var modelState = kvp.Value; 来获得它。您可以从 kvp.Key 获取密钥
D
Dunc

在 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);谢谢,邓克!
j
jerone

我能够使用一点 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


a
alexsuslin

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

如果这里有任何失败的边缘情况,请编辑答案以修复它
A
Alan Macdonald

正如我发现到目前为止给出的答案中的建议一样,您可以在没有设置错误消息的情况下发生异常,因此要捕获所有问题,您确实需要同时获取 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 而不仅仅是一个大字符串?
M
Mariusz Jamro

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

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

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


J
Josh Sutterfield

仅输出错误消息本身对我来说是不够的,但这起到了作用。

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 的情况进行偷偷摸摸的处理,就有风险。
C
CodeArtist

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

使用示例:

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

感谢代码艺术家!我在其实现下面的代码中做了一个小改动。
a
amiry jd

这也有效:

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 可用时使用它没有意义。
S
Steve Lydford

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

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

C
Chris Marisic

这是对@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;            
    }
}

J
Jivan Bhandari

任何人都在寻找 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});

r
r_piramoon

此代码片段也很有用,它为您提供了一个包含错误消息的列表。

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


T
Taryn

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


A
Armin Azhdari

只需使用 asp-validation-summary Tag Helper


d
dpricop

对于 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>)


M
Matt Ke
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 是贡献者
A
Alfred Severo

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

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

相当

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

m
mostafa kazemi

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