2010-02-02 7 views
6

Sono in esecuzione VS 2008 e .NET 3.5 SP1.ASP.NET - IHttpModule.BeginRequest che attiva 2X, Application_BeginRequest che spara 1X

Desidero implementare il rilevamento dei colpi in un HttpModule nella mia app ASP.NET. Abbastanza semplice, pensai. Tuttavia, l'evento BeginRequest del mio HttpModule viene attivato due volte per ogni colpo di pagina. Il sito è molto semplice in questo momento ... nessuna sicurezza, solo un po 'di lavoro nel database. Dovrebbe registrare una riga per colpo di pagina. Perché questo evento sta sparando due volte?

Inoltre, IHttpModule.BeginRequest genera effettivamente un numero diverso di volte per il primo colpo di pagina quando si esegue per la prima volta (da un browser Web chiuso) ... 3 volte quando sto colpendo il DB per fornire dati dinamici per la pagina, e solo 1 volta per le pagine in cui il DB non viene colpito. Spara 2 volte per ogni colpo di pagina dopo il primo, indipendentemente dal fatto che tocchi o meno il DB.

È interessante notare che Application_BeginRequest (in Global.asax) viene sempre attivato solo una volta.

Ecco il codice:

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

Puoi pubblicare il codice che stai utilizzando per HttpModule? Sembra che forse gli eventi non vengano collegati correttamente. –

risposta

0

Una possibilità è che ci sono altre richieste in corso che si potrebbe non essere considerato. Ad esempio, supponiamo che la tua pagina ASPX faccia riferimento ad alcune immagini o file CSS. Se tali richieste passano attraverso la pipeline ASP.NET, il modulo verrà chiamato e si registreranno come hit.

Inoltre, quando dici IHttpModule.BeginRequest intendi che in IHttpModule.Init() stai collegando HttpApplication.BeginRequest? Se è così, la ragione per cui ho menzionato sopra potrebbe ancora essere applicata.

+1

Un altro esempio comune che si potrebbe voler aggiungere: 'ScriptResource.axd' o' WebResource.axd' –

+0

Init() viene chiamato una sola volta. BeginRequest() viene chiamato più volte. Dovrò pensare a cos'altro potrebbe causare le chiamate extra. Grazie. – birdus

+0

@birdus - Intendi questo init solo una volta? 'public void Init (HttpApplication httpApp)', se è così l'Application Init, una volta all'avvio dell'app ... nessuna richiesta specifica, dovrebbe essere eseguita una sola volta. –

1

Questo è interessante. Ho rimosso il riferimento al file CSS dalla pagina master e sto ottenendo un minor numero di hit ripetuti su HttpModule per alcuni browser (come suggerito), ma continuo a ricevere ripetizioni. Ho installato 6 browser e sto ottenendo alcune variazioni tra loro.

Per avere un riferimento, questo è l'URL che sto collegando al mio browser per questo test:

http://localhost/BluHeron

default.aspx è impostato come pagina iniziale ed è, infatti, sempre restituiti per l'URL di cui sopra. Sto usando HttpRequest.RawUrl per aver segnalato quale pagina ha colpito l'utente. Nello specifico, sto suddividendo la stringa RawUrl e riferendo solo l'ultimo elemento dell'array di stringhe (vedi codice).

  • Ogni singolo browser segnala di default.aspx, come previsto (RawUrl = /BluHeron/default.aspx).
  • 4 dei 6 browser stanno segnalando anche BluHeron (RawUrl =/BluHeron).
  • 3 dei 6 browser stanno anche registrando uno spazio vuoto nel database (RawUrl =/BluHeron /).

Ci sono un paio di modi in cui posso ottenere una segnalazione accurata di quante persone stanno colpendo quali pagine.

  1. selezionate dal database solo le righe che in realtà elencano una delle mie pagine (ignorare/BluHeron e spazi)
  2. Basta usare Application_BeginRequest nel globale.asax (che sembra avere sempre chiamato solo una volta per pagina hit)
  3. Ottenere questo capito

Così, ho opzioni per ottenere buoni rapporti anche con i dati scadente nel database. Tuttavia, preferirei non avere spazzatura nel database e capire cosa sta succedendo qui.

Grazie per lo sguardo, a tutti!

3

Questo potrebbe essere troppo tardi per la risposta, ma può essere utile per qualcun altro. Ho affrontato lo stesso problema. Evento BeginRequest attivato per due volte per ogni richiesta. Ho eseguito il debug del codice e ho realizzato che il primo trigger per la richiesta di risorse effettiva, ma il secondo è il risultato della richiesta "favicon.ico". All'inizio dell'evento BeginRequest, un semplice controllo per la richiesta favicon.ico elimina la seconda esecuzione del metodo.

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

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

piuttosto tardi su questo, ma ha incontrato lo stesso problema. Nel nostro caso era dovuto alla prima richiesta anonima che restituisce il 401 per RFC. La seconda richiesta autentica.

0

abbiamo risolto questo usando

HttpContext.Current.ApplicationInstance.CompleteRequest(); 

Questo dovrebbe evitare che il due volte il fuoco si sta vedendo.

0

La parte "Documento predefinito" di IIS sembra generare un secondo evento BeginRequest. Se hai determinato che lo Request.Path è lo stesso per lo HttpApplication in entrambi i gestori di eventi e l'url termina con una barra, prova ad aggiungere una regola di riscrittura URL per collegare l'elaborazione "Documento predefinito".

-1

Disabilitare Browser Link in Visual Studio 2013 e versioni successive, che causa la seconda richiesta.

VS Snapshot

Ciò si verifica quando un'applicazione viene eseguito da Visual Studio.

+0

Dovrebbe essere immediatamente evidente che una nuova funzionalità di VS 2013 non avrebbe potuto causare problemi in VS 2008, quindi questa è quasi sicuramente la domanda sbagliata su cui questa risposta deve essere pubblicata. –

Problemi correlati