Create an ISession instance for the ViewModel

here is my problem: I am building a desktop application with the following tools:

  • Caliburn
  • Ninject
  • NHibernate

All my models and repositories are displayed using Ninject. My repositories all need ISession in their constructor.

I would like to follow ayende advice regarding ViewModels: each ViewModel opens a new session.

Is it possible to configure Ninject to open a new session when creating the ViewModel and use this session inside the repositories used by this view model?

I looked at the InScope function for Ninject, as well as the ICurrentSessionContext interface in NHibernate, but I don’t know how to simulate all this to get what I want ...

Did someone do something like this before?

Thanks in advance

Mike

+4
source share
5 answers

Well, I found a solution thanks to the ninject group.

The solution here is to use the InScope function when binding the ISession and look in the IContext variable to check the services. If one service in the query hierarchy is assigned to the base class of my view models, I use context as a scope.

So, when starting ISession for the first time, a new scope is used in the constructor of my ViewModel. And all subsequent ISession calls inside the ViewModel constructor will be resolved with the same scope. And then only one session is created for my ViewModel.

Here is the code:

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(); }); 

And the viewmodel constructor should contain all the nested dependencies that rely on ISession:

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

Hope that helps

0
source

I solved a similar scenario using the ViewModel life cycle: I created the ISessionAware interface (using the SetSession method), which will be implemented by repositories, and then initialized the repositories through ISessionAware in the OnInitialize ViewModel method (which is used by Caliburn when the VM is controlled by ScreenConductor).

Using reflection to check the properties that store repositories, I could put the entire infrastructure in the BaseDataVM class.

Using scope in a container would be more elegant, I think, but I don't know Ninject.

0
source

I have a very similar project (except that I do not use Caliburn) and try to figure out how to do it. I came up with one method that works well for injecting a constructor using the Ninject InScope () method.

I have a static IoC class that wraps access to the Ninject core. Since all dependencies are entered into the constructor, the context makes sense only when creating an object. Therefore, it doesn't matter what is provided for the context, but Guid feels like a safe choice. Program.OpenSession () is a static method for opening a new 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); } } } 

Using:

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

Signature of the form constructor:

 public frmCompanyViewer(ISession session, ICompanyRepository companyRepository) 

I have verified that using InScope on bindings to build the Repository company, the same ISession is also used, which is used to build frmCompanyViewer. If I remove InScope, then two ISessions are used.

Edited to add: This will also work, see comments. This must be made thread safe for real use. I changed the method name to ConstructInContext to clarify that context only applies when building an object.

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

We have it with AOP, in neddzinami. It is called "Conversation for business transaction."

google search

0
source

Source: https://habr.com/ru/post/1313856/


All Articles