如何限制 HttpModule 每个请求只能调用一次?

发布于 2024-10-29 09:45:43 字数 1202 浏览 7 评论 0原文

这是我对 HttpModule:

file with module:

public class HttpModuleRewriter : IHttpModule
{
    #region IHttpModule

    public void Init(HttpApplication app)
    {
        app.BeginRequest += ProcessRequest;
    }

    public void Dispose()
    {
    }

    #endregion

    #region Protected Methods

    protected void ProcessRequest(object sender, EventArgs e)
    {
        ...
    }
}

web.config 的实现:

<?xml version="1.0"?>
<configuration>  
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="HttpModuleRewriter" preCondition="managedHandler" type="HttpModuleRewriter" />
    </modules>
  </system.webServer>
</configuration>  

我在 HttpModuleRewriter 类的“Init”方法中放置了断点。当应用程序启动时调用第一次方法...并且每个页面请求仅调用模块一次。

如果我快速向页面发出请求(第二个请求将在第一个请求处理之前发送),那么方法“Init”会被额外调用一些,并且每个后续的页面请求都会导致对我的模块进行 2-3 次调用...

为什么?我怎样才能避免这种情况呢?

谢谢。

PS 我已将公共构造函数添加到 HttpModuleRewriter 中以计算引用量,在我的请求期间,我创建了 5 个模块...并且对于每个页面请求,实际上调用了 2 个模块...但仅适用于第一个导航页面,对于以下所有页面(我检查了其他 3 个)模块仅被调用一次(仅调用 1 个实例)...

为什么第一页被处理两次?建议的答案(使用“初始化”标志)也没有帮助。

Here is my implementation of HttpModule:

file with module:

public class HttpModuleRewriter : IHttpModule
{
    #region IHttpModule

    public void Init(HttpApplication app)
    {
        app.BeginRequest += ProcessRequest;
    }

    public void Dispose()
    {
    }

    #endregion

    #region Protected Methods

    protected void ProcessRequest(object sender, EventArgs e)
    {
        ...
    }
}

web.config:

<?xml version="1.0"?>
<configuration>  
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="HttpModuleRewriter" preCondition="managedHandler" type="HttpModuleRewriter" />
    </modules>
  </system.webServer>
</configuration>  

I've put break point in 'Init' method of HttpModuleRewriter class. The 1st time method is called when application is started... and each request to pages calls module only once.

If I do requests to pages quickly (2nd request will be send earlier than 1st request is processed) then method 'Init' is called few additionally and each following request to pages causes 2-3 calls to my module...

Why? How could I avoid that?

Thanks.

P.S. I've added public constructor into HttpModuleRewriter to calculate amount of references, and during my requests I have 5 modules created... and for each request to page 2 modules are actually called... but only for the 1st navigated page, for all following pages (I've checked 3 others) modules are called only once (only 1 instance is called)...

Why 1st page is processed twice? Suggested answer (to use 'initialized' flag) doesn't help too.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

尝蛊 2024-11-05 09:45:43

如果 Init() 在第二个请求出现之前尚未完成,那么您的 HttpModule 尚未准备好。如果您的 Init() 方法中有只应运行一次的代码,那么您可以设置一个标志(布尔初始化)并使用锁来防止代码由多个线程运行,例如:

private static bool initialised;
private static object lockObject = new object();

public void Init(HttpApplication app)
{
    lock(lockObject)
    {
         if(!initialised)
         {
           app.BeginRequest += ProcessRequest;
           //... other code here
           initialised = true;
         }
    }
}

更新:
作为 这篇文章解释了,ASP.NET 可能会创建多个 HttpModule 实例,因此 Init() 可以被多次调用。这是设计使然。因此,您必须设计模块,以便只应运行一次的代码仅运行一次 - 通过应用锁定,如上所示。

If Init() hasn't finished before the second request comes along then your HttpModule isn't ready yet. If you have code in your Init() method that should run only once then you can set a flag (bool initialised) and use a lock to prevent the code from being run by more than one thread, e.g.:

private static bool initialised;
private static object lockObject = new object();

public void Init(HttpApplication app)
{
    lock(lockObject)
    {
         if(!initialised)
         {
           app.BeginRequest += ProcessRequest;
           //... other code here
           initialised = true;
         }
    }
}

Update:
As this article explains, ASP.NET may create more than one instance of your HttpModule, so Init() can be called more than once. This is by design. Therefore you must fashion the module so that code that should run only once is run only once - by applying locking, like above.

浅笑依然 2024-11-05 09:45:43

我想说,明显的答案是您的处理程序正在处理多个请求,可能是样式表或图像。

将以下内容添加到 ProcessRequest 事件处理程序中,并向 context.Request.PhysicalPath 添加监视以确认这一点。

HttpApplication application = (HttpApplication)sender;
HttpContext context = application.Context;

string filename = Path.GetFileName(context.Request.PhysicalPath);

如果您不希望处理程序针对图像等请求运行,您所需要做的就是检查以“.aspx”或类似内容结尾的路径。

I'd say the obvious answer is that your handler is handling more than one request, likely for stylesheets or images.

Add the following into your ProcessRequest event handler and add a watch to context.Request.PhysicalPath to confirm this.

HttpApplication application = (HttpApplication)sender;
HttpContext context = application.Context;

string filename = Path.GetFileName(context.Request.PhysicalPath);

If you don't want your handler to run for requests for images etc, all you need to do is check for the path ending ".aspx" or something similar.

甚是思念 2024-11-05 09:45:43

当您执行 Init() 两次时,BeginRequest 事件将调用两次您的处理,因为它有两个事件处理程序。 += 运算符将新的事件处理程序添加到列表中,但不会替换旧的处理程序。

Øyvind 有一个正确的解决方案。

When you execute Init() twice, the BeginRequest event will call twice your processing because it has two event handlers in it. The += operator adds the new event handler in a list, it doesn't replace the old handler(s).

Øyvind has a correct solution.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文