访问 IHttpModule 中的 Form 集合会导致事件处理程序无法在默认页面上调用
好吧,这很奇怪。我创建了一个简单的示例网站来演示该问题。在其中,我有一个 Default.aspx 页面,上面有一个按钮:
<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>
后面的代码只是在按钮单击上设置标签文本:
protected void ButtonClick(object sender, EventArgs e)
{
output.Text = "Button Click!!";
}
然后我有一个为每个请求调用的 IHttpModule:
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 = context.Request[text];
var boolValue = value == null;
}
}
同样,这只是一个演示,但这里的重点是,我正在访问请求,以从查询字符串中获取值。如果我在卡西尼号上运行它,一切都会正常。然而,当我在 IIS 中运行它时,就会发生这种情况。当我运行该网站时:
http://mysamplesite.dev/
然后单击该按钮,没有任何反应。页面只是重新加载,但按钮的事件处理程序永远不会被调用,随后标签文本永远不会更新。但是,如果我然后在以下位置运行它:
http://mysamplesite.dev/Default.aspx
然后单击按钮,它工作正常并且我的事件处理程序确实被调用!
经过一番研究后,我将模块中的代码更改为:
string text = "queryStringParam";
var value = context.Request.QueryString[text];
var boolValue = value == null;
注意,这里我直接访问 QueryString 属性,而不是访问 context.Request。当我将其更改为这个时,无论我的网址中是否有 Default.aspx,它都可以正常工作?!
我所做的下一步是,我查看 Reflector 以了解 HttpRequest 索引器属性的代码实际上做了什么:
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;
}
}
看起来无害,它只是为我检查各种集合,因此我不需要单独检查每个集合。所以我想知道哪一个调用破坏了它。然后我将模块更改为:
string text = "queryStringParam";
var value = context.Request.QueryString[text];
var boolValue = value == null;
var value2 = context.Request.Form[text];
var boolValue2 = value2 == null;
现在它又坏了!因此,长话短说,只需访问 IHttpModule 中请求的 Form 集合,我就会以某种方式搞砸 PostBack,并且该事件永远不会被触发。
有谁知道为什么会发生这种情况?我更像是一个 ASP.Net MVC 人员,我不了解 ASP.Net 及其幕后的所有技巧,无法真正了解为什么会发生这种情况。
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 = 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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
当向“http://mysamplesite.dev/Default.aspx”发出请求时,如您所料,context_BeginRequest 事件处理程序仅被调用一次。但是,当向“http://mysamplesite.dev/”发出请求时,由于某种原因
context_BeginRequest
被调用两次。对于“http://mysamplesite.dev/”,第一次通过
context_BeginRequest
在context.Request["queryStringParam"]
时正确加载Form
值code> 被执行,但第二次传递没有执行(我使用反射检查了context.Request
上的私有_form
值)。在此期间,页面的Page_Load
方法仅被调用一次。因此,该事件没有得到正确处理,因为 ASP.NET 处理“/”的请求与处理“/Default.aspx”的请求略有不同,通过触发
BeginRequest
来处理“/”的请求。模块两次而不是一次。至于为什么 ASP.NET 这样做,我不太确定。您可能需要分析 ASP.NET 请求并查看HttpRequest
上调用了哪些方法,以了解为什么表单值第二次无法正确传递context_BeginRequest
被调用(另外为什么甚至首先进行第二次调用)。注意:这必须是一个内部 ASP.NET 事物(可能是从“/”到“/Default.aspx”的 Server.Transfer 或类似的事物),因为 Fiddler2 只显示来自浏览器的一个请求“http://mysamplesite” .dev/”。
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 reasoncontext_BeginRequest
is called twice.For "http://mysamplesite.dev/", the first pass through
context_BeginRequest
loads theForm
values properly whencontext.Request["queryStringParam"]
is executed, but the second pass through does not (I checked the private_form
value oncontext.Request
using reflection). During this time, thePage_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 onHttpRequest
to see why the form values don't get passed properly the second timecontext_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/".