简体   繁体   English

如何限制每个请求只有一个调用的HttpModule?

[英]How to limit HttpModule with ONLY ONE call per request?

Here is my implementation of HttpModule: 这是我对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: 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. 我已经在HttpModuleRewriter类的'Init'方法中放置了断点。 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... 如果我对页面的请求很快(第二个请求将在处理第一个请求之前发送),那么方法'Init'会被另外调用,每个随后的页面请求都会导致2-3次调用我的模块...

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)... PS我已将公共构造函数添加到HttpModuleRewriter中以计算引用量,并且在我的请求中,我创建了5个模块...并且对于第2页的每个请求,实际上都被调用了...但是仅对于第一个导航页而言,接下来的所有页面(我检查过3个其他页面)模块仅调用一次(仅调用1个实例)...

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. 如果在第二个请求出现之前Init()尚未完成,则您的HttpModule尚未准备好。 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: 如果您的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;
         }
    }
}

Update: As this article explains, ASP.NET may create more than one instance of your HttpModule, so Init() can be called more than once. 更新:如本文所述 ,ASP.NET可能会创建一个以上的HttpModule实例,因此Init()可以被多次调用。 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. 将以下内容添加到您的ProcessRequest事件处理程序中,并将监视添加到context.Request.PhysicalPath进行确认。

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. 如果您不希望处理程序为图像等请求运行,您所需要做的就是检查以“ .aspx”结尾的路径或类似内容。

When you execute Init() twice, the BeginRequest event will call twice your processing because it has two event handlers in it. 当您两次执行Init()时,BeginRequest事件将调用两次您的处理,因为其中有两个事件处理程序。 The += operator adds the new event handler in a list, it doesn't replace the old handler(s). + =运算符将新的事件处理程序添加到列表中,它不会替换旧的处理程序。

Øyvind has a correct solution. Øyvind有一个正确的解决方案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何限制每次安装仅使用一台计算机? - How to limit use to only one computer per installation? 在ASP.NET Mvc 4中,每个用户仅限制一个会话 - Limit Only One Session Per User In ASP.NET Mvc 4 在ASP.NET中每个用户仅限制一个会话 - Limit only one session per user in ASP.NET 如何在控制器中每个请求只能识别我的DbContext的一个内容? - How can i inejct only one intance of my DbContext per request in my controllers? 如何修复“每个表只能配置一列'Identity'。在 Ef Core 和 Oracle 中调用 'ValueGeneratedNever'... - How to fix "Only one column per table can be configured as 'Identity'. Call 'ValueGeneratedNever' ... in Ef Core and Oracle 如何在异步任务 C# 中限制每秒请求 - How to Limit request per Second in Async Task C# 如何传递IEnumerable <SelectListItem> 收集到MVC部分视图,每个请求只有一个数据库查找 - How to pass IEnumerable<SelectListItem> collection to a MVC Partial View with only one database lookup per request 如何在 ASP.NET 中限制每个请求 memory 的使用? - How to limit per-request memory usage in ASP.NET? 当一组中至少有一个射弹击中目标时,如何每组只调用一次函数? - When at least one projectile out of a group hits the target, how to call a function only once per group? 我如何将方法“utilities.DecryptStringFromBase64String”的调用限制为一次 - how I can limit the call to only one time for method "utilities.DecryptStringFromBase64String"
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM