La méthode HttpModule Init est appelée plusieurs fois – pourquoi?

J’étais en train de créer un module http et lors du débogage, j’ai remarqué quelque chose qui semblait au premier abord (au moins) un comportement étrange.

Lorsque je définis un point d’arrêt dans la méthode init du httpmodule, je peux voir que la méthode init du module http est appelée plusieurs fois, même si je n’ai démarré que le site Web pour le débogage et effectué une seule requête (parfois, cette requête n’est déclenchée qu’une seule fois , d’autres fois jusqu’à 10 fois).

Je sais que je devrais m’attendre à ce que plusieurs instances de HttpApplication soient en cours d’exécution et que chaque module http soit créé, mais lorsque je demande une page unique, elle doit être gérée par un seul object d’application http et ne déclencher par conséquent que les événements associés une fois. mais il déclenche toujours les événements plusieurs fois pour chaque requête, ce qui n’a aucun sens – mis à part le fait qu’il a été ajouté plusieurs fois dans cette application http – ce qui signifie qu’il s’agit de la même méthode httpmodule init qui est appelée à chaque fois et non d’une nouvelle application http. en cours de création à chaque fois qu’il atteint mon sharepoint rupture (voir mon exemple de code en bas, etc.).

Qu’est-ce qui pourrait mal se passer ici? est-ce parce que je suis en train de déboguer et de définir un point d’arrêt dans le module http?

Il a été remarqué qu’il semble que si je lance le site Web pour le débogage et que je survole rapidement le point d’arrêt dans le httpmodule, il ne frappe la méthode init qu’une seule fois et il en va de même pour le gestionnaire d’événements. Si au lieu de cela je le laisse pendre au point d’arrêt pendant quelques secondes, la méthode init est appelée plusieurs fois (cela semble dépendre du temps d’attente avant de franchir le point d’arrêt). Cela pourrait peut-être être une fonctionnalité intégrée permettant de s’assurer que le httpmodule est initialisé et que l’application http peut répondre aux demandes, mais cela peut également avoir des conséquences catastrophiques.

Cela pourrait sembler logique, car il pourrait essayer de terminer la demande et puisque j’ai défini le point d’arrêt, il pense que quelque chose a mal tourné et a essayé d’appeler à nouveau la méthode init? soo il peut gérer la demande?

Mais est-ce ce qui se passe et est-ce que tout va bien (je devine), ou est-ce un problème réel?

Ce qui me préoccupe particulièrement, c’est que si quelque chose le bloque sur le serveur “production / live” pendant quelques secondes, de nombreux gestionnaires d’événements sont ajoutés via init et par conséquent, chaque demande de la page déclenche soudainement le gestionnaire d’événements plusieurs fois.

Ce comportement pourrait rapidement faire tomber n’importe quel site.

J’ai examiné le code .net “original” utilisé pour les httpmodules pour l’authentification des formulaires et le rolemanagermodule, etc., mais mon code n’est pas différent de celui utilisé par ces modules.

Mon code ressemble à ceci.

public void Init(HttpApplication app) { if (CommunityAuthenticationIntegration.IsEnabled) { FormsAuthenticationModule formsAuthModule = (FormsAuthenticationModule) app.Modules["FormsAuthentication"]; formsAuthModule.Authenticate += new FormsAuthenticationEventHandler(this.OnAuthenticate); } } 

voici un exemple de la manière dont cela est fait dans le RoleManagerModule à partir du framework .NET

  public void Init(HttpApplication app) { if (Roles.Enabled) { app.PostAuthenticateRequest += new EventHandler(this.OnEnter); app.EndRequest += new EventHandler(this.OnLeave); } } 

Est-ce que quelqu’un sait ce qui se passe?

(J’espère juste que quelqu’un pourra me dire pourquoi cela se produit et m’assurer que tout va parfaitement bien) 🙂


METTRE À JOUR:

J’ai essayé de réduire le problème et jusqu’à présent, j’ai constaté que la méthode Init appelée est toujours sur un nouvel object de mon module http (contrairement à ce que je pensais auparavant).

Il semble que lors de la première demande (lors du démarrage du site), tous les objects HttpApplication en cours de création et ses modules tentent tous de servir la première demande et, par conséquent, tous atteignent le gestionnaire d’événements qui est ajouté. Je ne peux pas vraiment comprendre pourquoi cela se produit.

Si je demande une autre page, toutes les applications HttpApplication créées (et leurs modules) essaieront à nouveau de servir la demande, ce qui la fera toucher plusieurs fois au gestionnaire d’événements.

Mais il semble aussi que si je retourne à la première page (ou à une autre), un seul HttpApplication va commencer à prendre en charge la demande et tout se passe comme prévu – tant que je ne le laisse pas pendre à un sharepoint rupture.

Si je le laisse pendre à un point d’arrêt, il commence à créer de nouveaux objects HttpApplication et commence à append HttpApplications (plus de 1) pour servir / gérer la demande (qui est déjà en cours de traitement par HttpApplication qui est actuellement arrêtée au point d’arrêt). .

J’espère ou espère qu’il s’agira d’une manière intelligente “en coulisses” d’aider à répartir et à gérer la charge et / ou les erreurs. Mais je n’ai aucune idée. J’espère que certains pourront m’assurer que tout va bien et comment cela est censé être?

  1. Examinez le HttpContext.Current.Request pour voir pour quelle requête l’init du module est déclenché. Peut-être que le navigateur envoie plusieurs requêtes.

  2. Si vous êtes connecté à IIS, vérifiez les journaux IIS pour savoir si une demande est reçue pour la durée de votre séjour au sharepoint rupture.

Il est normal que la méthode Init () soit appelée plusieurs fois. Lors du démarrage d’une application, le processus ASP.NET Worker instancie autant d’objects HttpApplication qu’il pense en avoir besoin, puis les regroupe (par exemple, les réutilise pour les nouvelles demandes, comme le regroupement des connexions de firebase database).

Désormais, pour chaque object HttpApplication, il instanciera également une copie de chaque IHttpModule enregistré et appellera plusieurs fois la méthode Init. Donc, si 5 objects HttpApplication sont créés, 5 copies de votre IHttpModule seront créées et votre méthode Init appelée 5 fois. Avoir un sens?

Maintenant, pourquoi installe-t-il 5 objects HttpApplications? Votre page ASPX contient peut-être des liens vers d’autres ressources que votre navigateur essaiera de télécharger, css, javascript, WebResource.aspx, peut-être un iframe quelque part. Ou peut-être que le processus de travail ASP.NET est «d’humeur» à démarrer plus d’un object HttpApplication, il s’agit en réalité d’un détail / optimisation interne du processus ASP.NET exécuté sous IIS (ou le serveur Web intégré du VS).

Si vous souhaitez que le code ne s’exécute qu’une seule fois (et que vous ne souhaitez pas utiliser l’événement Application_StartUp dans Global.asax), vous pouvez procéder comme suit dans votre IHttpModule:

 private static bool HasAppStarted = false; private readonly static object _syncObject = new object(); public void Init(HttpApplication context) { if (!HasAppStarted) { lock (_syncObject) { if (!HasAppStarted) { // Run application StartUp code here HasAppStarted = true; } } } } 

J’ai fait quelque chose de similaire et cela semble fonctionner, mais j’accepterais les critiques de mon travail au cas où je manquerais quelque chose.

Voici un peu d’explication sur ce que vous devriez utiliser, quand et comment ils fonctionnent. Quand utiliser Application_Start vs Init dans Global.asax?

Edit: Plus de lecture

La colonne ASP: Modules HTTP

INFO: instances d’application, événements d’application et état d’application dans ASP.NET

L’examen ci-dessus verrouille le IHttpModule pour toutes les demandes, puis crée l’ensemble de l’application. Si votre demande d’appels IHttpModule à plusieurs resockets est nécessaire pour appeler la méthode HttpApplication CompleteRequest et pour supprimer l’instance HttpApplication de l’événement IHttpModule dans EndRequest afin de supprimer l’instance de HttpApplication comme suit:

 public class TestModule :IHttpModule { #region IHttpModule Members public void Dispose() { } public void Init(HttpApplication context) { context.BeginRequest += new EventHandler(context_BeginRequest); context.EndRequest += new EventHandler(context_EndRequest); } void context_EndRequest(object sender, EventArgs e) { HttpApplication app = sender as HttpApplication; app.CompleteRequest(); app.Dispose(); } void context_BeginRequest(object sender, EventArgs e) { //your code here } #endregion } 

Si vous avez besoin de cela, les demandes IHttpModule à chaque fois sans demande de réutilisation sur postback, utilisez le code ci-dessus.