Accessing the Form collection in an IHttpModule causes event Handler not to get called on Default page
Ok, this is a weird one. I've created a simple sample site to demonstrate the issue. In it, I have a Default.aspx Page that has a button on it:
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
<p><asp:Button OnClick="ButtonClick" Text="Button" runat="server" />
</p>
<asp:Label ID="output" runat="server" />
</asp:Content>
The code behind just sets the label text on the button click:
protected void ButtonClick(object sender, EventArgs e)
{
output.Text = "Button Click!!";
}
I then have an IHttpModule that gets called for every request:
public class SampleModule : IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
}
private void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication application = sender as HttpApplication;
if(application == null)
{
return;
}
HttpContext context = application.Context;
if(context == null)
{
return;
}
string text = "queryStringParam";
var value 开发者_StackOverflow社区= context.Request[text];
var boolValue = value == null;
}
}
Again, this is just a demo, but the point here is, I'm accessing the Request, to get the value off the query string. If I run this in Cassini, it all works fine. However when I run this in IIS, this is what happens. When I run the site at:
http://mysamplesite.dev/
and then click on the button, nothing happens. The page just reloads, but my event handler for the button never gets called, and subsequently the label text never gets updated. However if I then run it at:
http://mysamplesite.dev/Default.aspx
and then click the button, it works fine and my event handler does get called!
After digging around some I changed the code in the module to this:
string text = "queryStringParam";
var value = context.Request.QueryString[text];
var boolValue = value == null;
Notice, here I'm accessing the QueryString property directly, and not going to context.Request. When I changed it to this, it works fine regardless of whether or not I had Default.aspx in the url?!
Next step I did was, I looked at Reflector to see what the code of the HttpRequest indexer property actually does:
public string this[string key]
{
get
{
string str = this.QueryString[key];
if (str != null)
{
return str;
}
str = this.Form[key];
if (str != null)
{
return str;
}
HttpCookie cookie = this.Cookies[key];
if (cookie != null)
{
return cookie.Value;
}
str = this.ServerVariables[key];
if (str != null)
{
return str;
}
return null;
}
}
Seems harmless enough, it just checks various collections for me, so I don't need to check each one individually. So then I'm wondering, which one of those calls breaks it. I then changed my module to this:
string text = "queryStringParam";
var value = context.Request.QueryString[text];
var boolValue = value == null;
var value2 = context.Request.Form[text];
var boolValue2 = value2 == null;
And now it's broken again! So to make a long story short, just by accessing the Form collection on the request in the IHttpModule, I somehow screw up the PostBack, and the event never gets fired.
Does anyone have any idea why this is happening? I'm more of an ASP.Net MVC guy, I don't know ASP.Net and all the shtick it pulls behind the scenes well enough to really have a clue as to why this is happening.
- give your button an ID (no luck)
- try fiddler and see what the traffic looks like - something funny is going on here.
When a request is made to "http://mysamplesite.dev/Default.aspx", the context_BeginRequest
event handler is only called once, as you would expect. However, when a request is made to "http://mysamplesite.dev/", for some reason context_BeginRequest
is called twice.
For "http://mysamplesite.dev/", the first pass through context_BeginRequest
loads the Form
values properly when context.Request["queryStringParam"]
is executed, but the second pass through does not (I checked the private _form
value on context.Request
using reflection). During this time, the Page_Load
method for the page is only called once.
So, the event is not being handled properly because ASP.NET handles a request for "/" a little bit differently than it handles a request for "/Default.aspx", by firing the BeginRequest
for the module twice instead of once. As to why ASP.NET does this, I'm not really sure. You would probably need to profile the ASP.NET request and see what methods are being called on HttpRequest
to see why the form values don't get passed properly the second time context_BeginRequest
is called (and additionally why this second call is even made in the first place).
Note: this must be an internal ASP.NET thing (maybe a Server.Transfer from "/" to "/Default.aspx" or something like that) because Fiddler2 only shows one request coming from the browser for "http://mysamplesite.dev/".
精彩评论