这是我的问题:我正在使用以下工具构建桌面应用程序:
我的所有视图模型和存储库都与Ninject实现了。我的存储库都需要在构造函数中使用ISession。
我想关注有关ViewModel的ayende's advice:每个ViewModel都会打开一个新会话。
是否可以在创建ViewModel时将Ninject配置为打开新会话,并在此视图模型使用的存储库中使用此会话?
我查看了Ninject的InScope函数,以及NHibernate中的ICurrentSessionContext接口,但我不知道如何对所有这些进行建模以获得我想要的...
之前有人做过类似的事吗?
提前致谢
麦克
答案 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)
{
}
希望有所帮助