Подтвердить что ты не робот

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

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

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

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

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

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

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

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

То, что меня особенно беспокоит, заключается в том, что если что-то заставляет его зависать на сервере "production/live" в течение нескольких секунд, через 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, который в настоящее время остановлен на точка останова).

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

4b9b3361

Ответ 1

  • Осмотрите HttpContext.Current.Request, чтобы увидеть, для какого запроса запускается модуль init. Возможно, браузер отправляет несколько запросов.

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

Ответ 2

Это нормально для метода 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;
            }
        }
    }
}

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

Ответ 4

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