使用 AddCommandLine 后如何检索 args 数组

How to retrieve the args array after using AddCommandLine

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

csproj

<PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

计划class

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

ConsoleApp class

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

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

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

我用作参数的值是 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 class:

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

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

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

好吧,看来我把这个复杂化了,结果是这样的:

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

这是 ConsoleApp 中的 运行 方法:

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

这让我可以将它用作交互式控制台应用程序,效果很好。不过,我确实对 DI 有疑问。我创建了一个 OptionsBase class 来设置日志记录,我这样做是因为尝试向任何 Options classes 添加参数失败,说明无法找到无参数构造函数。所以我假设 CommandLine 需要默认构造函数才能工作。按照我的方式获取记录器给了我多个日志文件,所以我需要修复它。