在前文中我们通过Unity来注册各种类型和WiringUp
IUnityContainer container = new UnityContainer()
RegisterType(typeof(IRepository<>) typeof(Repository<>) new ContainerControlledLifetimeManager())
RegisterType(new ContainerControlledLifetimeManager())
RegisterType(new ContainerControlledLifetimeManager())
RegisterType(new ContainerControlledLifetimeManager())
RegisterType(new ContainerControlledLifetimeManager())
RegisterType(new ContainerControlledLifetimeManager())
RegisterType(new ContainerControlledLifetimeManager());
UnityServiceLocator locator = new UnityServiceLocator(container);
ServiceLocatorSetLocatorProvider(() => locator);
ICustomerRepository customerRepository = containerResolve();
但选择使用了ContainerControlledLifetimeManager对象生命周期管理器其将每个对象存储为Singleton这导致在多线程环境下会产生异常
例如我们尝试在多线程条件下更新Customer表
List tasks = new List();
for (int i = ; i < ; i++)
{
DomainModelsCustomer modifiedCustomer = MapperMap(customer);
modifiedCustomerName = modifiedCustomerName + i;
Task t = TaskFactoryStartNew(() =>
{
try
{
customerRepositoryUpdateCustomer(modifiedCustomer);
}
catch (Exception ex)
{
ConsoleWriteLine(Exception occurred in thread + ThreadCurrentThreadManagedThreadId);
ConsoleWriteLine(exMessage);
}
});
tasksAdd(t);
}
TaskWaitAll(tasksToArray());
但由于我们仍然需要EntityFramework的Local功能即在当前线程环境下始终使用当前上下文中的对象我们可能还无法选择其他Unity对象生命期管理模型
此时我们考虑一种新的方法引入线程Scope功能即在给定线程中使用同一个UnityContainer来维护对象这样间接利用的EntityFramework的上下文功能
原理很简单就是为每个线程生成一个单独的ChildUnityContainer
public class UnityContainerScope : IDisposable
{
private static ConcurrentDictionary scopeMapping
= new ConcurrentDictionary();
protected UnityContainerScope()
{
ScopeId = ThreadCurrentThreadManagedThreadId;
scopeMappingAdd(ScopeId true);
}
public int ScopeId { get; private set; }
public static int ScopeCount { get { return scopeMappingCount; } }
public static UnityContainerScope NewScope()
{
return new UnityContainerScope();
}
public static bool InScope(int scopeId)
{
return scopeMappingContainsKey(scopeId);
}
public void Dispose()
{
UnityContainerDispatcherDisposeContainer();
scopeMappingRemove(ScopeId);
}
}
这里同时需要一个UnityContainerDispatcher来负责为线程生成Container容器
public static class UnityContainerDispatcher
{
private static IUnityContainer parentContainer = null;
private static ConcurrentDictionary containerMapping
= new ConcurrentDictionary();
public static void InjectParentContainer(IUnityContainer unity)
{
if (unity == null)
throw new ArgumentNullException(unity);
parentContainer = unity;
}
public static IUnityContainer GetContainer()
{
int key = ThreadCurrentThreadManagedThreadId;
if (!UnityContainerScopeInScope(key))
{
throw new UnityContainerNotInScopeException(
stringFormat(CultureInfoInvariantCulture
The specified scope id [{}] is not in scope key));
}
if (!containerMappingContainsKey(key))
{
BuildUpContainer(key);
}
return containerMappingGet(key);
}
public static void DisposeContainer()
{
int key = ThreadCurrentThreadManagedThreadId;
IUnityContainer container = containerMappingRemove(key);
if (container != null)
{
containerDispose();
}
}
private static void BuildUpContainer(int key)
{
if (parentContainer == null)
throw new InvalidProgramException(The parent container cannot be null);
IUnityContainer childContainer = parentContainerCreateChildContainer();
containerMappingAdd(key childContainer);
}
}
在注入的根UnityContainer中我们通过使用CreateChildContainer方法来获取一个新的Container同时继承所有根容器的注册配置信息这要求使用HierarchicalLifetimeManager生命期管理器
此时我们的代码修改为
IUnityContainer container = new UnityContainer()
RegisterType(typeof(IRepository<>) typeof(Repository<>) new HierarchicalLifetimeManager())
RegisterType(new HierarchicalLifetimeManager())
RegisterType(new HierarchicalLifetimeManager())
RegisterType(new HierarchicalLifetimeManager())
RegisterType(new HierarchicalLifetimeManager())
RegisterType(new HierarchicalLifetimeManager())
RegisterType(new HierarchicalLifetimeManager());
UnityContainerDispatcherInjectParentContainer(container);
ICustomerRepository customerRepository = containerResolve();
创建多线程测试代码
List tasks = new List();
for (int i = ; i < ; i++)
{
DomainModelsCustomer modifiedCustomer = MapperMap(customer);
modifiedCustomerName = modifiedCustomerName + i;
Task t = TaskFactoryStartNew(() =>
{
try
{
using (UnityContainerScope scope = UnityContainerScopeNewScope())
{
customerRepositoryUpdateCustomer(modifiedCustomer);
ConsoleWriteLine(Modified + modifiedCustomerName + in thread + ThreadCurrentThreadManagedThreadId);
}
}
catch (Exception ex)
{
ConsoleWriteLine(Exception occurred in thread + ThreadCurrentThreadManagedThreadId);
ConsoleWriteLine(exMessage);
}
});
tasksAdd(t);
}
TaskWaitAll(tasksToArray());
测试结果表明已经可以安全的在多线程条件下工作了