如何在使用 AddCommandLine 后检索 args 数组

one*_*rth 6 command-line-parser .net-core

我正在为控制台应用程序开发 POC,在设置中使用 AddCommandLine 后,我正在努力从配置中检索命令行值。

工程项目

<PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>
Run Code Online (Sandbox Code Playgroud)

节目类

public static class Program
    {
        public static async Task Main(string[] args)
        {
            Log.Logger = new LoggerConfiguration()
            .Enrich.FromLogContext()
            .WriteTo.Console()
            .WriteTo.RollingFile("Logs//log.txt")
            .CreateLogger();

            await CreateHostBuilder(args)
                .Build()
                .RunAsync();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .UseSerilog()
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    config.AddJsonFile("settings.json", true, true);
                    config.AddCommandLine(args);
                })
                .ConfigureServices((hostcontext, services) =>
                {
                    services.AddHostedService<ConsoleApp>();
                });
    }
Run Code Online (Sandbox Code Playgroud)

控制台应用程序类

 public class ConsoleApp : IHostedService
    {
        private readonly IConfiguration config;
        private readonly ILogger<ConsoleApp> log;

        public ConsoleApp(IConfiguration configuration, ILogger<ConsoleApp> logger)
        {
            config = configuration;
            log = logger;
        }

        public Task StartAsync(CancellationToken cancellationToken)
        {
            var t = config.GetSection("Args");
            Parser.Default.ParseArguments<DeleteOptions>(t)
                .WithParsed<DeleteOptions>()
                .WithNotParsed();

            foreach (var c in config.AsEnumerable())
            {
                log.LogInformation($"{c.Key, -15}:{c.Value}");
            }


            log.LogInformation($"Completing Start Task");
            return Task.CompletedTask;
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            log.LogInformation($"Complete End Task");

            return Task.CompletedTask;
        }
    }
Run Code Online (Sandbox Code Playgroud)

foreach 循环之前的解析器部分不会编译,循环的输出不会打印出我添加的任何参数。

我知道一般建议是var someValue = Configuration.GetValue<int>("MySetting:SomeValue");参数所在的位置--MySetting=SomeValue是检索命令行值的推荐方法。

我用作参数的值是delete -e CI -t depchpolestar -l de-DE,当我查看我的配置对象时,我看到

在此输入图像描述

这就是为什么我认为该行var t = config.GetSection("Args");应该检索 args 数组。我也尝试过var t = config.GetValue<string[]>("Args");,但似乎都不起作用。在我看来,配置对象的索引 4 是一个以“Args”为键的字符串数组

如何检索字符串数组以便将其传递到 CommandLineParser 的 ParseArguments 方法中?

[编辑]一种解决方案:

我现在可以传递参数,但这不是一个特别好的方法;如果我将参数构造为--delete "-e CI -t depchpolestar -l de-DE"而不是delete -e CI -t depchpolestar -l de-DE将以下代码添加到 ConsoleApp 类中:

var args = config.GetValue<string>("delete");
            string[] arguments = null;
            if(!string.IsNullOrEmpty(args))
            {
                var tempArgs = args.Split(" ");
                arguments = new string[tempArgs.Length + 1];
                arguments[0] = "delete";
                for(int i = 0; i < tempArgs.Length; ++i)
                {
                    arguments[i + 1] = tempArgs[i];
                }
            }

            Parser.Default.ParseArguments<DeleteOptions>(arguments)
                .WithParsed<DeleteOptions>(async c => await c.Dowork())
                .WithNotParsed(HandleParseError);
Run Code Online (Sandbox Code Playgroud)

执行命中 DoWork 方法。很好,但DeleteOptions.cs 定义了一个动词,其目的是添加更多命令。所以还有更多的工作要做,但要走正确的路。

[编辑]我还意识到我不需要添加调用,AddCommandLine()因为它们是默认添加的。

one*_*rth 0

好吧,看来我把这个复杂化了,最终得到了这个:

public static class Program
{
    public static async Task Main(string[] args)
    {
        var builtHost = CreateHostBuilder(args).Build();

        var console = builtHost.Services.GetService<ConsoleApp>();
        await console.Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
         Host.CreateDefaultBuilder(args)
             .UseSerilog()
             .ConfigureAppConfiguration((hostingContext, config) =>
             {
                  config.AddJsonFile("settings.json", true, true);
                  config.AddCommandLine(args);
             })
             .ConfigureServices((hostcontext, services) =>
             {
                 services.AddTransient<ConsoleApp>();
             });
}
Run Code Online (Sandbox Code Playgroud)

这是 ConsoleApp 中的 run 方法:

public Task Run()
{
    while (true)
    {
       var input = ReadFromConsole();
       if (string.IsNullOrWhiteSpace(input))
       {
           continue;
       }
       else if (input.ToLower().Equals("exit"))
       {
           break;
       }
       else
       {
              Parser.Default.ParseArguments<DeleteOptions, ConcatOptions,   DownloadOptions, ReportOptions>(input.Split(" "))
                        .WithParsed<DeleteOptions>(async options => await options.DoWork())
                        .WithParsed<ConcatOptions>(async options => await options.DoWork())
                        .WithParsed<DownloadOptions>(async options => await options.DoWork())
                        .WithParsed<ReportOptions>(async options => await options.DoWork())
                        .WithNotParsed(HandleParseError);
        }
  }

  return Task.CompletedTask;
}
Run Code Online (Sandbox Code Playgroud)

这非常适合我将其用作交互式控制台应用程序。不过我的 DI 确实有问题。我创建了一个设置日志记录的 OptionsBase 类,并且我这样做是因为尝试向任何选项类添加参数失败,说明无法找到无参数构造函数。所以我假设 CommandLine 需要默认构造函数才能工作。按照我的方式获取记录器会给我多个日志文件,所以我需要解决这个问题。