nuits.jp blog

C#, Xamarin, WPFを中心に書いています。Microsoft MVP for Development Technologies。

ASP.NET CoreでSimpleInjectorを利用する

ASP.NET Coreには標準でDIの仕組みは用意されているのですが、他のプラットフォームとのアーキテクチャの統合を考えた場合、ASP.NET Core上でしか動かないDI Containerを利用するより、サードパーティのContainerを利用したいというのは十分考えられるシナリオです。

そこで今回は個人的に好きな(理由はこちら)SimpleInjectorをASP.NET Coreで利用する方法を詳解します。

ここでは最も簡単な方法のみを紹介します。より踏み込んだ利用方法はこちらをご覧ください。

ASP.NET Core MVC Integration Guide

前提条件

ASP.NET CoreのプロジェクトテンプレートからMVCを有効にしてプロジェクトを作成します。するとHomeControllerに次のようなコードが生成されます。

public class HomeController : Controller
{
    // 略
    public IActionResult About()
    {
        ViewData["Message"] = "Your application description page.";
        return View();
    }

Aboutで表示するメッセージを、つぎのようにInjectionされたオブジェクトから取得するようにします。

public class HomeController : Controller
{
    private readonly IUseCase _useCase;
    public HomeController(IUseCase useCase)
    {
        _useCase = useCase;
    }

    // 略
    public IActionResult About()
    {
        ViewData["Message"] = _useCase.GetMessage();
        return View();
    }

IUseCaseとその実装クラスであるUseCaseクラスのコードはつぎの通りです。

public interface IUseCase
{
    string GetMessage();
}

public class UseCase : IUseCase
{
    public string GetMessage()
    {
        return "Hello, SimpleInjector!!";
    }
}

NuGetパッケージの適用

SimpleInjectorではASP.NET Coreへ適用するためのパッケージをNuGetで公開しています。

まずは次のパッケージをNuGetからインストールしてください。

www.nuget.org

SimpleInjectorを適用する

つづいてSimpleInjectorをコンテナとして利用できるよう適用します。

Starup.csファイルを開き、つぎのように統合メソッドを作成します。

private readonly Container _container = new Container();
private void IntegrateSimpleInjector(IServiceCollection services)
{
    _container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

    services.AddSingleton<IControllerActivator>(
        new SimpleInjectorControllerActivator(_container));
    services.AddSingleton<IViewComponentActivator>(
        new SimpleInjectorViewComponentActivator(_container));

    services.EnableSimpleInjectorCrossWiring(_container);
    services.UseSimpleInjectorAspNetRequestScoping(_container);
}

そしてConfigureServicesメソッドの末尾から上記のコードを呼び出します。

public void ConfigureServices(IServiceCollection services)
{
    // 中略
    IntegrateSimpleInjector(services);
}

これで準備は完了です。

コンテナへサービスを登録する

つぎのようにサービスを登録するコンテナの初期化メソッドを作成します。

private void InitializeContainer(IApplicationBuilder app)
{
    // Add application presentation components:
    _container.RegisterMvcControllers(app);
    _container.RegisterMvcViewComponents(app);

    // Add application services. For instance:
    _container.Register<IUseCase, UseCase>(Lifestyle.Scoped);

    // Allow Simple Injector to resolve services from ASP.NET Core.
    _container.AutoCrossWireAspNetComponents(app);
}

IUseCaseの登録以外に、ASP.NET Core MVC上でコンテナが正しく動作するよう、MVCのControllerなどもコンテナへ登録します。

そしてこのコードをConfigureメソッドから呼び出します。

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    // 中略
    InitializeContainer(app);
    _container.Verify();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

ConfigureメソッドはASP.NET Coreのバージョンが上がると変わる事がありますが、UseMvcの呼び出し前あたりでコンテナを初期化すれば良いでしょう。

コンテナの初期化後にVeryfyメソッドを読んでいますが、これはコンテナへ登録されたオブジェクトが依存しているオブジェクトもすべて登録されているかどうかといったチェックをしてくれます。動作させるまでそれが判明しないこともDI Containerが多い中で、SimpleInjectorの強みの一つでしょう。

それでは実行してみましょう。次のように「Hello, SimpleInjector!!」というメッセージが表示されれば成功です。

f:id:nuitsjp:20190126015640p:plain

以上です。