简体   繁体   中英

Custom error response for incorrect json. Dotnet Core Web API

Is there a mechanism for returning a custom error response if an invalid type is given to a WebApi in Dotnet Core?

EG

if I have a class that looks like this

public class SomeApiClass
{
    public int Id { get; set; }
}

But make a post request like this (notice that I'm expecting an int and giving a string):

{
    "id": "f"
}

Then the standard dotnet response looks like this:

{
    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "traceId": "00-27be45d9cffab14698524a63120a4f88-6bfe2613f2328a42-00",
    "errors": {
        "$.id": [
            "The JSON value could not be converted to System.Int64. Path: $.wmdaid | LineNumber: 1 | BytePositionInLine: 15."
        ]
    }
}

However, I'd like all my responses to look the same for bad requests so that anybody implementing the API can always get a consistent JSON back. My problem being the JSON deserialisation is being done before the controller validation.

So, in a nutshell, Is it possible to change this response format as a part of the dotnet middleware?

You can use custom ActionFilter .

public class ReformatValidationProblemAttribute : ActionFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext context)
    {
        if (context.Result is BadRequestObjectResult badRequestObjectResult)
            if (badRequestObjectResult.Value is ValidationProblemDetails)
            {
                context.Result = new BadRequestObjectResult("Custom Result Here");
            }

        base.OnResultExecuting(context);
    }
}

Controller.cs

[ApiController]
[ReformatValidationProblem]
public class Controller : ControllerBase
{ 
    ...
}

or register it globally Startup.cs

services.AddMvc(options =>
{
    options.Filters.Add(typeof(ReformatValidationProblemAttribute));
});

You can implement your custom error model handler and replace it with the default ModelState object in each scenario such as bad request or ... First of all change service provider to inject your custom error class like following :

services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2)    
  .ConfigureApiBehaviorOptions(options => {      
   options.InvalidModelStateResponseFactory = actionCtx => {  
    return CustomBadRequestHandler(actionCtx);  
   };  
  });  

Next, we are going to create our custom Error Handler Class:

private BadRequestObjectResult CustomBadRequestHandler(ActionContext actionCtx) {      
 return new BadRequestObjectResult(actionCtx.ModelState  
  .Where(modelError => modelError.Value.Errors.Count > 0)  
  .Select(modelError => new Error {  
   ErrorFieldKey = modelError.Key,  
    ErrorDescription = modelError.Value.Errors.FirstOrDefault().ErrorMessage  
  }).ToList());  
} 

And finally, our custom error model that we want to return:

public class Error    
{    
    //your custom filed that you want to show
    public string ErrorFieldKey { get; set; }    
    public string ErrorDescription { get; set; }         
}  

You can also configure JsonOptions so that a generic message is displayed instead.

builder.Services.AddControllers().AddJsonOptions(o => o.AllowInputFormatterExceptionMessages = false);

This will preserve all the other fields from the automatic 400 response (from ValidationProblem) and display a generic error message for the malformed field: "The input was not valid."

{
    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "traceId": "00-190787f7ecae2a19b0e9c5da9c270fad-42237ddd1f920665-00",
    "errors": {
        "$.id": [
            "The input was not valid."
        ]
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM