ASP.NET MVC 5 で DI する - その2「生成の一元化」 #aspnetjp
前回、DI をするための基本的なことを説明しました。
今回は DI コンテナによる生成の一元化について説明します。
DI コンテナによる生成の一元化
コードは前回からの続きで、今回は Repository で必要になるであろう DB 接続も DI で注入するシナリオで進めます。DB 接続は SqlConnection を利用します。
DB 接続は、これまでに示した簡易なクラスとは違い、コンストラクターで接続文字列を要求しています。このまま Repository に対して SqlConnection を DI した場合、下記の例外が発生します。
例外の詳細: System.InvalidOperationException: The type String cannot be constructed. You must configure the container to supply this value.
この問題は、型の登録時に InjectionFactory を用いて生成方法を与えることで解決できます。
var connectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString; container.RegisterType<SqlConnection>( new PerRequestLifetimeManager(), new InjectionFactory(_ => new SqlConnection(connectionString)));
合わせて、確認のために Repository を下記のように変更しました。
public class SampleRepository : ISampleRepository { private readonly SqlConnection connection; public SampleRepository(SqlConnection connection) { this.connection = connection; Debug.WriteLine("SampleRepository: Constructor"); Debug.WriteLine(connection); } }
実行すると、SqlConnection が生成されていることが確認できます。
実用例
ここからは DI の説明ではないのですが、せっかくなので少し実用例を紹介します。
@neuecc さんの下記の記事で、SQL のロギングのための MiniProfiler というライブラリが紹介されています。
ここでは記事に倣って ProfiledDbConnection を利用するようにしてみます。
// DbConnection に対して登録しているのがミソで、 // SqlConnection を OracleConnection に変更しても大丈夫です。 // (もちろん SQL 文やストアドは修正が必要でしょう) // TraceDbProfiler は @neuecc さんの記事を参照 // NLog ではなく Debug.WriteLine を使うように改造して利用 container.RegisterType<DbConnection>( new PerRequestLifetimeManager(), new InjectionFactory(_ => new ProfiledDbConnection( new SqlConnection(connectionString), new TraceDbProfiler())));
public class SampleRepository : ISampleRepository { public SampleRepository(DbConnection connection) { // Dapper ライブラリの拡張メソッドを利用 var result = connection.ExecuteScalar<string>( "SELECT 'Hello, world!'"); Debug.WriteLine("SampleRepository: " + result); } }
これまで通りの手順で、難しいこともなく実現できました。さらに、Repository 自体も ProfiledDbConnection や SQL Server、Oracle などといった DB 接続に依存していません。
まとめ
型の登録時に InjectionFactory で生成方法を与えるだけです。使わない手はないですね!