簡體   English   中英

Unity WPF窗口生存期管理器

[英]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 ,使用自定義生命周期管理器。 INHSessionProviderSessionProviderParameters解析沒有任何問題。

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

  1. GetValue-生命周期管理器密鑰-{ca896ad2-1968-4bc7-94c6-ab2cb0ab08c2}-返回null
  2. SetValue-生命周期管理器密鑰-{ca896ad2-1968-4bc7-94c6-ab2cb0ab08c2}-ISession哈希碼-21438532
  3. GetValue-生命周期管理器密鑰-{ca896ad2-1968-4bc7-94c6-ab2cb0ab08c2}-返回ISession哈希碼-21438532

此時, Func<INHUnitOfWork>已返回,並且所提供的INHUnitOfWork的實際會話具有哈希碼21438532。

然后,我命中了第二條數據訪問語句,這就是命中ActiveWindowLifetimeManager

  1. SetValue-生命周期管理器密鑰-{ca896ad2-1968-4bc7-94c6-ab2cb0ab08c2}-ISession哈希碼-21320198
  2. GetValue-生命周期管理器密鑰-{ca896ad2-1968-4bc7-94c6-ab2cb0ab08c2}-返回ISession哈希碼-21438532

提供的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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM