Reputation: 365
I have the following method in a controller decorated with [ApiController] attribute:
public ActionResult<string> Test([FromQuery][ModelBinder(BinderType = typeof(ComplexObjectModelBinder)) TComplexObject complexObject)
{
return "Called!"
}
My model binder looks like this:
public class ComplexObjectModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
IQueryCollection query = bindingContext.HttpContext.Request.Query;
if (!query.ContainsKey("parameter1"))
{
bindingContext.ModelState.AddModelError("parameter1", $"The `{"parameter1"}` parameter is required.");
bindingContext.Result = ModelBindingResult.Failed();
return Task.CompletedTask;
}
TComplexObject complexObject = new();
bindingContext.Result = ModelBindingResult.Success(complexObject);
return Task.CompletedTask;
}
}
Overall it works fine; the object is bound properly when all parameters are found. The problem is that if "Parameter1" is not specified, I get 2 errors (instead of 1) in the 400 Bad Request:
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"complexObject": [
"The complexObject field is required."
],
"parameter1": [
"The `parameter1` parameter is required."
]
},
"traceId": "00-40b5c98a19d29dde8ce7614644b18011-b57f2db011466c7e-00"
}
I am expecting only to receive my custom error relating to parameter1
. I do not want the complexObject
parameter to be nullable and I expect that since I have taken the effort to write a custom model binder, that I would have full control of the error handling.
How can I prevent this error from being automatically added?
Upvotes: 0
Views: 41
Reputation: 36745
Firstly, Model Binding occurs before Model Validation. That is why you will receive other validation errors.
Secondly, it will receive an automatic HTTP 400 response containing error details is returned when model state is invalid if you use [ApiController]
.
For your scenario, I suggest you custom Action Filter and configure SuppressModelStateInvalidFilter
to disable automatic model state validation.
Custom IActionFilter:
public class MyActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
// Access a value from the request headers
if (!context.HttpContext.Request.Query.ContainsKey("parameter1"))
{
context.ModelState.Clear();
context.ModelState.AddModelError("parameter1", $"The `{"parameter1"}` parameter is required.");
context.Result = new BadRequestObjectResult(new ValidationProblemDetails(context.ModelState));
}
else
{
// Handle other model validation error
}
}
public void OnActionExecuted(ActionExecutedContext context)
{
// This method runs after the action is executed
}
}
Register the filter and configure SuppressModelStateInvalidFilter
:
builder.Services.AddControllers(options =>
{
options.Filters.Add(new MyActionFilter()); // Apply the filter globally
});
builder.Services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressModelStateInvalidFilter = true;
});
Upvotes: 1