我试图在WCF调用的客户端实现取消。我已经看到了一些关于取消服务器流程的问题,但我不需要这样做。我有一个UI需要响应取消长时间运行的服务器端进程。
所以我有以下代码:
Const WayLongerThanItShouldEverTakeMilliseconds As Integer = 60 * 30 * 1000
Public Async Function CallService(token as CancellationToken) As Task(Of ReturnType)
Dim client As IWcfService = _service
Dim returnTask As Task(Of ReturnType) = client.FunctionAsync()
Dim cancellationTask as Task = Task.Delay(WayLongerThanItShouldEverTakeMilliseconds, token).
ContinueWith(Function(t) Task.FromCanceled(token), TaskContinuationOptions.OnlyOnCanceled)
Await Task.WhenAny(returnTask, cancellationTask)
token.ThrowIfCancellationRequested()
Return Await returnTask
End Function
似乎有效。我不喜欢服务器效果,尽管客户端在这里更重要。是否有一些我失踪的种族案例?我还没有看到这样的东西漂浮在周围。
答案 0 :(得分:0)
这样可以正常工作。这是隔离和忽略无法取消的操作的常用方法。我不太了解你要对cancellationTask.ContinueWith
做些什么。似乎不是必需的。
请注意,您有资源泄漏:许多Delay
任务可能会累积并最终无法执行任何操作。在WhenAny
任务完成后,请考虑取消延迟任务。这释放了内部资源(计时器)。
我发现将所有这些逻辑打包成可重用的辅助方法很有用。这样,您可以轻松地为任何其他任务创建代理任务。如果您对实际操作继续进行操作,则可以立即取消任何操作。
修改:为将来的用户添加了扩展程序:
<Extension()>
Public Async Function ToIgnorableTask(Of T)(originalTask As Task(Of T), token As CancellationToken) As Task(Of T)
Using internalCts As New CancellationTokenSource()
Using combinedCts As CancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(token, internalCts.Token)
Try
Dim cancellationTask As Task = task.Delay(-1, combinedCts.Token)
Await Task.WhenAny(originalTask, cancellationTask)
token.ThrowIfCancellationRequested()
Return Await originalTask
Finally
internalCts.Cancel()
End Try
End Using
End Using
End Function
<Extension()>
Public Async Function ToIgnorableTask(originalTask As Task, token As CancellationToken) As Task
Using internalCts As New CancellationTokenSource()
Using combinedCts As CancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(token, internalCts.Token)
Try
Dim cancellationTask As Task = Task.Delay(-1, combinedCts.Token)
Await Task.WhenAny(originalTask, cancellationTask)
token.ThrowIfCancellationRequested()
Finally
internalCts.Cancel()
End Try
End Using
End Using
End Function