Partager via


Guide pratique pour utiliser un middleware dans System.CommandLine

Important

System.CommandLine est actuellement une PRÉVERSION et cette documentation concerne la version 2.0 beta 4. Certaines informations portent sur la préversion du produit qui est susceptible d’être en grande partie modifiée avant sa publication. Microsoft exclut toute garantie, expresse ou implicite, concernant les informations fournies ici.

Cet article explique comment utiliser les middlewares (intergiciels) dans les applications en ligne de commande générées avec la bibliothèque System.CommandLine. L’utilisation de middlewares est un sujet avancé que la plupart des utilisateurs de System.CommandLine n’ont pas à prendre en compte.

Présentation des middlewares

Bien que chaque commande ait un gestionnaire vers lequel System.CommandLine effectue le routage en fonction de l’entrée, il existe également un mécanisme permettant de court-circuiter ou de modifier l’entrée avant l’appel de la logique de votre application. Entre l’analyse et l’appel, il existe une chaîne de responsabilités, que vous pouvez personnaliser. Un certain nombre de fonctionnalités intégrées de System.CommandLine utilisent cette fonctionnalité. Voici comment les options --help et --version court-circuitent les appels à votre gestionnaire.

Chaque appel dans le pipeline peut effectuer une action en fonction de ParseResult et s’arrêter, ou appeler l’élément suivant du pipeline. ParseResult peut même être remplacé durant cette phase. Le dernier appel de la chaîne correspond au gestionnaire de la commande spécifiée.

Effectuer un ajout au pipeline de middleware

Vous pouvez ajouter un appel à ce pipeline en appelant CommandLineBuilderExtensions.AddMiddleware. Voici un exemple de code qui active une directive personnalisée. Une fois que vous avez créé une commande racine nommée rootCommand, le code ajoute, comme d’habitude, des options, des arguments et des gestionnaires. Le middleware est ensuite ajouté :

var commandLineBuilder = new CommandLineBuilder(rootCommand);

commandLineBuilder.AddMiddleware(async (context, next) =>
{
    if (context.ParseResult.Directives.Contains("just-say-hi"))
    {
        context.Console.WriteLine("Hi!");
    }
    else
    {
        await next(context);
    }
});

commandLineBuilder.UseDefaults();
var parser = commandLineBuilder.Build();
await parser.InvokeAsync(args);

Dans le code précédent, le middleware écrit « Hi! » si la directive [just-say-hi] se trouve dans le résultat de l’analyse. Quand cela se produit, le gestionnaire normal de la commande n’est pas appelé. Il n’est pas appelé, car le middleware n’appelle pas le délégué next.

Dans l’exemple, context représente InvocationContext, une structure singleton qui sert de « racine » de l’ensemble du processus de gestion des commandes. Il s’agit de la structure la plus puissante de System.CommandLine au niveau des fonctionnalités. Elle a deux utilisations principales dans le cadre d’un middleware :

  • Elle permet d’accéder à BindingContext, Parser, Console et HelpBuilder pour récupérer les dépendances dont un middleware a besoin pour sa logique personnalisée.
  • Vous pouvez définir les propriétés InvocationResult ou ExitCode pour arrêter le traitement des commandes à la façon d’un court-circuit. L’option --help, qui est implémentée de cette manière, en est un exemple.

Voici le programme complet, qui inclut les directives using obligatoires.

using System.CommandLine;
using System.CommandLine.Builder;
using System.CommandLine.Parsing;

class Program
{
    static async Task Main(string[] args)
    {
        var delayOption = new Option<int>("--delay");
        var messageOption = new Option<string>("--message");

        var rootCommand = new RootCommand("Middleware example");
        rootCommand.Add(delayOption);
        rootCommand.Add(messageOption);

        rootCommand.SetHandler((delayOptionValue, messageOptionValue) =>
            {
                DoRootCommand(delayOptionValue, messageOptionValue);
            },
            delayOption, messageOption);

        var commandLineBuilder = new CommandLineBuilder(rootCommand);

        commandLineBuilder.AddMiddleware(async (context, next) =>
        {
            if (context.ParseResult.Directives.Contains("just-say-hi"))
            {
                context.Console.WriteLine("Hi!");
            }
            else
            {
                await next(context);
            }
        });

        commandLineBuilder.UseDefaults();
        var parser = commandLineBuilder.Build();
        await parser.InvokeAsync(args);
    }

    public static void DoRootCommand(int delay, string message)
    {
        Console.WriteLine($"--delay = {delay}");
        Console.WriteLine($"--message = {message}");
    }
}

Voici un exemple de ligne de commande et de sortie résultante pour le code précédent :

myapp [just-say-hi] --delay 42 --message "Hello world!"
Hi!

Voir aussi

Vue d’ensemble de System.CommandLine