ASP.NET MVC如何将ModelState错误转换为json


127

您如何获得所有ModelState错误消息的列表?我找到了以下代码来获取所有键:(返回带有ModelState错误的键列表

var errorKeys = (from item in ModelState
        where item.Value.Errors.Any() 
        select item.Key).ToList();

但是,如何将错误消息显示为IList或IQueryable?

我可以去:

foreach (var key in errorKeys)
{
    string msg = ModelState[error].Errors[0].ErrorMessage;
    errorList.Add(msg);
}

但这就是手动完成-当然有办法使用LINQ吗?.ErrorMessage属性太远了,我不知道如何编写LINQ ...

Answers:


192

您可以在子句中放入任何想要的内容select

var errorList = (from item in ModelState
        where item.Value.Errors.Any() 
        select item.Value.Errors[0].ErrorMessage).ToList();

编辑:您可以通过添加from子句将多个错误提取到单独的列表项中,如下所示:

var errorList = (from item in ModelState.Values
        from error in item.Errors
        select error.ErrorMessage).ToList();

要么:

var errorList = ModelState.Values.SelectMany(m => m.Errors)
                                 .Select(e => e.ErrorMessage)
                                 .ToList();

2 编辑:你正在寻找一个Dictionary<string, string[]>

var errorList = ModelState.ToDictionary(
    kvp => kvp.Key,
    kvp => kvp.Value.Errors.Select(e => e.ErrorMessage).ToArray()
);

多数民众赞成在快速回复:)!嘿,看起来不错,但是如果ModelState [item.Key]出现多个错误怎么办?错误[0]仅适用于单个错误消息
JK。

您想如何将它们结合起来?
Slaks 2010年

多亏了,几乎可以了-但即使没有错误,它也会选择每个键-我们如何才能过滤出没有错误的键?
JK。

4
添加.Where(kvp => kvp.Value.Errors.Count > 0)
10年

3
要获得与您相同的输出,Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);应使用 var errorList = modelState.Where(elem => elem.Value.Errors.Any()) .ToDictionary( kvp => kvp.Key, kvp => kvp.Value.Errors.Select(e => string.IsNullOrEmpty(e.ErrorMessage) ? e.Exception.Message : e.ErrorMessage).ToArray());否则,您将没有ExceptionMessages
Silvos

74

这是将所有部分组合在一起的完整实现:

首先创建一个扩展方法:

public static class ModelStateHelper
{
    public static IEnumerable Errors(this ModelStateDictionary modelState)
    {
        if (!modelState.IsValid)
        {
            return modelState.ToDictionary(kvp => kvp.Key,
                kvp => kvp.Value.Errors
                                .Select(e => e.ErrorMessage).ToArray())
                                .Where(m => m.Value.Any());
        }
        return null;
    }
}

然后调用该扩展方法,并将控制器操作(如果有)中的错误作为json返回:

if (!ModelState.IsValid)
{
    return Json(new { Errors = ModelState.Errors() }, JsonRequestBehavior.AllowGet);
}

最后,在客户端显示这些错误(采用jquery.validation样式,但可以轻松更改为任何其他样式)

function DisplayErrors(errors) {
    for (var i = 0; i < errors.length; i++) {
        $("<label for='" + errors[i].Key + "' class='error'></label>")
        .html(errors[i].Value[0]).appendTo($("input#" + errors[i].Key).parent());
    }
}

这看起来像一个有趣的方法,但是助手类对我不起作用。这可能是由于MVC 2的更改引起的吗?我收到一个错误,指出在ModelState上不存在ToDictionary方法。
Cymen 2010年

@Cymen您忘记引用System.Linq吗?ToDictionary()是LINQ扩展方法。
内森·泰勒

8
根据您的喜好.Where(m => m.Value.Count() > 0),也可以写为.Where(m => m.Value.Any())
曼弗雷德2014年

可以与Kendo.Mvc中的ModelState.ToDataSourceResult()类似地使用它,以将错误返回到Grid并在编辑时显示错误消息。
malnosna

22

我喜欢在Hashtable这里使用,以便以字符串数组的形式获取具有属性作为键和错误作为值的JSON对象。

var errors = new Hashtable();
foreach (var pair in ModelState)
{
    if (pair.Value.Errors.Count > 0)
    {
        errors[pair.Key] = pair.Value.Errors.Select(error => error.ErrorMessage).ToList();
    }
}
return Json(new { success = false, errors });

这样,您将获得以下响应:

{
   "success":false,
   "errors":{
      "Phone":[
         "The Phone field is required."
      ]
   }
}

8

有许多不同的方法可以完成所有工作。现在在这里我做...

if (ModelState.IsValid)
{
    return Json("Success");
}
else
{
    return Json(ModelState.Values.SelectMany(x => x.Errors));
}

2
您还可以返回BadRequest(ModelState),它将为您序列化为JSON。
弗雷德(Fred)

6

最简单的方法是BadRequest使用ModelState本身返回一个:

例如在PUT

[HttpPut]
public async Task<IHttpActionResult> UpdateAsync(Update update)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    // perform the update

    return StatusCode(HttpStatusCode.NoContent);
}

如果我们在此类中的移动电话上使用数据注释,例如Update

public class Update {
    [StringLength(22, MinimumLength = 8)]
    [RegularExpression(@"^\d{8}$|^00\d{6,20}$|^\+\d{6,20}$")]
    public string MobileNumber { get; set; }
}

这将在无效请求上返回以下内容:

{
  "Message": "The request is invalid.",
  "ModelState": {
    "update.MobileNumber": [
      "The field MobileNumber must match the regular expression '^\\d{8}$|^00\\d{6,20}$|^\\+\\d{6,20}$'.",
      "The field MobileNumber must be a string with a minimum length of 8 and a maximum length of 22."
    ]
  }
}

1
BadRequest是特定于WebAPI的,此问题与MVC有关。
rgripper '16

5

@JK对我有很大帮助,但是为什么不呢?

 public class ErrorDetail {

        public string fieldName = "";
        public string[] messageList = null;
 }

        if (!modelState.IsValid)
        {
            var errorListAux = (from m in modelState 
                     where m.Value.Errors.Count() > 0 
                     select
                        new ErrorDetail
                        { 
                                fieldName = m.Key, 
                                errorList = (from msg in m.Value.Errors 
                                             select msg.ErrorMessage).ToArray() 
                        })
                     .AsEnumerable()
                     .ToDictionary(v => v.fieldName, v => v);
            return errorListAux;
        }

3

看一下System.Web.Http.Results.OkNegotiatedContentResult。

它将您扔到JSON中的任何内容转换为JSON。

所以我做到了

var errorList = ModelState.ToDictionary(kvp => kvp.Key.Replace("model.", ""), kvp => kvp.Value.Errors[0].ErrorMessage);

return Ok(errorList);

结果是:

{
  "Email":"The Email field is not a valid e-mail address."
}

我还没有检查每个字段有多个错误时会发生什么,但重点是OkNegoriatedContentResult非常好!

从@SLaks得到了linq / lambda的想法


3

通过使用内置功能来实现此目的的简单方法

[HttpPost]
public IActionResult Post([FromBody]CreateDoctorInput createDoctorInput) {
    if (!ModelState.IsValid) {
        return BadRequest(ModelState);
    }

    //do something
}

JSON结果将是


2

ToDictionary是在System.Web.Extensions dll http://msdn.microsoft.com/zh-cn/library/system.linq.enumerable.todictionary.aspx中打包的System.Linq中找到的Enumerable扩展名。这是完整课程对我来说的样子。

using System.Collections;
using System.Web.Mvc;
using System.Linq;

namespace MyNamespace
{
    public static class ModelStateExtensions
    {
        public static IEnumerable Errors(this ModelStateDictionary modelState)
        {
            if (!modelState.IsValid)
            {
                return modelState.ToDictionary(kvp => kvp.Key,
                    kvp => kvp.Value.Errors.Select(e => e.ErrorMessage).ToArray()).Where(m => m.Value.Count() > 0);
            }
            return null;
        }

    }

}

2

为什么不将原始ModelState对象返回给客户端,然后使用jQuery读取值。对我来说,它看起来要简单得多,并且使用通用的数据结构(.net's ModelState

返回 ModelState as Json,只需将其传递给Json类构造函数(可与ANY对象一起使用)

C#:

return Json(ModelState);

js:

        var message = "";
        if (e.response.length > 0) {
            $.each(e.response, function(i, fieldItem) {
                $.each(fieldItem.Value.Errors, function(j, errItem) {
                    message += errItem.ErrorMessage;
                });
                message += "\n";
            });
            alert(message);
        }

1

返回类型的变化,而不是返回IEnumerable

public static class ModelStateHelper
{
    public static IEnumerable<KeyValuePair<string, string[]>> Errors(this ModelStateDictionary modelState)
    {
        if (!modelState.IsValid)
        {
            return modelState
                .ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Errors.Select(e => e.ErrorMessage).ToArray())
                .Where(m => m.Value.Any());
        }

        return null;
    }
}

0

我做了一个扩展名,该扩展名返回带有分隔符“”的字符串(您可以使用自己的字符串):

   public static string GetFullErrorMessage(this ModelStateDictionary modelState) {
        var messages = new List<string>();

        foreach (var entry in modelState) {
            foreach (var error in entry.Value.Errors)
                messages.Add(error.ErrorMessage);
        }

        return String.Join(" ", messages);
    }

-1
  List<ErrorList> Errors = new List<ErrorList>(); 


        //test errors.
        var modelStateErrors = this.ModelState.Keys.SelectMany(key => this.ModelState[key].Errors);

        foreach (var x in modelStateErrors)
        {
            var errorInfo = new ErrorList()
            {
                ErrorMessage = x.ErrorMessage
            };
            Errors.Add(errorInfo);

        }

如果您使用jsonresult,则返回

return Json(Errors);

或者您可以简单地返回modelStateErrors,我还没有尝试过。我所做的是将Errors集合分配给ViewModel,然后循环它。在这种情况下,我可以通过json返回我的Errors。我有一个类/模型,我想获取源代码/密钥,但我仍在尝试找出答案。

    public class ErrorList
{
    public string ErrorMessage;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.