IHttpModule.BeginRequest 触发 2X,Application_BeginRequest 触发 1X

发布于 2024-08-20 02:40:46 字数 2326 浏览 7 评论 0原文

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

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

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

有趣的是,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 "";
        }
    }
}

I'm running VS 2008 and .NET 3.5 SP1.

I want to implement hit tracking in an HttpModule in my ASP.NET app. Pretty simple, I thought. However, the BeginRequest event of my HttpModule is firing twice for each page hit. The site is very simple right now...no security, just a bit of database work. Should log one row per page hit. Why is this event firing twice?

Moreover, IHttpModule.BeginRequest actually fires a different number of times for the first page hit when running for the first time (from a closed web browser)...3 times when I'm hitting the DB to provide dynamic data for the page, and only 1 time for pages where the DB isn't hit. It fires 2 times for every page hit after the first one, regardless of whether or not I'm touching the DB.

It's interesting to note that Application_BeginRequest (in Global.asax) is always firing only once.

Here's the code:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

仙女 2024-08-27 02:40:46

这对于答案来说可能为时已晚,但对其他人可能有用。我面临着同样的问题。每个请求都会触发 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; }

This might be too late for the answer but can be useful for someone else. I faced with the same problem. BeginRequest event triggered for twice for each request. I debugged the code and realized that the first trigger for actual resource request but the second is result of "favicon.ico" request. At the beginning of BeginRequest event, a simple check for favicon.ico request eliminates second execution of the method.

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

   if (ctx.Request.Path == "/favicon.ico") { return; }
她说她爱他 2024-08-27 02:40:46

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

quite late on this, but ran into the same issue. In our case it was due to the anonymous request first that returns the 401 per the RFC. The second request authenticates.

心是晴朗的。 2024-08-27 02:40:46

我们通过使用解决了这个问题

HttpContext.Current.ApplicationInstance.CompleteRequest();

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

We solved this by using

HttpContext.Current.ApplicationInstance.CompleteRequest();

This should prevent the the twice fire you are seeing.

意中人 2024-08-27 02:40:46

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

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

The "Default Document" part of IIS seems to fire a second BeginRequest event.

If you have determined that the Request.Path is the same for the HttpApplication in both event handlers and your URL ends with a slash, try adding a URL Rewrite rule to shortcut the "Default Document" processing.

怼怹恏 2024-08-27 02:40:46

这很有趣。我从母版页中删除了对 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. 把这个弄清楚吧。

因此,即使数据库中的数据很差,我也可以选择获得良好的报告。我更愿意了解这里发生了什么,而不是数据库中有垃圾。

谢谢大家的观看!

This is interesting. I removed the reference to the CSS file from the master page and I'm getting fewer repeat hits in the HttpModule for certain browsers (as was suggested), but I'm still getting repeats. I have 6 browsers installed, and I'm getting some variation between them.

For reference, this is the URL I'm plugging in to my browsers for this test:

http://localhost/BluHeron

default.aspx is set as the start page and is indeed returned for the aforementioned URL. I'm using HttpRequest.RawUrl for reporting which page the user hit. Specifically, I'm splitting the RawUrl string and just reporting the last item in the array of strings (see code).

  • Every single browser is reporting hitting default.aspx, as expected (RawUrl = /BluHeron/default.aspx).
  • 4 of the 6 browsers are also reporting BluHeron (RawUrl = /BluHeron).
  • 3 of the 6 browsers are also recording a blank in the database (RawUrl = /BluHeron/).

There are a couple ways I can get accurate reporting of how many people are hitting which pages.

  1. Select from the database only rows that actually list one of my pages (ignore /BluHeron and blanks)
  2. Just use Application_BeginRequest in the global.asax file, which seems to consistently get called only once per page hit.
  3. Get this figured out.

So, I've got options for getting good reports even with crappy data in the database. I would prefer to understand what's going on here and not to have junk in the database.

Thanks for looking, everyone!

你的他你的她 2024-08-27 02:40:46

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

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

One possibility is that there are other requests going on that you might not be considering. For example, let's say your ASPX page references some images or CSS files. If those requests go through the ASP.NET pipeline then your module will be called and they'll register as hits.

Also, when you say IHttpModule.BeginRequest, do you mean that in IHttpModule.Init() you are hooking up HttpApplication.BeginRequest? If so then the reason I mention above might still apply.

℉服软 2024-08-27 02:40:46

禁用 Visual Studio 2013 及更高版本中的浏览器链接,这会导致第二个请求。

VS 快照

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

Disable Browser Link in Visual Studio 2013 and up, which causes the second request.

VS Snapshot

This occurs when an Application is run from Visual Studio.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文