2016-06-02 9 views
1

Ich versuche, die Stornierung auf der Clientseite eines WCF-Aufrufs zu implementieren. Ich habe eine Reihe von Fragen zum Abbrechen des Serverprozesses gesehen, aber das muss ich nicht tun. Ich habe eine Benutzeroberfläche, die auf die Beendigung eines lang andauernden serverseitigen Prozesses reagieren muss.Abbrechen durch Ignorieren eines WCF-Anrufs

So habe ich den folgenden Code:

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 

Es scheint zu funktionieren. Ich mag die Server-Effekte nicht, obwohl der Client hier wichtiger ist. Gibt es einen Rennfall, den ich vermisse? So etwas habe ich noch nicht gesehen.

Antwort

0

Dies funktioniert wie es ist. Es ist ein gängiger Ansatz, Vorgänge zu isolieren und zu ignorieren, die nicht abgebrochen werden können. Ich verstehe nicht ganz, was Sie mit der cancellationTask.ContinueWith zu tun versuchen. Scheint nicht erforderlich.

Beachten Sie, dass Sie ein Ressourcenleck haben: Viele Delay Aufgaben können akkumulieren und am Ende nichts tun. Ziehen Sie in Betracht, die Verzögerungsaufgabe abzubrechen, nachdem die WhenAny Aufgabe abgeschlossen wurde. Das gibt die internen Ressourcen frei (ein Timer).

Ich fand es nützlich, all diese Logik in eine wiederverwendbare Hilfsmethode zu packen. Auf diese Weise können Sie problemlos eine Proxy-Aufgabe für jede andere Aufgabe erstellen. Sie können dann sofort alles abbrechen, wenn Sie mit der tatsächlichen Operation einverstanden sind.


Edit: Hinzugefügt Erweiterungen für zukünftige Benutzer:

<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 
+0

Danke für die Korrektur. Ich dachte, dass ohne die ContinueWith-Fortsetzung das 'WhenAny' nicht ausgelöst wird, in der Annahme, dass es nur ausgelöst wurde, wenn eine Aufgabe in den Status Completed abgeschlossen wurde. – Shlomo

+1

Code in Antwort integriert. Danke @usr. – Shlomo