Note
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier les répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de changer de répertoire.
Vous pouvez annuler une application console asynchrone si vous ne souhaitez pas attendre qu’elle se termine. En suivant l’exemple de cette rubrique, vous pouvez ajouter une annulation à une application qui télécharge le contenu d’une liste de sites web. Vous pouvez annuler de nombreuses tâches en associant l’instance CancellationTokenSource à chaque tâche. Si vous sélectionnez la Entrer clé, vous annulez toutes les tâches qui ne sont pas encore terminées.
Ce didacticiel contient les sections suivantes :
- Création d’une application console .NET
- Écriture d’une application asynchrone prenant en charge l’annulation
- Démonstration de l’annulation de la signalisation
Conditions préalables
- La dernière version du SDK .NET
- Éditeur de code Visual Studio
- Le DevKit C#
Créer un exemple d’application
Créez une application console .NET Core. Vous pouvez en créer un à l’aide de la commande dotnet new console ou à partir de Visual Studio. Ouvrez le fichier Program.cs dans votre éditeur de code favori.
Remplacer les directives d'utilisation
Remplacez les directives using existantes par les déclarations suivantes :
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
Ajouter des champs
Dans la définition de classe Program, ajoutez ces trois champs :
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"
};
Le CancellationTokenSource est utilisé pour signaler une annulation demandée à un CancellationToken. Le HttpClient expose la possibilité d’envoyer des requêtes HTTP et de recevoir des réponses HTTP. La s_urlList contient toutes les URL que l’application prévoit de traiter.
Mettre à jour le point d’entrée de l’application
Le point d’entrée principal dans l’application console est la méthode Main. Remplacez la méthode existante par ce qui suit :
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.");
}
La méthode Main mise à jour est désormais considérée comme une méthode Async main, ce qui autorise un point d’entrée asynchrone dans l’exécutable. Il écrit quelques messages d’instruction dans la console, puis déclare une instance Task nommée cancelTask, qui lit les traits de touches de la console. Si la touche Entrée est enfoncée, un appel à CancellationTokenSource.Cancel() est effectué. Cela signale l’annulation. Ensuite, la variable sumPageSizesTask est affectée à partir de la méthode SumPageSizesAsync. Les deux tâches sont ensuite passées à Task.WhenAny(Task[]), ce qui se poursuit lorsque l’une des deux tâches est terminée.
Le bloc de code suivant garantit que l’application ne se ferme pas tant que l’annulation n’a pas été traitée. Si la première tâche à effectuer est cancelTask, la tâche sumPageSizeTask est attendue. Si elle a été annulée, lorsqu’elle est attendue, cela lève une System.Threading.Tasks.TaskCanceledException. Le bloc intercepte cette exception et imprime un message.
Créer la méthode asynchrone de somme des tailles de pages
Sous la méthode Main, ajoutez la méthode 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");
}
La méthode commence par instancier et démarrer un Stopwatch. Il parcourt ensuite chaque URL du s_urlList et appelle ProcessUrlAsync. Avec chaque itération, la s_cts.Token est passée à la méthode ProcessUrlAsync et le code retourne un Task<TResult>, où TResult est un entier :
int total = 0;
foreach (string url in s_urlList)
{
int contentLength = await ProcessUrlAsync(url, s_client, s_cts.Token);
total += contentLength;
}
Ajouter une méthode de processus
Ajoutez la méthode ProcessUrlAsync suivante sous la méthode 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;
}
Pour une URL donnée, la méthode utilise l’instance client fournie pour obtenir la réponse en tant que byte[]. L’instance CancellationToken est passée aux méthodes HttpClient.GetAsync(String, CancellationToken) et HttpContent.ReadAsByteArrayAsync(). Le token est utilisé pour enregistrer une demande d'annulation. La longueur est retournée après l’URL et la longueur est écrite vers la console.
Exemple de sortie d’application
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.
Exemple complet
Le code suivant est le texte complet du fichier Program.cs pour l’exemple.
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;
}
}