使用 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 需要默认构造函数才能工作。按照我的方式获取记录器给了我多个日志文件,所以我需要修复它。
我正在为控制台应用程序开发 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 需要默认构造函数才能工作。按照我的方式获取记录器给了我多个日志文件,所以我需要修复它。