ASP.NET MVC 如何将 ModelState 错误转换为 json
Posted
技术标签:
【中文标题】ASP.NET MVC 如何将 ModelState 错误转换为 json【英文标题】:ASP.NET MVC How to convert ModelState errors to json 【发布时间】:2011-02-20 05:04:13 【问题描述】:如何获得所有 ModelState 错误消息的列表?我找到了这段代码来获取所有密钥: (Returning a list of keys with ModelState errors)
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...
【问题讨论】:
【参考方案1】:您可以将任何内容放入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();
2nd 编辑:
您正在寻找Dictionary<string, string[]>
:
var errorList = ModelState.ToDictionary(
kvp => kvp.Key,
kvp => kvp.Value.Errors.Select(e => e.ErrorMessage).ToArray()
);
【讨论】:
这是一个快速的回复:)!嘿,看起来不错,但是如果 ModelState[item.Key] 有超过 1 个错误怎么办? Errors[0] 仅适用于单个错误消息 你想如何组合它们? 谢谢,差不多了 - 但即使没有错误,它也会选择每个键 - 我们如何过滤掉没有错误的键? 添加.Where(kvp => kvp.Value.Errors.Count > 0)
要获得与 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【参考方案2】:
这是所有部分放在一起的完整实现:
首先创建一个扩展方法:
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 您是否忘记引用 System.Linq? ToDictionary() 是一种 LINQ 扩展方法。 根据你的喜好.Where(m => m.Value.Count() > 0)
也可以写成.Where(m => m.Value.Any())
。
这可以与 Kendo.Mvc 中的 ModelState.ToDataSourceResult() 类似地使用,以将错误返回到 Grid 并在编辑时显示错误消息。【参考方案3】:
我喜欢在这里使用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."
]
【讨论】:
【参考方案4】:最简单的方法是返回带有 ModelState 本身的 BadRequest
:
例如在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(@"^\d8$|^00\d6,20$|^\+\d6,20$")]
public string MobileNumber get; set;
这将在无效请求时返回以下内容:
"Message": "The request is invalid.",
"ModelState":
"update.MobileNumber": [
"The field MobileNumber must match the regular expression '^\\d8$|^00\\d6,20$|^\\+\\d6,20$'.",
"The field MobileNumber must be a string with a minimum length of 8 and a maximum length of 22."
]
【讨论】:
BadRequest 是特定于 WebAPI 的,这个问题是关于 MVC 的。 给新观众的注意事项:BadRequest 现在可以在 .NET Core 以上版本中使用【参考方案5】:有很多不同的方法可以做到这一点,所有这些都有效。这就是我现在做的......
if (ModelState.IsValid)
return Json("Success");
else
return Json(ModelState.Values.SelectMany(x => x.Errors));
【讨论】:
你也可以返回BadRequest(ModelState)
,它会为你序列化成JSON。【参考方案6】:
使用内置功能的简单方法
[HttpPost]
public IActionResult Post([FromBody]CreateDoctorInput createDoctorInput)
if (!ModelState.IsValid)
return BadRequest(ModelState);
//do something
JSON result will be
【讨论】:
【参考方案7】:@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;
【讨论】:
【参考方案8】:看看 System.Web.Http.Results.OkNegotiatedContentResult。
它将您输入的任何内容转换为 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 的想法
【讨论】:
【参考方案9】:ToDictionary 是在 System.Linq 中找到的可枚举扩展,打包在 System.Web.Extensions dll http://msdn.microsoft.com/en-us/library/system.linq.enumerable.todictionary.aspx 中。这是我的完整课程的样子。
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;
【讨论】:
【参考方案10】:为什么不将原始的ModelState
对象返回给客户端,然后使用jQuery读取值。对我来说,它看起来更简单,并使用通用数据结构(.net 的ModelState
)
要将ModelState
作为 Json 返回,只需将其传递给 Json 类构造函数(适用于任何对象)
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);
【讨论】:
【参考方案11】:返回类型的变化而不是返回 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;
【讨论】:
【参考方案12】:我遇到了同样的障碍,想控制我的 400 Bad Request 输出格式,但又不想弄脏序列化 ModelState
的内容。我会使用密封(但谢天谢地公开)SerializableError 类。
var errorDetails = new SerializableError(ModelState);
var errorResponse = new YourCustomResponseType
ModelValidationErrors = errorDetails,
LogMessages = new []
new LogMessage("Error", "Invalid model - see modelValidationErrors for detail")
;
return BadRequest(errorResponse);
YourCustomResponseType
的位置可能如下所示:
public class YourCustomResponseType
public LogMessage[] LogMessages get; set;
public Dictionary<string, object> ModelValidationErrors get; set;
SerializableError
是Dictionary<string, object>
,所以效果很好。您的回复可能如下所示:
"logMessages": [
"category": "Error",
"message": "Invalid model - see modelValidationErrors for detail"
],
"modelValidationErrors":
"aSettingsType.someEnumField": [
"The input was not valid."
]
【讨论】:
【参考方案13】:我制作了一个返回带有分隔符“”的字符串的扩展(你可以使用你自己的):
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);
【讨论】:
【参考方案14】: 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,我没试过。我所做的是将错误集合分配给我的 ViewModel,然后循环它。在这种情况下,我可以通过 json 返回我的错误。我有一个类/模型,我想获取源/密钥,但我仍在尝试弄清楚。
public class ErrorList
public string ErrorMessage;
【讨论】:
以上是关于ASP.NET MVC 如何将 ModelState 错误转换为 json的主要内容,如果未能解决你的问题,请参考以下文章
Asp.net Core 如何将 ReflectionIT.Mvc.Paging 与 ViewModel 一起使用?
ASP.NET MVC 如何将 ModelState 错误转换为 json
如何将项目引用添加到 ASP.NET Core 1.0 MVC 项目