4

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

  • 卡利本
  • 忍者
  • 休眠

我所有的视图模型和存储库都是用 Ninject 实例化的。我的存储库都需要在其构造函数中使用 ISession。

我想听从ayende关于 ViewModel 的建议:每个 ViewModel 都会打开一个新会话。

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

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

以前有人做过类似的东西吗?

提前致谢

麦克风

4

5 回答 5

0

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

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

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

于 2010-06-25T12:43:18.720 回答
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,则使用两个 ISession。

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

    public static T ConstructInContext<T>()
    {
        _context = Guid.NewGuid();
        var result = _kernel.Get<T>();
        _context = null;
        return result;
    }
于 2010-06-25T13:00:57.077 回答
0

在 unhaddins 中,我们在 AOP 中有这个。称为“每个业务事务的对话”。

在谷歌搜索

于 2010-06-25T20:43:20.393 回答
0

好吧,感谢 ninject 小组,我找到了解决方案。

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

因此,第一次将 ISession 注入到我的 ViewModel 的构造函数中时,会使用一个新的范围。并且在 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();
    });

并且视图模型的构造函数必须包含依赖于 ISession 的所有注入依赖项:

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

希望有帮助

于 2010-06-28T13:03:27.957 回答