IoC - WindsorContainer - Application_Start 后的 Asp.Net null

Posted

技术标签:

【中文标题】IoC - WindsorContainer - Application_Start 后的 Asp.Net null【英文标题】:IoC - WindsorContainer - Asp.Net null after Application_Start 【发布时间】:2010-08-03 04:31:19 【问题描述】:

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

但是,因为我在 IIS7 上使用 Sharp 架构和 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&lt;IInitOAuthProvider&gt;("initOauth").OAuthProvider 并且当 NHibernateSession 已初始化时,_container对象为空。

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

【问题讨论】:

请发布 CreateWindsorContainer() 的定义 另见***.com/questions/3353732/…,我在这里看到同样的错误。 【参考方案1】:

我认为主要问题(我认为 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。

希望这是有道理的。

【讨论】:

谢谢您,非常有用且很好的答案,是的,可以解决它。非常感谢。

以上是关于IoC - WindsorContainer - Application_Start 后的 Asp.Net null的主要内容,如果未能解决你的问题,请参考以下文章

如何访问 Castle Windsor 的 Fluent Interfaces API?

IoC容器Autofac -- 什么是IoC以及理解为什么要使用Ioc

[转帖]浅谈IOC--说清楚IOC是什么

Spring5源码分析(004)——IoC篇之理解Ioc

Spring(02)重新认识 IoC

一步一步造个IoC轮子:构造基本的IoC容器