在前文中我們通過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());
測試結果表明已經可以安全的在多線程條件下工作了
From:http://tw.wingwit.com/Article/program/net/201311/12626.html