I'm having troubles handling all types of errors in ASP.NET WebAPI.
I've successfully handled exceptions thrown inside my action methods using an ExceptionFilter and 404 errors for invalid routes, invalid controller or action name. However, I'm struggling to handle the error where the controller and action are both found, but the parameters for model binding are incorrect types.
Here's my action, which is routed to /api/users/{id}
.
[HttpGet]
public virtual TPoco Get(long id)
{
...
}
If I request the URL /api/users/notinteger
, I get a 400 Bad Request
error that is handled outside of my code:
{
Message: "The request is invalid.",
MessageDetail: "The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int64' for method '___ Get(Int64)' in '___'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter."
}
How can I intercept this error and respond with my own error message? Preferably not in the controller itself as I'd like to handle several controllers in the same way.
I've tried using global.asax.cs
's Application_Error
event as per this question, but that doesn't seem to be called in this case.
It appears that these errors are added to the ModelState as model binding errors. The action selector selects the correct action and the action invoker invokes it without throwing any errors.
The workaround I came up with is to create an action invoker that checks the ModelState
for errors. If it finds any, it passes the first one to the exception handling method used by my ExceptionFilter
and ErrorController
.
internal class ThrowModelStateErrorsActionInvoker : ApiControllerActionInvoker
{
public override Task<HttpResponseMessage> InvokeActionAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
{
foreach (var error in actionContext.ModelState.SelectMany(kvp => kvp.Value.Errors))
{
var exception = error.Exception ?? new ArgumentException(error.ErrorMessage);
//invoke global exception handling
}
return base.InvokeActionAsync(actionContext, cancellationToken);
}
}
It's nasty, but it works. This has taken up most of my day and I'm just glad to have finally got somewhere.
I'd be interested to know what the consequences are to this. What else uses the ModelState errors in Web API? Could anyone add some possible flaws in this solution?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With