如何限制HttpModule每个请求只有一个呼叫?

时间:2011-04-01 21:01:16

标签: c# asp.net httpmodule

这是我对HttpModule的实现:

带模块的

文件:

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次调用我的模块... < / p>

为什么呢?我怎么能避免这个?

感谢。

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

为什么第一页被处理两次?建议的答案(使用'初始化'标志)也无济于事。

3 个答案:

答案 0 :(得分:5)

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

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;
         }
    }
}

更新: 正如this article所解释的那样,ASP.NET可能会创建多个HttpModule实例,因此可以多次调用Init()。这是设计的。因此,您必须设计模块,以便只运行一次的代码只运行一次 - 通过应用锁定,如上所述。

答案 1 :(得分:3)

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

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

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

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

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

答案 2 :(得分:1)

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

Øyvind有正确的解决方案。