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

如何获得所有 ModelState 错误消息的列表?我找到了这个密码,可以拿到所有的钥匙: (返回带有 ModelState 错误的键列表)

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

但是如何以 ILlist 或 IQueryable 的形式获取错误消息呢?

我可以说:

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

但是那是手动做的——肯定有一种方法可以使用 LINQ 来做到这一点吧?那个。ErrorMessage 属性是如此的低级,以至于我不知道如何编写 LINQ..。

87102 次浏览

你可以把你想要的 什么都行放在 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 < sup > nd EDIT : 你要找的是 Dictionary<string, string[]>:

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

下面是将所有部分放在一起的完整实现:

首先创建一个扩展方法:

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.validystyle 中,但是可以很容易地更改为任何其他样式)

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

ToDictionary 是 System 中的可枚举扩展。系统中打包的 Linq。韦伯。分机 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;
}


}


}

@ 开玩笑,这对我很有帮助,但为什么不呢:

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

返回类型而不是返回 IEnumable 的变量

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

我喜欢在这里使用 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."
]
}
}

为什么不将原始的 ModelState对象返回给客户机,然后使用 jQuery 读取这些值。对我来说,它看起来简单多了,并且使用了通用的数据结构(。(网址为 ModelState)

要将 ModelState作为 Json 返回,只需将其传递给 Json 类构造函数(可以使用 ANY 对象)

C # :

return Json(ModelState);

约翰逊:

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

有很多不同的方法可以做到这一点,所有的工作。这里是现在我这样做..。

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

查看 System.Web.Http.Results.OkValatedContentResult。

它将您抛出的任何内容转换为 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 的想法

最简单的方法就是返回一个带 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(@"^\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."
]
}
}
  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);

或者您可以简单地返回 model StateError,我还没有试过。我所做的就是将 Error 集合分配给我的 ViewModel,然后循环它。.在这种情况下,我可以通过 json 返回我的错误。我有一个类/模型,我想得到源/键,但我仍然试图找出它。

    public class ErrorList
{
public string ErrorMessage;
}

通过使用内置功能实现这一点的简单方法

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


//do something
}

JSON 结果将是

我创建并扩展了返回带有分隔符“”的字符串(您可以使用自己的) :

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

我遇到了同样的障碍,想要控制我的400 Bad Request 输出格式,但又不想亲自动手序列化 ModelState的内核。我会使用密封的(但是公开的,谢天谢地) 序列化错误类。

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

SerializableErrorDictionary<string, object>,所以这个结果很好。你的回答可能是这样的:

{
"logMessages": [
{
"category": "Error",
"message": "Invalid model - see modelValidationErrors for detail"
}
],
"modelValidationErrors": {
"aSettingsType.someEnumField": [
"The input was not valid."
]
}
}

你可以使用中间件:

var builder = WebApplication.CreateBuilder(args);


builder.Services.AddControllers().ConfigureApiBehaviorOptions(options =>
{
options.InvalidModelStateResponseFactory = context =>
{
var result = new ValidationFailedResult(context.ModelState);
result.ContentTypes.Add(MediaTypeNames.Application.Json);
return result;
};
});

结果:

public class ValidationFailedResult : ObjectResult
{
public ValidationFailedResult(ModelStateDictionary modelState)
: base(new ErrorResponse(modelState.Keys
.SelectMany(key => modelState[key].Errors.Select(x => new ApplicationError(StatusCodes.Status422UnprocessableEntity, key, x.ErrorMessage)))
.ToList()))
{
StatusCode = StatusCodes.Status422UnprocessableEntity; //change the http status code to 422.
}
}

错误:

 public class ApplicationError
{
public ApplicationError(int code, string title, string detail)
{
Code=code;
Title=title;
Detail=detail;
}


public int Code { get; set; }
public string Title { get; set; }
public string Detail { get; set; }


public override string ToString()
{
return $"Status:{Code} Title:{Title} Detail:{Detail}";
}
}

结果是这样的:

{
"errors": [
{
"code": 422,
"title": "$",
"detail": "'\"' is invalid after a value. Expected either ',', '}', or ']'. Path: $ | LineNumber: 7 | BytePositionInLine: 1."
},
{
"code": 422,
"title": "input",
"detail": "The input field is required."
}
]
}

来源: Https://learn.microsoft.com/en-us/answers/questions/620570/net-core-web-api-model-validation-error-response-t.html