JamesBondCaesar
JamesBondCaesar

Reputation: 273

How to customize the error message returned when model binding fails due to a JSON deserialization exception?

I have a security problem in my app. When somebody sends wrong json to my endpoint (for example, pass type string instead if int), my API displays json deserialisation exception:

{
    "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "errors": {
        "$.questions[0].answers": [
            "The JSON value could not be converted to TestingService.Business.Features.V1.Test.Models.Answer[]. Path: $.questions[0].answers | LineNumber: 11 | BytePositionInLine: 20."
        ]
    },
    "traceId": "00-690e01e0fb451eed8afa4530616fa13f-0396f3a592bd1518-00"
}

When I try to handle it using IExceptionFilter, I can not do this, because the exception is thrown before this pipeline was reached.

When I use middleware - I can't catch this exception either.

My controller setup:

services.AddControllers(options =>
                options.Filters.Add(new ApiErrorFilter()))
        .AddJsonOptions(options =>
            {
                options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
                options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
                options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
                options.JsonSerializerOptions.Converters.Add(new Core.Infrastructure.DateTimeConverter());
            });

How to handle this exception and replace it with a custom one?

Upvotes: 0

Views: 128

Answers (1)

JamesBondCaesar
JamesBondCaesar

Reputation: 273

Thanks for @Parsa99 - he suggested the answer. For anyone who will try to find in in the future, I will post here an example that I was found in the internet.

services.AddControllers(options =>
            {
                options.Filters.Add<ApiErrorFilter>();
            })
            .ConfigureApiBehaviorOptions(opt=>
            {
                opt.SuppressModelStateInvalidFilter = false;
                opt.InvalidModelStateResponseFactory = context=>{
                
                    bool knownExceptions = context.ModelState.Values
                    .SelectMany(x => x.Errors)
                    .Where(x => x.Exception is JsonException || (x.Exception is null && String.IsNullOrWhiteSpace(x.ErrorMessage) == false)).Count() > 0;
                    if (knownExceptions)
                    {
                        var error = new ProblemDetails
                        {
                            Status = (int)HttpStatusCode.InternalServerError,
                            Title = "Test",
                        };

                            return new ObjectResult(error)
                        {
                            StatusCode = StatusCodes.Status422UnprocessableEntity,
                        }; //new BadRequestResult(new { state = false, message = "InvalidParameterError" });
                    }
                // ...
                    return new BadRequestObjectResult(context.ModelState);
                };
            })
            .AddJsonOptions(DefaultJsonOptions.OptionsConfiguration);

Upvotes: 2

Related Questions