2

In my Windows Store app I have a method

public async static Task InitAds()
{
    Debug.WriteLine("API: Loading Ad images");
    await Task.WhenAll(ads.Select(l => l.Value).Where(l=>l!=null).Select(l => l.StartRotation()));
 }

I use to download and initialize (download, parse| Ads in a project. This method is awaited when called

...
await AdReader.InitAds()
...

The problem is that Ads server sometimes responds very slowly. I want to have a timeout, say 10 seconds for this method to run. If it does not finish in this timeout, I want it to be killed and my code to continue.

What is the best way to implement this? I found How to cancel a Task in await? but it uses a TaskFactory and when I try that approach and call my method in Task.Run it is not awaited and the code continues.

Edit:

The StartRotation is also an async method calling another async methods

public async Task StartRotation(CancellationToken ct)
{
        if (Images.Count == 1)
        {
            await Image.LoadAndSaveImage(ct);
        }

        if (Images.Count <2) return;

        foreach (var img in Images)
        {
            await img.LoadAndSaveImage(ct);
        }

        Delay = Image.Delay;
        DispatcherTimer dt = new DispatcherTimer();
        dt.Interval = TimeSpan.FromMilliseconds(Delay);
        dt.Tick += (s, e) =>
        {
            ++index;
            if (index > Images.Count - 1)
            {
                index = 0;
            }
            Image = Images[index];
        };
        dt.Start();
    }
Community
  • 1
  • 1
Igor Kulman
  • 16,211
  • 10
  • 57
  • 118
  • 2
    [How do I cancel non-cancelable async operations?](http://blogs.msdn.com/b/pfxteam/archive/2012/10/05/how-do-i-cancel-non-cancelable-async-operations.aspx) – Servy Nov 27 '12 at 15:25
  • What is the signature of l.StartRotation? You might try implement the StartRotation synchronously, wrap it into TaskFactory.StartNew and provide proper CancellationToken in it. – Martin Suchan Nov 27 '12 at 14:49
  • How would that help? It wouldn't actually cancel execution of the method. – svick Nov 28 '12 at 17:49

1 Answers1

6

Cancellation is cooperative. You just need to pass CancellationToken into your StartRotation:

public async static Task InitAds(CancellationToken token)
{
  Debug.WriteLine("API: Loading Ad images");
  await Task.WhenAll(ads.Select(l => l.Value).Where(l=>l!=null).Select(l => l.StartRotation(token)));
}

And then call it as such:

var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
await InitAds(cts.Token);
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • by "cooperative" you mean that I need to pass it to every one asyc method I call n the way? If so, what if I use a thrid-party async method that does no take CancellationToken? Will it not work because of this? – Igor Kulman Nov 27 '12 at 14:54
  • 3
    Yes. If you have an `async` method that doesn't take a `CancellationToken`, then that method can't be cancelled. You can write a wrapper that you can "cancel" (and have it return early), but the un-cancelable `async` method will continue to run. – Stephen Cleary Nov 27 '12 at 14:59