C# 多次调用 HttpModule Init 方法 - 为什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1140915/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 09:12:48  来源:igfitidea点击:

HttpModule Init method is called several times - why?

c#.nethttpmoduleinit

提问by MartinF

I was creating a http module and while debugging I noticed something which at first (at least) seemed like weird behaviour.

我正在创建一个 http 模块,在调试时我注意到一些起初(至少)看起来很奇怪的行为。

When I set a breakpoint in the init method of the httpmodule I can see that the http module init methodis being called several times even though I have only started up the website for debugging and made one single request (sometimes it is hit only 1 time, other times as many as 10 times).

当我在 httpmodule 的 init 方法中设置断点时,我可以看到http 模块的 init 方法被多次调用,即使我只启动了网站进行调试并发出了一个请求(有时它只被击中了 1 次) ,其他次数多达 10 次)。

I know that I should expect several instances of the HttpApplicationto be running and for each the http modules will be created, but when I request a single page it should be handled by a single http application object and therefore only fire the events associated once, but still it fires the events several times for each request which makes no sense - other than it must have been added several times within that httpApplication- which means it is the same httpmodule init methodwhich is being called every time and not a new http application being created each time it hits my break point (see my code example at the bottom etc.).

我知道我应该期望HttpApplication 的多个实例正在运行,并且将为每个实例创建 http 模块,但是当我请求单个页面时,它应该由单个 http 应用程序对象处理,因此只触发一次关联的事件,但它仍然为每个请求多次触发事件,这是没有意义的 - 除了它必须在该httpApplication 中添加多次- 这意味着它是每次调用的相同httpmodule init 方法,而不是新的 http 应用程序每次到达我的断点时都会被创建(请参阅底部的代码示例等)。

What could be going wrong here? Is it because I am debugging and set a breakpoint in the http module?

这里可能出了什么问题?是不是因为我正在调试并在http模块中设置了断点?

It have noticed that it seems that if I startup the website for debugging and quickly step over the breakpoint in the httpmodule it will only hit the init methodonce and the same goes for the eventhandler. If I instead let it hang at the breakpoint for a few seconds the init methodis being called several times (seems like it depends on how long time I wait before stepping over the breakpoint). Maybe this could be some build in feature to make sure that the httpmodule is initialized and the http application can serve requests , but it also seems like something that could have catastrophic consequences.

它已经注意到,似乎如果我启动网站进行调试并快速跳过 httpmodule 中的断点,它只会命中init 方法一次,事件处理程序也是如此。如果我让它在断点处挂起几秒钟,则会多次调用init 方法(似乎这取决于我在跨过断点之前等待的时间)。也许这可能是一些内置功能,以确保 httpmodule 已初始化并且 http 应用程序可以为 requests 提供服务,但这似乎也可能会带来灾难性后果。

This could seem logical, as it might be trying to finish the request and since I have set the break point it thinks something have gone wrong and try to call the init method again? Soo it can handle the request?

这似乎合乎逻辑,因为它可能试图完成请求,并且由于我设置了断点,它认为出现问题并再次尝试调用 init 方法?Soo 它可以处理请求吗?

But is this what is happening and is everything fine (I am just guessing), or is it a real problem?

但这是正在发生的事情吗,一切都很好(我只是猜测),还是一个真正的问题?

What I am specially concerned about is that if something makes it hang on the "production/live" server for a few seconds a lot of event handlers are added through the initand therefore each request to the page suddenly fires the eventhandlerseveral times.

我特别担心的是,如果有什么事情让它在“生产/实时”服务器上挂起几秒钟,就会通过init添加大量事件处理程序,因此对页面的每个请求都会突然多次触发事件处理程序。

This behaviour could quickly bring any site down.

这种行为可能会迅速导致任何网站瘫痪。

I have looked at the "original" .net code used for the httpmodules for formsauthenticationand the rolemanagermodule, etc... But my code isn't any different that those modules uses.

我查看了用于表单身份验证的 httpmodulesrolemanagermodule等的“原始”.net 代码......但我的代码与这些模块使用的没有任何不同。

My code looks like this.

我的代码看起来像这样。

public void Init(HttpApplication app)
{
    if (CommunityAuthenticationIntegration.IsEnabled)
    {
        FormsAuthenticationModule formsAuthModule = (FormsAuthenticationModule) app.Modules["FormsAuthentication"];         

        formsAuthModule.Authenticate += new FormsAuthenticationEventHandler(this.OnAuthenticate);
    }
}

Here is an example how it is done in the RoleManagerModulefrom the .NET framework:

以下是如何在 .NET 框架的RoleManagerModule 中完成的示例:

public void Init(HttpApplication app)
{
    if (Roles.Enabled)
    {
        app.PostAuthenticateRequest += new EventHandler(this.OnEnter);
        app.EndRequest += new EventHandler(this.OnLeave);
    }
}

Does anyone know what is going on?

有谁知道发生了什么?

(I just hope someone out there can tell me why this is happening and assure me that everything is perfectly fine) :)

(我只是希望有人能告诉我为什么会这样,并向我保证一切都很好):)



UPDATE:

更新:

I have tried to narrow down the problem and so far I have found that the initmethod being called is always on a new object of my http module (contrary to what I thought before).

我试图缩小问题的范围,到目前为止我发现被调用的init方法总是在我的 http 模块的一个新对象上(与我之前的想法相反)。

I seems that for the first request (when starting up the site) all of the HttpApplicationobjects being created and their modules are all trying to serve the first request and therefore all hit the eventhandlerthat is being added. I can't really figure out why this is happening.

我似乎对于第一个请求(在启动站点时)所有正在创建的HttpApplication对象及其模块都试图为第一个请求提供服务,因此都命中了正在添加的事件处理程序。我真的不明白为什么会这样。

If I request another page all the HttpApplication's created (and their modules) will again try to serve the request causing it to hit the eventhandlermultiple times.

如果我请求另一个页面,所有HttpApplication的创建(及其模块)将再次尝试为请求提供服务,导致它多次点击事件处理程序

But it also seems that if I then jump back to the first page (or another one) only one HttpApplicationwill start to take care of the request and everything is as expected - as long as I don't let it hang at a break point.

但似乎如果我然后跳回第一页(或另一页),只有一个HttpApplication将开始处理请求,一切都如预期 - 只要我不让它挂在断点处.

If I let it hang at a breakpoint it begins to create new HttpApplication's objects and starts adding HttpApplications(more than 1) to serve/handle the request (which is already in process of being served by the HttpApplicationwhich is currently stopped at the breakpoint).

如果我将其悬挂在断点处就开始创造新的HttpApplication的对象,并开始增加HttpApplications(大于1)来服务/处理请求(这已经是由被服务的过程的HttpApplication这是目前在停断点)。

I guess or hope that it might be some intelligent "behind the scenes" way of helping to distribute and handle load and / or errors. But I have no clue. I hope some out there can assure me that it is perfectly fine and how it is supposed to be?

我猜想或希望它可能是某种智能的“幕后”方式来帮助分发和处理负载和/或错误。但我没有头绪。我希望那里的一些人可以向我保证它非常好,它应该是怎样的?

采纳答案by Ramesh

  1. Inspect the HttpContext.Current.Request to see, for what request the module's init is fired. Could be browser sending multiple request.

  2. If you are connected to IIS, do check IIS logs to know whether any request is received for the time you are staying at the break point.

  1. 检查 HttpContext.Current.Request 以查看模块的 init 被触发的请求。可能是浏览器发送多个请求。

  2. 如果您连接到 IIS,请检查 IIS 日志以了解在您停留在断点时是否收到任何请求。

回答by Greg Ogle

回答by Sunday Ironfoot

It's normal for the Init() method to be called multiple times. When an application starts up, the ASP.NET Worker process will instantiate as many HttpApplication objects as it thinks it needs, then it'll pool them (eg. resuse them for new requests, similar to database connection pooling).

多次调用 Init() 方法是正常的。当应用程序启动时,ASP.NET Worker 进程将实例化它认为需要的尽可能多的 HttpApplication 对象,然后将它们池化(例如,将它们重新用于新请求,类似于数据库连接池)。

Now for each HttpApplication object, it will also instantiate one copy of each IHttpModule that is registered and call the Init method that many times. So if 5 HttpApplication objects are created, 5 copies of your IHttpModule will be created, and your Init method called 5 times. Make sense?

现在对于每个 HttpApplication 对象,它还将实例化每个注册的 IHttpModule 的一个副本,并多次调用 Init 方法。因此,如果创建了 5 个 HttpApplication 对象,则会创建您的 IHttpModule 的 5 个副本,并且您的 Init 方法将调用 5 次。有道理?

Now why is it instantiating 5 HttpApplications objects say? Well maybe your ASPX page has links to other resources which your browser will try to download, css, javascript, WebResource.aspx, maybe an iframe somewhere. Or maybe the ASP.NET Worker Process 'is in the mood' for starting more than 1 HttpApplication object, that's really an internal detail/optimisation of the ASP.NET process running under IIS (or the VS built in webserver).

现在为什么要实例化 5 个 HttpApplications 对象说?好吧,也许你的 ASPX 页面有链接到你的浏览器会尝试下载的其他资源、css、javascript、WebResource.aspx,也许某个地方的 iframe。或者,也许 ASP.NET 工作进程“有心情”启动 1 个以上的 HttpApplication 对象,这实际上是在 IIS(或 VS 内置网络服务器)下运行的 ASP.NET 进程的内部细节/优化。

If you want code that's guaranteed to run just once (and don't want to use the Application_StartUp event in the Global.asax), you could try the following in your IHttpModule:

如果您希望代码保证只运行一次(并且不想在 Global.asax 中使用 Application_StartUp 事件),您可以在 IHttpModule 中尝试以下操作:

private static bool HasAppStarted = false;
private readonly static object _syncObject = new object();

public void Init(HttpApplication context)
{
    if (!HasAppStarted)
    {
        lock (_syncObject)
        {
            if (!HasAppStarted)
            {
                // Run application StartUp code here

                HasAppStarted = true;
            }
        }
    }
}

I've done something similar and it seems to work, though I'd welcome critiques of my work in case I've missed something.

我做过类似的事情并且它似乎有效,尽管我欢迎对我的工作提出批评,以防万一我错过了什么。

回答by kinki

Examle above locks the IHttpModule for all requests, and then, it frezes the whole application. If your IHttpModule calls request several times is needed to call HttpApplication method CompleteRequest and dispose the HttpApplication instance of the IHttpModule in EndRequest event in order to remove instance of the HttpApplication like this:

上面的示例锁定所有请求的 IHttpModule,然后冻结整个应用程序。如果您的 IHttpModule 多次调用 request 需要调用 HttpApplication 方法 CompleteRequest 并在 EndRequest 事件中处理 IHttpModule 的 HttpApplication 实例,以便像这样删除 HttpApplication 的实例:

public class TestModule :IHttpModule
    {
        #region IHttpModule Members

        public void Dispose()
        {

        }

        public void Init(HttpApplication context)
        {
            context.BeginRequest += new EventHandler(context_BeginRequest);
            context.EndRequest += new EventHandler(context_EndRequest);
        }

        void context_EndRequest(object sender, EventArgs e)
        {
            HttpApplication app = sender as HttpApplication;
            app.CompleteRequest();
            app.Dispose();
        }

        void context_BeginRequest(object sender, EventArgs e)
        {
            //your code here
        }

        #endregion
    }

If you need that IHttpModule requests every time without rerequest on postback use this code above.

如果您每次都需要 IHttpModule 请求而无需在回发时重新请求,请使用上面的代码。