C# 如何限制每个请求只有一个调用的HttpModule?
以下是我对HttpModule的实现: 包含模块的文件:C# 如何限制每个请求只有一个调用的HttpModule?,c#,asp.net,httpmodule,C#,Asp.net,Httpmodule,以下是我对HttpModule的实现: 包含模块的文件: public class HttpModuleRewriter : IHttpModule { #region IHttpModule public void Init(HttpApplication app) { app.BeginRequest += ProcessRequest; } public void Dispose() { } #endre
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”方法中设置了断点。应用程序启动时调用第一次方法。。。并且每个对pages的请求只调用一次模块
如果我快速请求页面(第二个请求将在处理第一个请求之前发送),则会另外调用方法“Init”,并且每个后续页面请求都会导致对我的模块进行2-3次调用
为什么??我怎么能避免呢
谢谢
另外,我已经在HttpModuleRewriter中添加了公共构造函数来计算引用的数量,在我的请求期间,我创建了5个模块。。。对于第2页的每个请求,模块实际上被称为。。。但仅在第一个导航页面中,对于所有后续页面(我已经检查了其他3个页面),模块只调用一次(只调用了1个实例)
为什么第一页要处理两次?建议的答案(使用'initialized'标志)也没有帮助。如果Init()在第二个请求出现之前还没有完成,那么您的HttpModule还没有准备好。如果Init()方法中的代码只应运行一次,则可以设置标志(bool initialized)并使用锁防止代码由多个线程运行,例如:
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()。这是故意的。因此,您必须调整模块的样式,以便只运行一次的代码只运行一次—通过应用锁定,如上所述。如果在第二个请求出现之前Init()尚未完成,则您的HttpModule尚未就绪。如果Init()方法中的代码只应运行一次,则可以设置标志(bool initialized)并使用锁防止代码由多个线程运行,例如:
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()。这是故意的。因此,您必须设计模块,以便只运行一次的代码只运行一次—通过应用锁定,如上所述。我想说的是,显而易见的答案是,您的处理程序正在处理多个请求,可能是样式表或图像 将以下内容添加到ProcessRequest事件处理程序中,并向context.Request.PhysicalPath添加一个监视以确认这一点
HttpApplication application = (HttpApplication)sender;
HttpContext context = application.Context;
string filename = Path.GetFileName(context.Request.PhysicalPath);
如果您不希望处理程序运行图像请求等,则只需检查以“.aspx”结尾的路径或类似的路径。我想说的是,显而易见的答案是处理程序正在处理多个请求,可能是样式表或图像 将以下内容添加到ProcessRequest事件处理程序中,并向context.Request.PhysicalPath添加一个监视以确认这一点
HttpApplication application = (HttpApplication)sender;
HttpContext context = application.Context;
string filename = Path.GetFileName(context.Request.PhysicalPath);
如果不希望处理程序运行图像等请求,则只需检查以“.aspx”结尾的路径或类似的路径。当执行Init()两次时,BeginRequest事件将调用两次处理,因为其中有两个事件处理程序。+=运算符在列表中添加新的事件处理程序,但不会替换旧的处理程序
Øyvind有一个正确的解决方案。当您两次执行Init()时,BeginRequest事件将调用两次您的处理,因为它有两个事件处理程序。+=运算符在列表中添加新的事件处理程序,但不会替换旧的处理程序
Øyvind有一个正确的解决方案。那么,您认为模块初始化两次或更多次是可以的吗。。。也许你是对的。谢谢。但我想,您应该为“initialized”字段使用静态变量。而且,如果没有其他可用的模块,asp.net应用程序似乎会创建一个新模块。如果未将当前创建模块的ProcessRequest分配给app.BeginRequest,则以下调用模块的尝试将不会按预期调用“ProcessRequest”方法。。。所以模块实际上不会被连接。建议的解决方案似乎不可行。您好,是的,成员变量应该是静态的。我更新了答案以反映这一点。如果您实现这样的锁定,那么您的事件处理程序将在处理任何请求之前注册。因此,您认为模块初始化两次或更多次可以吗。。。也许你是对的。谢谢。但我想,您应该为“initialized”字段使用静态变量。而且,如果没有其他可用的模块,asp.net应用程序似乎会创建一个新模块。如果未将当前创建模块的ProcessRequest分配给app.BeginRequest,则以下调用模块的尝试将不会按预期调用“ProcessRequest”方法。。。所以模块实际上不会被连接。建议的解决方案似乎不可行。您好,是的,成员变量应该是静态的。我已经更新了答案以反映这一点。如果您实现这样的锁定,那么在处理任何请求之前,您的事件处理程序都将被注册。