【问题标题】:ASP.NET postback from wrong dropdownlist after using browser Back button使用浏览器后退按钮后从错误下拉列表中的 ASP.NET 回发
【发布时间】:2012-02-03 22:42:52
【问题描述】:

我有一个使用DropDownList 控件进行部分导航的 ASP.NET 2.0 Web 应用程序。当其中一个发生更改时,它会导致回发,然后根据下拉列表中选择的内容将其重定向到另一个 URL。

我注意到在使用下拉菜单后使用浏览器的后退按钮时出现了奇怪的行为。程序是这样的:

  1. 在其中一个下拉列表中进行选择,导致回发和重定向。到目前为止很好。
  2. 点击浏览器的返回按钮。
  3. 在另一个导航下拉列表中在之前使用的下拉列表下方(它们都包含在一个div 中),进行选择。页面重定向到与第一次相同的 URL,而不是根据其他下拉列表重定向到的位置。

我在 Firefox 10 和 IE9 中都尝试过,并且看到了同样的结果。我查看了 Firebug 中的 Net 选项卡,发现在第 3 步的 POST 中,引用了正确的控件。但是当我调试它时,错误下拉列表(第 1 步中使用的下拉列表)的事件处理程序会触发。

代码非常简单明了。标记示例:

<asp:DropDownList runat="server" ID="ddlTest" AutoPostBack="true" />

下拉菜单实际上不是普通的&lt;asp:DropDownList ... /&gt; 元素;我使用类似于this 的方法插入optgroup 元素。

C# 示例:

ddlTest.Click += new EventHandler(ddlTest_SelectedIndexChanged);

ddlTest_SelectedIndexChanged:

if (ddlTest.SelectedValue != "")
{
   Response.Redirect(MyUtilClass.GetUrl(ddlTest.SelectedValue));
}

这是怎么回事?

2012 年 2 月 6 日更新:我已通过在我的 SelectedIndexChanged 事件处理程序中检查 Request["__EVENTTARGET"] 的内容来解决此问题。不过,我仍然很好奇为什么会这样。为什么第一个事件会重复?为什么只有当第二个回发发生在第一个下方的控件时才会发生这种情况?

【问题讨论】:

  • 您可以为下拉菜单添加页面中的标签吗?会有所帮助。
  • 下拉菜单的标签?你是指他们在页面上的ID吗?还是他们的标记?它看起来很像我在问题中发布的标记。
  • 只是一个建议:即使不使用后退按钮,您的导航也不会表现出我所谓的预期行为。通常,导航应该与您的内容同步。这样,当您单击学校名称时,就会在您的下拉列表中选择该学校。其实,越看越觉得off。好像您可以摆脱整个左侧导航(将房地产收回)并在顶部提供两个下拉菜单:学校和运动。无论如何,其他人完全依赖于该信息......它的价值为 0.02 美元。
  • @ChrisLively - 日历除外。在这种情况下,您不能保持下拉菜单与内容同步,因为日历可以显示今天、昨天、明天、本周、下周或上周以外的内容。不过,这是个好建议;我会进一步调查。

标签: c# asp.net postback


【解决方案1】:

单击后退按钮后,将显示上次访问的页面,因为它保存在客户端上,不会再次向/从服务器发送/请求,这包括上次发布的值,如您选择后显示的一次点击后退按钮后的第二个 DropDownlist。

当您按下第二个页面的后退按钮时,第一页的 IE 上的 onload 方法(对于其他浏览器,请参见:http://dean.edwards.name/weblog/2005/09/busted/)被触发,因此使用我们可以尝试在重定向页面之前将回发操作保存在客户端,我们使用 JS 将其保存在隐藏值上,然后一旦用户返回,onload 方法会评估隐藏的值是否存在,如果是,则更改页面的位置到自身,因此再次请求页面并清除所有发布的值:

page1.aspx

 <script type="text/javascript">
        function redir(){    
            var h=document.getElementById('hdR');
            if (h.value=='1'){
                h.value='0';
                document.location.href='page1.aspx';
            }         
        }

        function changeHids(){
            var h=document.getElementById('hdR');
            h.value='1';
        }
        </script>
    </head>
    <body onload="redir();">
        <form id="form1" runat="server">
        <div>
            <asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="true" onchange="changeHids();">
                <asp:ListItem>1</asp:ListItem>
                <asp:ListItem>2</asp:ListItem>
                <asp:ListItem>3</asp:ListItem>
                <asp:ListItem>4</asp:ListItem>
            </asp:DropDownList>
            <br />
            <asp:DropDownList ID="DropDownList2" runat="server" AutoPostBack="true" onchange="changeHids();">
                <asp:ListItem>5</asp:ListItem>
                <asp:ListItem>6</asp:ListItem>
                <asp:ListItem>7</asp:ListItem>
                <asp:ListItem>8</asp:ListItem>
            </asp:DropDownList>
            <asp:HiddenField ID="hdR" runat="server"/>
        </div>
        </form>
    </body>

Protected Sub DropDownList1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DropDownList1.SelectedIndexChanged

    Response.Redirect("page2.aspx?ddl=1&val=" & Me.DropDownList1.SelectedValue, True)

End Sub

Protected Sub DropDownList2_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DropDownList2.SelectedIndexChanged

    Response.Redirect("page2.aspx?ddl=2&val=" & Me.DropDownList2.SelectedValue, True)

End Sub

page2.aspx

  Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        Response.Write("ddl:" & Request.QueryString("ddl") & " " & "value:" & Request.QueryString("val"))

    End Sub

【讨论】:

    【解决方案2】:

    Firefox - 在后面添加代码:

    protected void Page_Load(object sender, EventArgs e)
    { 
        Response.AppendHeader("Cache-Control", "no-store");
    }
    

    Chrome - 添加 javascript 页面加载:

    var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
    if (is_chrome) {
        document.getElementById("form1").reset();
    }
    

    【讨论】:

      【解决方案3】:

      您可以使用 Response.Cache 属性来解决此问题,因为您允许将列表缓存在浏览器内存中。来自 MSDN SetAllowResponseInBrowserHistory

      当 HttpCacheability 设置为 NoCache 或 ServerAndNoCache 时 Expires HTTP 标头默认设置为 -1;这告诉客户不 在 History 文件夹中缓存响应,这样当您使用 后退/前进按钮 客户端请求新版本的响应 每一次。您可以通过调用 设置了允许参数的 SetAllowResponseInBrowserHistory 方法 为真。

      在您的页面加载方法中,添加此行。

       protected void Page_Load(object sender, EventArgs e)
        {
             Response.Cache.SetCacheability(HttpCacheability.NoCache); 
             Response.Cache.SetAllowResponseInBrowserHistory(false);
      
              // or else you can do like this 
      
             Response.ExpiresAbsolute = DateTime.Now.AddDays(-1d);
              Response.Expires = -1;
              Response.CacheControl = "No-cache";
        }
      

      这样,每当您按下返回时,t 每次都会请求新版本的响应。

      【讨论】:

      • 这看起来不错。我已更新问题以澄清我正在寻找的信息。
      • 我尝试将前两行添加到我的 Page_Load 中,但问题仍然存在。
      【解决方案4】:

      @Ravi 的答案略有不同对我有用...

      protected override void OnInit(EventArgs e)
      {
          base.OnInit(e);
      
          Context.Response.AddHeader("Cache-Control", "max-age=0,no-cache,no-store");
          Context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
          Context.Response.Cache.SetMaxAge(TimeSpan.Zero);
      
          ....
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-17
        • 1970-01-01
        • 2016-08-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-15
        • 2012-04-04
        相关资源
        最近更新 更多