C# BeginRequest被调用两次

C# BeginRequest被调用两次,c#,asp.net,.net,iis,C#,Asp.net,.net,Iis,我已经创建了一个HttpModule: using System; using System.Web; public class TestModule : IHttpModule { public TestModule() { } public String ModuleName { get { return "TestModule"; } } public void Dispose() { } public void Init(HttpApplica

我已经创建了一个
HttpModule

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());
    }
}
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
具体来说,
内容长度
头在第二次调用时设置。这在发出的请求
curl
中不存在:

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

这是IIS试图提供帮助吗?处理完整个请求后,它知道主体的长度(0),并使用该集合再次调用它?

使用LogRequest事件侦听器而不是BeginRequest应该可以满足您的需要:

是的,我在非常干净的ASP.NET Web应用程序上看到了您的行为。 它与favicon.ico附加请求无关。
它可能与IIS在应用程序池中创建的多个应用程序实例有关。以及具有对同一事件的多个订阅的模块的多个实例。它就在这里的某个地方……但是我现在无法在我的代码中证明这些理论。

好吧,在经历了很多挫折之后,我发现特定的URL没有受到这种行为的影响。带有“扩展名”的URL不会这样做:

通过进一步的在线挖掘,我找到了一个名为
ExtensionlessUrl-Integrated-4.0
的处理程序的引用,该处理程序由主配置文件
applicationhost.config
加载。我真的不知道这是在做什么,也不知道它为什么会导致请求重复,但在我自己的
web.config
中明确删除它解决了问题:



我必须承认,我有点担心我以后可能会遇到其他类似的陷阱-
applicationhost.config
加载了许多其他处理程序和模块,其中任何一个都可能在我的模块能够处理它之前弄乱了这样的东西。但这是另一天的问题…

问题可能隐藏在很多地方。。。我建议在响应值附加字符串的地方设置一个断点,并查看第二次触发的时间。检查调用堆栈以查看是谁发起了第二次调用。是否有方法将IISExpress置于某种调试模式?我在调用堆栈中看到的只是
DoBeginRequest
之前的
[External code]
非常有趣的IIS行为……您可能会发现本文很有用,但它的解决方案在我们的案例中不起作用:使用
LogRequest
似乎行为正确,但使用它来做实际工作感觉不“正确”(在本例中,我将使用它通过一些IPC机制有效地代理另一个进程)。我也没有信心我对它理解得足够透彻,能够依靠
LogRequest
工作!进一步调查后,
LogRequest
也被调用了两次,但是只有一个
响应流
返回到客户端。IIS总是这么难吗?我感觉就是这样一个简单的“Hello World”应用程序,但有些地方仍然很不对劲,我肯定错过了一些明显的东西。
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
> GET /example HTTP/1.1
> User-Agent: curl/7.35.0
> Host: localhost:2017
> Accept: */*
public void Init(HttpApplication app)
{
    app.LogRequest += DoBeginRequest; // TODO: Rename your function
}
curl http://localhost:2017/test
 > BeginRequest
 > BeginRequest 

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

curl http://localhost:2017/.a
 > BeginRequest
   <system.webServer>
      <handlers>
        <remove name="ExtensionlessUrl-Integrated-4.0" />
      </handlers>
      <modules>
        <add name="TestModule" type="TestModule"/>
      </modules>
    </system.webServer>