各種DIコンテナとASP.NETのWeb Formとの連携
MEFを使おうと思っているんですが、MEFにはWeb Form(Page)に依存注入するような機能はないので(サンプルはありますが)、自分で考える必要があります。例えばこんなことです。
- コンテナの生成をフレームワーク側で行うのか、アプリにまかせるか
- 生成したコンテナをどこで保持しておくか? HttpApplication、シングルトン?
- 依存注入をどこで行うか? IHttpModule、IHttpHandlerFactory、IHttpHandler?
- リクエストスコープは必要か?
- サーバーコントロールの依存注入には対応する?
MEFのサンプルや他のDIコンテナではどう対応しているのか見てみます。
MEF
サンプルがあります。
IHttpModuleの実装クラスでアプリケーションレベルのコンテナとリクエストスコープなコンテナを生成してます。アプリケーションレベルのコンテナには、アプリからはアクセスできなくて、リクエストスコープなコンテナはHttpContext.Current.Itemsで管理してます。
Web Form(Page)への依存注入は、IHttpHandlerFactoryの実装クラスでやっています。
特徴的な処理としては、コントロールをコンテナ管理できるための仕組みを持っています。ただ、素のコントロールには依存注入できなさそう。
Unity
Unity自体には、ASP.NETのWeb Formと連携する機能はないみたいですが、サンプルコードを公開している方がいました。
IHttpModuleの実装クラスでWeb Form(Page)とコントロールへの依存注入をやっています。Pageへの依存注入はIHttpModuleのOnPreRequestHandlerExecuteイベント、コントロールへの依存注入はPageのInitCompleteイベントでやっています。
コンテナの生成はどこでやっているかはわからないですが、コンテナの管理はMyから参照できるようです。My.Unityとなっていますが、VB.NETのMyって自分で拡張できるんでしたっけ。
Seasar.NET
設定がシンプル。
- https://www.seasar.org/svn/s2container.net/tags/s2container.net-1.3.9/s2container.net/source/Seasar/Seasar.Framework.Container/Web/S2HttpModule.cs
- http://s2container.net.seasar.org/ja/asp.html
IHttpModuleの実装クラスでWeb Form(Page)への依存注入をやっています。コントロールは対象外。
IHttpModuleのAcquireRequestStateイベントで依存注入しているのが他のコンテナに比べて特徴的かも(AcquireRequestStateが最適なのかそうでないのかはわからないです)。
コンテナの生成は、Global.asaxのApplication_Startメソッドで行います。コンテナの管理はフレームワーク側でシングルトン。
Spring.NET
Spring.NET、ちょっと見る限りASP.NETの推奨方法とは別の方向を目指しているようです。コードが多くてゴテゴテとした印象。Javaの実装Java版の仕様に引きずられているのかな?
- https://fisheye.springsource.org/browse/spring-net/tags/spring-net-1.3.0/src/Spring/Spring.Web/Context/Support/WebSupportModule.cs?r=HEAD
- https://fisheye.springsource.org/browse/spring-net/tags/spring-net-1.3.0/src/Spring/Spring.Web/Web/Support/PageHandlerFactory.cs?r=HEAD
- http://www.springframework.net/doc-latest/reference/html/web.html#web-configuration。
IHttpModuleでコンテナ管理、IHttpHandlerFactoryで依存注入をしています。コンテナはフレームワークで管理して直接アプリに触れさせるわけではないようです。
リクエストやセッションなどのスコープは用意されている、コントロールへの依存注入もサポートされているようです。
Ninject.Web
アプリがGlobal.asaxで生成したコンテナをフレームワークのクラスがシングルトンとして保持するつくりです。
- http://github.com/ninject/ninject.web/blob/master/source/Ninject.Web/NinjectHttpApplication.cs
- http://github.com/ninject/ninject.web/blob/master/source/Ninject.Web/NinjectHttpModule.cs
依存注入はIHttpModuleのOnPreRequestHandlerExecuteイベントでやっています。Pageだけでなくコントロールも対象。他にも、Pageの既定クラスで依存注入するほうほうもサポートされているようです。
autofac
コンテナの生成は、Global.asaxのApplication_Startメソッドで行ってGlobal.asaxに保持するつくりです。インタフェースを介して外部へ渡せるようにする必要があります。
- http://code.google.com/p/autofac/source/browse/src/Source/Autofac.Integration.Web/Forms/DependencyInjectionModule.cs
- http://code.google.com/p/autofac/wiki/AspNetIntegration
Pageへの依存注入はIHttpModuleのOnPreRequestHandlerExecuteイベントで行っています。コントロールを対象としているかどうかは定かではありません。DependencyInjectionModule.csを見る限りは対象外のよう。
Comparing .NET DI (IoC) Frameworks, Part 2だと、autofacって評価高いですね。
StructureMap
本家のドキュメントに特に記載がなくて、ASP.NETでの利用法を紹介しているブログを見つけました。
ObjectFactoryというのがシングルトンなコンテナのようです。Global.asaxのApplication_Startメソッドからコンテナを生成して、あとはPageの既定クラスで依存注入をしています。
Castle Windsor
こちらも本家のドキュメントに特に記載がなくて、サンプルコードはこんな感じでいいのか?と質問している方をみつけました。
Global.asaxですが、Application_StartメソッドじゃなくてInitでコンテナ生成しているのはよくないですね。
後半のほうは疲れてきて雑になってしまいました。