2011-04-01 84 views
1

这是我实现的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类的 '初始化' 的方法。第一次方法在应用程序启动时被调用...并且每个页面请求调用模块只有一次。

如果我赶紧做请求的页面(第2请求将早于1日请求被处理后发送),那么方法“初始化”另外几个叫每个如下要求的网页导致2-3呼叫我的模块...

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

谢谢。

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

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

回答

5

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

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()可以多次调用。这是设计。因此,您必须对模块进行调整,以便仅应运行一次的代码只能运行一次 - 通过应用锁定(如上所述)。

+0

所以,你认为模块初始化两次或更多次都可以吗? ......可能你是对的。谢谢。 – Budda 2011-04-01 21:51:10

+0

但我想,你应该使用静态变量'已初始化'的字段。 – Budda 2011-04-01 21:51:39

+0

似乎asp.net应用程序创建一个新的模块,如果没有其他可用。如果您没有将当前创建的模块的ProcessRequest分配给app.BeginRequest,那么以下尝试调用模块将不会像预期的那样调用'ProcessRequest'方法...因此模块将不会实际连接。建议的解决方案似乎不可行。 – Budda 2011-04-01 22:29:30

3

我想说的显而易见的答案是,你的操作是处理多个请求,可能用于样式表或图像。

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

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

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

如果你不想让你的处理程序为图像等的要求运行,所有你需要做的是检查结束“的.aspx”或类似的路径。

1

当您执行的init()两次,BeginRequest事件将调用两次你的处理,因为它有两个事件处理程序在里面。 + =操作符将新的事件处理程序添加到列表中,它不会替换旧的处理程序。

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