2009-07-17 12 views
30

Я создавал модуль http, и во время отладки я заметил что-то, что сначала (по крайней мере) казалось странным поведением.Метод HttpModule Init вызывается несколько раз - почему?

Когда я установил точку останова в методе init httpmodule, я вижу, что метод init модуля http вызывается несколько раз, хотя я только запустил веб-сайт для отладки и сделал один единственный запрос (иногда это ударить только 1 раз, в других случаях - 10 раз).

Я знаю, что я должен ожидать, что несколько экземпляров HttpApplication будут запущены, и для каждого из них будут созданы http-модули, но когда я запрашиваю одну страницу, она должна обрабатываться одним объектом приложения http и, следовательно, события, связанные один раз, но все же он несколько раз запускает события для каждого запроса, что не имеет смысла - кроме того, что он должен быть добавлен несколько раз в течение этого httpApplication, что означает, что это тот же самый метод init httpmodule, который вызывается каждый раз, а не новое приложение http, создаваемое каждый раз, когда оно попадает в мою точку разрыва (см. мой пример кода внизу и т. д.).

Что здесь может быть не так? это потому, что я отлаживаю и устанавливаю точку останова в модуле http?

Он заметил, что, если я запустил веб-сайт для отладки и быстро перешагнул точку останова в httpmodule, он только ударит по методу init один раз, и то же самое касается обработчика событий. Если я вместо этого позволю ему зависнуть в точке останова в течение нескольких секунд, метод init вызывается несколько раз (похоже, это зависит от того, сколько времени я жду, прежде чем переходить на точку останова). Возможно, это может быть какая-то функция сборки, чтобы убедиться, что httpmodule инициализирован, и приложение http может обслуживать запросы, но также похоже на то, что может иметь катастрофические последствия.

Это может показаться логичным, поскольку это может быть попытка завершить запрос, и поскольку я установил точку останова, он думает, что что-то пошло не так, и попробуйте снова вызвать метод init. soo может обрабатывать запрос?

Но это то, что происходит, и все прекрасно (я просто догадываюсь), или это настоящая проблема?

Что меня особенно беспокоит, так это то, что если что-то заставляет его висеть на «производственном/живом» сервере в течение нескольких секунд, через init запускается много обработчиков событий, и поэтому каждый запрос на страницу внезапно запускает обработчик событий несколько раз.

Такое поведение может привести к быстрому удалению любого сайта.

Я рассмотрел «оригинальный» .net-код, используемый для httpmodules для проверки форм и rolemanagermodule и т. Д., Но мой код не отличается от того, что используют эти модули.

Мой код выглядит следующим образом.

public void Init(HttpApplication app) 
    { 
     if (CommunityAuthenticationIntegration.IsEnabled) 
     { 
      FormsAuthenticationModule formsAuthModule = (FormsAuthenticationModule) app.Modules["FormsAuthentication"];   

      formsAuthModule.Authenticate += new FormsAuthenticationEventHandler(this.OnAuthenticate); 
     } 
    } 

вот пример того, как это делается в RoleManagerModule от платформы .NET

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

ли кто-нибудь знает, что происходит?

(я просто надеюсь, что кто-то может сказать мне, почему это происходит, и уверяют меня, что все это прекрасно) :)


UPDATE:

Я пытался сузить проблему и до сих пор я обнаружил, что вызываемый метод Init всегда находится на новом объекте моего модуля http (в зависимости от того, что я думал раньше).

Похоже, что для первого запроса (при запуске сайта) создаются все объекты HttpApplication и его модули, которые пытаются обслуживать первый запрос, и поэтому все удаляют добавленный обработчик событий. Я не могу понять, почему это происходит.

Если я запрашиваю другую страницу, все созданные HttpApplication (и их модуляция) снова попытаются выполнить запрос, заставив его несколько раз ударить обработчик событий.

Но также кажется, что если я затем вернусь на первую страницу (или другую), только один HttpApplication начнет заботиться о запросе, и все будет как ожидалось - до тех пор, пока я не позволяю ему висеть на точка останова.

Если я позволю ему висеть на точке останова, он начинает создавать новые объекты HttpApplication и начинает добавлять HttpApplications (более 1) для обслуживания/обработки запроса (который уже выполняется службой HttpApplication, которая в настоящее время остановлена в точке останова).

Я думаю или надеюсь, что это может быть разумный способ «за кулисами» помочь распределить и обработать нагрузку и/или ошибки. Но я понятия не имею. Надеюсь, некоторые там могут заверить меня, что это прекрасно, и как это должно быть?

+2

Я также вижу это поведение в нашем HttpModule –

+0

John: Я забыл закрыть этот. Это происходит (по крайней мере, в моем случае), потому что модуль попадает в каждый отдельный запрос, который браузер делает для любого ресурса (изображения, javascripts, stylesheets). Причина, по которой он попадает, - это модуль маршрутизации, используемый в и т. Д. MVC. Все запросы должны обрабатываться модулем маршрутизации, и поэтому все запросы попадают в модуль к несчастью. Я задал вопрос об этом, но никто на это не ответил. – MartinF

ответ

7
  1. Осмотрите HttpContext.Current.Request, чтобы увидеть, для чего просить инициализации модуля обжигают. Может быть, браузер отправляет несколько запросов.

  2. Если вы подключены к IIS, проверьте журналы IIS, чтобы узнать, получен ли какой-либо запрос на время пребывания в точке останова.

+0

Правильно. Это происходит потому, что все запросы (для любого ресурса) попадают в модуль. В моем случае из-за модуля маршрутизации кажется. – MartinF

2

Вот несколько объяснений относительно того, что вы должны использовать, когда и как они работают. When to use Application_Start vs Init in Global.asax?

Edit: Больше чтения

The ASP Column: HTTP Modules

INFO: Application Instances, Application Events, and Application State in ASP.NET

+0

Спасибо за ваш ответ. Я не использую ни один из них. Init в глобальном asax переопределяет init в HttpApplication. Моя проблема в том, что метод Init в моем httpmodule вызывается несколько раз. Насколько я понимаю, он должен создать http-модули для каждого HTTP-приложения. По каждому запросу один из индуцированных HttpApplication обрабатывает запрос и запускает добавленные события, но по какой-то причине обработчик событий * иногда * добавляется несколько раз в качестве метода init в том же http-модуле (не один из новых, созданных для другое приложение httpapplication) называется серверным временем. – MartinF

+0

Больше, чтобы читать добавлено. –

40

Это нормально для метода Init(), который вызывается несколько раз. Когда приложение запускается, процесс ASP.NET Worker будет создавать как можно больше объектов HttpApplication, поскольку он считает, что он нужен, тогда он будет их объединять (например, повторно использовать их для новых запросов, аналогично пулу соединений с базой данных).

Теперь для каждого объекта HttpApplication он также создает экземпляр одной копии каждого зарегистрированного IHttpModule и многократно вызывает метод Init. Таким образом, если создано 5 объектов HttpApplication, будет создано 5 копий вашего IHttpModule, а метод Init - 5 раз. Имеют смысл?

Теперь почему это создает экземпляр 5 объектов HttpApplications? Возможно, на вашей странице ASPX есть ссылки на другие ресурсы, которые ваш браузер попытается загрузить, css, javascript, WebResource.aspx, возможно, где-нибудь в iframe. Или, может быть, рабочий процесс ASP.NET «находится в настроении» для запуска более одного объекта HttpApplication, это действительно внутренняя детальность/оптимизация процесса ASP.NET, работающего под IIS (или встроенным веб-сервером VS).

Если вы хотите код, который гарантированно работать только один раз (и не хотите использовать событие Application_Startup в Global.asax), вы можете попробовать следующее в вашем 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; 
      } 
     } 
    } 
} 

Я я сделал что-то похожее и, похоже, сработал, хотя я бы приветствовал критику моей работы на случай, если я что-то пропустил.

+10

Это место, где вы можете использовать 'Interlocked.CompareExchange' вместо блокировки :) –

+1

Выполняет ли даже запрос к файлу ресурсов создание класса приложения и его собственный модуль и, таким образом, запуск этого события? –

1

Экзамен выше блокирует IHttpModule для всех запросов, а затем он освобождает все приложение. Если IHttpModule вызовы запрашивать несколько раз необходимо вызвать HttpApplication метод CompleteRequest и утилизировать экземпляр HttpApplication в IHttpModule в EndRequest случае для того, чтобы удалить экземпляр HttpApplication как это:

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 
    } 

Если вам нужно что IHttpModule запросы каждый раз без переэкспонирования при обратной передаче используйте этот код выше.

+0

Это хороший момент, но для некоторых приложений (например, у меня) код, который должен быть выполнен, составляет не более нескольких микросекунд, поэтому блокировка определенно экономична. Но спасибо за эту идею, я думаю, зная, что это улучшит мое кодирование. – Abacus

Смежные вопросы