【发布时间】:2017-10-09 15:58:04
【问题描述】:
我正在将控制器移植到异步。部分工作涉及使用在请求的生命周期内有效的取消令牌等待一次性对象上的异步、可取消操作。在这种特殊情况下,它是WebClient.UploadStringTaskAsync(Uri uri, string data)。
我知道使用cancellationToken.Register(() => webClient.CancelAsync()) 取消WebClient 的异步操作的正确方法。但是,WebClient 是在 using 语句中创建的,因此它被放置在块的末尾。因此,从回调中调用 webClient.CancelAsync() 会正确地导致“访问已处置的闭包”警告。我发现CancellationToken.Register(Action callback) 会产生一个CancellationTokenRegistration 对象,该对象实现IDisposable 并在处理时取消注册回调。最后,我的代码如下所示:
using (var webClient = new WebClient())
using (cancellationToken.Register(() => webClient.CancelAsync())
{
await webClient.UploadStringTaskAsync(uri, data);
}
// cancellationToken can be cancelled later.
我制作了一个控制台应用程序来显示具有相同精神的代码可以工作,并且在一次性对象和令牌注册被释放后取消令牌不会导致一次性对象的回调被调用。不过我想确定:这是正确和安全的吗?
编辑:我想我应该稍微改一下我的问题。使用取消令牌取消对一次性对象的异步操作的标准解决方案是什么,该操作仅支持通过注册回调来取消?
【问题讨论】:
-
“在一次性对象和令牌注册被释放后取消令牌不会导致一次性对象的回调被调用” - 你为什么期望
CancellationTokenRegistration的回调被调用? -
@Dai 我没有,但我也找不到任何可以依赖的直接例子,我不想做任何假设。
-
没有一个好的minimal reproducible example,没有人能确切地告诉你代码会做什么。有太多的可能性。由于
CancellationToken的源代码是公开的,您 可以自己检查它并确定它在您的 特定场景中会做什么。您的问题似乎无法按原样回答。根据您发布的代码,您的WebClient似乎不可能在回调仍在注册时被处置,因为这又是 C# 规范规则。但是我们如何才能确定其余代码在做什么呢? -
@PeterDuniho 也许我不清楚,但我更关心一般情况及其标准解决方案“在一次性对象上取消异步方法的最佳实践是什么?支持取消令牌吗?”
-
具有“最佳实践是什么...”形式的问题实际上总是过于宽泛,主要基于意见,或(大多数情况下)两者兼而有之。尤其是因为不支持取消令牌的一次性对象有各种各样的其他机制来取消。它只取决于对象。
标签: c# .net asynchronous async-await cancellation