简体   繁体   中英

How to limit HttpModule with ONLY ONE call per request?

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.

PS 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.

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, eg:

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.

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM