WebException при вызове WebClient.CancelAsync в «ожидании загрузкиTaskAsync» - PullRequest
1 голос
/ 26 апреля 2019

Это прекрасно работает:

private WebClient _webClient;

private void ButtonStart_Click(object sender, RoutedEventArgs e) {
    using (_webClient = new WebClient()) {
        _webClient.DownloadFileTaskAsync("https://speed.hetzner.de/100MB.bin", @"D:\100MB.bin");
    }
}

private void ButtonStop_Click(object sender, RoutedEventArgs e) {
    _webClient.CancelAsync();
}

Пока этот код (обратите внимание на шаблон асинхронного / ожидающего) ...:

private WebClient _webClient;

private async void ButtonStart_Click(object sender, RoutedEventArgs e) {
    using (_webClient = new WebClient()) {
        await _webClient.DownloadFileTaskAsync("https://speed.hetzner.de/100MB.bin", @"D:\100MB.bin");
    }
}

private void ButtonStop_Click(object sender, RoutedEventArgs e) {
    _webClient.CancelAsync();
}

... выдает следующее исключение:

System.Net.WebException

Запрос был прерван: запрос был отменен.

   at System.Net.ConnectStream.EndRead(IAsyncResult asyncResult)
   at System.Net.WebClient.DownloadBitsReadCallbackState(DownloadBitsState state, IAsyncResult result)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at WpfApp1.MainWindow.<ButtonStart_Click>d__2.MoveNext() in WpfApp1\MainWindow.xaml.cs:line 19

Как я могу отменитьзадание началось с await WebClient.DownloadFileTaskAsync() без исключения?

Ответы [ 2 ]

7 голосов
/ 26 апреля 2019

Исключение составляет именно то, как должно работать.

Если вы не хотите, чтобы это исключение распространялось из вашего обработчика событий, перехватите исключение.

3 голосов
/ 27 апреля 2019

Вы можете перехватить исключение следующим образом:

using (_webClient = new WebClient())
{
    try
    {
        await _webClient.DownloadFileTaskAsync("https://speed.hetzner.de/100MB.bin", @"D:\100MB.bin");
    }
    catch (WebException ex) when (ex.Status == WebExceptionStatus.RequestCanceled)
    {
        Console.WriteLine("Cancelled");
    }
}

Обновление: Как изменить поведение по умолчанию CancelAsync, чтобы избежать необходимости перехватывать исключение:

public static Task<bool> OnCancelReturnTrue(this Task task)
{
    return task.ContinueWith(t =>
    {
        if (t.IsFaulted)
        {
            if (t.Exception.InnerException is WebException webEx
                && webEx.Status == WebExceptionStatus.RequestCanceled) return true;
            throw t.Exception;
        }
        return t.IsCanceled;
    }, TaskContinuationOptions.ExecuteSynchronously);
}

Пример использования:

bool cancelled = await _webClient.DownloadFileTaskAsync(
    "https://speed.hetzner.de/100MB.bin", @"D:\100MB.bin").OnCancelReturnTrue();
if (cancelled) Console.WriteLine("Cancelled");
...