2017-02-06 8 views
1

Я создал HttpModule:BeginRequest вызывается дважды

using System; 
using System.Web; 

public class TestModule : IHttpModule 
{ 
    public TestModule() { } 

    public String ModuleName { get { return "TestModule"; } } 

    public void Dispose() { } 

    public void Init(HttpApplication app) 
    { 
     app.BeginRequest += (new EventHandler(this.DoBeginRequest)); 
    } 

    private void DoBeginRequest(Object source, EventArgs e) 
    { 
     HttpApplication application = (HttpApplication)source; 
     HttpContext context = application.Context; 
     context.Response.Write("<pre>Request URL: " + context.Request.FilePath + "</pre>"); 
     context.Response.Flush();    
     System.Diagnostics.Debug.WriteLine(context.Request.ToString()); 
    } 
} 

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

<system.webServer> 
    <modules> 
    <add name="TestModule" type="TestModule"/> 
    </modules> 
</system.webServer> 

Когда я называю это с помощью веб-браузера или из curl, я получаю два журнала линии на вкладке «Вывод», и я вижу следующий ответ:

<pre>Request URL: /example</pre><pre>Request URL: /example</pre> 

Что указывает, что это i с тем же Контекстом каждый раз. Почему это происходит? В объекте Request есть много полей, но я не смог обнаружить разницу между ними в двух вызовах. Есть ли какое-то свойство, которое я должен проверять, что дает «этап», на который я должен отвечать только одному?

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

MSDN кажется немного светлым для деталей для BeginRequest, так что я пока не нашел много помощи.

Возможно, мне не хватает чего-то очевидного, это моя первая встреча с .NET/IIS и т. Д. Я обычно являюсь разработчиком Java.

Update:

Я бросил все открытые свойства из Request и это разница между этими двумя:

Headers == Accept=*%2f*&Host=localhost%3a2017&User-Agent=curl%2f7.35.0 
Headers == Content-Length=0&Accept=*%2f*&Host=localhost%3a2017&User-Agent=curl%2f7.35.0 

В частности, заголовок Content-Length становится на втором вызове , Это не присутствует в запросе curl сделано:

> GET /example HTTP/1.1 
> User-Agent: curl/7.35.0 
> Host: localhost:2017 
> Accept: */* 

Это IIS пытается быть полезным? После того, как он обрабатывает весь запрос, он знает, как долго тело (0) и вызывает его снова с этим набором?

+0

Проблема может скрыться во многих местах ... Я предлагаю установить точку останова, где значение Response добавляется к строке, и посмотреть, когда она будет запущена для 2 и время. Проверьте стек вызовов, чтобы узнать, кто инициировал 2-й вызов. – Nikita

+0

Есть ли способ поставить IISExpress в какой-то режим отладки? Все, что я вижу в стеке вызовов, это 'DoBeginRequest', предшествующий' [Внешний код] ' – Stik

+0

Очень интересное поведение IIS ... вы можете найти эту статью полезной, но решение от нее не будет работать в нашем случае: http: // erraticdev.blogspot.com/2011/01/how-to-correctly-use-ihttpmodule-to.html – Nikita

ответ

0

Хорошо, после многих разочарований я обнаружил, что определенные URL-адреса не страдают от этого поведения. URL-адрес с «расширением» не делайте этого:

curl http://localhost:2017/test 
> BeginRequest 
> BeginRequest 

curl http://localhost:2017/test.abc 
> BeginRequest 

curl http://localhost:2017/.a 
> BeginRequest 

Через несколько более рытье онлайн я нашел ссылок на Обработчик называется ExtensionlessUrl-Integrated-4.0, который загружается в основном конфигурационном файле applicationhost.config.Я не знаю, что это делает, и почему он вызывает запросы дублируются, но явно удалить его в моей собственной web.config решил проблему:

<system.webServer> 
     <handlers> 
     <remove name="ExtensionlessUrl-Integrated-4.0" /> 
     </handlers> 
     <modules> 
     <add name="TestModule" type="TestModule"/> 
     </modules> 
    </system.webServer> 

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

0

Использование LogRequest событие слушателя вместо BeginRequest должен работать для своей цели:

public void Init(HttpApplication app) 
{ 
    app.LogRequest += DoBeginRequest; // TODO: Rename your function 
} 

Да, я вижу свое поведение на очень чистый вебе ASP.NET Application. И это не связано с favicon.ico дополнительный запрос. Он может относиться к нескольким экземплярам приложений, которые IIS может создавать в пуле приложений. И несколько экземпляров вашего модуля с несколькими подписками на одно и то же событие. Это где-то здесь ... но я пока не могу доказать ни одну из этих теорий в моем коде.

+0

Использование 'LogRequest', похоже, ведет себя правильно, но не кажется« правильным »использовать его для выполнения фактических (в этом случае я собираюсь использовать его для эффективного проксирования другого процесса через некоторый механизм IPC). Я также не чувствую уверенности в себе, что понимаю это достаточно хорошо, чтобы иметь возможность полагаться на 'LogRequest', работающий либо! – Stik

+0

При дальнейшем расследовании 'LogRequest' также вызывается дважды, однако только один из потоков' Response' когда-либо возвращается клиенту. IIS всегда так сложно? Я чувствую, что это такое простое приложение «Hello World», но что-то по-прежнему очень не так, и я должен упустить что-то очевидное. – Stik