[英]Which lifetime-manager do I register my DbContext into Unity container when writing a WPF application?
[英]Unity WPF window lifetime manager
我在c#/ WPF / NHibernate應用程序中將Unity用作DI容器。
我想使用一個自定義的生存期管理器,它將為每個WPF窗口提供一個單獨的NHibernate會話。 容器返回的會話應該是當前活動窗口的會話。
問題是,我無法正常工作。 容器似乎在每次請求時創建一個新會話,然后嘗試將其存儲在生命周期管理器中,而不是先從生命周期管理器請求會話。
這是我的自定義生命周期管理器的代碼:
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
:
此時, Func<INHUnitOfWork>
已返回,並且所提供的INHUnitOfWork
的實際會話具有哈希碼21438532。
然后,我命中了第二條數據訪問語句,這就是命中ActiveWindowLifetimeManager
:
提供的INHUnitOfWork
中的實際會話具有哈希碼21320198,即容器似乎首先創建了一個新會話並更新了1中的生存期管理器。由調用2返回的會話似乎被忽略了。
沒關系,這是我自己的錯。 這就是問題:
public override object GetValue()
{
object result = null;
_uiContext.Send(InternalGetValue, result);
return result;
}
當然,在InternalGetValue
設置的對象值與傳入的對象值不同,因為它已被編組到另一個線程。 不太確定如何解決此問題,但至少我現在看到了問題。
編輯-最后,我使用帶有信號量的靜態類變量來控制訪問。 似乎工作正常。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.