スレッドセーフな型登録を持つ .net IOC コンテナーはありますか?
アプリケーションの存続期間中に固定されている多数のバインディングがありますが、「スレッドごと」または「リクエストごと」に調整する必要があるいくつかの登録があります。このアプリのスレッドがスレッド プールとの間でリサイクルされると、新しい要求がディスパッチされると、少数の動的 IOC 登録がクリアまたは上書きされます。
明確にするために、以下は、コンテナーの "モジュール" または "レジストリ" の概念と WCF サービスを組み合わせた Unity ベースのサンプル コードです。
public class AccountServiceRegistry : UnityContainerExtension, IBindingOverride
{
//From UnityContainerExtension
protected override void Initialize()
{
Container.RegisterType<IAccountService, AccountService>();
}
//From IBindingOverride
public void ReInitialize(IUnityContainer child, string action, object[] parms){
child.RegisterType<AccountService>(new InjectionProperty("log"), new InjectionProperty("dao"));
child.AddNewExtension<DataAccessRegistry>();
string connectionString = action == "GetMoreData" ? "Alpha" : "Bravo";
child.Configure<IDataAccessConfig>().WithConnection(connectionString);
}
}
このサンプルでは、AcccountServiceRegisty
メソッドInitialize()
はアプリケーションの存続期間中に 1 回呼び出されますが、ReInitialize()
WCF サービス要求ごとに呼び出されます。にReInitialize()
は、実行される WCF 操作の名前と、提供されるパラメーターが指定されます。完了後、サービス インスタンスでReInitialize()
最後の UnityBuildUp()
呼び出しが行われ、サービス操作が実行されます。
例がさらに示すように、サービス呼び出しに関する情報は、DataAccess インスタンスがインスタンス化される DB 接続文字列を決定するために使用されます。
この動作を作成するために、当初は、一意のバインディングが必要なリクエストごとに Unity 子コンテナーを作成することを計画していました。これが、呼び出しに childContainer パラメーターが渡された理由です。しかし、それ自体がスレッド セーフではないことがReInitialize()
わかりました。CreateChildContainer
実際、.net IOC コンテナーのスレッド セーフの主張を見つけるのは難しいことがわかりました ( Autofac を除いて、かなり明確になります)。
スレッドセーフな登録を許可するコンテナーは、ConcurrentDictionaryまたは不変の collectionsを利用するのではないかと思います。見てみましょう。
一方、この動的なマルチスレッド登録プロセスを絶対に避けなければならない場合は、型から型への登録ではなく、型からデリゲートへの登録を行うと思います。このようにして、デリゲートは、バインディング自体が動的である代わりに、何を作成するかを動的に決定できます。その場合、前のサンプル コードはすべての登録をReInitialize()
メソッドからメソッドに移動しInitialize()
、IDataAccessConfig
実装は次のように変更されます。
public class DataAccessRegistry: UnityContainerExtension, IDataAccessConfig
{
[ThreadStatic]
string connection;
protected override void Initialize()
{
Container.RegisterType<IDataAccess>(new InjectionFactory(c => new DataAccess(connection)));
}
public IDataAccessConfig WithConnection(string connection)
{
this.connection = connection;
return this;
}
}
上記のサンプルの重要な部分は、複数のスレッドが安全に[ThreadStatic]
呼び出せるようにすることです。WithConnection()
しかし、これは私の質問を変更しません-スレッドセーフな登録を持つ .net コンテナーはありますか?