2010-06-25 6 views
4

voici mon problème: Je construis une application de bureau, avec les outils suivants:Créer une instance de ISession par ViewModel

  • Caliburn
  • Ninject
  • NHibernate

Tous mes modèles de vue et dépôts sont instanciés avec Ninject. Mes dépôts ont tous besoin d'une ISession dans leur constructeur.

Je voudrais suivre ayende's advice concernant les ViewModels: chaque ViewModel ouvre une nouvelle session.

Est-il possible de configurer Ninject pour ouvrir une nouvelle session lorsqu'un ViewModel est créé, et utiliser cette session dans les référentiels utilisés par ce modèle de vue?

J'ai eu un coup d'œil à la fonction InScope de Ninject, ainsi que l'interface ICurrentSessionContext dans NHibernate, mais je ne sais pas comment modéliser tout cela pour obtenir ce que je veux ...

Quelqu'un at-il faire quelque chose comme ça avant?

Merci à l'avance

Mike

Répondre

0

Eh bien, je l'ai trouvé une solution grâce au groupe ninject.

La solution ici est d'utiliser la fonction InScope lorsque je lie ISession, et de naviguer dans la variable IContext pour inspecter les services. Si un service de la hiérarchie des demandes est assignable à la classe de base de mes modèles de vue, j'utilise le contexte en tant que portée.

La première fois qu'une ISession sera injectée dans le constructeur de mon ViewModel, une nouvelle portée est utilisée. Et tous les appels suivants à ISession dans le constructeur du ViewModel seront résolus avec la même portée. Et puis une seule session est créée pour mon ViewModel.

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

Et le constructeur du moût de viewmodel contient toutes les dépendances injectées qui reposent sur la ISession:

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

Espoir qui aide

+1

Qu'est-ce que IScreen? –

+1

IScreen est l'interface de base des modèles de vue à Caliburn – Mike

0

Je résolus un scénario similaire tirant parti du cycle de vie ViewModel: J'ai créé une interface ISessionAware (avec une méthode de setSession) à mettre en œuvre par les référentiels centraux, alors j'initialisés les dépôts par ISessionAware dans la méthode OnInitialize de ViewModel (qui est appliquée par Caliburn lorsque la VM est gérée par un ScreenConductor). En utilisant la réflexion pour inspecter les propriétés contenant les dépôts, je pourrais mettre toute l'infrastructure sur une classe BaseDataVM.

L'utilisation d'un champ dans le conteneur serait plus élégant, je pense, mais je ne sais pas Ninject.

0

J'ai un projet très similaire (sauf que je n'utilise pas Caliburn) et j'ai essayé de comprendre comment faire cela aussi. J'ai trouvé une méthode qui fonctionne bien pour l'injection de constructeur en utilisant la méthode InScope() de Ninject.

J'ai une classe statique appelée IoC qui enveloppe l'accès au noyau de Ninject. Puisque les dépendances sont toutes injectées dans le constructeur, le contexte n'est pertinent que lorsque l'objet est créé. Donc ce n'est pas important ce qui est fourni pour le contexte, mais un Guid se sent comme le choix sûr. Program.OpenSession() est une méthode statique pour ouvrir une nouvelle 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); 
     } 
    } 
} 

utilisation est la suivante:

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

signature du constructeur de la forme est la suivante:

public frmCompanyViewer(ISession session, ICompanyRepository companyRepository) 

I vérifié que avec InScope sur les liaisons, le même ISession qui est utilisé pour construire frmCompanyViewer est également utilisé pour construire companyRepository. Si j'enlève InScope, deux ISessions sont utilisées.

Modifié pour ajouter: Cela fonctionnerait également, voir les commentaires.Cela devrait être rendu sûr pour une application réelle. J'ai changé le nom de la méthode en ConstructInContext pour clarifier que le contexte s'applique uniquement pendant la construction de l'objet.

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

Et le fait travailler si je n'instancie pas le dépôt avec injection de constructeur, mais faire quelque chose comme ça dans le constructeur? Ce dépôt = IoC.ResolveInContext (formulaire.Guid); – Mike

+0

Si vous voulez dire avoir une propriété Guid statique sur votre formulaire, alors oui cela devrait fonctionner. Le contexte s'applique uniquement lorsque Ninject construit l'objet, donc même si vous avez passé le même Guid en tant que propriété statique sur le formulaire, chaque formulaire aurait sa propre ISession. Maintenant que j'y pense, vous n'avez pas besoin de le passer car le contexte ne s'applique qu'à la construction. ResolveInContext pourrait simplement définir le contexte. Il est évidemment pas thread safe cependant. –

0

Nous avons ceci avec AOP, dans unhaddins. Appelé "Conversation par transaction commerciale".

recherche dans google

+1

Pourquoi la downvote? – apollodude217

Questions connexes