Customize automatic response on validation error
With asp.net core 2.1 an ApiController will automatically respond with a 400 BadRequest when validation errors occur.
How can I change/modify the response (json-body) that is sent back to the client? Is there some kind of middleware?
I´m using FluentValidation to validate the parameters sent to my controller, but I am not happy with the response that I am get. It looks like
{
"Url": [
"'Url' must not be empty.",
"'Url' should not be empty."
]
}
I want to change the response, cause we have some default values that we attach to responses. So it should look like
{
"code": 400,
"request_id": "dfdfddf",
"messages": [
"'Url' must not be empty.",
"'Url' should not be empty."
]
}
Solution 1:
The ApiBehaviorOptions
class allows for the generation of ModelState
responses to be customised via its InvalidModelStateResponseFactory
property, which is of type Func<ActionContext, IActionResult>
.
Here's an example implementation:
apiBehaviorOptions.InvalidModelStateResponseFactory = actionContext => {
return new BadRequestObjectResult(new {
Code = 400,
Request_Id = "dfdfddf",
Messages = actionContext.ModelState.Values.SelectMany(x => x.Errors)
.Select(x => x.ErrorMessage)
});
};
The incoming ActionContext
instance provides both ModelState
and HttpContext
properties for the active request, which contains everything I expect you could need. I'm not sure where your request_id
value is coming from, so I've left that as your static example.
To use this implementation, configure the ApiBehaviorOptions
instance in ConfigureServices
:
serviceCollection.Configure<ApiBehaviorOptions>(apiBehaviorOptions =>
apiBehaviorOptions.InvalidModelStateResponseFactory = ...
);
Solution 2:
Consider creating of custom action filer, e.g.:
public class CustomValidationResponseActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
var errors = new List<string>();
foreach (var modelState in context.ModelState.Values)
{
foreach (var error in modelState.Errors)
{
errors.Add(error.ErrorMessage);
}
}
var responseObj = new
{
code = 400,
request_id = "dfdfddf",
messages = errors
};
context.Result = new JsonResult(responseObj)
{
StatusCode = 400
};
}
}
public void OnActionExecuted(ActionExecutedContext context)
{ }
}
You can register it in ConfigureServices
:
services.AddMvc(options =>
{
options.Filters.Add(new CustomValidationResponseActionFilter());
});