前回のDI(依存性の注入)をふまえて、今回は DIコンテナ についてまとめていきます。
一口に DIコンテナ といっても、多くの種類があるのですが、今回は ASP.NET Core の DIコンテナ についてのまとめになります。
2回くらいに分けて掲載する予定です。
今回は、DIコンテナ についての概要と全体の流れについて掲載します。
次に、Razor Pages や Entity Framework Core の DI について掲載する予定です。
さて、DIコンテナ では、他のオブジェクトが利用するオブジェクトのことを、サービス といいます。
このサービスは、他のオブジェクトに利用してもらうことが目的で作られているわけです。
つまり、サービスとは、サービスを提供するオブジェクトになります。
サービスを提供するオブジェクトは、前回の DI で見てきたように、依存性の弱い疎結合で作りたいものになります。
前回の おさらい ですが、疎結合にするためには、インターフェースでメソッドを定義し、それを実装するクラスを作成するのでした。
この実装クラスは疎結合になっているため、依存性が弱いクラスです。
この実装クラスを登録して保管しておく 入れ物 が DIコンテナ です。
実装クラスで作成した様々なサービスを一カ所に保管しておきましょう、ということです。
もちろん、DIコンテナは、単なる 入れ物 ではなく、DIコンテナ に登録されているサービスをインスタンス化する役割などを担ってくれます。
さきほど、DIコンテナに登録するオブジェクトをサービスという、といいましたが、サービスは実装クラスのことを指すと言ってよいでしょう。
以下の記述で登場する「サービス」は「実装クラス」のことを指しています。
次に、DIコンテナ に登録したサービスを利用する方法についてです。
これも、前回のおさらいですが、実装クラスをインスタンス化し、そのインスタンスをインターフェース型の変数に代入するのでした。
インターフェース型変数に代入することを注入といいます。
そして、インターフェース型変数を通じて、インスタンスのメソッドを利用する、というものでした。
つまり、実装クラスをインスタンス化し、インターフェース型変数に注入して利用します。
DIコンテナ に登録したサービスを利用する場合も、原理は同じです。
ただし、サービスのコンストラクタを指定してnew演算子を使用してインスタンスの生成をしたり、あるいは自分でFactoryクラスを作ってインスタンス化したりする必要はありません。
DIコンテナ に登録されているサービスをインスタンス化するメソッドが用意されていて、それを使うことで、DIコンテナ がインスタンスを生成し、返り値にそのインスタンスを返してくれます。
その返り値をインスタンス変数に注入して、サービスを利用します。
このように DIコンテナ は、サービスを保管する役割と、サービスをインスタンス化する役割があります。
では、次の順番で、サンプルコード(C#)を使って、一連の流れを見てましょう。
- 実装クラスの作成
- 実装クラス(サービス)の DIコンテナ への追加
- DIコンテナ に登録されている実装クラス(サービス)の取得・注入
以上の順番でサンプルコードを示して確認していきます。
●実装クラスの作成
まず、インタフェースを作成します。
public interface IMyService { void WriteMessage(string message); } |
実装クラスを作成します。
public class MyService : IMyService { public void WriteMessage(string message) { Console.WriteLine($”MyService.WriteMessage Message: {message}”); } } |
●実装クラス(サービス)のDIコンテナへの追加
DIコンテナ へのサービスの追加は、Program.csクラス の ConfigureServicesメソッド 内で次のいずれかのメソッドを使用します。
AddSingleton メソッド
AddTransient メソッド
AddScoped メソッド
状況に応じてメソッドを使い分けします。
詳細は.NET の依存関係の挿入を参照してください。
下記コードの青字の部分で追加しています。
public void ConfigureServices(IServiceCollection services) { services.AddTransient<IMyService, MyService>(); } |
●DIコンテナに登録されている実装クラス(サービス)の取得・注入
DIコンテナからサービスを取得するには、IServiceProviderインターフェイスのGetServiceメソッドを使用します。
GetServiceメソッドによって DIコンテナ がサービスのインスタンスを作成して、必要に応じてサービスを解決するため、new演算子を使用する必要はありません。
青字の_myService = serviceProvider.GetService< IMyService >();の右辺でサービスを取得し、左辺の_myServiceに注入しています。
public class MyController : Controller { private readonly IMyService _myService; public MyController(IServiceProvider serviceProvider) { _myService = serviceProvider.GetService< IMyService >(); _ myService. WriteMessage(“ハロー”); } } |
「MyService.WriteMessage Message: ハロー」とコンソールに表示します。
以上、ASP.NET Coreにおける DIコンテナ の概要をみてきました。
実装クラスをサービスとして DIコンテナ に登録しておくことで、インスタンス化を DIコンテナ が適切に行ってくれます。
Spring Bootはアノテーション@injectionを使ってインスタンス化と注入を行うなど、フレームワークによってその方法は異なりますが、原理は共通しているはずです。
ここをしっかりと把握しておけば、応用が利きそうです。
徒然に思うこと
私の父は95歳です。
スープの冷めない距離ではありますが、一人暮らしです。
じっとしていません。
腰が曲がり、歩く速度もゆっくりですが、
バスに乗って図書館へ行ったり、100円均一のショップへ行ったり、区役所などに確認したいことがあればそこへ行ったり、畑で収穫をしたり、(結構広い畑なのです)何かしら動いています。
記憶力も確かです。
本人曰く「構想を練っている。」「計画を立てている。」
私は、そんな父を見習っているのかもしれません。