任务Continuation NullReferenceException

时间:2015-02-10 03:27:13

标签: c# task-parallel-library async-await continuations

所以我有一个延续定义:

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

我在ContinueWith行收到编译器警告:

  

由于未等待此调用,因此在完成调用之前会继续执行当前方法。考虑应用“等待”#39;运算符到调用的结果。

但是,正如您所看到的,我将await应用于响应。

当包含此代码的方法退出时,我会得到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)

我的问题是:如何正确使用任务延续和ConfigureAwait(false)

2 个答案:

答案 0 :(得分:1)

ContinueWith是您在async-await之前使用的内容。 Await自动将方法的其余部分注册为继续,因此您不需要这样做。要使用await实现您想要的效果,您可以使用CancellationToken注册回调,以便在取消时进行记录。

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

ConfigureAwait(false)只是告诉编译器不要切换回捕获的同步上下文。如果您使用ContinueWith,则可以提供TaskContinutationOptions.ExecuteSynchronously

var task = _httpClient.SendAsync(request, cts.Token);
return task.ContinueWith(i => { /* TODO: log */ },
TaskContinuationOptions.OnlyOnCanceled | TaskContinutationOptions.ExecuteSynchronously);

答案 1 :(得分:0)

事实证明,我遗漏了一些重要信息:如果<{em>你<{em>> await导致异常的方法,异常将按照正常冒充你的代码。所以,我所要做的就是:

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

由于await是继续的语法糖,因此将继续例外。