Merging .NET 4.0 Tasks/continuations of different types

.net, async-await, asynchronous, c#-4.0, task

Solution

Your problem is that if you don't use `Result`, `ContinueWith()` will return `Task<Task<HttpResponseMessage>>` and not the `Task<HttpResponseMessage>` you need.

Fortunately, there already is a method that converts any `Task<Task<T>>` to `Task<T>`: `Unwrap()`. So just `return continuation();` from the `ContinueWith()` lambda and then call `Unwrap()` on the result.

If you want the continuation to execute in the ASP.NET context, you can use `TaskScheduler.FromCurrentSynchronizationContext()`.

Problem

I'm currently implementing a `System.Web.Http.IActionFilter` which calls an internal service to determine whether the current request can continue. The problem I'm having is returning a `Task<T1>` based on a piece of logic encapsulated by a `Task<T2>`. An example might help. The internal service API is implemented using Tasks. The logic is trivial using .NET 4.5's async/await: ``` public async Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation) { UserAuthenticationResult authResult = await HitInternalServiceAsync(); if (!authResult.IsAuthenticated) { throw new HttpResponseException("User is not authenticated", HttpStatusCode.Unauthorized); } return await continuation(); } ``` However it is more difficult with the old Task API in .NET 4.0; ``` public Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation) { return HitInternalServiceAsync() .ContinueWith(t1 => { UserAuthenticationResult authResult = t1.Result; if (!authResult.IsAuthenticated) { throw new HttpResponseException("User is not authenticated", HttpStatusCode.Unauthorized); } //Hack hack - this blocks the thread until the task retuned by continuation() completes return continuation().Result; }); } ``` The difficult part comes when the authentication check has succeeded - I then want to await the task returned by the continuation function. Using .NET 4.0 it looks like I have explicitly block when waiting for the `continuation()` task to complete, rather than instructing the Tasks API to automatically continue with the `continuation()` task when my task is done. The question: Is this the only way to implement this behaviour in .NET 4.0? Given a sufficiently complicated internal service API, I can easily see the number of Tasks waiting on other Tasks multiplying quickly. EDIT: Looks like the above 4.0 code isn't viable either - because the continuation lambda does not execute in the ASP.NET thread context services like HttpContext.Current are not available. A better implementation would be... ``` public Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation) { Task<UserAuthenticationResult> authResultTask = HitInternalServiceAsync(); var authResult = authResultTask.Result; if (!authResult.IsAuthenticated) { throw new HttpResponseException("User is not authenticated", HttpStatusCode.Unauthorized); } return continuation(); } ```

Original source

Related problems