ConsoleAppFrameworkリリースしました!破壊的大変更でより便利に!なりました。 / “neue cc - ConsoleAppFramework - .NET Coreコンソールアプリ作成のためのマイクロフレームワーク(旧MicroBatchFramework)” https://t.co/CEXtQ4iJwp
— neuecc (@neuecc) January 9, 2020
とのことで記事修正しました。
#はじめに
たまたまツイッターのタイムラインを眺めていたら以下のツイートを拝見しました。
はてブ数的にはMicroBatchFrameworkがMagicOnionのリリース記事より超えてしまうやん……。なんか複雑……。 https://t.co/XZNr35rSOq
— neuecc (@neuecc) 2019年4月10日
ちょうどCLIを作成していたのでConsoleAppFrameworkを試したところ、DIコンテナの差替えではまったので投稿します。
この話はConsoleAppFrameworkではなくベースとなっている.NET Generic Hostのほうの話です。
#そもそも
詳細は@neueccさんのConsoleAppFrameworkの記事を読んでいただいたほうが早いのですが、ASP.NET Core 2.1で汎用ホスト(.NET Generic Host)なる機能が追加されていたそうです。
汎用ホスト(.NET Generic Host)はASP.NET Core 2.xですのでDependency Injectionを標準でサポートしています。
しかしながら標準のDIだとコンストラクタインジェクションしかできなかったり、IServiceProviderのGetServiceしか解決方法がなかったりとかゆいところに手が届きません。
そこでDIコンテナを差し替えることにしました。
#結論
using ConsoleAppFramework;
using Microsoft.Extensions.Hosting;
using Unity;
using Unity.Microsoft.DependencyInjection; // <-- 重要!
public static async Task Main(string[] args)
{
await Host.CreateDefaultBuilder()
.UseUnityServiceProvider() // <-- こっちが正解.
.ConfigureServices(services => {
services.AddSingleton<I~~Repository, ~~Repository>();
})
//.UseServiceProviderFactory<IUnityContainer>(new ServiceProviderFactory(new UnityContainer()))
//.ConfigureContainer<IUnityContainer>((hostContext, container) =>
//{
// container.RegisterType<I~~Repository, ~~Repository>();
// // 省略
//})
.RunConsoleAppFrameworkAsync<MainApp>(args);
}
大事なことはUnityをNugetする他にもUnity.Microsoft.DependencyInjectionをNugetすることです。
=> Unity.Microsoft.DependencyInjectionのGitHubに使い方書いていました。
利用する際はIServiceProviderをコンストラクタインジェクションしてIUnityContainerを呼び出してResolveします。
UseUnityServiceProviderを使用すればIUnityContainerをコンストラクタインジェクションできました。
public class MainApp : ConsoleAppBase
{
private I~~Repository ~~Repository { get; }
public MainApp(IServiceProvider provider)
: base()
{
var container = provider.GetService<IUnityContainer>();
~~Repository = container.Resolve<I~~Repository>();
}
}
public class MainApp : ConsoleAppBase
{
private I~~Repository ~~Repository { get; }
public MainApp(IUnityContainer _container)
: base()
{
~~Repository = _container.Resolve<I~~Repository>();
}
}
直接I~~Repositoryをコンストラクタインジェクション出来ればよかったんですけど駄目でした。
何か設定が足りないかも?
UseUnityServiceProviderを呼んだあとサービスとして登録(services.AddSingleton)してやればコンストラクタインジェクション出来ました。
public class MainApp : ConsoleAppBase
{
private I~~Repository ~~Repository { get; }
public MainApp(I~~Repository _~~Repository)
: base()
{
~~Repository = _~~Repository;
}
}
#まとめ
ConsoleAppFrameworkを利用する前段としての汎用ホスト(.NET Generic Host)の話でした。
汎用ホスト(.NET Generic Host)の存在はまったく知らなかったのでもう少し新情報のアンテナを広げなければなと思いました。
それからConsoleAppFrameworkですがまだ少ししか触ってませんがとても良い感じです。
#参考
- ConsoleAppFramework — Micro-framework for console applications, for C# .NET Core
- Microsoft.Extensions.DependencyInjection を使った DI の基本
- MicroBatchFramework – クラウドネイティブ時代のC#バッチフレームワーク
- Adding a custom dependency injection container in ASP.NET Core
- Use HostBuilder.ConfigureServices with DryIoc container?