我有一种情况,我在.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。
任何帮助都将不胜感激,谢谢。
答案 0 :(得分:4)
我认为主要问题(我认为Mauricio Scheffer的评论是
暗示HttpApplication对象可以有多个实例,因此可以创建IWindsorContainer _container
和WebSessionStorage _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。
希望这是有道理的。