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.Typ
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/