代码之家  ›  专栏  ›  技术社区  ›  Emidee

为每个ViewModel创建ISession实例

  •  4
  • Emidee  · 技术社区  · 16 年前

    我的问题是:我正在用以下工具构建一个桌面应用程序:

    • 尼杰特
    • 纤维酸盐

    我的所有视图模型和存储库都与Ninject关联。我的存储库都需要在其构造函数中使用ISession。

    我想跟着你 ayende's advice 关于ViewModels:每个ViewModel都会打开一个新会话。

    是否可以将Ninject配置为在创建ViewModel时打开一个新会话,并在此视图模型使用的存储库中使用此会话?

    我查看了Ninject的InScope函数,以及NHibernate中的iccurrentsessioncontext接口,但我不知道如何对所有这些进行建模以获得我想要的。。。

    提前谢谢

    迈克

    5 回复  |  直到 16 年前
        1
  •  0
  •   Marco Amendola    16 年前

    使用反射来检查保存存储库的属性,我可以将所有基础结构放在BaseDataVM类上。

    在容器中使用示波器会更优雅,我想,但我不知道Ninject。

        2
  •  0
  •   Jamie Ide    16 年前

    我有一个名为IoC的静态类,它封装了对Ninject内核的访问。由于依赖项都被注入到构造函数中,因此上下文仅在创建对象时才相关。因此,为上下文提供什么并不重要,但是Guid是一个安全的选择。OpenSession()是一个打开新ISession的静态方法。

    public static class Ioc
    {
        private static readonly IKernel _kernel;
    
        static IoC()
        {
            _kernel = new StandardKernel();
            _kernel.Load(new ContextModule());
        }
    
        private static object _context;
    
        public static T ResolveInContext<T>(object context)
        {
            _context = context;
            var result = _kernel.Get<T>();
            _context = null;
            return result;
        }
    
        private class ContextModule : NinjectModule
        {
            public override void Load()
            {
                Bind<ISession>().ToMethod(x => Program.OpenSession()).InScope(x => _context);
                Bind<frmCompanyViewer>().ToSelf().InScope(x => _context);
            }
        }
    }
    

    用法是:

    var frm = IoC.ResolveInContext<frmCompanyViewer>(Guid.NewGuid());
    

    public frmCompanyViewer(ISession session, ICompanyRepository companyRepository)
    

    编辑以添加:这也会起作用,请参见注释。对于真正的应用程序,这应该是线程安全的。我将方法名改为 ConstructInContext

        public static T ConstructInContext<T>()
        {
            _context = Guid.NewGuid();
            var result = _kernel.Get<T>();
            _context = null;
            return result;
        }
    
        3
  •  0
  •   José F. Romaniello    16 年前

    被称为“每笔交易的对话”。

        5
  •  0
  •   Emidee    16 年前

    好吧,多亏了ninject小组,我找到了解决办法。

    这里的解决方案是在绑定ISession时使用函数InScope,并在IContext变量中浏览以检查服务。如果请求层次结构中的一个服务可分配给视图模型的基类,则使用上下文作为作用域。

    因此,第一次在ViewModel的构造函数中注入ISession时,将使用一个新的作用域。并且ViewModel的构造函数中对ISession的所有后续调用都将在同一范围内解析。然后只为我的ViewModel创建一个会话。

    Bind<ISession>().ToMethod(ctx =>
        {
            var session = ctx.Kernel.Get<INHibernateSessionFactoryBuilder>()
                .GetSessionFactory()
                .OpenSession();
    
            session.FlushMode = FlushMode.Commit;
    
            return session;
        })
        .InScope(ctx =>
        {
            var request = ctx.Request;
    
            if (request.Service is IScreen)
                return request;
    
            while ((request = request.ParentRequest) != null)
                if (typeof(IScreen).IsAssignableFrom(request.Service))
                    return request;
    
            return new object();
        });
    

    viewmodel的构造函数必须包含依赖ISession的所有注入依赖项:

    [Inject]
    public PlayersManagementViewModel(ISession session, IPlayersRepository playersRepository)
    {
    }
    

    希望有帮助