Como usar middleware no System.CommandLine
Importante
Atualmente, System.CommandLine
está em VERSÃO PRÉVIA, e essa documentação é para a versão 2.0 beta 4.
Algumas informações estão relacionadas a produtos de pré-lançamento que poderão ser substancialmente modificados antes do lançamento. A Microsoft não oferece garantias, expressas ou implícitas, das informações aqui fornecidas.
Este artigo explica como trabalhar com middleware em aplicativos de linha de comando criados com a biblioteca System.CommandLine
. O uso de middleware é um tópico avançado que a maioria dos usuários System.CommandLine
não precisa considerar.
Introdução ao middleware
Embora cada comando tenha um manipulador para o qual System.CommandLine
roteará com base na entrada, há também um mecanismo para curto-circuitar ou alterar a entrada antes que a lógica do aplicativo seja invocada. Entre a análise e a invocação, há uma cadeia de responsabilidade, que você pode personalizar. Vários recursos integrados de System.CommandLine
fazem uso desse recurso. É assim que as opções --help
e --version
fazem chamadas de curto-circuito para seu manipulador.
Cada chamada no pipeline pode realizar uma ação com base em ParseResult e retornar antecipadamente ou optar por chamar o próximo item no pipeline. ParseResult
pode até ser substituído durante esta fase. A última chamada na cadeia é o manipulador do comando especificado.
Adicionar ao pipeline de middleware
Você pode adicionar uma chamada a este pipeline chamando CommandLineBuilderExtensions.AddMiddleware. Aqui está um exemplo de código que habilita uma diretiva personalizada. Depois de criar um comando raiz chamado rootCommand
, o código normalmente adiciona opções, argumentos e manipuladores. Em seguida, o middleware é adicionado:
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);
No código anterior, o middleware escreve "Oi!" se a diretiva [just-say-hi]
for encontrada no resultado da análise. Quando isso acontece, o manipulador normal do comando não é invocado. Ele não é invocado porque o middleware não chama o delegado next
.
No exemplo, context
é InvocationContext, uma estrutura singleton que atua como a "raiz" de todo o processo de manipulação de comandos. Esta é a estrutura mais poderosa em System.CommandLine
, em termos de recursos. Há dois usos principais para ele no middleware:
- Ele fornece acesso a BindingContext, Parser, Console e HelpBuilder para recuperar dependências que um middleware requer para sua lógica customizada.
- Você pode definir as propriedades InvocationResult ou ExitCode para encerrar o processamento do comando em curto-circuito. Um exemplo é a opção
--help
, que é implementada dessa maneira.
Aqui está o programa completo, incluindo as diretivas using
obrigatórias.
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}");
}
}
Aqui está um exemplo de linha de comando e a saída resultante do código anterior:
myapp [just-say-hi] --delay 42 --message "Hello world!"
Hi!