3

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

csproj

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

节目班

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 类

 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 循环之前的 Parser 部分无法编译,并且循环的输出不会打印出我添加的任何参数。

我知道一般建议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 类:

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()调用,因为它们是默认添加的。

4

1 回答 1

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

这作为 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 类,并且我已经这样做了,因为尝试向任何 Options 类添加参数失败,说明无法找到无参数构造函数。所以我假设 CommandLine 需要默认构造函数才能工作。以我的方式获取记录器会给我多个日志文件,所以我需要修复它。

于 2020-01-31T12:40:51.280 回答