LoginSignup
5
5

More than 3 years have passed since last update.

ConsoleAppFramework(旧MicroBatchFramework)(.NET Generic Host)でDIコンテナを差し替える(例としてUnity)

Last updated at Posted at 2019-04-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;
        }
    }

類似例

DryIocAutofacにもありました。

まとめ

ConsoleAppFrameworkを利用する前段としての汎用ホスト(.NET Generic Host)の話でした。
汎用ホスト(.NET Generic Host)の存在はまったく知らなかったのでもう少し新情報のアンテナを広げなければなと思いました。
それからConsoleAppFrameworkですがまだ少ししか触ってませんがとても良い感じです。

参考

5
5
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
5
5