如何反序列化 422 无法处理的实体错误模型并将错误绑定到 asp.net core razor pages 模型状态
Posted
技术标签:
【中文标题】如何反序列化 422 无法处理的实体错误模型并将错误绑定到 asp.net core razor pages 模型状态【英文标题】:How to deserialize 422 unprocessable entity error model and bind the errors to asp.net core razor pages model state 【发布时间】:2020-07-09 16:11:04 【问题描述】:我的Asp.Net Core 3.1 API
返回422 Unprocessable Entity
错误响应如下图:
"type": "https://test.com/modelvalidationproblem",
"title": "One or more model validation errors occurred.",
"status": 422,
"detail": "See the errors property for details.",
"instance": "/api/path",
"traceId": "8000003f-0001-ec00-b63f-84710c7967bb",
"errors":
"FirstName": [
"The FirstName field is required."
]
如何反序列化此响应并将错误添加到Asp.Net Core 3.1 Razor Pages
中的模型验证错误?
我尝试创建如下所示的模型,
错误模型:
public class UnprocessableEntity
public string Type get; set;
public string Title get; set;
public int Status get; set;
public string Detail get; set;
public string Instance get; set;
public string TraceId get; set;
public Errors Errors get; set;
public class Errors
....// what should I need to add here? Keys and messages will be dynamic
但是我应该在Errors
类中添加什么?错误键和消息将是动态的。
一旦知道了以上内容,我就可以在我的 razor 页面中添加模型状态错误,如下所示,
using var responseStream = await response.Content.ReadAsStreamAsync();
var errorResponse = await JsonSerializer.DeserializeAsync<UnprocessableEntity>(responseStream);
foreach (var error in errorResponse.errors)
ModelState.AddModelError(error.key, error.Message[0]); // I'm stuck here
【问题讨论】:
【参考方案1】:我已经修改了@Yongqing Yu 的答案并使其通用。
422 错误模型:
public class UnprocessableEntity<T>
[JsonPropertyName("type")]
public string Type get; set;
[JsonPropertyName("title")]
public string Title get; set;
[JsonPropertyName("status")]
public int Status get; set;
[JsonPropertyName("detail")]
public string Detail get; set;
[JsonPropertyName("instance")]
public string Instance get; set;
[JsonPropertyName("traceId")]
public string TraceId get; set;
[JsonPropertyName("errors")]
public T Errors get; set;
型号:
public class EventRegisterViewModel
[Required]
[MaxLength(200)]
[RegularExpression(ValidationConstants.ALPHABETSWITHSPACE, ErrorMessage = "Enter only alphabets")]
[Display(Name = "First Name")]
public string FirstName get; set;
[Required]
[MaxLength(200)]
[RegularExpression(ValidationConstants.ALPHABETSWITHSPACE, ErrorMessage = "Enter only alphabets")]
[Display(Name = "Last Name")]
public string LastName get; set;
[MinLength(10, ErrorMessage = "Please Enter 10 digit Mobile Number")]
[MaxLength(10)]
[RegularExpression(ValidationConstants.NUMBERSONLY, ErrorMessage = "Invalid Mobile Number")]
[Display(Name = "Mobile Number")]
public string MobileNumber get; set;
[Required]
[MaxLength(200)]
[EmailAddress]
[Display(Name = "Email Address")]
public string EmailAddress get; set;
错误模型:
public class EventRegistrationValidationErrors
public IEnumerable<string> FirstName get; set;
public IEnumerable<string> LastName get; set;
public IEnumerable<string> MobileNumber get; set;
public IEnumerable<string> EmailAddress get; set;
在反序列化时,
using var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
var errorResponse = await JsonSerializer.DeserializeAsync<UnprocessableEntity<EventRegistrationValidationErrors>>(responseStream).ConfigureAwait(false);
var errorFieldNames = typeof(EventRegistrationValidationErrors)
.GetProperties()
.Select(field => field.Name)
.ToList();
foreach (var errorField in errorFieldNames)
var errorLists = (List<string>)errorResponse.errors
.GetType()
.GetProperty(errorField)
.GetValue(errorResponse.errors);
if (!(errorLists is null))
ModelState.AddModelError($"Event.errorField", errorLists[0]);
希望这对那里的人有所帮助。
【讨论】:
【参考方案2】:首先,您应该确保关键字段名称与从 api(pay attention to case
) 返回的 json 相同。
public class UnprocessableEntity
public string type get; set;
public string tTitle get; set;
public int status get; set;
public string detail get; set;
public string instance get; set;
public string traceId get; set;
public Errors errors get; set;
那么Errors
类的字段应该包含验证类的所有字段,并且字段名称要一致,但是需要define their type as an array to receive
,因为json中errors返回的每个字段都是一个数组. (这里我创建了一个名为StudInfo
的简单验证类):
public class StudInfo
[Key]
public int Id get; set;
[Required]
public string Name get; set;
public class Errors
public List<string> Id get; set;
public List<string> Name get; set;
然后你可以使用如下代码:
using var responseStream = await response.Content.ReadAsStreamAsync();
var errorResponse = await JsonSerializer.DeserializeAsync<UnprocessableEntity>(responseStream);
var t = typeof(Errors);
var fieldNames = typeof(Errors).GetProperties()
.Select(field => field.Name)
.ToList();
foreach (var name in fieldNames)
List<string> errorLists = (List<string>)errorResponse.errors.GetType().GetProperty(name).GetValue(errorResponse.errors);
if (errorLists != null)
ModelState.AddModelError(name, errorLists[0]);
【讨论】:
以上是关于如何反序列化 422 无法处理的实体错误模型并将错误绑定到 asp.net core razor pages 模型状态的主要内容,如果未能解决你的问题,请参考以下文章
Rails API 422 无法处理的实体:没有可用的验证密钥,heroku
422 无法处理的实体错误。我尝试上传 Excel 文件以导入数据,但它不工作