コンテンツにスキップ

コンソールアプリケーションで DI を利用する⚓︎

概要⚓︎

コンソールアプリケーションでは、通常 Microsoft.Extensions.DependencyInjection を用いた DI を利用できません。 DI を利用するためには、汎用ホストを用いてコンソールアプリケーションを構築しなければなりません。 この実装は定型的なものが多いにも関わらず、デファクトスタンダードとなった OSS ライブラリは現在存在しません。

またコンソールアプリケーションでは、通常コマンドラインから起動パラメーターを設定できるように設計します。 .NET のコンソールアプリケーションプロジェクトでは、起動パラメーターをパースする機能が提供されておらず、何かしらの OSS ライブラリに依存する必要があります。

このサンプルでは、上記の課題を解決するためのコンソールアプリケーションのフレームワークを提供します。

簡易な実装サンプル⚓︎

このサンプルを利用すると、起動パラメーターをバインドするためのパラメータークラスと、アプリケーションの処理本体となるコマンドクラスを実装できます。 以下に実装サンプルを示します。 実装サンプルの全体像は、 サンプルアプリケーションをダウンロード して確認してください。

パラメータークラスの実装例
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
using CommandLine;
using Maris.ConsoleApp.Core;

namespace Maris.Samples.Cli.Commands.GetProductsByUnitPriceRange;

[Command("get-by-unit-price-range", typeof(Command))]
internal class Parameter
{
    [Option("minimum", Required = false)]
    public decimal? MinimumUnitPrice { get; set; }

    [Option("maximum", Required = false)]
    public decimal? MaximumUnitPrice { get; set; }
}
コマンドクラスの実装例
 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
using Maris.ConsoleApp.Core;
using Maris.Samples.ApplicationCore;
using Microsoft.Extensions.Logging;

namespace Maris.Samples.Cli.Commands.GetProductsByUnitPriceRange;

internal class Command : AsyncCommand<Parameter>
{
    private readonly ProductApplicationService service;
    private readonly ILogger logger;
    private readonly EventId Over10ProductsFoundInRange = new(1001, nameof(Over10ProductsFoundInRange));

    public Command(ProductApplicationService service, ILogger<Command> logger)
    {
        this.service = service ?? throw new ArgumentNullException(nameof(service));
        this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    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(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;
    }
}
コマンドラインからの実行例
1
Maris.Samples.Cli.exe get-by-unit-price-range --minimum 2000 --maximum 3000

フレームワークを用いたコンソールアプリケーションの開発方法⚓︎

詳細なフレームワークの使い方や開発方法については、 サンプルアプリケーション に付属する README.md を参照してください。

本サンプルで利用する代表的な OSS⚓︎

本サンプルでは以下の OSS ライブラリを使用しています。 他の OSS ライブラリについては、 サンプルアプリケーションをダウンロード して確認してください。

ダウンロード⚓︎

サンプルアプリケーションと詳細な解説は以下からダウンロードできます。