2017-02-06 184 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,在這裏情況並非如此。

MSDNBeginRequest的細節上似乎有點亮,所以到目前爲止我還沒有找到很多幫助。

我可能會錯過某些明顯的東西,這是我第一次遇到.NET/IIS等,我通常是一個Java開發人員。

更新

我已經傾倒的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

這個問題可以隱藏在很多地方... 我建議設置一個斷點,其中響應值附加字符串,看看它將何時觸發2 - 時間。 檢查呼叫堆棧以查看誰發起了第二次呼叫。 – Nikita

+0

有沒有辦法讓IISExpress進入某種調試模式?我在調用堆棧中看到的是'DoBeginRequest',前面有'[External code]' – Stik

+0

非常有趣的IIS行爲......您可能會發現這篇文章很有用,但是它的解決方案在我們的例子中不起作用:http:// erraticdev.blogspot.com/2011/01/how-to-correctly-use-ihttpmodule-to.html – Nikita

回答

0

好吧,經過多次的挫折之後,我發現具體的網址確實不是而是患有這種行爲。與「擴展」的網址不這樣做:

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

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

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

通過一些更多的挖掘網上我發現一個處理程序引用稱爲這是由主配置文件加載applicationhost.configExtensionlessUrl-Integrated-4.0。我真的不知道這是什麼做的,也不知道爲什麼它會導致請求被複制,但在我自己的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 Web應用程序你的行爲。 而且它與favicon.ico附加請求無關。 它可能與IIS可能在應用程序池中創建的多個應用程序實例有關。以及您的模塊的多個實例具有對同一事件的多個訂閱。它在某處......但我現在還不能證明我的代碼中沒有這些理論。

+0

使用'LogRequest'似乎表現正確,但它不覺得「正確」使用它來做實際工作(在這種情況下,我打算用它通過一些IPC機制有效地代理另一個進程)。我也沒有自信,我能夠依靠'LogRequest'工作來理解它! – Stik

+0

經過進一步調查,'LogRequest'也被調用兩次,但只有一個'Response'流返回給客戶端。 IIS總是這麼難嗎?我覺得這是一個如此簡單的「Hello World」應用程序,但仍然有些錯誤,我必須忽略一些明顯的東西。 – Stik