Help us understand the problem. What is going on with this article?

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

とのことで記事修正しました。

はじめに

たまたまツイッターのタイムラインを眺めていたら以下のツイートを拝見しました。

ちょうど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ですがまだ少ししか触ってませんがとても良い感じです。

参考

kwhrkzk
業務系に従事。WPF,PRISM,C#,F#,.NET Core,Laravel,Vue,TypeScript,DDD,CQRS,SOLIDらへんに興味有。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away