【问题标题】:IHttpModule.BeginRequest firing 2X, Application_BeginRequest firing 1XIHttpModule.BeginRequest 触发 2X,Application_BeginRequest 触发 1X
【发布时间】:2010-02-02 03:03:41
【问题描述】:

我正在运行 VS 2008 和 .NET 3.5 SP1。

我想在我的 ASP.NET 应用程序的 HttpModule 中实现命中跟踪。很简单,我想。但是,我的HttpModuleBeginRequest 事件会为每个页面点击触发两次。该站点现在非常简单......没有安全性,只是一些数据库工作。应记录每页命中一行。为什么这个事件会触发两次?

此外,IHttpModule.BeginRequest 在第一次运行时(从关闭的 Web 浏览器)实际上触发了不同次数的第一页命中...当我点击数据库以提供动态数据时 3 次该页面,对于未命中数据库的页面只有 1 次。在第一个页面点击之后,它会触发 2 次,无论我是否触摸数据库。

有趣的是Application_BeginRequest(在Global.asax)总是只触发一次。

代码如下:

using System;
using System.Data;
using System.Data.Common;
using System.Net;
using System.Web;
using BluHeron.BusinessLayer;
using Microsoft.Practices.EnterpriseLibrary.Data.Sql;

namespace BluHeron.HttpModules
{
    public class SiteUsageModule : IHttpModule
    {
        public void Init(HttpApplication httpApp)
        {
            httpApp.BeginRequest += OnBeginRequest;
        }

        static void OnBeginRequest(object sender, EventArgs a)
        {
            UsageLogger.LogSiteUsage(((HttpApplication)sender).Context.Request);
        }

        public void Dispose()
        { }
    }

    public static class UsageLogger
    {
        public static void LogSiteUsage(HttpRequest r)
        {
            string ipAddress = GetHostAddress(Dns.GetHostAddresses(Dns.GetHostName()));
            string browserVersion = r.Browser.Type;

            string[] urlChunks = r.RawUrl.Split('/');
            string page = urlChunks[urlChunks.GetLength(0)-1];

            SqlDatabase db = new SqlDatabase(Common.GetConnectionString());
            DbCommand cmd = db.GetStoredProcCommand("LogUsage");

            db.AddInParameter(cmd, "IPAddress", SqlDbType.NVarChar, ipAddress);
            db.AddInParameter(cmd, "BrowserVersion", SqlDbType.NVarChar, browserVersion);
            db.AddInParameter(cmd, "PageName", SqlDbType.NVarChar, page);
            db.AddInParameter(cmd, "Notes", SqlDbType.NVarChar, "");

            db.ExecuteNonQuery(cmd);
        }

        private static string GetHostAddress(IPAddress[] addresses)
        {
            foreach (IPAddress ip in addresses)
            {
                if (ip.ToString().Length <= 15)
                {
                    return ip.ToString();
                }
            }

            return "";
        }
    }
}

【问题讨论】:

  • 您可以发布您用于 HttpModule 的代码吗?听起来可能事件没有正确连接。

标签: asp.net httpmodule


【解决方案1】:

这对于答案来说可能为时已晚,但对其他人可能有用。我遇到了同样的问题。 BeginRequest 事件为每个请求触发两次。我调试了代码并意识到实际资源请求的第一个触发器,但第二个是“favicon.ico”请求的结果。在 BeginRequest 事件开始时,对 favicon.ico 请求的简单检查消除了该方法的第二次执行。

public void Application_BeginRequest(object sender, EventArgs e) {
   HttpApplication app = (HttpApplication)sender;
   HttpContext ctx = app.Context;

   if (ctx.Request.Path == "/favicon.ico") { return; }

【讨论】:

    【解决方案2】:

    这很有趣。我从母版页中删除了对 CSS 文件的引用,并且某些浏览器的 HttpModule 中的重复点击次数减少了(如建议的那样),但我仍然重复。我已经安装了 6 个浏览器,并且它们之间存在一些差异。

    作为参考,这是我为此测试插入浏览器的 URL:

    http://localhost/BluHeron

    default.aspx 被设置为起始页,实际上是为上述 URL 返回的。我正在使用 HttpRequest.RawUrl 来报告用户点击了哪个页面。具体来说,我正在拆分 RawUrl 字符串并仅报告字符串数组中的最后一项(参见代码)。

    • 每个浏览器都按预期报告了 default.aspx (RawUrl = /BluHeron/default.aspx)。
    • 6 个浏览器中有 4 个也报告了 BluHeron (RawUrl = /BluHeron)。
    • 6 个浏览器中有 3 个也在数据库中记录空白 (RawUrl = /BluHeron/)。

    有几种方法可以准确地报告有多少人访问了哪些页面。

    1. 从数据库中仅选择实际列出我的一个页面的行(忽略 /BluHeron 和空白)
    2. 只需在 global.asax 文件中使用 Application_BeginRequest(似乎每次页面点击始终只调用一次)
    3. 搞清楚这个

    所以,即使数据库中的数据很糟糕,我也可以选择获得好的报告。但是,我宁愿不要在数据库中有垃圾,并了解这里发生了什么。

    感谢大家观看!

    【讨论】:

      【解决方案3】:

      这很晚,但遇到了同样的问题。在我们的例子中,这是由于匿名请求首先根据 RFC 返回 401。第二个请求进行身份验证。

      【讨论】:

        【解决方案4】:

        IIS 的“默认文档”部分似乎触发了第二个 BeginRequest 事件。

        如果您确定两个事件处理程序中的 Request.PathHttpApplication 相同,并且您的 URL 以斜杠结尾,请尝试添加 URL 重写规则以简化“默认文档”处理。

        【讨论】:

          【解决方案5】:

          一种可能性是您可能没有考虑其他请求。例如,假设您的 ASPX 页面引用了一些图像或 CSS 文件。如果这些请求通过 ASP.NET 管道,那么您的模块将被调用并将它们注册为命中。

          另外,当您说 IHttpModule.BeginRequest 时,您的意思是在 IHttpModule.Init() 中您正在连接 HttpApplication.BeginRequest?如果是这样,那么我上面提到的原因可能仍然适用。

          【讨论】:

          • 另一个您可能想要添加的常见示例:ScriptResource.axdWebResource.axd
          • Init() 只被调用一次。 BeginRequest() 被多次调用。我将不得不考虑还有什么可能导致额外的电话。谢谢。
          • @birdus - 你的意思是这个初始化只有一次? public void Init(HttpApplication httpApp),如果是这样,那就是应用程序初始化,一旦应用程序启动......没有特定的请求,它应该只运行一次。
          • 没错,尼克。该 Init (见上面的代码)只被调用一次。因此,我的事件处理程序 (OnBeginRequest) 只订阅该事件一次,这样就消除了多次调用的原因。
          【解决方案6】:

          我们通过使用

          解决了这个问题
          HttpContext.Current.ApplicationInstance.CompleteRequest();
          

          这应该可以防止您看到的两次火灾。

          【讨论】:

            【解决方案7】:

            在 Visual Studio 2013 及更高版本中禁用 Browser Link,这会导致第二个请求。

            从 Visual Studio 运行应用程序时会发生这种情况。

            【讨论】:

            • 很明显,VS 2013 的新功能不会在 VS 2008 中引起问题,因此几乎可以肯定,发布此答案的问题是错误的。
            猜你喜欢
            • 2015-06-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-07-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多