IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

NHibernate Discussion :

[WCF][NHibernate] HttpModule pour gérer les sessions NHibernate


Sujet :

NHibernate

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    35
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juin 2009
    Messages : 35
    Par défaut [WCF][NHibernate] HttpModule pour gérer les sessions NHibernate
    Bonjour à tous

    3 couches dans mon "projet" :
    1. Accés aux données avec NHibernate (via Fluent NHibernate)
    2. Service Librairy (avec les références de l’accès aux données)
    3. WebService (.svc) (avec les références au Service Librairy)


    Je voudrais que les sessions (NHibernate) soient créées et détruites dans le même timing que les requêtes http. J'ai vu et lu beaucoup d'articles sur le net qui parle de ce système. Malgré cela je ne parviens pas réussir cette prouesse.

    Voici ce que j'ai fait :

    ** Web service **

    web.config

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    <httpModules>
    	<add name="NHibernateHttpModule" type="Data.Connection.HttpModule.NHibernateHttpModule"/>
    </httpModules>
    ** Service Librairy **

    Appel à une methode du contract

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    public IList<ContactData> GetContactInfo(string param){
    (...)
    ContactRepository.GetContacts(param);
    Le repository est créé de cette manière

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    private IContactRepository ContactRepository {
                get {
                    if (_contactRepository == null)
                        _contactRepository = RepositoryFactory<IContactRepository>.CreateRepository();
                    return _contactRepository;
                }
                set { ;}
            }
    ** Accès aux données **

    Repository contact fait appel à la propriété Session

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ICriteria criteria = Session.CreateCriteria<Contact>();
    C'est ici que ça ne se passe pas bien. _session me renvoi null

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    protected ISession Session{
                get {
                    if (_session == null) { 
                        //_session = FNSettings.CreateSession();
                        log.Debug("Create new session");
                        _session = FNSettings.GetCurrentSession();
                    }
                    return _session;
                }
            }
    HttpModule dans la couche d'accès au données

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
    public class NHibernateHttpModule : IHttpModule
        {
     
            public void Dispose(){ ; }
     
            public void Init(HttpApplication context)
            {
                context.EndRequest += ApplicationEndRequest;
                context.BeginRequest += ApplicationBeginRequest;
            }
     
            public void ApplicationBeginRequest(object sender, EventArgs e) {
                NHibernate.Context.CurrentSessionContext.Bind(FNSettings.CreateSession());
            }
     
            public void ApplicationEndRequest(object sender, EventArgs e) {
                ISession currentSession = NHibernate.Context.CurrentSessionContext.Unbind(FNSettings.SessionFactory);
                currentSession.Close();
                currentSession.Dispose();
            }
        }
    Create Session

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    public static ISession CreateSession() {
                return SessionFactory.OpenSession();
            }
    SessionFactory

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    public static ISessionFactory SessionFactory {
                get {
                    if (_sessionFactory == null)
                        _sessionFactory = FNSettings.CreateSessionFactory();
                    return _sessionFactory;
                }
            }
    Configuration Nhibernate (via Fluent NHibernate)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    private static FluentConfiguration FNConfiguration{
                get {
                    if (_fnConfiguration == null){
                        var cfg = OracleClientConfiguration.Oracle10
                            .ConnectionString(c => c.Is(FNSettings.ConnectionString))
                            .Dialect<NHibernate.Dialect.Oracle10gDialect>()
                            .ShowSql();
     
                        _fnConfiguration = Fluently.Configure()
                            .Database(cfg)
                            .ExposeConfiguration(
                                c => c.SetProperty("current_session_context_class", "web")) //use for HttpModule 
                            .Mappings(m => m.FluentMappings.AddFromAssemblyOf<ContactMap>());
                    }
                    return _fnConfiguration;
                }
            }
    Voilà qqu'un peut-il m'aider ?

    Bien à vous

  2. #2
    Membre émérite Avatar de NicoL__
    Homme Profil pro
    Architecte
    Inscrit en
    Janvier 2011
    Messages
    399
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Architecte

    Informations forums :
    Inscription : Janvier 2011
    Messages : 399
    Par défaut
    Tout ces morceaux de codes ne donne pas la vision de l'architecture des classes.
    Mais comme ça je dirais que ton NHibernateHttpModule me semble un peu light et bien qu'il gère le close des sessions hibernate ne gère pas vraiment leur création et leur cycle de vie.
    Je pense qu'il faut ce genre de méthode devrait se trouver dans NHibernateHttpModule
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    public static ISession CurrentSession
        {
            get
            {
                if (HttpContext.Current != null)
                {                           
                    HttpContext currentContext = HttpContext.Current;
                    ISession session = currentContext.Items[KEY] as ISession;
                    if (session == null)
                    {
                        session = SessionHelper.OpenSession(); 
                        currentContext.Items[KEY] = session;
                    }
                    return session;
                }
            }
        }
    Et de passer par NHibernateHttpModule.CurrentSession() pour récupérer la bonne session hibernate.

    Après le SessionHelper peut utiliser Fluent pour créer la session mais n'utilise pas un singleton (sinon une session pour tout le monde et toutes les requêtes). Mais les sessions doivent être gérer au niveau du HttpContext pour une session par requête.

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    35
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juin 2009
    Messages : 35
    Par défaut
    Bonjour

    Merci de votre réponse.

    Je viens de logger le tout et je me rend compte que c'est vraiment à l'appel de la GetCurrentSession que j'ai un souci.

    Donc mon HttpModule travail très bien. Lors du bind je log l'id de la session. De même je log l'id de la session lors du unbind.

    Les deux sont identiques.

    Je travail avec des WCF peut être que la gestion de context ("current_session_context_class" , "web") n'est pas adapté pour les wcf. J'ai également essayer managed_web, mais même résultat.

    Le but est d'utiliser le GetCurrentSession de ma SessionFactory. Je continue donc mes recherches

    Bien à vous

  4. #4
    Membre émérite Avatar de NicoL__
    Homme Profil pro
    Architecte
    Inscrit en
    Janvier 2011
    Messages
    399
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Architecte

    Informations forums :
    Inscription : Janvier 2011
    Messages : 399
    Par défaut
    Vous voulez tour simplement dire que l'appel :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    _session = FNSettings.GetCurrentSession();
    ne fonctionne pas et renvoie null. Je ne vois pas trop à quoi correspond FNSettings.
    Mais que donne le la ligne commenté
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    _session = FNSettings.CreateSession()
    Mais à mon sens ça devrait ressemble à ça
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    _session = FNSettings.SessionFactory.OpenSession()

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    35
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juin 2009
    Messages : 35
    Par défaut
    Bonjour

    FNSettings est une classe abstraite contenant toute la logique de configuration de Fluent Nhibernate.

    Exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    public static ISession CreateSession() {
                return SessionFactory.OpenSession();
            }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
      public static ISession GetCurrentSession() {
                return SessionFactory.GetCurrentSession();
            }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    public static ISessionFactory SessionFactory {
                get {
                    if (_sessionFactory == null){
                        _sessionFactory = FNSettings.CreateSessionFactory();
                    }
                    return _sessionFactory;
                }
            }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    private static FluentConfiguration FNConfiguration{
                get {
                    if (_fnConfiguration == null){
                        var cfg = OracleClientConfiguration.Oracle10
                            .ConnectionString(c => c.Is(FNSettings.ConnectionString))
                            .Dialect<NHibernate.Dialect.Oracle10gDialect>()
                            .ShowSql();
     
                        _fnConfiguration = Fluently.Configure()
                            .Database(cfg)
                            .CurrentSessionContext<NHibernate.Context.WebSessionContext>() //use for HttpModule 
                            //.ExposeConfiguration(
                            //    c => c.SetProperty("current_session_context_class", "web")) 
                            .Mappings(m => m.FluentMappings.AddFromAssemblyOf<ContactMap>())
                            .Mappings(m => m.FluentMappings.AddFromAssemblyOf<PersonMap>())
                            .Mappings(m => m.FluentMappings.AddFromAssemblyOf<ScreeningMap>())
                            .Mappings(m => m.FluentMappings.AddFromAssemblyOf<SxCurrentAccountMap>())
                            .Mappings(m => m.FluentMappings.AddFromAssemblyOf<AgencyMap>())
                            .Mappings(m => m.FluentMappings.AddFromAssemblyOf<UserMap>())
                            .Mappings(m => m.FluentMappings.AddFromAssemblyOf<CurrentAccountMap>())
                            .Mappings(m => m.FluentMappings.AddFromAssemblyOf<ClientMap>())
                            .Mappings(m => m.FluentMappings.AddFromAssemblyOf<OpeningHoursMap>());
                    }
                    return _fnConfiguration;
                }
            }
    Juste pour info voici a quoi ressemble la dernière version de mon HttpModule.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    public void ApplicationBeginRequest(object sender, EventArgs e) {
                ISession session = FNSettings.CreateSession();
                //NHibernate.Context.ManagedWebSessionContext.Bind(HttpContext.Current, FNSettings.CreateSession());
                NHibernate.Context.WebSessionContext.Bind(session);
     
                //log
                log.Debug("ApplicationBeginRequest - Bind Session : " + ((ISessionImplementor)session).SessionId);
     
            }
     
            public void ApplicationEndRequest(object sender, EventArgs e) {
                //ISession session = NHibernate.Context.ManagedWebSessionContext.Unbind(HttpContext.Current, FNSettings.SessionFactory);
                ISession session = NHibernate.Context.WebSessionContext.Unbind(FNSettings.SessionFactory);
     
                if (session != null) {
     
                    //log
                    log.Debug("ApplicationEndRequest - Unbind session : " + ((ISessionImplementor)session).SessionId);
     
                    if (session.Transaction != null
                        && session.Transaction.IsActive){
                        session.Transaction.Rollback();
     
                        //log
                        log.Warn("ApplicationEndRequest - Force transaction to rollback");
                    }else{
                        session.Flush();
     
                        //log
                        log.Debug("ApplicationEndRequest - Session were flush");
                    }
                    session.Close();
                    session.Dispose();
                }
            }
    C'est comme si au moment de l'appel de GetCurrentSession il ne trouve pas le context Http et que du coup il me renvoi null...

    Pourtant ce que j'ai fait c'est
    1. Dans la configuration ajouter un ligne pour dire que le current context était gérer "web"
    2. Créer un Http module qui lit le context http à une session NHibernate
    3. ajouter dans le webconfig tout ce qu'il faut


    Pour qu'au final l'appel de GetCurrentSession ne fonctionne pas MAIS que le http module fait bien son boulot.

    Punaise, là je suis vraiment paumé

  6. #6
    Membre émérite Avatar de NicoL__
    Homme Profil pro
    Architecte
    Inscrit en
    Janvier 2011
    Messages
    399
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Architecte

    Informations forums :
    Inscription : Janvier 2011
    Messages : 399
    Par défaut
    Il faudrait vérifier l'état de la SessionFactory

    Mais sinon je ne vois pas, et je ne vois pas l’intérêt de FNSettings puisque fluent a déjà une interface simplifiée.

    Il y a peut-être un problème de lock... en tout cas ça manque de l'implémentation des singletons que tu as réalisé. Et en web le contexte est forcement multithreadé.

    Un truc touvé sur internet qui semble simple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    static readonly object factorylock = new object();
     
    public ISession OpenSession()
    {
        lock (factorylock)
        {
           if (_sessionFactory == null)
           {
                var cfg = Fluently.Configure().
                     Database(SQLiteConfiguration.Standard.ShowSql().UsingFile("Foo.db")).
                   Mappings(m => m.FluentMappings.AddFromAssemblyOf<MappingsPersistenceModel>());
                _sessionFactory = cfg.BuildSessionFactory();
                BuildSchema(cfg);
            }
        }
        return _sessionFactory.OpenSession();
    }

Discussions similaires

  1. Script pour gérer les sessions utilisateurs sous Ubuntu
    Par thucydide dans le forum Shell et commandes GNU
    Réponses: 4
    Dernier message: 08/06/2012, 11h51
  2. Quels modules Perl pour gérer les documents XML ?
    Par djibril dans le forum Modules
    Réponses: 8
    Dernier message: 02/12/2010, 23h54
  3. [Info] Conseils pour gérer les ressources
    Par calogerogigante dans le forum Eclipse Java
    Réponses: 10
    Dernier message: 05/07/2009, 12h49
  4. Réponses: 13
    Dernier message: 07/02/2007, 12h10
  5. Méthode simple pour gérer les collisions
    Par Hyoga dans le forum OpenGL
    Réponses: 2
    Dernier message: 19/02/2005, 13h43

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo