Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Jeśli nie chcesz czekać na zakończenie, możesz anulować aplikację konsolową asynchroniczną. Korzystając z przykładu w tym temacie, możesz dodać anulowanie do aplikacji, która pobiera zawartość listy witryn internetowych. Można anulować wiele zadań, łącząc wystąpienie CancellationTokenSource z każdym zadaniem. Jeśli wybierzesz Enter , anulujesz wszystkie zadania, które nie zostały jeszcze ukończone.
Ten samouczek obejmuje:
- Tworzenie aplikacji konsolowej platformy .NET
- Pisanie aplikacji asynchronicznej obsługującej możliwość anulowania
- Demonstrowanie anulowania sygnału
Wymagania wstępne
Tworzenie przykładowej aplikacji
Utwórz nową aplikację konsolową platformy .NET Core. Możesz go utworzyć przy użyciu dotnet new console
polecenia lub programu Visual Studio. Otwórz plik Program.cs w ulubionym edytorze kodu.
Zamień dyrektywy using
Zastąp istniejące using
dyrektywy następującymi deklaracjami:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
Dodaj pola
Program
W definicji klasy dodaj następujące trzy pola:
static readonly CancellationTokenSource s_cts = new CancellationTokenSource();
static readonly HttpClient s_client = new HttpClient
{
MaxResponseContentBufferSize = 1_000_000
};
static readonly IEnumerable<string> s_urlList = new string[]
{
"https://learn.microsoft.com",
"https://learn.microsoft.com/aspnet/core",
"https://learn.microsoft.com/azure",
"https://learn.microsoft.com/azure/devops",
"https://learn.microsoft.com/dotnet",
"https://learn.microsoft.com/dynamics365",
"https://learn.microsoft.com/education",
"https://learn.microsoft.com/enterprise-mobility-security",
"https://learn.microsoft.com/gaming",
"https://learn.microsoft.com/graph",
"https://learn.microsoft.com/microsoft-365",
"https://learn.microsoft.com/office",
"https://learn.microsoft.com/powershell",
"https://learn.microsoft.com/sql",
"https://learn.microsoft.com/surface",
"https://learn.microsoft.com/system-center",
"https://learn.microsoft.com/visualstudio",
"https://learn.microsoft.com/windows",
"https://learn.microsoft.com/maui"
};
Element CancellationTokenSource służy do sygnalizowania żądanego anulowania dla CancellationToken. Funkcja HttpClient
uwidacznia możliwość wysyłania żądań HTTP i odbierania odpowiedzi HTTP.
s_urlList
zawiera wszystkie adresy URL, które aplikacja planuje przetworzyć.
Aktualizowanie punktu wejścia aplikacji
Głównym punktem wejścia do aplikacji konsolowej jest Main
metoda . Zastąp istniejącą metodę następującym kodem:
static async Task Main()
{
Console.WriteLine("Application started.");
Console.WriteLine("Press the ENTER key to cancel...\n");
Task cancelTask = Task.Run(() =>
{
while (Console.ReadKey().Key != ConsoleKey.Enter)
{
Console.WriteLine("Press the ENTER key to cancel...");
}
Console.WriteLine("\nENTER key pressed: cancelling downloads.\n");
s_cts.Cancel();
});
Task sumPageSizesTask = SumPageSizesAsync();
Task finishedTask = await Task.WhenAny(new[] { cancelTask, sumPageSizesTask });
if (finishedTask == cancelTask)
{
// wait for the cancellation to take place:
try
{
await sumPageSizesTask;
Console.WriteLine("Download task completed before cancel request was processed.");
}
catch (TaskCanceledException)
{
Console.WriteLine("Download task has been cancelled.");
}
}
Console.WriteLine("Application ending.");
}
Zaktualizowana Main
metoda jest teraz traktowana jako główna asynchroniczna, która umożliwia asynchroniczny punkt wejścia do pliku wykonywalnego. Zapisuje kilka komunikatów instruktażowych w konsoli, a następnie deklaruje wystąpienie Task o nazwie cancelTask
, które odczytuje naciśnięcia klawiszy konsoli. Jeśli naciśnięty zostanie klawisz Enter, zostanie wykonane wywołanie do CancellationTokenSource.Cancel(). Zasygnalizuje to anulowanie. Następnie zmiennej sumPageSizesTask
przypisuje się wartość z metody SumPageSizesAsync
. Oba zadania są następnie przekazywane do Task.WhenAny(Task[]), który będzie kontynuował po zakończeniu któregokolwiek z tych dwóch zadań.
Następny blok kodu gwarantuje, że aplikacja nie zostanie zamknięta, dopóki anulowanie nie zostanie przetworzone. Jeśli pierwszym zadaniem do ukończenia jest cancelTask
, oczekiwany jest sumPageSizeTask
. Jeśli zostało anulowane, podczas oczekiwania rzuca System.Threading.Tasks.TaskCanceledException. Blok przechwytuje ten wyjątek i wyświetla komunikat.
Tworzenie metody asynchronicznej sumowania rozmiarów stron
Main
Poniżej metody dodaj metodę SumPageSizesAsync
:
static async Task SumPageSizesAsync()
{
var stopwatch = Stopwatch.StartNew();
int total = 0;
foreach (string url in s_urlList)
{
int contentLength = await ProcessUrlAsync(url, s_client, s_cts.Token);
total += contentLength;
}
stopwatch.Stop();
Console.WriteLine($"\nTotal bytes returned: {total:#,#}");
Console.WriteLine($"Elapsed time: {stopwatch.Elapsed}\n");
}
Metoda rozpoczyna się od utworzenia wystąpienia i uruchomienia Stopwatch. Następnie iteruje przez każdy adres URL w s_urlList
i wywołuje ProcessUrlAsync
. W przypadku każdej iteracji element s_cts.Token
jest przekazywany do ProcessUrlAsync
metody, a kod zwraca Task<TResult>, gdzie TResult
jest liczbą całkowitą:
int total = 0;
foreach (string url in s_urlList)
{
int contentLength = await ProcessUrlAsync(url, s_client, s_cts.Token);
total += contentLength;
}
Dodawanie metody procesu
Dodaj następującą metodę ProcessUrlAsync
poniżej metody SumPageSizesAsync
:
static async Task<int> ProcessUrlAsync(string url, HttpClient client, CancellationToken token)
{
HttpResponseMessage response = await client.GetAsync(url, token);
byte[] content = await response.Content.ReadAsByteArrayAsync(token);
Console.WriteLine($"{url,-60} {content.Length,10:#,#}");
return content.Length;
}
W przypadku dowolnego adresu URL metoda użyje podanego client
wystąpienia, aby uzyskać odpowiedź w formacie byte[]
. Wystąpienie CancellationToken jest przekazywane do metod HttpClient.GetAsync(String, CancellationToken) i HttpContent.ReadAsByteArrayAsync(). Element token
służy do rejestracji zażądanego anulowania. Długość jest zwracana po zapisaniu adresu URL i długości do konsoli.
Przykładowe dane wyjściowe aplikacji
Application started.
Press the ENTER key to cancel...
https://learn.microsoft.com 37,357
https://learn.microsoft.com/aspnet/core 85,589
https://learn.microsoft.com/azure 398,939
https://learn.microsoft.com/azure/devops 73,663
https://learn.microsoft.com/dotnet 67,452
https://learn.microsoft.com/dynamics365 48,582
https://learn.microsoft.com/education 22,924
ENTER key pressed: cancelling downloads.
Application ending.
Kompletny przykład
Poniższy kod jest kompletnym tekstem pliku Program.cs dla przykładu.
using System.Diagnostics;
class Program
{
static readonly CancellationTokenSource s_cts = new CancellationTokenSource();
static readonly HttpClient s_client = new HttpClient
{
MaxResponseContentBufferSize = 1_000_000
};
static readonly IEnumerable<string> s_urlList = new string[]
{
"https://learn.microsoft.com",
"https://learn.microsoft.com/aspnet/core",
"https://learn.microsoft.com/azure",
"https://learn.microsoft.com/azure/devops",
"https://learn.microsoft.com/dotnet",
"https://learn.microsoft.com/dynamics365",
"https://learn.microsoft.com/education",
"https://learn.microsoft.com/enterprise-mobility-security",
"https://learn.microsoft.com/gaming",
"https://learn.microsoft.com/graph",
"https://learn.microsoft.com/microsoft-365",
"https://learn.microsoft.com/office",
"https://learn.microsoft.com/powershell",
"https://learn.microsoft.com/sql",
"https://learn.microsoft.com/surface",
"https://learn.microsoft.com/system-center",
"https://learn.microsoft.com/visualstudio",
"https://learn.microsoft.com/windows",
"https://learn.microsoft.com/maui"
};
static async Task Main()
{
Console.WriteLine("Application started.");
Console.WriteLine("Press the ENTER key to cancel...\n");
Task cancelTask = Task.Run(() =>
{
while (Console.ReadKey().Key != ConsoleKey.Enter)
{
Console.WriteLine("Press the ENTER key to cancel...");
}
Console.WriteLine("\nENTER key pressed: cancelling downloads.\n");
s_cts.Cancel();
});
Task sumPageSizesTask = SumPageSizesAsync();
Task finishedTask = await Task.WhenAny(new[] { cancelTask, sumPageSizesTask });
if (finishedTask == cancelTask)
{
// wait for the cancellation to take place:
try
{
await sumPageSizesTask;
Console.WriteLine("Download task completed before cancel request was processed.");
}
catch (OperationCanceledException)
{
Console.WriteLine("Download task has been cancelled.");
}
}
Console.WriteLine("Application ending.");
}
static async Task SumPageSizesAsync()
{
var stopwatch = Stopwatch.StartNew();
int total = 0;
foreach (string url in s_urlList)
{
int contentLength = await ProcessUrlAsync(url, s_client, s_cts.Token);
total += contentLength;
}
stopwatch.Stop();
Console.WriteLine($"\nTotal bytes returned: {total:#,#}");
Console.WriteLine($"Elapsed time: {stopwatch.Elapsed}\n");
}
static async Task<int> ProcessUrlAsync(string url, HttpClient client, CancellationToken token)
{
HttpResponseMessage response = await client.GetAsync(url, token);
byte[] content = await response.Content.ReadAsByteArrayAsync(token);
Console.WriteLine($"{url,-60} {content.Length,10:#,#}");
return content.Length;
}
}