【问题标题】:Advanced: How many times does HttpModule Init() method get called during application's life?高级:在应用程序的生命周期中,HttpModule Init() 方法被调用了多少次?
【发布时间】:2010-07-30 11:02:10
【问题描述】:

Web应用初始化如下:

  1. 我们知道,当 IIS 收到对特定 Asp.net 应用程序资源的第一个请求时,IIS 会创建一个 HttpApplication 的实例(在 global.asax 代码隐藏中定义)。
  2. 创建此新实例时,会进行初始化,同时检查所有已配置的 HTTP 模块。
  3. 然后实例化所有模块并放入应用程序的Modules 集合(HttpModuleCollection 类型)
  4. 模块循环并调用它们的Init() 方法(当它们注册请求事件时)

据我了解,上述情况发生在 Web 应用程序启动/初始化时(因此是应用程序启动事件)。

模块会发生什么?

当 Web 应用程序处于活动状态时,它们是在每个请求上(重新)启用还是在每个连续请求上从 Modules 属性中重复使用?据我了解,IIS 和 Asp.net 在 Web 应用程序的整个生命周期中都会重复使用它们。

如果它们被重用,我们是否可以假设它们的Init() 方法实际上是应用程序启动事件的伪事件处理程序?问题是我们不能附加到 http 模块中的应用程序级事件。但如果它们被重用,我们可以使用 Init() 作为应用程序启动事件,并执行我们在 global.asax 中放入的任何操作。

问题

我们可以假设模块的Init() 方法在应用程序启动事件中仅被调用吗?我们是否可以使用这个假设来为我们无法更改 global.asax 代码隐藏的应用程序注册路由? web.config 通常是可访问的,我们可以按照我们想要的方式对其进行更改。
这真的有效吗?

其他信息

我们可以检查HttpApplication 代码并检查其InitModulesCommon() 方法。这个实际上调用了每个已注册 HTTP 模块的Init()。更有趣的是,这个方法只被InitIntegratedModules()和InitModules()方法使用。在HttpApplication.InitInternal() 方法中,它们都仅使用。这是我假设的基础,但我想知道是否有人滥用IHttpModule.Init() 进行应用程序启动事件。

【问题讨论】:

    标签: asp.net events httpmodule


    【解决方案1】:

    Init() 仅被调用一次(每个 HttpApplication 实例)

    经过我的测试,IHttpModule初始化的内部工作如下:

    1. 每个 IHttpModule 在 Web 应用程序启动时通过实例化和调用 Init() 方法进行初始化
    2. HttpApplication 将所有模块实例存储在其 Modules 属性中
    3. 然后在 HttpApplication 的整个生命周期内重复使用模块,并且只要应用程序处于活动状态,就不会丢弃/重新初始化模块

    所以最好的结果是

    您不能将IHttpModule 附加到应用程序级事件,但您可以将其Init() 方法用作伪应用程序启动事件委托。在其中,您可以执行通常放在Application_Start 委托中的任何代码。

    您也可以在我的blog post阅读有关它的详细信息。

    但在现实生活中的 Web 服务器环境中要小心

    但是 IIS 使用一种叫做 应用程序池 的东西。每个池可以有任意数量的HttpApplication 实例。是的,多个。应用程序启动会创建所有这些实例。他们每个人都初始化自己的模块列表,但只有第一个执行Application_OnStart 事件处理程序。

    因此,每当您的模块修改了一些公共共享资源时,您应该采取额外的措施来表明第一个模块已经这样做了,而其他模块不会再这样做了。阅读有关它的additional blog post,它将向您展示如何以及何时对您的模块使用线程锁定以使其实际充当Application_OnStart 事件处理程序。顺便说一句:如果需要,也可以处理 Application_OnEnd 事件。 ;)

    详细的博文链接

    1. Writing a custom IHttpModule that handles Application_OnStart event
    2. How to correctly use IHttpModule to handle Application_OnStart event

    【讨论】:

    • @MatteS:以什么方式误导?这是完全正确的,因为每个HttpApplication 实例只调用一次Init。当一个人通读整个答案时(他们应该这样做),他们就会明白如何解决自己的问题。
    • 我不知道为什么,但是您在博客中提供的解决方案对我不起作用,我收到以下错误:[NullReferenceException: Object reference not set to an instance of an object.] 系统.Web.PipelineModuleStepContainer.GetEventCount(RequestNotification notification, Boolean isPostEvent) +30 System.Web.PipelineStepManager.ResumeSteps(Exception error) +408 如果我从函数逻辑中删除“applicationStarted”变量,网站加载正常。我目前正在使用 IIS 8.5、.NET 4.5.1 和集成管道。你知道为什么吗?谢谢
    • @RobertKoritnik 你知道这些是否一次性发生:“instatiating and a call to Init()”?即我主要想知道模块实例是否是在应用程序实例之后创建的。
    【解决方案2】:

    Application_Start 在应用程序的整个生命周期内只运行一次。

    IHttpModule.Init 在请求处理开始之前为每个 HttpApplication 实例运行。请参阅walkthrough。 Init 是您可以注册用于处理请求的事件的地方。

    一个 HttpApplication 实例可以重复用于多个请求。 ASP.Net 池化 HttpApplication 对象,因此每次 HttpApplication 的新实例都会调用一次 Init

    【讨论】:

    • 您提供的链接没有说明Init() 何时被调用。根据HttpApplication 的代码,我已经检查过它看起来不会为每个请求重新实例化模块。这是您提供的模块的一个非常基本的示例,它没有提供任何关于实际执行管道的信息。
    • 查看我的附加信息。它将让您更好地了解这个问题。
    • 没错!所以HttpModule 的Init() 方法可以被认为是一个应用程序启动事件。正如我所预料的那样。我认为开发人员在开发应用程序时并没有真正意识到或想到这一点。仍然无法在HttpModule 中访问 Session 事件。
    • Init 确实充当应用程序启动事件。最好说是应用程序初始化事件。只有第一个实例也执行Application_OnStart。但这也可以通过模块来完成。每当您的模块修改公共共享资源时,您都必须使用它。阅读我的博客文章中的所有详细信息。 erraticdev.blogspot.com/2011/01/…
    猜你喜欢
    • 2010-11-11
    • 1970-01-01
    • 2020-09-19
    • 2017-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-14
    • 2020-12-27
    相关资源
    最近更新 更多