Sending a Cancellation Token in a Task<TResult>

952 views Asked by At

I have an async method that I want to be able to cancel that is currently called

        string html = await Html.WebClientRetryAsync(state);

I have been trying to figure out the syntax to be able to call this method passing it a CancellationToken. Here is what I have attempted so far.

        CancellationToken ct;
        Func<object, Task<string>> func = async (s) => await WebClientRetryAsync((string)s);
        Task<Task<string>> task = Task<Task<string>>.Factory.StartNew(func, state.Uri.AbsoluteUri, ct);
        string html = await task.Result;

I plan to check inside the method to see if cancellation was requested prior to proceeding. I couldn't find any examples in the documentation

What I have won't get the token to the WebClientRetryAsync method, so this won't work.

1

There are 1 answers

0
Servy On

If the underlying async method simply doesn't support cancellation in any way then there simply isn't any way for you to cancel it, and that's that, as is discussed in How do I cancel non-cancelable async operations?. You can have your code continue executing on after the cancellation token is cancelled, but if the underlying asynchronous operation has no way of being told it should stop, you have no way of stopping it.

If you do just want a way of moving on when the task finishes, assuming the timeout is reached, then you can use these extension methods to add that functionality:

public static Task AddCancellation(this Task task, CancellationToken token)
{
    return Task.WhenAny(task, task.ContinueWith(t => { }, token))
        .Unwrap();
}
public static Task<T> AddCancellation<T>(this Task<T> task, 
    CancellationToken token)
{
    return Task.WhenAny(task, task.ContinueWith(t => t.Result, token))
        .Unwrap();
}

Realize of course that if you await the result of a call like this and the task is cancelled, it will throw an exception, which is how you would support that path.