Compartir a través de


Procedimiento para usar middleware en System.CommandLine

Importante

System.CommandLine se encuentra actualmente en versión preliminar y esta documentación es para la versión 2.0 beta 4. Parte de la información hace referencia a la versión preliminar del producto, que puede haberse modificado sustancialmente antes de lanzar la versión definitiva. Microsoft no otorga ninguna garantía, explícita o implícita, con respecto a la información proporcionada aquí.

En este artículo se explica cómo trabajar con middleware en aplicaciones de línea de comandos compiladas con la biblioteca System.CommandLine. El uso de middleware es un tema avanzado que la mayoría de los usuarios de System.CommandLine no debe tener en cuenta.

Introducción al middleware

Aunque cada comando tiene un controlador al que System.CommandLine se enruta en función de la entrada, también hay un mecanismo para cortocircuitar o modificar la entrada antes de invocar a la lógica de la aplicación. Entre el análisis y la invocación, hay una cadena de responsabilidad que se puede personalizar. Varias características integradas de System.CommandLine usan esta capacidad. Así es como las opciones --help y --version cortocircuitan las llamadas al controlador.

Cada llamada de la canalización puede actuar en función de ParseResult y devolver con anticipación, u optar por llamar al siguiente elemento de la canalización. ParseResult incluso se puede reemplazar durante esta fase. La última llamada de la cadena es el controlador del comando especificado.

Incorporación a la canalización de middleware

Puede agregar una llamada a esta canalización si llama a CommandLineBuilderExtensions.AddMiddleware. Este es un ejemplo de código que habilita una directiva personalizada. Después de crear un comando raíz de nombre rootCommand, el código, como de costumbre, agrega opciones, argumentos y controladores. Luego se agrega el 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);

En el código anterior, el middleware escribe "Hi!" si la directiva [just-say-hi] se encuentra en el resultado del análisis. Cuando sucede esto, no se invoca al controlador normal del comando. No se invoca porque el middleware no llama al delegado next.

En el ejemplo, context es InvocationContext, una estructura singleton que actúa como la "raíz" de todo el proceso de control de comandos. Esta es la estructura más eficaz de System.CommandLine en términos de capacidades. Tiene dos usos principales en el middleware:

  • Proporciona acceso a BindingContext, Parser, Console y HelpBuilder para recuperar dependencias que un middleware necesita para su lógica personalizada.
  • Puede establecer las propiedades InvocationResult o ExitCode para finalizar el procesamiento de comandos en forma de cortocircuito. Un ejemplo es la opción --help, que se implementa de esta manera.

Este es el programa completo, incluidas las directivas using necesarias.

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

Esta es una línea de comandos de ejemplo y la salida resultante del código anterior:

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

Vea también

Información general de System.CommandLine