C# Unity WPF窗口生命周期管理器

C# Unity WPF窗口生命周期管理器,c#,wpf,unity-container,C#,Wpf,Unity Container,我在c#/WPF/NHibernate应用程序中使用Unity作为DI容器 我想使用一个定制的生命周期管理器,它将为每个WPF窗口提供一个单独的NHibernate会话。容器返回的会话应该是当前活动窗口的会话 问题是,我不能让它工作。容器似乎会在每次请求时创建一个新会话,然后尝试将其存储到生存期管理器中,而不是首先从生存期管理器请求会话 这是我的自定义终身管理器的代码: class ActiveWindowLifetimeManager : LifetimeManager { priva

我在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;
    }
}
下一个寄存器是UnitOfWork中的
,其中填充了来自上述注册的
ISession

container.RegisterType<INHUnitOfWork>("mainDBUoW", new InjectionFactory(c =>
{
     return c.Resolve<NHUnitOfWork>(new ParameterOverride("session", c.Resolve<ISession>("mainDBSession")));
}));
container.RegisterType(“mainDBUoW”),新注入工厂(c=>
{
返回c.Resolve(新参数覆盖(“会话”,c.Resolve(“mainDBSession”));
}));
最后,
Func
是任何实际数据访问类的依赖项

container.RegisterType<Func<INHUnitOfWork>>("mainDBUoWFactory",
    new InjectionFactory(f => new Func<INHUnitOfWork>(() => f.Resolve<INHUnitOfWork>("mainDBUoW"))));
container.RegisterType(“mainDBUoWFactory”,
新注入工厂(f=>newfunc(()=>f.Resolve(“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
    已返回,并且在UnitOfWork
    中提供的
    中的实际会话具有哈希代码21438532

    然后我点击第二条数据访问语句,这就是点击的
    ActiveWindowLifetimeManager

  • SetValue-生存期管理器密钥{ca896ad2-1968-4bc7-94c6-ab2cb0ab08c2}-ISession哈希代码-21320198
  • GetValue-生存期管理器密钥-{ca896ad2-1968-4bc7-94c6-ab2cb0ab08c2}-返回ISession哈希代码-21438532
  • UnitOfWork中提供的
    中的实际会话具有哈希代码21320198
    
    i、 容器似乎首先创建了一个新会话,并在1中更新了生存期管理器。调用2返回的会话似乎已被忽略。

    别担心,这是我自己的错。 这就是问题所在:

    public override object GetValue()
    {
        object result = null;
        _uiContext.Send(InternalGetValue, result);
        return result;
    }
    
    当然,
    InternalGetValue
    中设置的对象值与传入的对象不同,因为它被封送到不同的线程。 不太确定我将如何解决这个问题,但至少我现在看到了问题所在

    编辑-最后我使用了一个带有信号量的静态类变量来控制访问。看起来效果很好

    public override object GetValue()
    {
        object result = null;
        _uiContext.Send(InternalGetValue, result);
        return result;
    }