コンソールアプリケーションで DI を利用する 概要 コンソールアプリケーションでは、通常 Microsoft.Extensions.DependencyInjection を用いた DI を利用できません。 DI を利用するためには、汎用ホストを用いてコンソールアプリケーションを構築しなければなりません。 この実装は定型的なものが多いにも関わらず、デファクトスタンダードとなった OSS ライブラリは現在存在しません。
またコンソールアプリケーションでは、通常コマンドラインから起動パラメーターを設定できるように設計します。 .NET のコンソールアプリケーションプロジェクトでは、起動パラメーターをパースする機能が提供されておらず、何かしらの OSS ライブラリに依存する必要があります。
このサンプルでは、上記の課題を解決するためのコンソールアプリケーションのフレームワークを提供します。
簡易な実装サンプル このサンプルを利用すると、起動パラメーターをバインドするためのパラメータークラスと、アプリケーションの処理本体となるコマンドクラスを実装できます。 以下に実装サンプルを示します。 実装サンプルの全体像は、 サンプルアプリケーションをダウンロード して確認してください。
サンプルアプリケーションにおけるパラメータークラスの実装例 Parameter.cs 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 using CommandLine ;
using Maris.ConsoleApp.Core ;
namespace Maris.Samples.Cli.Commands.GetProductsByUnitPriceRange ;
/// <summary>
/// 単価の範囲を検索キーにして商品情報を取得するコマンドのパラメーターです。
/// </summary>
[Command("get-by-unit-price-range", typeof(Command), HelpText = "単価の範囲内の商品情報を取得します。")]
internal class Parameter
{
/// <summary>
/// 単価の最小値を取得または設定します。
/// </summary>
[Option("minimum", Required = false, HelpText = "検索範囲の単価の最小値を指定します。")]
public decimal? MinimumUnitPrice { get ; set ; }
/// <summary>
/// 単価の最大値を取得または設定します。
/// </summary>
[Option("maximum", Required = false, HelpText = "検索範囲の単価の最大値を指定します。")]
public decimal? MaximumUnitPrice { get ; set ; }
}
サンプルアプリケーションにおけるコマンドクラスの実装例 Command.cs 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58 using Maris.ConsoleApp.Core ;
using Maris.Samples.ApplicationCore ;
using Microsoft.Extensions.Logging ;
namespace Maris.Samples.Cli.Commands.GetProductsByUnitPriceRange ;
/// <summary>
/// 単価の範囲を検索キーにして商品情報を取得する非同期コマンドです。
/// </summary>
internal class Command : AsyncCommand < Parameter >
{
private readonly ProductApplicationService service ;
private readonly ILogger logger ;
/// <summary>
/// <see cref="Command"/> クラスの新しいインスタンスを初期化します。
/// </summary>
/// <param name="service">商品情報を取り扱うアプリケーションサービス。</param>
/// <param name="logger">ロガー。</param>
/// <exception cref="ArgumentNullException">
/// <list type="bullet">
/// <item><paramref name="service"/> が <see langword="null"/> です。</item>
/// <item><paramref name="logger"/> が <see langword="null"/> です。</item>
/// </list>
/// </exception>
public Command ( ProductApplicationService service , ILogger < Command > logger )
{
this . service = service ?? throw new ArgumentNullException ( nameof ( service ));
this . logger = logger ?? throw new ArgumentNullException ( nameof ( logger ));
}
/// <summary>
/// パラメーターに指定した単価の範囲を検索条件にして商品情報の一覧を取得し、コンソールに出力します。
/// </summary>
/// <param name="parameter">パラメーター。</param>
/// <param name="cancellationToken">キャンセルトークン。</param>
/// <returns>コマンドの実行結果。</returns>
protected override async Task < ICommandResult > ExecuteAsync (
Parameter parameter , CancellationToken cancellationToken )
{
var products = await this . service . GetProductsByUnitPriceRangeAsync (
parameter . MinimumUnitPrice , parameter . MaximumUnitPrice , cancellationToken );
if ( products . Count >= 10 )
{
this . logger . LogWarning ( Events . Over10ProductsFoundInRange , $"単価が {parameter.MinimumUnitPrice} ~ " +
$"{parameter.MaximumUnitPrice} の商品情報が 10 件以上あります。" +
$"範囲を絞り込んでください。" );
return CommandResult . CreateWarning ( 2 );
}
foreach ( var product in products )
{
Console . WriteLine ( $"{product.Id,3} : {product.Name} {product.UnitPrice,7}円" );
}
return CommandResult . Success ;
}
}
コマンドラインからの実行例 Maris.Samples.Cli.exe get-by-unit-price-range --minimum 2000 --maximum 3000
フレームワークを用いたコンソールアプリケーションの開発方法 詳細なフレームワークの使い方や開発方法については、 サンプルアプリケーション に付属する README.md を参照してください。
本サンプルで利用する代表的な OSS 本サンプルでは以下の OSS ライブラリを使用しています。 他の OSS ライブラリについては、 サンプルアプリケーションをダウンロード して確認してください。
コンソールアプリケーションのフレームワーク本体
テストプロジェクト
ダウンロード サンプルアプリケーションと詳細な解説は以下からダウンロードできます。