Konfigurieren der Abhängigkeitsinjektion in System.CommandLine

Wichtig

System.CommandLine befindet sich derzeit in der VORSCHAU, und diese Dokumentation gilt für Version 2.0 Beta 4. Einige Informationen beziehen sich auf Vorabversionen des Produkts, die vor dem Release ggf. grundlegend überarbeitet werden. Microsoft übernimmt hinsichtlich der hier bereitgestellten Informationen keine Gewährleistungen, seien sie ausdrücklich oder konkludent.

Verwenden Sie einen benutzerdefinierten Ordner, um benutzerdefinierte Typen in einen Befehlshandler einzufügen.

Aus den folgenden Gründen wird die handlerspezifische Abhängigkeitsinjektion (DI) empfohlen:

  • Befehlszeilen-Apps sind häufig kurzlebige Prozesse, bei denen die Startkosten spürbare Auswirkungen auf die Leistung haben können. Die Optimierung der Leistung ist besonders wichtig, wenn Tabstoppabschlusse berechnet werden müssen. Befehlszeilen-Apps sind im Gegensatz zu Web- und GUI-Apps, die tendenziell relativ langlebige Prozesse sind. Unnötige Startzeit ist für kurzlebige Prozesse nicht geeignet.
  • Wenn eine Befehlszeilen-App mit mehreren Unterbefehlen ausgeführt wird, wird nur eine dieser Unterbefehle ausgeführt. Wenn eine App Abhängigkeiten für die nicht ausgeführten Unterbefehle konfiguriert, beeinträchtigt sie die Leistung unnötig.

Um DI zu konfigurieren, erstellen Sie eine Klasse, die von BinderBase<T> abgeleitet wird, wobei T die Schnittstelle ist, für die Sie eine Instanz einfügen möchten. Rufen Sie in der GetBoundValue-Methodenüberschreibung die Instanz ab, die Sie einfügen möchten, und geben Sie sie zurück. Im folgenden Beispiel wird die Standardprotokollierungsimplementierung für ILogger injiziert:

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

Übergeben Sie beim Aufrufen der SetHandler-Methode an die Lambda-Funktion eine Instanz der injizierten Klasse, und übergeben Sie eine Instanz Ihrer Ordnerklasse in der Liste der Dienste:

rootCommand.SetHandler(async (fileOptionValue, logger) =>
    {
        await DoRootCommand(fileOptionValue!, logger);
    },
    fileOption, new MyCustomBinder());

Der folgende Code ist ein vollständiges Programm, das die vorherigen Beispiele enthält:

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

Weitere Informationen

System.CommandLine – Übersicht