Application_Start 与 OnInit 与构造函数
自从 12(大约)年前我开始编写经典 ASP 以来,我就一直在研究这个问题,但我从未找到一个很好的解决方案,因为 ASP 和 ASP.NET 的体系结构一直是不良实践的沼泽,魔法共享我最大的问题是 HttpApplication< /code>
对象及其非事件事件(
Application_Start
、Application_End
等)。
如果您想在 HTTP 应用程序的整个生命周期内执行一次操作,Application_Start
显然是执行此操作的位置。正确的?不完全是。首先,这本身不是一个事件,而是一个神奇的命名约定,如果遵循该约定,将导致 IIS 创建的每个 AppDomain 调用该方法一次。
除了神奇的命名约定是一种可怕的做法之外,我开始认为这可能是 HttpApplication
对象上不存在 Start
事件之类的原因。因此,我尝试了确实存在的事件,例如 Init
。好吧,这也不是真正的事件,它是一个可重写的方法,这是下一个最好的事情。
似乎每次 HttpApplication
对象的实例化都会调用 Init()
方法,这种情况在每个 AppDomain 中会发生多次。这意味着我不妨将启动逻辑放入 HttpApplication
对象的构造函数中。
现在我的问题是,为什么我不应该将启动逻辑放在构造函数中?为什么Init()
存在并且我需要关心Application_Start
?如果我这样做,任何人都可以解释为什么 HttpApplication
对象中没有针对此伪事件的正确事件或可重写方法?
谁能向我解释为什么在典型的 ASP.NET 应用程序中,创建了 8 个 HttpApplication 实例(这导致构造函数和 Init 运行同样多次)当然;当我的应用程序只有一个 AppDomain 时,可以通过锁定和名为 initialized
的共享静态布尔值来缓解这种情况?
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.).
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.
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.
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.
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?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
Asp.Net 运行时保留一个 HttpApplication 对象池。每个 .aspx 请求都由从池中分配的单个对象(在您的情况下为 8 个对象)处理。
您的问题的答案,Application_Start 事件确实被调用,但仅针对 HttpApplication 的第一个实例,而不是后续实例,因此您可以确保每当您的应用程序启动或 IIS 的应用程序池重新启动时,它都会被调用一次。 同时,Application_OnEnd 事件(最后一个实例)
也是如此,在 HttpApplication 对象的每个实例上调用 Init() 和 Dispose()。这将在每个实例(也称为每个请求)上调用。
他们为什么要这样做..?也许是为了平衡性能和内存优化。
希望我回答了你的问题。
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).
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)
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.
Why do they do it that way..? maybe to balance performance and memory optimizations.
Hope i answered your question.
第一次创建 HttpApplication 实例时调用 Application_Start,但在后续实例中不调用 Application_Start 似乎有点麻烦。也许微软不想向那些并不真正想了解的人解释静态构造函数的概念。
然而,Application_End() 似乎是必需的,因为 C# 中没有静态析构函数/终结器的等效项。就黑客而言,这并没有那么糟糕。只是闻起来有点好笑。
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.
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.
为每个并发请求创建一个 HttpApplication 对象。也就是说,ASP.NET 创建的每个线程都会获得自己的 HttpApplication 实例。实例将被重新用于后续请求,就像重新使用线程池中的线程一样。
使用 Init 方法初始化 HttpApplication 上的实例字段,因为如果在 Application_Start 事件中完成,这些字段只会在第一个实例中初始化。
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.
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 .