简体   繁体   中英

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

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;
    }
}

There's a couple of common ways to observe cancellation tokens : periodic polling with ThrowIfCancellationRequested and registering callbacks with Register .

In this case, polling isn't possible, since you don't control the code in DoLongWork . So you'll have to register a callback, which is more work.

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

This wrapper assumes that DoLongWork will throw OperationCanceledException if canceled by StopWork .

The wrapper can then be invoked as:

await Task.Run(() => _thirdPartyServiceProxy.StartWork(_cancellationTokenSource.Token));

As a side note, I have switched to Task.Run ; this is because StartNew is dangerous .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM