IHttpModule.BeginRequest firing 2X, Application_BeginRequest firing 1X
Asked Answered
A

7

6

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 "";
        }
    }
}
Alberic answered 2/2, 2010 at 3:3 Comment(1)
Can you post the code you're using for the HttpModule? It sounds like maybe the events aren't being hooked up just right.Payment
C
3

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; }
Canoness answered 19/8, 2011 at 10:56 Comment(0)
A
1

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!

Alberic answered 4/2, 2010 at 5:43 Comment(0)
T
1

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.

Thrasher answered 8/8, 2012 at 20:45 Comment(0)
R
1

We solved this by using

HttpContext.Current.ApplicationInstance.CompleteRequest();

This should prevent the the twice fire you are seeing.

Reactant answered 1/11, 2014 at 7:10 Comment(0)
N
1

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.

Nunciata answered 15/12, 2016 at 22:7 Comment(0)
E
0

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.

Esau answered 2/2, 2010 at 3:8 Comment(4)
Another common example you may want to add: ScriptResource.axd or WebResource.axdPayment
Init() is being called only once. BeginRequest() is being called multiple times. I'll have to think about what else might be causing the extra calls. Thx.Alberic
@Alberic - You mean this init only once? public void Init(HttpApplication httpApp), if so that's the Application Init, once when the app starts...nothing request specific, it should only run once.Payment
That's correct, Nick. That Init (see code above) is getting called only once. So, my event handler (OnBeginRequest) is subscribing to the event only once, so that eliminates that as the cause of the multiple calls.Alberic
P
-1

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.

Perce answered 18/4, 2017 at 4:45 Comment(1)
It should be readily apparent that a feature new to VS 2013 could not have been causing problems in VS 2008, so this is almost certainly the wrong question for this answer to be posted on.Galvanize

© 2022 - 2024 — McMap. All rights reserved.