Condividi tramite


Come usare il middleware in System.CommandLine

Importante

System.CommandLine è attualmente in ANTEPRIMA e questa documentazione si riferisce alla versione 2.0 beta 4. Alcune informazioni riguardano il prodotto in versione non definitiva che potrebbe essere modificato in modo sostanziale prima del rilascio. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.

Questo articolo illustra come usare il middleware nelle app da riga di comando compilate con la libreria System.CommandLine. L'uso del middleware è un argomento avanzato che la maggior parte degli utenti System.CommandLine non dovrà considerare.

Introduzione al middleware

Anche se ogni comando dispone di un gestore che verrà indirizzato a System.CommandLine in base all'input, esiste anche un meccanismo che consente il corto circuito o la modifica dell'input prima che venga richiamata la logica dell'applicazione. Tra l'analisi e la chiamata, è presente una catena di responsabilità, che è possibile personalizzare. Serie di funzionalità predefinite di System.CommandLine per usare questa capacotà. Questo è il modo in cui le opzioni --help e --version cortocircuitano le chiamate al gestore.

Ogni chiamata nella pipeline può intervenire in base alle ParseResult e restituire in anticipo, oppure scegliere di chiamare l'elemento successivo nella pipeline. È anche possibile sostituire ParseResult durante questa fase. L'ultima chiamata della catena è quella del gestore per il comando specificato.

Aggiungere alla pipeline middleware

È possibile aggiungere una chiamata a questa pipeline tramite CommandLineBuilderExtensions.AddMiddleware. Di seguito è riportato un esempio di codice che abilita una direttiva personalizzata. Dopo aver creato un comando radice denominato rootCommand, come di consueto il codice aggiunge opzioni, argomenti e gestori. Viene quindi aggiunto il middleware:

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);

Nel codice precedente, il middleware scrive "Hi!" se viene trovata la direttiva [just-say-hi] nel risultato dell'analisi. In questo caso, il gestore normale del comando non viene richiamato. Ciò accade perché il middleware non chiama il delegato next.

Nell'esempio, context è InvocationContext, ovvero una struttura di database singolo che funge da "radice" dell'intero processo di gestione dei comandi. Si tratta della struttura più potente nel System.CommandLine, in termini di capacità. Gli usi principali di questo tipo di struttura nel middleware sono due:

  • Fornisce l'accesso a BindingContext, ParserConsole, e HelpBuilder per recuperare le dipendenze richieste da un middleware per la logica personalizzata.
  • È possibile impostare le proprietàInvocationResulto ExitCode per terminare l'elaborazione dei comandi in modo cortocircuitante. Un esempio è l'opzione --help, che viene implementata in questo modo.

Di seguito è riportato il programma completo, incluse le direttive using obbligatorie.

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}");
    }
}

Di seguito è riportato un esempio di riga di comando e l'output risultante dal codice precedente:

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

Vedi anche

System.CommandLine panoramica