How to add custom “Cannot deserialize” error message in ASP.NET Core 2

雨燕双飞 提交于 2021-02-05 09:27:08

问题


I am building an asp.net-core REST api.

How to change the default error: "Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'Namespace.Name.Space.Type' because the type requires a JSON object (e.g. {\"name\":\"value\"}) to deserialize correctly.

I don't want to expose namespaces or any implementation details with our clients.

This error message is added to 400 - Bad Request response, when the client POST an object different from the required JSON. Could be configurable for the model binder. Any ideas?


回答1:


I think something already catches it and wraps it in 400 bad request.

ASP.NET Core 2.1 and later version have added the [ApiController] attribute, which automatically handles model validation errors by returning a BadRequestObjectResult with ModelState passed in.

A simple solution is that you remove the [ApiController] and return your own error message totally:

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

If you want to keep the ProblemDetails template, you could make use of the InvalidModelStateResponseFactory property.

The default response type for HTTP 400 responses is ValidationProblemDetails class. So, we will create a custom class which inherits ValidationProblemDetails class and define our custom error messages.

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

In startup.cs:

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

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

Postman Result:

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



来源:https://stackoverflow.com/questions/59718157/how-to-add-custom-cannot-deserialize-error-message-in-asp-net-core-2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!