【问题标题】:How to deserialize 422 unprocessable entity error model and bind the errors to asp.net core razor pages model state如何反序列化 422 无法处理的实体错误模型并将错误绑定到 asp.net core razor pages 模型状态
【发布时间】: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
}

【问题讨论】:

    标签: asp.net-core-webapi razor-pages asp.net-core-3.1 modelstate http-status-code-422


    【解决方案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]); 
                  }
      
              }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-02-19
        • 2018-12-11
        • 2014-12-24
        • 2017-04-11
        • 2019-07-27
        • 2011-12-31
        • 2020-11-27
        相关资源
        最近更新 更多