IActionFilter returning a new Task<HttpResponseMessage> never returns

action-filter, asp.net-web-api, async-await, c#, task

Solution

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();
}

Problem

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.

Original source