IoC - WindsorContainer - 在Application_Start之后的Asp.Net null

时间:2010-08-03 04:31:19

标签: .net nhibernate s#arp-architecture

我有一种情况,我在.Net Web应用程序中使用IoC(WindsorContainer),在Global.asax中我注册了我的容器,但在我注册我的WindsorContainer之后,我还需要实例化另一个类(Oauth) Global.asax。

但是因为我在IIS7上使用了Sharp Architecture和Nhibernate,所以这种情况非常棘手,因为webSessionStorage在Global.asax文件的Init()方法中被注册,我必须在NhibernateSession之后实例化OauthInit类已初始化,但此时WindsorContainer已经为空,因为Init发生在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));
    }


}

所以我现在正处于捕获22中。当我在Application_Start请求期间创建WindsorContainer时,NHibernateSession尚未初始化,因此我无法调用_container.Resolve<IInitOAuthProvider>("initOauth").OAuthProvider并且当NHibernateSession已初始化时, _container对象为null。

任何帮助都将不胜感激,谢谢。

1 个答案:

答案 0 :(得分:4)

我认为主要问题(我认为Mauricio Scheffer的评论是  暗示HttpApplication对象可以有多个实例,因此可以创建IWindsorContainer _containerWebSessionStorage _webSessionStorage的多个副本,当(如果我理解正确的代码)你只能想要一个实例。还要记住你的HttpApplication的Init()方法也可以多次被调用。

这基本上是对HttpApplication生命周期的一个基本误解。当传入的HTTP请求进入应用程序时,ASP.NET工作进程将启动多个HttpApplication实例来处理这些请求,一旦完成将它们放入池中,准备再次使用(它不会销毁它们) 。这类似于数据库连接池。

但从根本上说,你必须要知道 HttpApplication不是单身人士,可能有多个实例。这是一个非常常见的错误,也让我感到沮丧,which is why I wrote a blog post on it

尝试将IWindsorContainer和WebSessionStorage设置为静态。


编辑:好的,更仔细地研究了代码的更详细的答案。

请参阅您的Application_Start事件,其中您正在初始化

的实例
private IWindsorContainer _container;

...但是因为它不是静态变量,所以只会为实例化的第一个HttpApplication对象进行初始化。随着其他HttpApplication对象被实例化,它们的_container变量副本将为NULL。为什么?因为_container变量仅在Application_Start事件中初始化,该事件已被触发。因此_container将被设置为第一个HttpApplication实例的对象,但在此之后每个HttpApplication实例将为NULL。

希望这是有道理的。