I've gone rounds with this ever since I started programming classic ASP 12 (or so) years ago and I've never found a great solution because the architecture of ASP and ASP.NET has always been a swamp of bad practices, magic shared singletons, etc. My biggest issue is with the HttpApplication
object with its non-event events (Application_Start
, Application_End
, etc.).
自从我几年前开始编写经典的ASP 12(左右)以来,我已经完成了这一切,我从来没有找到一个很好的解决方案,因为ASP和ASP.NET的架构一直是不良做法的沼泽,魔术共享单个人等。我最大的问题是HttpApplication对象及其非事件事件(Application_Start,Application_End等)。
If you want to do stuff once for the entire lifespan of an HTTP application, Application_Start
is the obvious place to do it. Right? Not exactly. Firstly, this is not an event per se, it's a magic naming convention that, when followed, causes the method to be called once per AppDomain created by IIS.
如果你想在HTTP应用程序的整个生命周期内做一次东西,Application_Start就是显而易见的地方。对?不完全是。首先,这本身不是一个事件,它是一个神奇的命名约定,如果遵循这个约定,会导致每个由IIS创建的AppDomain调用该方法。
Besides magic naming conventions being a horrible practice, I've started to think it might be a reason there exist no such thing as a Start
event on the HttpApplication
object. So I've experimented with events that do exist, such as Init
. Well, this isn't really an event either, it's an overridable method, which is the next best thing.
除了魔术命名约定是一种可怕的做法之外,我开始认为这可能是HttpApplication对象上不存在Start事件的原因。所以我已经尝试过确实存在的事件,例如Init。嗯,这也不是一个真正的事件,它是一个可以覆盖的方法,这是下一个最好的事情。
It seems that the Init()
method is called for every instantiation of an HttpApplication
object, which happens a lot more than once per AppDomain. This means that I might as well just put my startup logic inside the HttpApplication
object's constructor.
似乎为HttpApplication对象的每个实例化调用了Init()方法,每个AppDomain发生一次。这意味着我不妨把我的启动逻辑放在HttpApplication对象的构造函数中。
Now my question is, why shouldn't I put my startup logic in the constructor? Why does even Init()
exist and do I need to care about Application_Start
? If I do, can anyone explain why there is no proper event or overridable method for this pseudo-event in the HttpApplication
object?
现在我的问题是,为什么我不应该将我的启动逻辑放在构造函数中?为什么甚至Init()存在,我是否需要关心Application_Start?如果我这样做,有人可以解释为什么HttpApplication对象中没有适当的事件或可覆盖的伪事件方法吗?
And can anyone explain to me why in a typical ASP.NET application, 8 instances of my HttpApplication
are created (which causes the constructor and Init
to run just as many times, of course; this can be mitigated with locking and a shared static boolean called initialized
) when my application only has a single AppDomain?
任何人都可以向我解释为什么在一个典型的ASP.NET应用程序中,我的HttpApplication的8个实例被创建(这导致构造函数和Init运行多次,当然;这可以通过锁定和共享的静态布尔值来缓解当我的应用程序只有一个AppDomain时,调用initialized)
3 个解决方案
#1
3
Calling Application_Start the first time an instance of HttpApplication is created, but not on subsequent instances seems a bit of a hack. Perhaps Microsoft didn't want to explain the concept of a static constructor to people who didn't really want to know.
在第一次创建HttpApplication实例时调用Application_Start,但在后续实例上没有,这似乎有点黑客。也许微软不想向那些不想知道的人解释静态构造函数的概念。
Application_End(), however, seems to be a necessity, as there is no C# equivalent of a static destructor/finalizer. As hacks go, this isn't that bad. It just smells a little funny.
然而,Application_End()似乎是必需的,因为没有静态析构函数/终结器的C#等价物。随着黑客的进展,这并不是那么糟糕。它只是闻起来有点搞笑。
#2
4
The Asp.Net runtime keeps a pool of HttpApplication objects. Every .aspx request is processed by a single object which is allocated from the pool(8 objects in your case).
Asp.Net运行时保留了一个HttpApplication对象池。每个.aspx请求都由从池中分配的单个对象处理(在您的情况下为8个对象)。
The answer to your question, Application_Start event is indeed called, but only for the first instance of the HttpApplication, not subsequent ones, so you can be sure that it is called exactly once whenever your application is started or the application pool of IIS is restarted. So is Application_OnEnd event (last instance)
您的问题的答案,确实调用了Application_Start事件,但仅适用于HttpApplication的第一个实例,而不是后续实例,因此您可以确保在应用程序启动或IIS的应用程序池重新启动时只调用一次。 Application_OnEnd事件也是如此(最后一个实例)
meanwhile, the Init() and Dispose() are called on every instance of the HttpApplication object. That will be called on each instance a.k.a. each request.
同时,在HttpApplication对象的每个实例上调用Init()和Dispose()。这将在每个实例a.k.a.每个请求上调用。
Why do they do it that way..? maybe to balance performance and memory optimizations.
为什么他们这样做..?也许是为了平衡性能和内存优化。
Hope i answered your question.
希望我回答你的问题。
#3
0
There is one HttpApplication object created for each concurrent request. That is each thread that ASP.NET creates gets its own instance of HttpApplication. Instances are re-used for subsequent requests in the same way that threads are re-used from the thread pool.
为每个并发请求创建了一个HttpApplication对象。这就是ASP.NET创建的每个线程都有自己的HttpApplication实例。实例以与从线程池重用线程相同的方式重用于后续请求。
Use the Init method to initialize instance fields on the HttpApplication as these will only be initialized one the first instance if it is done in the Application_Start event .
使用Init方法初始化HttpApplication上的实例字段,因为只有在Application_Start事件中完成后才会初始化第一个实例。
#1
3
Calling Application_Start the first time an instance of HttpApplication is created, but not on subsequent instances seems a bit of a hack. Perhaps Microsoft didn't want to explain the concept of a static constructor to people who didn't really want to know.
在第一次创建HttpApplication实例时调用Application_Start,但在后续实例上没有,这似乎有点黑客。也许微软不想向那些不想知道的人解释静态构造函数的概念。
Application_End(), however, seems to be a necessity, as there is no C# equivalent of a static destructor/finalizer. As hacks go, this isn't that bad. It just smells a little funny.
然而,Application_End()似乎是必需的,因为没有静态析构函数/终结器的C#等价物。随着黑客的进展,这并不是那么糟糕。它只是闻起来有点搞笑。
#2
4
The Asp.Net runtime keeps a pool of HttpApplication objects. Every .aspx request is processed by a single object which is allocated from the pool(8 objects in your case).
Asp.Net运行时保留了一个HttpApplication对象池。每个.aspx请求都由从池中分配的单个对象处理(在您的情况下为8个对象)。
The answer to your question, Application_Start event is indeed called, but only for the first instance of the HttpApplication, not subsequent ones, so you can be sure that it is called exactly once whenever your application is started or the application pool of IIS is restarted. So is Application_OnEnd event (last instance)
您的问题的答案,确实调用了Application_Start事件,但仅适用于HttpApplication的第一个实例,而不是后续实例,因此您可以确保在应用程序启动或IIS的应用程序池重新启动时只调用一次。 Application_OnEnd事件也是如此(最后一个实例)
meanwhile, the Init() and Dispose() are called on every instance of the HttpApplication object. That will be called on each instance a.k.a. each request.
同时,在HttpApplication对象的每个实例上调用Init()和Dispose()。这将在每个实例a.k.a.每个请求上调用。
Why do they do it that way..? maybe to balance performance and memory optimizations.
为什么他们这样做..?也许是为了平衡性能和内存优化。
Hope i answered your question.
希望我回答你的问题。
#3
0
There is one HttpApplication object created for each concurrent request. That is each thread that ASP.NET creates gets its own instance of HttpApplication. Instances are re-used for subsequent requests in the same way that threads are re-used from the thread pool.
为每个并发请求创建了一个HttpApplication对象。这就是ASP.NET创建的每个线程都有自己的HttpApplication实例。实例以与从线程池重用线程相同的方式重用于后续请求。
Use the Init method to initialize instance fields on the HttpApplication as these will only be initialized one the first instance if it is done in the Application_Start event .
使用Init方法初始化HttpApplication上的实例字段,因为只有在Application_Start事件中完成后才会初始化第一个实例。