2010-08-03 4 views
1

J'ai une situation où je l'utilisateur IoC (WindsorContainer) dans une application web .Net, et dans le Global.asax je enregistre mon conteneur, mais tout de suite après que j'inscris mon WindsorContainer I aussi besoin d'instancier une autre classe (Oauth) dans le Global.asax. Cependant, comme j'utilise l'architecture Sharp et Nhibernate sur IIS7, la situation est très délicate car le webSessionStorage est enregistré pendant la méthode Init() dans le fichier Global.asax et je dois instancier la classe OauthInit après la NhibernateSession a été initialisé, cependant, à ce moment-là, le WindsorContainer est déjà nul, puisque l'initialisation se produit après le démarrage de l'application. Voici le code:IoC - WindsorContainer - Asp.Net null après Application_Start

public class Global : HttpApplication, IOAuthServices 
    { 
     static ITokenRepository<AccessToken> _accessTokenRepository; 
     static ITokenRepository<RequestToken> _requestTokenRepository; 
     private IWindsorContainer _container; 
     private WebSessionStorage _webSessionStorage; 
     private IOAuthProvider _provider; 

     public ITokenRepository<AccessToken> AccessTokenRepository 
     { 
      get { return _accessTokenRepository; } 
     } 

     public ITokenRepository<RequestToken> RequestTokenRepository 
     { 
      get { return _requestTokenRepository; } 
     } 


     public IOAuthProvider Provider 
     { 
      get { return _provider; } 
     } 

     void Application_Start(object sender, EventArgs e) 
     { 
      _requestTokenRepository = new InMemoryTokenRepository<RequestToken>(); 
      _accessTokenRepository = new InMemoryTokenRepository<AccessToken>(); 

      CreateWindsorContainer(); 
     } 


     public override void Init() 
     { 
      base.Init(); 

      // The WebSessionStorage must be created during the Init() to tie in HttpApplication events 
      _webSessionStorage = new WebSessionStorage(this); 

     } 

     /// <summary> 
     /// Due to issues on IIS7, the NHibernate initialization cannot reside in Init() but 
     /// must only be called once. Consequently, we invoke a thread-safe singleton class to 
     /// ensure it's only initialized once. 
     /// </summary> 
     protected void Application_BeginRequest(object sender, EventArgs e) 
     { 
      NHibernateInitializer.Instance().InitializeNHibernateOnce(InitializeNHibernateSession); 
      _provider = _container.Resolve<IInitOAuthProvider>("initOauth").OAuthProvider); // <-- THIS IS THE ISSUE HERE 
     } 

     /// <summary> 
     /// If you need to communicate to multiple databases, you'd add a line to this method to 
     /// initialize the other database as well. 
     /// </summary> 
     private void InitializeNHibernateSession() 
     { 
      NHibernateSession.Init(
       _webSessionStorage, 
       new[] { Server.MapPath("~/bin/MyAppSuite.Data.dll") }, 
       new AutoPersistenceModelGenerator().Generate(), 
       Server.MapPath("~/NHibernate.config")); 
     } 

    private void CreateWindsorContainer() 
    { 
     _container = new WindsorContainer(); 

     ComponentRegistrar.AddComponentsTo(_container); 

     ServiceLocator.SetLocatorProvider(() => new WindsorServiceLocator(_container)); 
    } 


} 

Je suis vraiment au moment d'une prise 22. Quand je crée mon WindsorContainer lors de la demande Application_Start, le NHibernateSession n'a pas été initialisées, donc je ne peux pas appeler _container.Resolve<IInitOAuthProvider>("initOauth").OAuthProvider et lorsque le NHibernateSession a été initialisé, l'objet _container est null.

Toute aide serait appréciée, merci.

+0

veuillez publier la définition de CreateWindsorContainer() –

+2

également voir http: // stackoverflow.com/questions/3353732/comment-résoudre-un-user-repository-using-windsor-ioc-au-début-de-la-applicati, je vois la même erreur ici. –

Répondre

4

Je pense que le principal problème (comme je pense que le commentaire de Mauricio Scheffer est faisant allusion à) est qu'il peut y avoir plusieurs instances de l'objet HttpApplication, et à cause de cela, il peut y avoir plusieurs copies du IWindsorContainer _container et WebSessionStorage _webSessionStorage créés, lorsque (si je comprends bien le code), vous ne voulez qu'une seule instance. La méthode Init() de votre application HttpApplication peut également être appelée plusieurs fois à cause de cela.

Il s'agit fondamentalement d'une incompréhension fondamentale du cycle de vie de HttpApplication. Lorsque des requêtes HTTP entrantes arrivent dans l'application, le processus de travail ASP.NET lancera plusieurs instances HttpApplication pour traiter ces requêtes, et une fois terminé les mettra dans un pool, prêt à être utilisé à nouveau (il ne les détruira pas) . Ceci est similaire au pool de connexions de base de données.

Mais fondamentalement, vous devez être conscient que le HttpApplication n'est pas un Singleton, il peut y avoir plusieurs instances. C'est une erreur assez courante et m'a également fait trébucher, which is why I wrote a blog post on it.

Essayez de définir votre IWindsorContainer et WebSessionStorage comme étant statiques.


EDIT: OK, réponse plus détaillée ayant étudié le code plus attentivement.

Voir votre événement Application_Start, en elle vous initialisant une instance de

private IWindsorContainer _container; 

... mais parce que ce n'est pas une variable statique, il ne fera que s'initialisées pour le premier objet qui est instancié HttpApplication . Lorsque des objets HttpApplication supplémentaires sont instanciés, leurs copies de la variable _container seront NULL. Pourquoi? Parce que la variable _container est initialisée uniquement dans l'événement Application_Start, qui a déjà été déclenché. Ainsi _container sera défini sur un objet pour la première instance HttpApplication, mais sera NULL pour chaque instance HttpApplication après cela.

Espérons que cela a du sens.

+0

Merci, très utile et bonne réponse, et oui qui le répare. Très appréciée. – Ryk

Questions connexes