0

So I have a continuation defined:

var task = _httpClient.SendAsync(request, cts.Token);
task.ContinueWith(i => { /* TODO: log */ },
    TaskContinuationOptions.OnlyOnCanceled);
var response = await task.ConfigureAwait(false);

I get a compiler warning on the ContinueWith line:

Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.

However, as you can see, I apply the await to the response.

When the method that contains this code exits, I get a NullReferenceException:

at System.Web.ThreadContext.AssociateWithCurrentThread(Boolean setImpersonationContext)
at System.Web.HttpApplication.OnThreadEnterPrivate(Boolean setImpersonationContext)
at System.Web.LegacyAspNetSynchronizationContext.CallCallbackPossiblyUnderLock(SendOrPostCallback callback, Object state)
at System.Web.LegacyAspNetSynchronizationContext.CallCallback(SendOrPostCallback callback, Object state)
at System.Threading.Tasks.AwaitTaskContinuation.RunCallback(ContextCallback callback, Object state, Task& currentTask)

My question is: how do I properly use task continuations and ConfigureAwait(false) at the same time?

2
  • ContinueWith returns new task so there is nothing surprising about the warning... Commented Feb 10, 2015 at 3:54
  • @AlexeiLevenkov it's possible that I'm just missing some important knowledge here, as I've never really tried to use ContinueWith before. Any idea of how to properly use it with async/await? Commented Feb 10, 2015 at 4:04

2 Answers 2

1

ContinueWith is what you used prior to async-await. Await automatically registers the rest of the method as a continueation so you don't need to do that. To achieve what you want with await, you can register a callback with the CancellationToken to log when it is cancelled.

CancellationTokenSource cts = new CancellationTokenSource();
cts.Token.Register(() => /* TODO: log */);  
var task =  _httpClient.SendAsync(request, cts.Token).ConfigureAwait(false);

ConfigureAwait(false) simply tells the compiler not to switch back to the captured synchronization context. If you used ContinueWith, then you can supply a TaskContinutationOptions.ExecuteSynchronously.

var task = _httpClient.SendAsync(request, cts.Token);
return task.ContinueWith(i => { /* TODO: log */ },
TaskContinuationOptions.OnlyOnCanceled | TaskContinutationOptions.ExecuteSynchronously);
Sign up to request clarification or add additional context in comments.

Comments

0

It turns out that I was missing some vital information: exceptions will bubble up to your code per normal if you await the method causing the exception. So, all I have to do is this:

try
{
    await queue.AddMessageAsync(message).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
    throw new Exception(string.Format("Unable to push message to queue {0}", queueName));
}

Since await is syntactic sugar for a continuation, the exception will be continued to it.

1 Comment

Right. The correct answer to Any idea of how to properly use ContinueWith with async/await? is to replace ContinueWith with await.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.