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


<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ConsoleAppFrameworkリリースしました！破壊的大変更でより便利に！なりました。 / “neue cc - ConsoleAppFramework - .NET Coreコンソールアプリ作成のためのマイクロフレームワーク（旧MicroBatchFramework)” <a href="https://t.co/CEXtQ4iJwp">https://t.co/CEXtQ4iJwp</a></p>&mdash; neuecc (@neuecc) <a href="https://twitter.com/neuecc/status/1215183642814664705?ref_src=twsrc%5Etfw">January 9, 2020</a></blockquote> 

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


#はじめに

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

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">はてブ数的にはMicroBatchFrameworkがMagicOnionのリリース記事より超えてしまうやん……。なんか複雑……。 <a href="https://t.co/XZNr35rSOq">https://t.co/XZNr35rSOq</a></p>&mdash; neuecc (@neuecc) <a href="https://twitter.com/neuecc/status/1115773305980510208?ref_src=twsrc%5Etfw">2019年4月10日</a></blockquote>


ちょうどCLIを作成していたので[ConsoleAppFramework][]を試したところ、DIコンテナの差替えではまったので投稿します。
この話は[ConsoleAppFramework][]ではなくベースとなっている[.NET Generic Host]のほうの話です。





#そもそも
詳細は@neueccさんの[ConsoleAppFramework][]の記事を読んでいただいたほうが早いのですが、ASP.NET Core 2.1で[汎用ホスト(.NET Generic Host)][.NET Generic Host]なる機能が追加されていたそうです。
[汎用ホスト(.NET Generic Host)][.NET Generic Host]はASP.NET Core 2.xですので[Dependency Injectionを標準でサポートしています。](https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.2)
しかしながら標準のDIだと[コンストラクタインジェクションしかできなかったり](http://ryuichi111std.hatenablog.com/entry/2016/07/17/102129)、[IServiceProviderのGetServiceしか解決方法がなかったり](https://docs.microsoft.com/ja-jp/dotnet/api/system.iserviceprovider?view=netframework-4.7.2)とかゆいところに手が届きません。
そこでDIコンテナを差し替えることにしました。

#結論

```C#:実装例
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](https://www.nuget.org/packages/Unity/)をNugetする他にも[Unity.Microsoft.DependencyInjection][]をNugetすることです。
=> Unity.Microsoft.DependencyInjectionの[GitHub](https://github.com/unitycontainer/microsoft-dependency-injection)に使い方書いていました。

~~利用する際はIServiceProviderをコンストラクタインジェクションしてIUnityContainerを呼び出してResolveします。~~
UseUnityServiceProviderを使用すればIUnityContainerをコンストラクタインジェクションできました。

```C#:冗長
    public class MainApp : ConsoleAppBase
    {
       private I~~Repository ~~Repository { get; }

        public MainApp(IServiceProvider provider)
         : base()
        {
            var container = provider.GetService<IUnityContainer>();
            ~~Repository = container.Resolve<I~~Repository>();
        }
    }
```

```C#:コンテナ直接
    public class MainApp : ConsoleAppBase
    {
       private I~~Repository ~~Repository { get; }

        public MainApp(IUnityContainer _container)
         : base()
        {
            ~~Repository = _container.Resolve<I~~Repository>();
        }
    }
```


~~直接**I\~~Repository**をコンストラクタインジェクション出来ればよかったんですけど駄目でした。~~
~~何か設定が足りないかも？~~
UseUnityServiceProviderを呼んだあとサービスとして登録(services.AddSingleton)してやればコンストラクタインジェクション出来ました。

```C#:ほしいクラス直接
    public class MainApp : ConsoleAppBase
    {
       private I~~Repository ~~Repository { get; }

        public MainApp(I~~Repository _~~Repository)
         : base()
        {
            ~~Repository = _~~Repository;
        }
    }
```



#類似例
[DryIoc](https://www.nuget.org/packages/DryIoc/)と[Autofac](https://www.nuget.org/packages/Autofac/)にもありました。

+ [DryIoc.Microsoft.DependencyInjection](https://www.nuget.org/packages/DryIoc.Microsoft.DependencyInjection/)
+ [Autofac.Extensions.DependencyInjection](https://www.nuget.org/packages/Autofac.Extensions.DependencyInjection/)

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

#参考

+ [ConsoleAppFramework — Micro-framework for console applications, for C# .NET Core](https://medium.com/@neuecc/consoleappframework-micro-framework-for-console-applications-for-c-net-core-4e69daa7e149)
+ [Microsoft.Extensions.DependencyInjection を使った DI の基本](https://qiita.com/TsuyoshiUshio@github/items/20412b36fe63f05671c9#%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%E3%83%BC%E3%82%A4%E3%83%B3%E3%82%B8%E3%82%A7%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3)
+ [MicroBatchFramework – クラウドネイティブ時代のC#バッチフレームワーク](http://tech.cygames.co.jp/archives/3241/)
+ [Adding a custom dependency injection container in ASP.NET Core](https://asp.net-hacker.rocks/2017/05/08/add-custom-ioc-in-aspnetcore.html)
+ [Use HostBuilder.ConfigureServices with DryIoc container?](https://stackoverflow.com/questions/51872490/use-hostbuilder-configureservices-with-dryioc-container/51877235#51877235)

[ConsoleAppFramework]:http://neue.cc/2020/01/09_588.html
[MicroBatchFramework]:http://tech.cygames.co.jp/archives/3241/
[.NET Generic Host]:https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-2.2#configureservices
[Unity.Microsoft.DependencyInjection]:https://www.nuget.org/packages/Unity.Microsoft.DependencyInjection/