Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9314

基本的なコンソールアプリケーションの構造 2021年版

$
0
0
かつてはコマンドライン引数の解析も自前でやる必要があったりログ出力も苦労して作ってたりするけど、今時はそういうパッケージがあるのでガンガン利用すべし。 というわけで今時のコンソールアプリを作るための初期構造。 使うパッケージ <ItemGroup> <PackageReference Include="DryIoc.Microsoft.DependencyInjection" Version="5.1.0" /> <PackageReference Include="Microsoft.Extensions.Configuration" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.1" /> <PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="5.0.0" /> <PackageReference Include="NLog.Extensions.Logging" Version="1.7.2" /> <PackageReference Include="System.CommandLine" Version="2.0.0-beta1.21216.1" /> </ItemGroup> ログ出力 NLog DI DryIoc コマンドライン解析 System.CommandLine System.CommandLine はまだプレビュー版だけれども自前で解析するよりまし。 GenericHost 使わないのはバッチ処理とかちょっとしたコマンドとかには過剰なので。 コード program.cs using DryIoc; using DryIoc.Microsoft.DependencyInjection; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using NLog.Extensions.Logging; using System; using System.CommandLine; using System.CommandLine.Invocation; using System.IO; using System.Threading.Tasks; class Program { static IServiceProvider serviceProvider; static async Task<int> Main(string[] args) { serviceProvider = BuildServiceProvider(BuildConfiguration()); var rootCommand = BuildCommand(); return await rootCommand.InvokeAsync(args); } static IConfigurationRoot BuildConfiguration() { return new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile(path: "appsettings.json") .Build(); } static IServiceProvider BuildServiceProvider(IConfigurationRoot configuration) { var services = new ServiceCollection(); services.Configure<SampleSettings>(configuration.GetSection("SampleSettings")); services.AddLogging(loggingBuilder => { loggingBuilder.ClearProviders(); loggingBuilder.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace); loggingBuilder.AddNLog(); }); var container = new DryIoc.Container(rules => rules.With()).WithDependencyInjectionAdapter(services); container.Register<ISampleService, SampleService>(reuse: Reuse.Scoped); return container.BuildServiceProvider(); } static RootCommand BuildCommand() { var rootCommand = new RootCommand(); rootCommand.Description = "console app sample"; rootCommand.AddOption(new Option<string>(aliases: new string[] { "--name", "-n" })); rootCommand.AddOption(new Option<string>(aliases: new string[] { "--value", "-v" })); rootCommand.Handler = CommandHandler.Create<ConsoleAppOptions>(options => { ExecuteCommand(options); }); return rootCommand; } static void ExecuteCommand(ConsoleAppOptions options) { using(var scope = serviceProvider.CreateScope()) { var service = scope.ServiceProvider.GetRequiredService<ISampleService>(); service.DoSomething(options); } } } Service // interface interface ISampleService { void DoSomething(ConsoleAppOptions options); } // implementation using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; public class SampleService : ISampleService { private readonly SampleSettings sampleSettings; private readonly ILogger<SampleService> logger; public SampleService(IOptions<SampleSettings> settings, ILogger<SampleService> logger) { this.sampleSettings = settings.Value; this.logger = logger; } public void DoSomething(ConsoleAppOptions options) { logger.LogTrace($"execute {nameof(DoSomething)}"); logger.LogTrace($"options {nameof(options.Name)} {options.Name}"); logger.LogTrace($"options {nameof(options.Value)} {options.Value}"); logger.LogTrace($"settings {nameof(sampleSettings.Id)} {sampleSettings.Id}"); logger.LogTrace($"settings {nameof(sampleSettings.Name)} {sampleSettings.Name}"); } } コマンドラインオプション public class ConsoleAppOptions { public string Name { get; set; } public string Value { get; set; } } 設定ファイルマッピングクラス public class SampleSettings { public int Id { get; set; } public string Name { get; set; } } 設定ファイル { "Logging": { "LogLevel": { "Default": "Error", "Microsoft": "Trace" } }, "SampleSettings": { "Id": 1, "Name": "name" } } json 設定ファイルの読み込みやらDI設定やらコマンドライン解析やら、だいたいこんな感じ。 実行 [ConsoleAppSample] > dotnet run --name 111 --value 222 [TRACE] [1] ConsoleAppSample.SampleService.DoSomething#19 execute DoSomething [TRACE] [1] ConsoleAppSample.SampleService.DoSomething#20 options Name 111 [TRACE] [1] ConsoleAppSample.SampleService.DoSomething#21 options Value 222 [TRACE] [1] ConsoleAppSample.SampleService.DoSomething#22 settings Id 1 [TRACE] [1] ConsoleAppSample.SampleService.DoSomething#23 settings Name name 設定ファイルの内容とコマンドライン引数はそれぞれのクラスにマッピングされる。 その他 `git log' みたいなコマンドのコマンドとかRootCommandにCommandを追加すればよい。 DIはAutofacでもDryIocでも Unity Container でも何でもよい。最終的には Microsoft.Extensions.DependencyInjection を通して使う。 参考 System.CommandLine https://docs.microsoft.com/ja-jp/archive/msdn-magazine/2019/march/net-parse-the-command-line-with-system-commandline DryIoc https://github.com/dadhi/DryIoc NLog https://nlog-project.org/

Viewing all articles
Browse latest Browse all 9314

Latest Images

Trending Articles