通过忽略WCF调用取消

时间:2016-06-02 19:41:31

标签: .net wcf asynchronous task-parallel-library

我试图在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

似乎有效。我不喜欢服务器效果,尽管客户端在这里更重要。是否有一些我失踪的种族案例?我还没有看到这样的东西漂浮在周围。

1 个答案:

答案 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