Поделиться через


Настройка внедрения зависимостей в System.CommandLine

Внимание

System.CommandLine в настоящее время находится в предварительной версии, и эта документация предназначена для версии 2.0 бета-версии 4. Некоторые сведения относятся к предварительному выпуску продукта, который может быть существенно изменен до его выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.

Используйте пользовательский привязчик для внедрения пользовательских типов в обработчик команд.

Мы рекомендуем внедрение зависимостей для определенных обработчиков (DI) по следующим причинам:

  • Приложения командной строки часто являются короткими процессами, в которых затраты на запуск могут оказать заметное влияние на производительность. Оптимизация производительности особенно важна при вычислении завершения вкладок. Приложения командной строки отличаются от веб-приложений и графических интерфейсов, которые, как правило, являются относительно длительными процессами. Ненужное время запуска не подходит для кратковременных процессов.
  • Когда выполняется приложение командной строки с несколькими вложенными командами, будет выполнено только одно из этих вложенных команд. Если приложение настраивает зависимости для вложенных команд, которые не выполняются, он не обязательно снижает производительность.

Чтобы настроить di, создайте класс, производный от BinderBase<T> того, где T находится интерфейс, для которого требуется внедрить экземпляр. GetBoundValue В переопределении метода получите и верните экземпляр, который требуется внедрить. В следующем примере реализована реализация средства ведения журнала по умолчанию для 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;
    }
}

При вызове SetHandler метода передайте лямбда-экземпляр внедренного класса и передайте экземпляр класса binder в списке служб:

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

Следующий код представляет собой полную программу, содержащую предыдущие примеры:

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

См. также

Обзор System.CommandLine