2010-02-02 13 views
6

Ich verwende VS 2008 und .NET 3.5 SP1.ASP.NET - IHttpModule.BeginRequest feuern 2X, Application_BeginRequest feuern 1X

Ich möchte Hit-Tracking in einem HttpModule in meiner ASP.NET-App implementieren. Ziemlich einfach, dachte ich. Das BeginRequest-Ereignis meines HttpModule wird jedoch zweimal für jeden Seitentreffer ausgelöst. Die Seite ist momentan sehr einfach ... keine Sicherheit, nur ein bisschen Datenbankarbeit. Sollte eine Zeile pro Seite aufschlagen. Warum wird dieses Ereignis zweimal ausgelöst?

Darüber hinaus feuert IHttpModule.BeginRequest tatsächlich eine andere Anzahl von Zeiten für die erste Seite Treffer beim ersten Mal (von einem geschlossenen Webbrowser) ... 3 Mal wenn ich die DB treffen, um dynamische Daten bereitzustellen für die Seite und nur 1 Mal für Seiten, auf denen die DB nicht getroffen wird. Es wird 2 Mal für jede Seite ausgelöst, die nach der ersten getroffen wird, unabhängig davon, ob ich die DB berühre oder nicht.

Es ist interessant zu beachten, dass Application_BeginRequest (in Global.asax) immer nur einmal ausgelöst wird.

Hier ist der 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 ""; 
     } 
    } 
} 
+0

Können Sie den Code, den Sie für das HttpModule verwenden, veröffentlichen? Es hört sich so an, als ob die Ereignisse nicht genau richtig sind. –

Antwort

0

Eine Möglichkeit besteht darin, dass es andere Anfragen los, dass Sie nicht in Erwägung ziehen könnte. Angenommen, Ihre ASPX-Seite verweist auf einige Bilder oder CSS-Dateien. Wenn diese Anforderungen die ASP.NET-Pipeline durchlaufen, wird Ihr Modul aufgerufen und als Treffer registriert.

Wenn Sie IHHTpModule.BeginRequest sagen, meinen Sie auch, dass Sie in IHttpModule.Init() HttpApplication.BeginRequest? Wenn ja, könnte der Grund, den ich oben erwähnt habe, immer noch gelten.

+1

Ein weiteres gängiges Beispiel, das Sie hinzufügen möchten: 'ScriptResource.axd' oder' WebResource.axd' –

+0

Init() wird nur einmal aufgerufen. BeginRequest() wird mehrmals aufgerufen. Ich muss darüber nachdenken, was sonst die zusätzlichen Anrufe verursachen könnte. Danke. – birdus

+0

@birdus - Du meinst diese init nur einmal? 'public void Init (HttpApplication httpApp)', wenn das so ist, das Application Init, sobald die App startet ... nichts anforderungsspezifisch, sollte es nur einmal ausgeführt werden. –

1

Das ist interessant. Ich habe den Verweis auf die CSS-Datei von der Masterseite entfernt und ich bekomme weniger Wiederholungstreffer in dem HttpModule für bestimmte Browser (wie vorgeschlagen), aber ich bekomme immer noch Wiederholungen. Ich habe 6 Browser installiert und ich habe einige Unterschiede zwischen ihnen.

Als Referenz ist dies die URL ich für diesen Test in meinem Browser bin Aufstecken:

http://localhost/BluHeron

default.aspx als Startseite festgelegt und ist in der Tat kehrte immer für die oben genannte URL Ich verwende HttpRequest.RawUrl, um zu melden, welche Seite der Benutzer getroffen hat. Insbesondere spalte ich die RawUrl-Zeichenfolge und berichte nur das letzte Element im String-Array (siehe Code).

  • Jeder einzelne Browser meldet wie erwartet default.aspx (RawUrl = /BluHeron/default.aspx).
  • 4 der 6 Browser melden auch BluHeron (RawUrl =/BluHeron).
  • 3 der 6 Browser zeichnen ebenfalls ein Leerzeichen in der Datenbank auf (RawUrl =/BluHeron /).
  • Es gibt ein paar Möglichkeiten, wie ich genaue Berichte erhalten kann, wie viele Leute welche Seiten schlagen.

    1. wählen Sie aus der Datenbank nur die Zeilen, die tatsächlich eine meiner Seiten Liste (ignorieren/BluHeron und Leerzeichen)
    2. Gerade Application_BeginRequest im weltweiten Einsatz.asax-Datei (das scheint konsequent nur einmal pro Seite Hit- zu bekommen)
    3. Erhalten Sie diese

    So herausgefunden habe ich Optionen bekam für immer gute Berichte sogar mit crappy Daten in der Datenbank. Ich würde jedoch lieber keinen Müll in der Datenbank haben und verstehen, was hier vor sich geht.

    Danke fürs schauen, jeder!

    3

    Dies könnte für die Antwort zu spät sein, kann aber für jemand anderen nützlich sein. Ich stand vor dem gleichen Problem. BeginRequest-Ereignis wird für jede Anforderung zweimal ausgelöst. Ich debuggte den Code und erkannte, dass der erste Auslöser für die tatsächliche Ressourcenanforderung, aber die zweite das Ergebnis der "favicon.ico" -Anforderung ist. Zu Beginn des BeginRequest-Ereignisses wird durch eine einfache Überprüfung der favicon.ico-Anforderung die zweite Ausführung der Methode beendet.

    public void Application_BeginRequest(object sender, EventArgs e) { 
        HttpApplication app = (HttpApplication)sender; 
        HttpContext ctx = app.Context; 
    
        if (ctx.Request.Path == "/favicon.ico") { return; } 
    
    1

    ziemlich spät auf, aber lief in das gleiche Problem. In unserem Fall war es aufgrund der anonymen Anfrage zuerst, die 401 per RFC zurückgibt. Die zweite Anfrage authentifiziert sich.

    0

    Wir lösten diese von

    HttpContext.Current.ApplicationInstance.CompleteRequest(); 
    

    mit diesem die doppelt so groß wie Feuer verhindern sollten Sie sehen.

    0

    Der "Standarddokument" Teil von II scheint ein zweites BeginRequest Ereignis auszulösen. Wenn Sie festgestellt haben, dass die Request.Path für die HttpApplication in beiden Ereignishandlern identisch ist und Ihre URL mit einem Schrägstrich endet, versuchen Sie eine URL Rewrite-Regel hinzufügen, um die Verarbeitung "Standarddokument" zu verkürzen.

    -1

    Deaktivieren Sie Browser Link in Visual Studio 2013 und höher, wodurch die zweite Anforderung verursacht wird.

    VS Snapshot

    Dies tritt auf, wenn eine Anwendung von Visual Studio ausgeführt wird.

    +0

    Es sollte leicht ersichtlich sein, dass ein Feature, das für VS 2013 neu ist, in VS 2008 keine Probleme verursacht haben könnte, also ist dies mit ziemlicher Sicherheit die falsche Frage für diese Antwort. –