Как получить массив args после использования AddCommandLine - PullRequest
0 голосов
/ 23 января 2020

Я работаю над ПО C для консольного приложения и пытаюсь получить значения командной строки из конфигурации после использования 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 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;
        }
    }

Раздел Parser перед foreach l oop не компилируется, а вывод l oop не выводит ни одного из добавленных мною аргументов.

Мне известен общий совет, что var someValue = Configuration.GetValue<int>("MySetting:SomeValue");, где аргумент --MySetting=SomeValue - это рекомендуемый способ получения значений строки cmd.

Значения, которые я использую в качестве параметров, delete -e CI -t depchpolestar -l de-DE, и когда я смотрю на свой объект конфигурации, я вижу

enter image description here

, поэтому я думаю, что строка var t = config.GetSection("Args"); должна получить массив args. Я также попробовал var t = config.GetValue<string[]>("Args");, но ни один из них не работает. Мне кажется, что индекс 4 объекта конфигурации - это строковый массив с ключом «Args»

Как мне получить массив строк, чтобы я мог передать его в метод ParseArguments CommandLineParser?

[ Править] Одно решение:

Теперь я могу передать аргументы, но это не очень хороший подход; Если я создаю аргумент как --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 определяет глагол, и намерение состоит в том, чтобы добавить больше команд. Так что больше работы, но идти в правильном направлении.

[Edit] Я также понял, что мне не нужно добавлять вызов AddCommandLine(), поскольку они добавляются по умолчанию.

1 Ответ

0 голосов
/ 31 января 2020

хорошо, мне показалось, что я слишком усложнил это и закончил с этим:

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 требует конструкторов по умолчанию для работы. Получение регистратора, как у меня, дает мне несколько файлов журнала, поэтому мне нужно это исправить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...