根据ViewModel创建ISession实例

时间:2010-06-25 10:48:54

标签: nhibernate viewmodel ninject caliburn isession

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

  • 卡利
  • Ninject
  • NHibernate的

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

我想关注有关ViewModel的ayende's advice:每个ViewModel都会打开一个新会话。

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

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

之前有人做过类似的事吗?

提前致谢

麦克

5 个答案:

答案 0 :(得分:0)

我解决了利用ViewModel生命周期的类似场景:我创建了一个由存储库实现的ISessionAware接口(带有SetSession方法),然后我在ViewModel的OnInitialize方法中通过ISessionAware初始化了存储库(由Caliburn强制执行)当VM由ScreenConductor管理时)。

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

我认为在容器中使用范围会更优雅,但我不知道Ninject。

答案 1 :(得分:0)

我有一个非常相似的项目(除了我没有使用Caliburn)并且一直试图弄清楚如何做到这一点。我确实提出了一种适用于使用Ninject的InScope()方法进行构造函数注入的方法。

我有一个名为IoC的静态类,它包含对Ninject内核的访问。由于依赖项都被注入到构造函数中,因此上下文仅在创建对象时才相关。因此,为上下文提供的内容并不重要,但Guid感觉就像是安全的选择。 Program.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)

我验证了在绑定上使用InScope,用于构造frmCompanyViewer的相同ISession也用于构造companyRepository。如果我删除InScope,则使用两个ISess。

编辑添加:这也可以,请参阅评论。这应该是真正的应用程序的线程安全。我将方法名称更改为ConstructInContext以阐明上下文仅适用于对象构造期间。

    public static T ConstructInContext<T>()
    {
        _context = Guid.NewGuid();
        var result = _kernel.Get<T>();
        _context = null;
        return result;
    }

答案 2 :(得分:0)

我们有这个与AOP,在unhaddins。 被称为“每个业务交易的对话”。

在谷歌搜索

答案 3 :(得分:0)

答案 4 :(得分:0)

好吧,感谢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)
{
}

希望有所帮助