How to handle cancellation on Task that wraping a third-party long running method

时间:2017-07-11 08:04:59

标签: c# .net asynchronous task

I using some third-party class that have a long time work call DoLongWork(). When the user want to stop the "DoLongWork" we need to call the method StopWork(). When the DoLongWork method is working the UI need to show some loading bar.

I want to create a third-party proxy class. In this class I will create a method called StartWork - this method will return Task and when the user is cancel the task using CancellationToken two actions will made:

1) the third-party method "StopWork" will called

2) the UI will stop the loading bar.

I try this but there is some problems catching the cancellation in the third-party proxy class and bubbling the cancellation to the ViewModel class.

public class MyViewModel
{
    private CancellationTokenSource _cancellationTokenSource;
    private ThirdPartyServiceProxy _thirdPartyServiceProxy = new ThirdPartyServiceProxy();
    public bool IsUIInLoadingMode { get; set; }
    public async void Start()
    {
        try
        {
            _cancellationTokenSource = new CancellationTokenSource();
            IsUIInLoadingMode = true;
            await _thirdPartyServiceProxy.StartWork(_cancellationTokenSource.Token);
            _cancellationTokenSource = null;
        }
        catch (OperationCanceledException)/*Issue - This never called*/
        {
            IsUIInLoadingMode = false;
        }
    }
    public void Stop()
    {
        _cancellationTokenSource?.Cancel();
    }
}

public class ThirdPartyServiceProxy
{
    private ThirdPartyService _thirdPartyService = new ThirdPartyService();
    public Task StartWork(CancellationToken token)
    {
        var task = Task.Factory.StartNew(() =>
        {
            _thirdPartyService.DoLongWork();
        },token);

        //?? - Handle when task canceld - call _thirdPartyService.StopWork();

        return task;
    }
}

1 个答案:

答案 0 :(得分:2)

couple of common ways to observe cancellation tokens:定期轮询ThrowIfCancellationRequested并使用Register注册回调。

在这种情况下,无法进行轮询,因为您无法控制DoLongWork中的代码。所以你必须注册一个回调,这是更多的工作。

public void DoWork(CancellationToken token)
{
  token.ThrowIfCancellationRequested();
  using (token.Register(() => _thirdPartyService.StopWork()))
    _thirdPartyService.DoLongWork();
}

此包装器假定DoLongWork如果OperationCanceledException取消,StopWork会抛出await Task.Run(() => _thirdPartyServiceProxy.StartWork(_cancellationTokenSource.Token));

然后可以调用包装器:

Task.Run

作为旁注,我已切换到&&;这是因为StartNew is dangerous

相关问题