HttpModule.Init - безопасно добавить обработчик HttpApplication.BeginRequest в интегрированный режим IIS7

Мой вопрос аналогичен, но не идентичен:

Почему мой хост (softsyshosting.com) не поддерживает обработчики событий BeginRequest и EndRequest? (Я также прочитал блог mvolo, на который они ссылаются)

Цель состоит в том, чтобы успешно перехватить HttpApplication.BeginRequest в событии IHttpModule.Init(или где-либо внутри модуля), используя обычный HttpModule, интегрированный через конфигурацию system.webServer, то есть тот, который не выполняет:

  • введите global.asax или
  • переопределить HttpApplication (модуль предназначен для автономного и многоразового использования, например, у меня есть такая конфигурация):

    <system.webServer>
    <validation validateIntegratedModeConfiguration="false"/>
    <modules>
      <remove name="TheHttpModule" />
      <add name="TheHttpModule" type="Company.HttpModules.TheHttpModule" preCondition="managedHandler" /> 
    

До сих пор любая стратегия, которую я пытался подключить слушателю к HttpApplication.BeginRequest, приводит к одной из двух вещей: симптом 1 - это то, что BeginRequest никогда не срабатывает, или симптом 2 заключается в том, что следующее исключение попадает во все управляемые запросы, и я не могу поймать и обработать его из кода пользователя:

Stack Trace:
[NullReferenceException: Object reference not set to an instance of an object.]
System.Web.PipelineModuleStepContainer.GetEventCount(RequestNotification notification, Boolean isPostEvent) +30
System.Web.PipelineStepManager.ResumeSteps(Exception error) +1112
System.Web.HttpApplication.BeginProcessRequestNotification(HttpContext context, AsyncCallback cb) +113
System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) +616

Комментирование app.BeginRequest += new EventHandler(this.OnBeginRequest) в Init останавливает исключение из курса. Init не ссылается на объекты контекста или запроса вообще.

Я пробовал:

  • Удалены все ссылки на HttpContext.Current в любом месте проекта (все еще симптом 1)
  • Протестировано удаление всего кода из тела моего метода OnBeginRequest, чтобы убедиться, что проблема не была внутренней для метода (= исключение)
  • Обнюхивание трассировки стека и вызов вызывающего приложения .BeginRequest + =... когда, если стек не запускается с помощью InitializeApplication (= BeginRequest не запускается)
  • Только вызов app.BeginRequest + = на втором проходе через Init (= BeginRequest не срабатывает)

Кто-нибудь знает о хорошем подходе? Есть ли какая-то косвенная стратегия для подключения Application_Start в модуле (кажется маловероятным)? Другое событие, которое: a) можно взять с помощью конструктора модуля или метода Init, и b), который впоследствии является безопасным местом для присоединения обработчиков событий BeginRequest?

Спасибо большое

Ответ 1

Ваш метод HttpModule Init будет вызван несколько раз одним веб-приложением (тогда как Application_Start в вашем global.asax будет вызываться только один раз для AppDomain).

Инициал действительно является местом, где можно подключиться к BeginRequest.

Я тоже столкнулся с этой ошибкой, и это было вызвано подключением к событию BeginRequest более одного раза. Я не уверен, что это ошибка в интегрированном режиме IIS 7 или нет...

Когда вы выполняете app.BeginRequest, вы вызываете context.BeginRequest, используя параметр контекста для вашего метода IHttpModule Init или вызываете HttpContext.Current.BeginRequest + =...?

Ответ 2

У меня были те же проблемы, о которых говорилось выше. Я обнаружил, что практическая работа всегда заключалась в том, чтобы всегда удалять, а затем добавлять обработчика. таким образом:

    public override void Init()
    {
        base.Init();

        lock (_initialisationLockObject)
        {
            BeginRequest -= Global_BeginRequest;
            BeginRequest += Global_BeginRequest;
        }
    }

Я подозреваю, что обработчики событий очищаются после одного или нескольких из нескольких вызовов init. Если вы тщательно только попытаетесь добавить обработчик событий в первый раз, то последующие вызовы init будут вызваны, не получите добавленное событие и, следовательно, обработчик вообще не будет вызван. Если вы не попробуете ничего хитрого, чтобы ограничить количество раз, когда событие добавляется, то вы видели, чтобы получить несколько вложений. Сначала пытаясь удалить, добавьте (внутри замка, чтобы остановить любые гнусные условия гонки), похоже, делает трюк.

Это ужасно, но нам не нужно это делать!

Надеюсь, что поможет