Een lijst met taken annuleren
U kunt een asynchrone consoletoepassing annuleren als u niet wilt wachten totdat deze is voltooid. Door het voorbeeld in dit onderwerp te volgen, kunt u een annulering toevoegen aan een toepassing waarmee de inhoud van een lijst met websites wordt gedownload. U kunt veel taken annuleren door het CancellationTokenSource exemplaar aan elke taak te koppelen. Als u de Enter-toets selecteert, annuleert u alle taken die nog niet zijn voltooid.
In deze zelfstudie komt het volgende aan bod:
- Een .NET-consoletoepassing maken
- Een asynchrone toepassing schrijven die annulering ondersteunt
- Signaleringsannulering demonstreren
Vereisten
Voor deze zelfstudie hebt u het volgende nodig:
- SDK voor .NET 5 of hoger
- Integrated Development Environment (IDE)
Voorbeeldtoepassing maken
Maak een nieuwe .NET Core-consoletoepassing. U kunt er een maken met behulp van de dotnet new console
opdracht of vanuit Visual Studio. Open het bestand Program.cs in uw favoriete code-editor.
Vervangen met behulp van instructies
Vervang de bestaande using-instructies door deze declaraties:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
Velden toevoegen
Voeg in de Program
klassedefinitie deze drie velden toe:
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"
};
De CancellationTokenSource wordt gebruikt om een aangevraagde annulering aan te geven aan een CancellationToken. De HttpClient
mogelijkheid om HTTP-aanvragen te verzenden en HTTP-antwoorden te ontvangen. De s_urlList
bevat alle URL's die door de toepassing moeten worden verwerkt.
Toepassingsinvoerpunt bijwerken
Het belangrijkste toegangspunt in de consoletoepassing is de Main
methode. Vervang de bestaande methode door het volgende:
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.");
}
De bijgewerkte Main
methode wordt nu beschouwd als een Async-hoofd, waardoor een asynchroon toegangspunt in het uitvoerbare bestand mogelijk is. Er worden enkele instructieberichten naar de console geschreven en vervolgens een Task exemplaar met de naam cancelTask
declareert, waarmee de toetsstreken van de console worden gelezen. Als de Enter-toets wordt ingedrukt, wordt een aanroep uitgevoerd CancellationTokenSource.Cancel() . Dit geeft annulering aan. Vervolgens wordt de sumPageSizesTask
variabele toegewezen vanuit de SumPageSizesAsync
methode. Beide taken worden vervolgens doorgegeven, Task.WhenAny(Task[])die worden voortgezet wanneer een van de twee taken is voltooid.
Het volgende codeblok zorgt ervoor dat de toepassing pas wordt afgesloten nadat de annulering is verwerkt. Als de eerste taak moet worden voltooid, wordt cancelTask
de taak in afwachting van de sumPageSizeTask
taak verwacht. Als het werd geannuleerd, wanneer wachtte het gooit een System.Threading.Tasks.TaskCanceledException. Het blok onderschept die uitzondering en drukt een bericht af.
De methode asynchrone som van paginaformaten maken
Voeg onder de Main
methode de SumPageSizesAsync
methode toe:
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");
}
De methode begint met het instantiƫren en starten van een Stopwatch. Vervolgens wordt elke URL in de s_urlList
en aanroepen ProcessUrlAsync
doorlopen. Bij elke iteratie wordt de s_cts.Token
methode doorgegeven ProcessUrlAsync
en retourneert de code een Task<TResult>, waarbij TResult
een geheel getal is:
int total = 0;
foreach (string url in s_urlList)
{
int contentLength = await ProcessUrlAsync(url, s_client, s_cts.Token);
total += contentLength;
}
Procesmethode toevoegen
Voeg de volgende ProcessUrlAsync
methode toe onder de SumPageSizesAsync
methode:
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;
}
Voor een bepaalde URL gebruikt de methode het client
exemplaar dat is opgegeven om het antwoord op te halen als een byte[]
. Het CancellationToken exemplaar wordt doorgegeven aan de HttpClient.GetAsync(String, CancellationToken) en HttpContent.ReadAsByteArrayAsync() methoden. De token
wordt gebruikt om u te registreren voor aangevraagde annulering. De lengte wordt geretourneerd nadat de URL en lengte naar de console is geschreven.
Voorbeeld van toepassingsuitvoer
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.
Volledig voorbeeld
De volgende code is de volledige tekst van het bestand Program.cs voor het voorbeeld.
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;
}
}