【C#】CoconaでMicrosoft.Extensions.DependencyInjectionを用いてDIを行う方法 (original) (raw)

やり方

下準備

まずは雑にそれっぽいファイルを用意しました。

$ tree . ├── Command │   └── UserCommand.cs ├── DI │   └── ServiceConfigurator.cs ├── Domain │   └── IUserRepository.cs ├── Infrastructure │   └── UserRepository.cs ├── Program.cs ├── UseCase    └── UserUseCase.cs

public interface IUserRepository { int Add(string name); }

public class UserRepository(ILogger logger) : IUserRepository { private readonly ILogger _logger = logger;

private readonly Dictionary<int, string> _users = new();

public int Add(string name)
{
    var id = _users.Count + 1;
    _users.Add(id, name);
    _logger.LogDebug("Added {name} with id {id}", name, id);
    return id;
}

}

public interface IUserUseCase { void AddPerson(string name); }

public class UserUseCase(IUserRepository userRepository, ILogger logger) : IUserUseCase { public void AddPerson(string name) { userRepository.Add(name); logger.LogDebug("Added {name}", name); } }

それぞれ以下の対応で依存性注入を行ってほしいとします。

CoconaAppBuilderで設定を行う

public class ServiceConfigurator(CoconaAppBuilder builder) { public void Configure() {

    builder.Logging.AddConsole();
    
    
    builder.Services
        .AddSingleton<IUserRepository, UserRepository>()
        .AddSingleton<IUserUseCase, UserUseCase>();
    
    
}

}

Microsoft.Extensions.DependencyInjectionの詳細の使い方はここでは説明しませんが、CoconaAppBuilder.Services(IServiceCollection)からDIコンテナに設定を行います。
依存関係の挿入を使用する - .NET | Microsoft Learn

builder.Services.AddSingleton<ISomeClient, SomeClient>();

CoconaAppBuilder.LoggingAddConsoleAddJsonConsoleなどを利用することでILoggerでどのように出力するのか設定することができます。このあたりはMicrosoft.Extensions.Loggingを参照してください。
【C#】MS製のLoggingライブラリである「Microsoft.Extensions.Logging」の基礎的な使い方 - はなちるのマイノート

builder.Logging.AddConsole();

また出力するログレベルの設定もできたりします。

builder.Logging.SetMinimumLevel(LogLevel.Debug);

コンストラクタに渡す値を設定したい場合は、引数にラムダ式を渡します。IServiceProviderを用いるとDIコンテナに登録されているインスタンスを取得することができます。

builder.Services .AddSingleton(sp => new UserRepository(sp.GetRequiredService<ILogger>()));

コマンド作成

CoconaApp.AddCommandによるコマンド登録ですが、[FromService]を付与しなくても自動でCoconaが渡してくれます。少し古い? class-based styleのときは[FromService]が必要だったのですが、今はいらないようです。まあ分かりづらいのであっても悪くはない気もしますが。

public class UserCommand(CoconaApp app) { public void AddCommand() {

    app.AddCommand("add",(string name, IUserUseCase userUseCase, ILogger<UserCommand> logger) =>
    {
        userUseCase.AddPerson(name);
        logger.LogInformation("Added: " + name);
    });
}

}

エントリポイント作成

一応今回は細かくファイルを分けたので、それらを呼び出してあげます。

var builder = CoconaApp.CreateBuilder();

new ServiceConfigurator(builder).Configure();

var app = builder.Build();

new UserCommand(app).AddCommand();

app.Run();

あとがき

CoconaはMicrosoft.Extensions.DependencyInjection + Microsoft.Extensions.Logging + Microsoft.Extensions.Hostingがデフォルトで入っています。
github.com

それぞれ多少学習コストはあるものの、使ってみるとかなり便利なので是非有効活用してみてください。

またそれらMicrosoft.Extensions.*を入れないCocona.Liteも一応用意されています。
www.nuget.org