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

StackOverflow https://stackoverflow.com/questions/1140915

  •  16-09-2019
  •  | 
  •  

Вопрос

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

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

Я знаю, что я должен ожидать, что будут созданы несколько экземпляров HTTPApplication, и для каждого модули HTTP будут созданы модули HTTP, но когда я запрашиваю одну страницу, его следует обрабатывать одним объектом приложения HTTP и, следовательно, только один раз запускает события, связанные, один раз, Но все же это запускает события несколько раз для каждого запроса, который не имеет смысла - кроме того, что он должен был быть добавлен несколько раз в этом httpapplication - что означает, что это один и тот же метод httpmodule init, который называется каждый раз, а не новое приложение HTTP Создание каждый раз, когда он попадает в мою точку разрыва (см. Пример кода внизу и т. Д.).

Что здесь может пойти не так? Это потому, что я отладка и устанавливаю точку останова в модуле HTTP?

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

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

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

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

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

Я посмотрел на «оригинальный» .NET -код, используемый для HTTPModules для FormAuthentication и 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. Я не могу понять, почему это происходит.

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

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

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

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

Это было полезно?

Решение

  1. Осмотрите httpcontext.current.request, чтобы увидеть, чтобы запрашивать инициировано модуль. Может быть, браузер отправляет несколько запросов.

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

Другие советы

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

Теперь для каждого объекта httpapplication он также создаст одну копию каждого зарегистрированного ihttpmodule, и вызовут метод init, который много раз. Таким образом, если будут созданы 5 объектов HTTPApplication, будут созданы 5 копий вашего iHTTPModule, и ваш метод инициирования называется 5 раз. Иметь смысл?

Теперь, почему это создает 5 -й объекты HTTPApplications? Ну, может быть, на вашей странице ASPX есть ссылки на другие ресурсы, которые ваш браузер попытается скачать, CSS, JavaScript, webresource.aspx, возможно, где -то iframe. Или, может быть, работник ASP.NET «в настроении» для запуска более 1 объекта HTTPApplication, это действительно внутренняя детализация/оптимизация процесса ASP.NET, работающего под IIS (или VS, встроенный в WebServer).

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

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

Вот немного объяснения того, что вы должны использовать, когда и как они работают.Когда использовать Application_start vs init in global.asax?

РЕДАКТИРОВАТЬ: больше чтения

Столбец ASP: модули HTTP

Информация: экземпляры приложения, события приложений и состояние приложения в ASP.NET

Экзамен выше блокирует ihttpmodule для всех запросов, а затем он облегает все приложение. Если ваш запрос на вызовы ihttpmodule несколько раз требуется для вызова метода httpapplication exploseeRequest и утилизации экземпляра 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 запрашивает каждый раз без повторного регистрации в Prosback, используйте этот код выше.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top