Delen via


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:

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 cancelTaskdeclareert, 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 cancelTaskde 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 ProcessUrlAsyncdoorlopen. 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;
    }
}

Zie ook

Volgende stappen