Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

BeginRequest is called twice

Tags:

c#

.net

asp.net

iis

I have created an 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());
    }
}

Which is loaded like so:

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

When i call this from a web browser, or from curl, i get two log lines in the Output tab, and i see the following response:

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

Which indicates that it is the same Context each time. Why is this happening? There are a lot of fields in the Request object, but i've not been able to spot any difference between them in the two calls. Is there some property i should be checking that gives a "stage" that i should only be responding to one of?

I have found a few related questions here on the site, but most of them seem to lean toward it being the web browser looking for another resource, like favicon.ico, and that is not the case here.

MSDN seems a bit light on details for BeginRequest, so i've not found a lot of help there so far.

I may be missing something obvious, this is my first encounter with .NET/IIS etc, i am a Java dev usually.

Update:

I've dumped all the public properties of Request and this is the difference between the two:

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

Specifically, the Content-Length header is getting set on the second call. This wasn't present in the request curl made:

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

Is this IIS trying to be helpful? After it's handled the whole request it knows how long the body is (0) and calls it again with that set?

like image 308
Stik Avatar asked Oct 22 '25 05:10

Stik


2 Answers

Ok, after much frustration i discovered that specific URLs did not suffer from this behaviour. URLs with an "extension" don't do it:

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

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

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

Through some more digging online i've found references to a Handler called ExtensionlessUrl-Integrated-4.0 which is loaded by the main config file applicationhost.config. I don't really know what this is doing, nor why it causes requests to be duplicated, but explicitly removing it in my own web.config has solved the problem:

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

I must admit that i am a bit afraid of what other similar pitfalls i might encounter later on - applicationhost.config loads a lot of other handlers and modules, any of which might be messing with stuff like this before my module is able to get at it. But that's a problem for another day...

like image 60
Stik Avatar answered Oct 23 '25 21:10

Stik


(Note: this solution may not be appropriate in every application)

Just call CompleteRequest() at the end of your event handler (be it BeginRequest, PostAuthorizeRequest, or something else).

This call finishes request processing and prevents other handlers from working, but if you have already handled it, most likely, you don't expect post-processing to take place, so no big deal.

like image 24
Eugene Mayevski 'Callback Avatar answered Oct 23 '25 22:10

Eugene Mayevski 'Callback