Как добавить пользовательское сообщение об ошибке «Невозможно десериализовать» в ASP. NET Core 2 - PullRequest
0 голосов
/ 13 января 2020

Я создаю asp. net ядро ​​REST API.

Как изменить ошибку по умолчанию: «Невозможно десериализовать текущий массив JSON (например, [1,2,3]) в тип« Namespace.Name.Space.Type », поскольку для типа требуется JSON объект (например, {\ "name \": \ "value \"}) для правильной десериализации.

Я не хочу показывать пространства имен или какие-либо подробности реализации нашим клиентам.

Это сообщение об ошибке добавляется в ответ 400 - Плохой запрос, когда клиент POST-объект отличается от требуемого JSON. Может быть настраивается для подшивки модели. Есть идеи?

1 Ответ

1 голос
/ 14 января 2020

Я думаю, что-то уже ловит это и оборачивает это в 400 неправильных запросов.

ASP. NET В Core 2.1 и более поздней версии добавлен атрибут [ApiController], который автоматически обрабатывает ошибки проверки модели, возвращая BadRequestObjectResult с ModelState, переданным.

Простое решение состоит в том, что вы удаляете [ApiController] и полностью возвращаете свое собственное сообщение об ошибке:

if (!ModelState.IsValid)
{
    return BadRequest(new { ErrorMessage = "Cannot deserialize" });
}

Если вы хотите сохранить шаблон ProblemDetails, вы можете использовать InvalidModelStateResponseFactory свойство.

Тип ответа по умолчанию для ответов HTTP 400: ValidationProblemDetails class. Итак, мы создадим пользовательский класс, который наследует класс ValidationProblemDetails и определим наши пользовательские сообщения об ошибках.

public class CustomBadRequest : ValidationProblemDetails
{
    public CustomBadRequest(ActionContext context)
    {
        ConstructErrorMessages(context);
        Type = context.HttpContext.TraceIdentifier;
    }

    private void ConstructErrorMessages(ActionContext context)
    {
        var myerror = "Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'Core22APITest.Controllers.TestBindController+RetrieveMultipleResponse' because the type requires a JSON object (e.g. {\"name\":\"value\"}) to deserialize correctly.\r\nTo fix this error either change the JSON to a JSON object (e.g. {\"name\":\"value\"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.\r\nPath '', line 1, position 1.";
        foreach (var keyModelStatePair in context.ModelState)
        {
            var key = keyModelStatePair.Key;
            var errors = keyModelStatePair.Value.Errors;
            if (errors != null && errors.Count > 0)
            {
                if (errors.Count == 1)
                {
                    var errorMessage = GetErrorMessage(errors[0]);
                    if(errorMessage == myerror)
                    {
                        Errors.Add(key, new[] { "Cannot deserialize" });
                    }
                    else
                    {
                        Errors.Add(key, new[] { errorMessage });
                    }

                }
                else
                {
                    var errorMessages = new string[errors.Count];
                    for (var i = 0; i < errors.Count; i++)
                    {
                        errorMessages[i] = GetErrorMessage(errors[i]);
                        if (errorMessages[i] == myerror)
                        {
                            errorMessages[i] =  "Cannot deserialize" ;
                        }
                    }

                    Errors.Add(key, errorMessages);
                }
            }
        }
    }

    string GetErrorMessage(ModelError error)
    {
        return string.IsNullOrEmpty(error.ErrorMessage) ?
            "The input was not valid." :
        error.ErrorMessage;
    }
}

В файле startup.cs:

services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
            .ConfigureApiBehaviorOptions(options =>
            {
                options.InvalidModelStateResponseFactory = context =>
                {
                    var problems = new CustomBadRequest(context);

                    return new BadRequestObjectResult(problems);
                };
            });

Почтальон Результат:

enter image description here

См. https://coderethinked.com/customizing-automatic-http-400-error-response-in-asp-net-core-web-apis/

...