任务继续 NullReferenceException
Task Continuation NullReferenceException
所以我定义了一个延续:
var task = _httpClient.SendAsync(request, cts.Token);
task.ContinueWith(i => { /* TODO: log */ },
TaskContinuationOptions.OnlyOnCanceled);
var response = await task.ConfigureAwait(false);
我在 ContinueWith
行收到编译器警告:
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.
但是,如您所见,我将 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)
?
事实证明我遗漏了一些重要信息:异常会按照正常情况冒泡到您的代码中 如果 您 await
方法导致异常。所以,我所要做的就是:
try
{
await queue.AddMessageAsync(message).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
throw new Exception(string.Format("Unable to push message to queue {0}", queueName));
}
由于await
是continuation的语法糖,异常会继续到它。
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);
所以我定义了一个延续:
var task = _httpClient.SendAsync(request, cts.Token);
task.ContinueWith(i => { /* TODO: log */ },
TaskContinuationOptions.OnlyOnCanceled);
var response = await task.ConfigureAwait(false);
我在 ContinueWith
行收到编译器警告:
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.
但是,如您所见,我将 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)
?
事实证明我遗漏了一些重要信息:异常会按照正常情况冒泡到您的代码中 如果 您 await
方法导致异常。所以,我所要做的就是:
try
{
await queue.AddMessageAsync(message).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
throw new Exception(string.Format("Unable to push message to queue {0}", queueName));
}
由于await
是continuation的语法糖,异常会继续到它。
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);