Метод HttpModule Init вызывается несколько раз-почему?

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

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

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

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

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

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

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

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

это поведение может быстро сбить любой сайт.

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

мой код выглядит так.

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

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

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

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

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

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


обновление:

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

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

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

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

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

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

4 ответов


  1. Проверьте HttpContext.Текущий.Запрос на просмотр, по какому запросу запускается init модуля. Возможно, браузер отправляет несколько запросов.

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


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

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

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

Если вы хотите код, который гарантированно запускается только один раз (и не хотите использовать событие Application_StartUp в глобальном.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;
            }
        }
    }
}

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


вот немного объяснений о том, что вы должны использовать, когда и как они работают. когда использовать Application_Start vs Init в глобальном.асакс?

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

столбец ASP: HTTP Modules

INFO: экземпляры приложения, события приложения и состояние приложения в ASP.NET


Examle выше блокирует 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 каждый раз без повторного запроса на обратной передаче использовали этот код выше.