是否有任何具有线程安全类型注册的 .net IOC 容器?
我有许多在应用程序的生命周期内固定的绑定 - 但是有一些注册需要在“每个线程”或“每个请求”的基础上进行调整。当这个应用程序的线程被回收到线程池或从线程池回收时,少数动态 IOC 注册将被清除或覆盖,因为新请求被分派。
澄清一下,下面是基于 Unity 的示例代码,它将 WCF 服务与容器“模块”或“注册表”的概念相结合。
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()
将在应用程序的整个生命周期内调用一次,但ReInitialize()
会随每个 WCF 服务请求调用。将ReInitialize()
给出将执行的 WCF 操作的名称以及将提供的参数。完成后ReInitialize()
,对服务实例进行最后一次 UnityBuildUp()
调用,然后执行服务操作。
正如示例进一步说明的那样,有关服务调用的信息用于确定 DataAccess 实例将被实例化的数据库连接字符串。
为了创建这种行为,我最初计划为每个需要唯一绑定的请求创建一个 Unity 子容器。这就是ReInitialize()
调用传入 childContainer 参数的原因。但后来我发现它CreateChildContainer
本身似乎不是线程安全的。事实上,我发现很难找到任何 .net IOC 容器的线程安全声明(Autofac 除外,这使得它相当清楚)。
我怀疑允许线程安全注册的容器会使用ConcurrentDictionary或不可变集合。走着瞧。
另一方面,如果我绝对必须避免这种动态的、多线程的注册过程——我想我会进行类型到委托的注册而不是类型到类型的注册。这样,委托可以动态决定要创建什么,而不是绑定本身是动态的。在这种情况下,前面的示例代码会将所有注册从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 容器?