我在我的 c#/WPF/NHibernate 应用程序中使用 Unity 作为 DI 容器。
我想使用一个自定义生命周期管理器,它将为每个 WPF 窗口提供一个单独的 NHibernate 会话。容器返回的 Session 应该是当前活动窗口的会话。
问题是,我无法让它工作。容器似乎会在每次请求时创建一个新会话,然后尝试将其存储在生命周期管理器中,而不是首先从生命周期管理器请求会话。
这是我的自定义生命周期管理器的代码:
class ActiveWindowLifetimeManager : LifetimeManager
{
private SynchronizationContext _uiContext;
private ICacheFactory _cacheFactory;
private ICache<Window, ICache<Guid, object>> _data;
private Guid _key;
public ActiveWindowLifetimeManager(ICacheFactory cacheFactory, SynchronizationContext uiContext,
ICache<Window, ICache<Guid, object>> cache)
{
_key = Guid.NewGuid();
_uiContext = uiContext;
_cacheFactory = cacheFactory;
_data = cache;
}
public override object GetValue()
{
object result = null;
_uiContext.Send(InternalGetValue, result);
return result;
}
public override void SetValue(object newValue)
{
_uiContext.Send(InternalSetValue, newValue);
}
public override void RemoveValue()
{
_uiContext.Send(InternalRemoveValue, null);
}
// Note - I don't think we need to worry about concurrency issues as everything
// is marshalled to the UI thread anyway
private void InternalGetValue(object state)
{
ICache<Guid, object> cache = GetActiveWindowCache();
if (cache != null)
{
state = cache.Get(_key);
}
}
private void InternalSetValue(object state)
{
ICache<Guid, object> cache = GetActiveWindowCache();
if (cache != null)
{
if (cache.Get(_key) == null)
{
cache.Add(_key, state);
}
}
}
private void InternalRemoveValue(object state)
{
ICache<Guid, object> cache = GetActiveWindowCache();
if (cache != null)
{
cache.Remove(_key);
}
}
private ICache<Guid, object> GetActiveWindowCache()
{
ICache<Guid, object> result = null;
Window activeWindow = Application.Current.Windows.OfType<Window>().FirstOrDefault(x => x.IsActive);
if (activeWindow == null)
{
activeWindow = Application.Current.Windows.OfType<Window>().FirstOrDefault();
}
if (activeWindow != null)
{
result = _data.Get(activeWindow);
if (result == null)
{
result = _cacheFactory.GetCache<Guid, object>(100);
_data.Add(activeWindow, result);
}
}
return result;
}
}
该容器有三个相关的注册。第一个是ISession
,使用自定义生命周期管理器。并解决没有任何问题INHSessionProvider
。SessionProviderParameters
container.RegisterType<ISession>("mainDBSession", container.Resolve<ActiveWindowLifetimeManager>(), new InjectionFactory(c =>
{
SessionProviderParameters parameters = c.Resolve<SessionProviderParameters>("mainDBSessionProviderParams");
return c.Resolve<INHSessionProvider>(new ParameterOverride("parameters", parameters)).Session;
}));
下一个寄存器INHUnitOfWork
,其中填充ISession
了上述注册中的一个。
container.RegisterType<INHUnitOfWork>("mainDBUoW", new InjectionFactory(c =>
{
return c.Resolve<NHUnitOfWork>(new ParameterOverride("session", c.Resolve<ISession>("mainDBSession")));
}));
最后,Func<INHUnitOfWork>
是任何实际数据访问类的依赖关系。
container.RegisterType<Func<INHUnitOfWork>>("mainDBUoWFactory",
new InjectionFactory(f => new Func<INHUnitOfWork>(() => f.Resolve<INHUnitOfWork>("mainDBUoW"))));
我在我的第一个数据访问语句上放了一个断点,这就是命中ActiveWindowLifetimeManager
:
- GetValue - 生命周期管理器密钥 - {ca896ad2-1968-4bc7-94c6-ab2cb0ab08c2} - 返回 null
- SetValue - 生命周期管理器密钥 - {ca896ad2-1968-4bc7-94c6-ab2cb0ab08c2} - ISession 哈希码 - 21438532
- GetValue - 生命周期管理器密钥 - {ca896ad2-1968-4bc7-94c6-ab2cb0ab08c2} - 返回 ISession 哈希码 - 21438532
此时,Func<INHUnitOfWork>
已返回并且提供的实际会话INHUnitOfWork
具有哈希码 21438532。
然后我点击了我的第二个数据访问语句,这就是命中ActiveWindowLifetimeManager
:
- SetValue - 生命周期管理器密钥 - {ca896ad2-1968-4bc7-94c6-ab2cb0ab08c2} - ISession 哈希码 - 21320198
- GetValue - 生命周期管理器密钥 - {ca896ad2-1968-4bc7-94c6-ab2cb0ab08c2} - 返回 ISession 哈希码 - 21438532
提供的实际会话INHUnitOfWork
具有哈希码 21320198,即容器似乎首先创建了一个新会话并更新了 1 中的生命周期管理器。调用 2 返回的会话似乎被忽略了。