Обратная передача ASP.NET из неправильного выпадающего списка после использования кнопки «Назад» в браузере - PullRequest
5 голосов
/ 04 февраля 2012

У меня есть веб-приложение ASP.NET 2.0, которое частично перемещается с помощью элементов управления DropDownList. Когда один из них изменяется, он вызывает обратную передачу, которая затем перенаправляется на другой URL в зависимости от того, что было выбрано в раскрывающемся списке.

Я заметил странное поведение при использовании кнопки «Назад» браузера после использования выпадающих меню. Процедура такая:

  1. Сделайте выбор в одном из выпадающих меню, вызывая обратную передачу и перенаправление. Пока все хорошо.
  2. Нажмите кнопку «Назад» браузера.
  3. В другом раскрывающемся списке ниже того, который использовался до (они все содержатся в одном div), сделайте выбор. Страница перенаправляется на тот же URL-адрес, что и в первый раз, а не на тот, на который она должна перенаправляться, исходя из этого другого раскрывающегося списка.

Я пробовал это и в Firefox 10, и в IE9 и видел одно и то же. Я посмотрел на вкладку Net в Firebug и увидел, что в POST для шага 3 указан правильный элемент управления. Но когда я отлаживаю его, запускается обработчик событий для неправильного раскрывающегося списка (использованного на шаге 1).

Код довольно прост и понятен. Пример разметки:

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

Выпадающие списки на самом деле не являются <asp:DropDownList ... /> элементами; Я вставляю optgroup элементы с подходом, аналогичным this .

Пример C #:

ddlTest.Click += new EventHandler(ddlTest_SelectedIndexChanged);

А в ddlTest_SelectedIndexChanged:

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

Что здесь происходит?

ОБНОВЛЕНИЕ 2/6/2012 : Я исправил это, проверив содержимое Request["__EVENTTARGET"] в моих SelectedIndexChanged обработчиках событий. Мне все еще интересно, почему это происходит. Почему первое событие повторяется? И почему это происходит только тогда, когда второй постбэк происходит из элемента управления ниже первого?

Ответы [ 4 ]

3 голосов
/ 20 ноября 2012

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 голосов
/ 04 февраля 2012

После нажатия кнопки «Назад» отображается последняя посещенная страница, так как она сохраняется на клиенте и больше не отправляется обратно / не запрашивается на сервере, включая последнее опубликованное значение, такое как показанное после выбораВторой DropDownlist сразу после нажатия кнопки «Назад».

Метод загрузки в IE (для других браузеров см .: 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 голосов
/ 04 февраля 2012

вы можете использовать свойства Response.Cache для решения этой проблемы, поскольку вы разрешаете кэшировать список в памяти браузера. из MSDN SetAllowResponseInBrowserHistory

Когда для HttpCacheability установлено значение NoCache или ServerAndNoCache, HTTP-заголовок Expires по умолчанию имеет значение -1; это говорит клиенту не кэшировать ответы в папке «История», чтобы при использовании кнопки назад / вперед клиент запрашивает новую версию ответа каждый раз. Вы можете изменить это поведение, вызвав Метод SetAllowResponseInBrowserHistory с установленным параметром allow к истине.

в методе загрузки страницы вы добавляете эту строку.

 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 каждый раз запрашивалась новая версия ответа.

0 голосов
/ 20 мая 2013

У меня сработал небольшой вариант ответа от @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);

    ....
}
...