Как десериализовать 422 модель ошибки необработанного объекта и связать ошибки с состоянием модели страниц asp. net основной бритвы - PullRequest
1 голос
/ 29 марта 2020

My 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 класса? Ключи и сообщения об ошибках будут динамическими c.

После того, как все вышеперечисленное станет известно, я могу добавить ошибки состояния модели на своих страницах бритвы, как показано ниже,

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
}

Ответы [ 2 ]

1 голос
/ 30 марта 2020

Во-первых, вы должны убедиться, что имена полей ключей совпадают с json, возвращаемым из API (pay attention to case).

 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, является массивом. (здесь я создал простой проверенный класс с именем 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]); 
            }

        }
0 голосов
/ 03 мая 2020

Я изменил ответ @Yongqing Yu и сделал его обобщенным c.

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

Надеюсь, это поможет кому-то там.

...