2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ConsoleAppFramework を使ったコンソールアプリケーションの作り方(2025/10)

Last updated at Posted at 2025-10-12

ConsoleAppFramework を使ったコンソールアプリケーションの作り方

このドキュメントは、.NET ConsoleAppFramework を使用してコンソールアプリケーションを開発するためのガイドです。
最初のプロジェクト作成から、DI(依存性注入)、設定ファイル、ロギングの統合までを段階的に説明しています。
開発者がモダンなコンソールアプリケーションを効率的に構築できるよう、実用的なサンプルコードとともに解説しています。

ConsoleAppFramework の説明 https://github.com/Cysharp/ConsoleAppFramework

前提条件

  • .NET 9.0
  • ConsoleAppFramework 5.6
  • DryIoc 6.2

最初のプロジェクトを作成する

プロジェクトを作成する

dotnet new console -n ConsoleApp1

以下の作業では ConsoleApp1 ディレクトリで作業するので移動する

cd ConsoleApp1

パッケージ ConsoleAppFramework をインストールする

dotnet add package ConsoleAppFramework

簡単なコマンドライン処理を実装する

Program.cs

using ConsoleAppFramework;

ConsoleApp.Run(args, (int x) =>
{
    Console.WriteLine($"Hello World! {x}");
});

実行例

PS ConsoleApp1> dotnet run -- --x 10          
Hello World! 10

コマンドクラスを自動登録して実行する

Commands/SampleCommand.cs

using ConsoleAppFramework;

namespace ConsoleAppFramework.Commands;

[RegisterCommands("sample")]
public class SampleCommand
{
    [Command("run")]
    public void Run(int x)
    {
        Console.WriteLine($"Hello World! {x}");
    }
}

Program.cs

using ConsoleAppFramework;

var app = ConsoleApp.Create();
app.Run(args);

古いバージョンでは SampleCommand : ConsoleAppBase のように基底クラスに ConsoleAppBase とかを使っていたようだけど、現在のバージョンでは不要になっている。

実行と結果

PS ConsoleApp1> dotnet run -- sample run --x 12
Hello World! 12

[RegisterCommands("sample")] がコマンド、 [Command("run")] がサブコマンドのように登録される。
機能が一個しかないようなコンソールアプリケーションでは過剰かもしれないけど後々色々追加するならこのやり方は便利。

設定ファイル、ロギング、DI を使えるようにする

Generic Host などを使う場合は以下のようにして 設定ファイル、ロギング、DIの設定をしていた

var host = Host.CreateDefaultBuilder(args)
        // Configurationの追加・上書き
        .ConfigureAppConfiguration((hostingContext, config) =>
        {
            config
                .AddJsonFile("appsettings.json")
                .AddJsonFile($"appsettings.{environment}.json", optional: true)
                .AddEnvironmentVariables();
        })
        // Loggingの設定
        .ConfigureLogging((hostingContext, logging) =>
        {
            logging.ClearProviders();
            logging.AddNConsole();
            logging.SetMinimumLevel(LogLevel.Information);
        })
        // DIコンテナにサービス登録
        .ConfigureServices((hostContext, services) =>
        {
            services.AddSingleton<IConfiguration>(hostContext.Configuration);
            services.AddDbContext<SampleDbContext>(options =>
            {
                options.UseSqlite(hostContext.Configuration.GetConnectionString("default"));
                options.UseLoggerFactory(new NLogLoggerFactory());
            })
            ;

        })
        .Build();

もちろんこのようにして Generic Host を使ってもいいのだけど、このために Generic Host を使うのも少々過剰気味ではあるので ServiceCollection -> ServiceProvider を使う。

パッケージを追加する

DI、設定、ロギングの基本コンポーネントをインストールする。

dotnet add package Microsoft.Extensions.DependencyInjection
dotnet add package Microsoft.Extensions.Configuration
dotnet add package Microsoft.Extensions.Configuration.Json
dotnet add package Microsoft.Extensions.Logging
dotnet add package Microsoft.Extensions.Logging.Console

設定ファイルを追加する

appsettings.json

{
    "SampleSettings": {
        "Setting1": "Value1",
        "Setting2": "Value2"
    }
}

ビルド時に出力ディレクトリに最新fileをコピーするようにしておく

ConsoleApp1.csporj

  <ItemGroup>
    <None Update="appsettings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>

DIによって注入されるサービスを実装する

サンプルのため、設定を受け取って出力するだけのサービス

using Microsoft.Extensions.Configuration;

namespace ConsoleApp1.Services;
public class SampleService
{
    IConfiguration _configuration;
    public SampleService(IConfiguration configuration)
    {
        _configuration = configuration;
    }
    public void Run()
    {
        var settingValue = _configuration["SampleSettings:Setting1"];
        Console.WriteLine($"SampleService Run: Setting1={settingValue}");
    }
}

コマンドがDI注入されたサービスを使えるようにする

コンストラクタで注入されたサービスを受け取るようにする。

using ConsoleApp1.Services;
using ConsoleAppFramework;
using Microsoft.Extensions.Logging;

namespace ConsoleAppFramework.Commands;

[RegisterCommands("sample")]
public class SampleCommand
{
    ILogger<SampleCommand> _logger;
    SampleService _service;
    public SampleCommand(SampleService service, ILogger<SampleCommand> logger)
    {
        _logger = logger;
        _logger.LogInformation("SampleCommand Constructor");
        _service = service;
    }
    [Command("run")]
    public void Run(int x)
    {
        _logger.LogInformation($"SampleCommand Run: {x}");
        _service.Run();

        _logger.LogInformation("SampleCommand Run End");
    }
}

設定、ロギング、DIを構成する

using ConsoleAppFramework;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Configuration;
using ConsoleApp1.Services;


// 設定ファイルの読み込み
var configuration = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", optional: true)
    .Build();

// DI、ロギングの設定
var services = new ServiceCollection()
    .AddSingleton<IConfiguration>(configuration)
    .AddLogging(builder =>
    {
        builder.ClearProviders();
        builder.AddConsole();
    })
   ;
// サービスの登録
services.AddTransient<SampleService>();

ConsoleApp.ServiceProvider = services.BuildServiceProvider();
var app = ConsoleApp.Create();
app.Run(args);

実行例

PS ConsoleApp1> dotnet run -- sample run --x 12
info: ConsoleAppFramework.Commands.SampleCommand[0]
      SampleCommand Constructor
info: ConsoleAppFramework.Commands.SampleCommand[0]
      SampleCommand Run: 12
info: ConsoleApp1.Services.SampleService[0]
      SampleService Run: Setting1=Value1
info: ConsoleAppFramework.Commands.SampleCommand[0]
      SampleCommand Run End

DryIoc と統合する

デコレーターやAOPを使いたいなら Microsoft.Extensions.DependencyInjection だけでは少々力不足なので DryIocなど外部のDIコンテナを使う。

DryIoc パッケージをインストールする

 dotnet add package DryIoc.Microsoft.DependencyInjection

コンテナを構成する

using DryIoc.Microsoft.DependencyInjection;
// DryIoc コンテナの生成
var container = new DryIoc.Container(rules => rules.With(propertiesAndFields: PropertiesAndFields.Auto))
    .WithDependencyInjectionAdapter(services);
container.Register<SampleService>();

ConsoleApp が DryIoc のコンテナを使うようにする

ConsoleApp.ServiceProvider = container.BuildServiceProvider();

統合した結果の Program.cs

using ConsoleAppFramework;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Configuration;
using ConsoleApp1.Services;
using DryIoc;
using DryIoc.Microsoft.DependencyInjection;

// 設定ファイルの読み込み
var configuration = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", optional: true)
    .Build();

// DI、ロギングの設定
var services = new ServiceCollection()
    .AddSingleton<IConfiguration>(configuration)
    .AddLogging(builder =>
    {
        builder.ClearProviders();
        builder.AddConsole();
    })
   ;

// DryIoc コンテナの生成
var container = new DryIoc.Container(rules => rules.With(propertiesAndFields: PropertiesAndFields.Auto))
    .WithDependencyInjectionAdapter(services);
container.Register<SampleService>();


ConsoleApp.ServiceProvider = container.BuildServiceProvider();
var app = ConsoleApp.Create();
app.Run(args);

応用

  • Microsoft.Extensions.DependencyInjection が使えるということは IServiceProvider が使えるDIコンテナが使えるということ。例えば DryIoc
  • コマンド実行フィルターはコマンドの実行前後に処理を挟める。例えばコマンド実行開始・終了のログなど。

    その他

サンプルコード

ConsoleAppFramework のドキュメントに ConsoleApp.Create().ConfigureServices() みたいなサンプルが書かれていて、これをもとにDryIocとかはめ込めばいいじゃんとか思っていたらサービスも注入されないしアスペクトも使えないし何なのこれ、ConsoleApp.Services = container.BuildServiceProvider() みたいにしてもダメだし、とか思ってたけど単純に ConsoleAppBuilder.ConfigureService とか使わなくても済むことがだいぶたってから分かった。ドキュメントを読むべし、とは言うけどチェリーピックだとよくわからなくなる。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?