访问IHttpModule中的Form集合会导致在默认页面上不调用事件处理程序

时间:2011-03-18 14:49:14

标签: c# asp.net iis ihttpmodule

好的,这很奇怪。我已经创建了一个简单的示例站点来演示该问题。在其中,我有一个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;
    }
}

同样,这只是一个演示,但这里的重点是,我正在访问请求,以获取查询字符串的值。如果我在Cassini中运行它,一切正常。但是,当我在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以及它在幕后的所有内容,以便真正了解为什么会发生这种情况。

2 个答案:

答案 0 :(得分:1)

  1. 给你的按钮一个ID(没有运气)
  2. 尝试fiddler,看看流量是什么样子 - 这里有趣的事情。

答案 1 :(得分:1)

当请求“http://mysamplesite.dev/Default.aspx”时,context_BeginRequest事件处理程序只调用一次,如您所料。但是,当请求“http://mysamplesite.dev/”时,由于某种原因context_BeginRequest被调用两次。

对于“http://mysamplesite.dev/”,第一次传递context_BeginRequest会在执行Form时正确加载context.Request["queryStringParam"]值,但第二次传递不会(我使用反射检查了_form上的私有context.Request值。在此期间,页面的Page_Load方法仅调用一次。

因此,事件处理不正确,因为ASP.NET处理对“/”的请求与处理“/Default.aspx”请求略有不同,方法是触发BeginRequest模块两次而不是一次。至于为什么ASP.NET这样做,我不太确定。您可能需要分析ASP.NET请求并查看HttpRequest上调用的方法,以查看第二次调用context_BeginRequest时表单值未正确传递的原因(另外为什么第二个电话甚至是第一个电话。)

注意:这必须是内部ASP.NET的东西(可能是从“/”到“/Default.aspx”的Server.Transfer或类似的东西)因为Fiddler2只显示来自浏览器的一个请求“http: //mysamplesite.dev /".