Información sobre cómo configurar la inserción de dependencias 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í.
Use un enlazador personalizado para insertar tipos personalizados en un controlador de comandos.
Se recomienda la inserción de dependencias (DI) específica del controlador por los siguientes motivos:
- Las aplicaciones de línea de comandos suelen ser procesos de corta duración, en los que el coste de inicio puede tener un impacto notable en el rendimiento. La optimización del rendimiento es especialmente importante cuando se deben calcular las finalizaciones de pestañas. Las aplicaciones de línea de comandos no son similares a las aplicaciones web y de interfaz gráfica de usuario, que tienden a ser procesos de duración relativamente larga. El tiempo de inicio innecesario no es adecuado para los procesos de corta duración.
- Cuando se ejecuta una aplicación de línea de comandos que tiene varios subcomandos, solo se ejecutará uno de esos subcomandos. Si una aplicación configura dependencias de subcomandos que no se ejecutan, el rendimiento se ve reducido de forma innecesaria.
Para configurar la inserción de dependencias, cree una clase que se derive de BinderBase<T>, donde T
es la interfaz para la que desea insertar una instancia. En la invalidación del método GetBoundValue, obtenga y devuelva la instancia que desea insertar. En el ejemplo siguiente se inserta la implementación predeterminada del registrador para ILogger:
public class MyCustomBinder : BinderBase<ILogger>
{
protected override ILogger GetBoundValue(
BindingContext bindingContext) => GetLogger(bindingContext);
ILogger GetLogger(BindingContext bindingContext)
{
using ILoggerFactory loggerFactory = LoggerFactory.Create(
builder => builder.AddConsole());
ILogger logger = loggerFactory.CreateLogger("LoggerCategory");
return logger;
}
}
Al llamar al método SetHandler, pase a la expresión lambda una instancia de la clase insertada y pase una instancia de la clase del enlazador en la lista de servicios:
rootCommand.SetHandler(async (fileOptionValue, logger) =>
{
await DoRootCommand(fileOptionValue!, logger);
},
fileOption, new MyCustomBinder());
El código siguiente es un programa completo que contiene los ejemplos anteriores:
using System.CommandLine;
using System.CommandLine.Binding;
using Microsoft.Extensions.Logging;
class Program
{
static async Task Main(string[] args)
{
var fileOption = new Option<FileInfo?>(
name: "--file",
description: "An option whose argument is parsed as a FileInfo");
var rootCommand = new RootCommand("Dependency Injection sample");
rootCommand.Add(fileOption);
rootCommand.SetHandler(async (fileOptionValue, logger) =>
{
await DoRootCommand(fileOptionValue!, logger);
},
fileOption, new MyCustomBinder());
await rootCommand.InvokeAsync("--file scl.runtimeconfig.json");
}
public static async Task DoRootCommand(FileInfo aFile, ILogger logger)
{
Console.WriteLine($"File = {aFile?.FullName}");
logger.LogCritical("Test message");
await Task.Delay(1000);
}
public class MyCustomBinder : BinderBase<ILogger>
{
protected override ILogger GetBoundValue(
BindingContext bindingContext) => GetLogger(bindingContext);
ILogger GetLogger(BindingContext bindingContext)
{
using ILoggerFactory loggerFactory = LoggerFactory.Create(
builder => builder.AddConsole());
ILogger logger = loggerFactory.CreateLogger("LoggerCategory");
return logger;
}
}
}