In an ASP.NET Web API project, I have an action filter which checks for model state errors and returns the Bad Request
status code if there are any. It looks like this:
public class ValidationFilter : IActionFilter
{
public Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext context,
CancellationToken cancellationToken,
Func<Task<HttpResponseMessage>> continuation)
{
if(!actionContext.ModelState.IsValid)
{
return new Task<HttpResponseMessage>(() =>
actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest,
actionContext.ModelState);
}
return continuation();
}
}
Now, for some reason, any request with a model state error never returns. It just hangs there. If I debug, I get to the next filter in the pipeline, which starts with
var result = await continuation();
If I "Step Over" that line, the debugger sort of drops out to "waiting" mode, but no more code seems to be run.
I assume all of this is because I've somehow misunderstood how all these things interact, but despite hours of googling and reading, I still can't figure out how to make this work properly. Any help - both for understanding and bugfixing - is deeply appreciated.
You never start your task. You need to call Start
when you use the Task
constructor. Instead of calling the constructor and then Start
a better option would be to use Task.Run
:
if(!actionContext.ModelState.IsValid)
{
return Task.Run(() =>
actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest,
actionContext.ModelState);
}
In your case there's nothing really asynchronous about your operation, so you can simply use Task.FromResult
to create a task with the result you get synchronously:
public Task<HttpResponseMessage> ExecuteActionFilterAsync(
HttpActionContext context,
CancellationToken cancellationToken,
Func<Task<HttpResponseMessage>> continuation)
{
if(!actionContext.ModelState.IsValid)
{
return Task.FromResult(actionContext.Request.CreateErrorResponse(
HttpStatusCode.BadRequest,
actionContext.ModelState);
}
return continuation();
}