Post-Redirect- Получить с ASP.NET

Как я могу реализовать шаблон Post-Redirect-Get с ASP.NET?

Нажатие кнопки выполняет некоторую обработку:

<asp:Button id="bbLaunch" OnCommand="bbLaunch_Click" />

Пользователь нажимает кнопку, космический корабль запускается, веб-страница снова отображается. Если пользователь нажимает F5, он получает предупреждение:

Решением проблемы является шаблон Post-Redirect-Get.

Каким способом PRG может быть реализован в ASP.NET?


Вопрос сосредоточен вокруг проблем:

  • как можно <asp:Button> выполнить POSTв место, которое не является его первоначальной формой?
  • что происходит сViewState, когда вы публикуете форму, которая не читает состояние просмотра?
  • что происходит с ViewState, когда вы перенаправляете на "настоящую" веб-форму aspx?
  • ViewState принципиально несовместим с ASP.net Post-Redirect-Get?
  • ASP.net принципиально несовместим с Post-Redirect - Get?
  • как (т.е. какой код) вы перенаправляете на "настоящую" веб-форму aspx?
  • как (т.е. какой URL) вы перенаправляете на "настоящую" веб-форму aspx? Вопрос об отношениях упоминает Response.Redirect(Request.RawUrl);
  • когда (т.е. в каком обработчике событий) вы перенаправляете на "настоящую" веб-форму aspx?
  • связанные вопросы поднимают вопросы о том, как вы публикуете данные формы. Подразумевается, что формы HTML нельзя использовать - и все данные формы должны быть добавлены в строку запроса. Это правда? Если так, то почему? Если нет, то почему нет? Может ли браузер поместить данные формы в строку запроса?
  • связанный вопрос упоминает Server.Transfer, С помощью Server.Transfer совершенно неверно и никоим образом не решает проблему Post-Redirect-Get (потому что Redirect не существует). Правильный?
  • какое изменение кода должно произойти в aspx или же aspx.cs файл для поддержки PRG? Предположительно, по крайней мере, код должен быть изменен на post где-то кроме MyPage.aspx,

Другими словами: как вы делаете Post-Redirect-Get в ASP.net?

Примечание: ASP.net (т.е. не ASP.net MVC)

Смотрите также

6 ответов

Решение

Обычно это можно сделать, создав веб-форму aspx, которая использует строку запроса, чтобы указать, какую запись следует загрузить / обработать.

Допустим, у вас есть страница, на которой вы можете обновить информацию о клиентах:

http://www.mysite.com/customer.aspx

Вы бы загрузили форму, используя идентификатор в строке запроса:

http://www.mysite.com/customer.aspx?CustomerId=42

В коде у вас будет что-то вроде этого:

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        int customerId = 0;
        if (!string.IsNullOrEmpty(Request.QueryString["CustomerId"]))
        {
            int.TryParse(Request.QueryString["CustomerId"], out customerId );
        }
        if (customerId == 0) 
        {
            //handle case when no valid customer id was passed in the qs here
        }
        else 
        {
            //load customer details, bind controls etc
            //make sure to handle the case when no customer was found using the id in the qs
        }
    }
}

Тогда где-нибудь на вашей странице у вас будет кнопка, которая сохраняет изменения. Эта кнопка будет иметь обработчик OnClick в коде:

protected void SaveClicked(object sender, EventArgs e)
{
    //save changes to database here

    //Redirect if all went well
    Response.Redirect("http://www.mysite.com/customer.aspx?CustomerId=" 
        + idOfSavedCustomer.ToString());
}

Это должно быть в принципе. Перенаправление приведет к тому, что браузер выдаст новый запрос GET для URL в Redirect(...). Это загрузит страницу, if (!IsPostBack) запустит и инициализирует страницу новыми значениями, которые вы только что сохранили в предыдущем посте назад.

Для всего этого процесса трафик между браузером и сервером будет выглядеть примерно так:

Browser: GET http://www.mysite.com/customer.aspx?CustomerId=42
Server: 200 (send back some html)

Browser: POST http://www.mysite.com/customer.aspx?CustomerId=42 (post data sent in request)
Server: 302 (point to http://www.mysite.com/customer.aspx?CustomerId=42)

Browser: GET http://www.mysite.com/customer.aspx?CustomerId=42
Server: 200 (send html)

На среднем этапе сервер в основном говорит:

"Запрос на отправку, который вы мне отправили, я с этим закончил. Теперь, пожалуйста, перейдите на другую страницу здесь..."

Факт, что URL фактически ссылается на одну и ту же страницу, не важен.


Некоторые размышления в ответ на ваш список вопросов:

  • Как выполнить POST в месте, которое не является его первоначальной формой?

Вы можете сделать это, установив action атрибут в форме, или вы можете установить PostBackUrl на кнопке.

  • что происходит с ViewState, когда вы публикуете форму, которая не читает состояние просмотра?

Зависит. Если вы просто публикуете форму на другой странице, вы можете использовать директиву <% @ PreviousPageType... />, чтобы сообщить "новой" странице, откуда пришло сообщение. Это просто поможет работать с опубликованными данными на новой странице. Смотрите эту ссылку для деталей.

  • что происходит с ViewState, когда вы перенаправляете на "настоящую" веб-форму aspx?

Просмотр состояния отправляется в сообщении с запросом. При перенаправлении браузер загрузит новую страницу и создаст свое собственное состояние.

  • ViewState принципиально несовместим с ASP.net Post-Redirect-Get?

Зависит от того, как ты смотришь на это. После перенаправления новая страница не будет иметь доступа к состоянию просмотра страницы ранее.

  • ASP.net принципиально несовместим с Post-Redirect - Get?

Нет. Смотрите пример выше.

  • как (т.е. какой код) вы перенаправляете на "настоящую" веб-форму aspx?

Response.Redirect (URL). Это отправит ответ в браузер с указанием сделать новый запрос на получение.

  • когда (т.е. в каком обработчике событий) вы перенаправляете на "настоящую" веб-форму aspx?

Когда вы выполнили всю работу, необходимую для обработки почтового запроса.

  • связанные вопросы поднимают вопросы о том, как вы публикуете данные формы. Подразумевается, что формы HTML нельзя использовать - и все данные формы должны быть добавлены в строку запроса. Это правда? Если так, то почему? Если нет, то почему нет? Может ли браузер поместить данные формы в строку запроса?

Перенаправление почтового запроса не очень хорошо поддерживается, и его, вероятно, следует избегать. Это можно сделать (с помощью некоторого браузера), используя http-ответ 307. При этом сервер фактически сообщает браузеру, что "я не буду обрабатывать ваш запрос на публикацию, вместо этого отправьте его на эту другую страницу".

  • в связанном вопросе упоминается Server.Transfer. Использование Server.Transfer совершенно неверно и никоим образом не решает проблему Post-Redirect-Get (потому что Redirect не существует). Правильный?

Server.Transfer (...) - это то, что происходит на стороне сервера. Браузер не знает об этом. По сути, страница может использовать Server.Transfer, чтобы какая-то другая страница выполняла некоторую обработку, и эта страница будет отвечать за отправку ответа обратно в браузер. Но браузер будет думать, что это была оригинальная страница, на которую ответили.

  • какое изменение кода должно произойти в файле aspx или aspx.cs для поддержки PRG? Предположительно, по крайней мере, код должен быть изменен, чтобы публиковать где-то помимо MyPage.aspx.

Нет, обычный пост обратно можно использовать. Хитрость заключается в том, чтобы иметь на странице один (или несколько) определенных обработчиков событий, которые выполняют Repsonse.Redirect после обработки опубликованных данных.

Q) как выполнить POST в месте, которое не является его первоначальной формой?

A) С PRG вы не размещаете POST на другой странице, вы отправляете обратно на ту же страницу (см. Диаграмму на странице википедии, на которую вы ссылаетесь.) Но ответ с этой страницы ДОЛЖЕН БЫТЬ ответом 30X (обычно 302)..)

Q) что происходит с ViewState, когда вы публикуете форму, которая не читает состояние просмотра?

A) Состояние просмотра существует, когда вы выполняете POST, но там не будет состояния просмотра для новой страницы, на которой вы выполняете GET.

Q) что происходит с ViewState, когда вы перенаправляете на "настоящую" веб-форму aspx?

A) Как указано выше, больше нет состояния просмотра, перенаправляющего на страницу.

Q) является ли ViewState несовместимым с ASP.net?

A) ViewState не является несовместимым с ASP.NET. Это (в основном) бесполезно для P/R/G для рендеринга страницы, на которую вы перенаправлены.

Q) ASP.net принципиально несовместим с Post-Redirect-Get?

A) Нет - но вы не можете чрезмерно полагаться на использование одной страницы и поддержание всего состояния в viewstate, как указано выше. Тем не менее, ASP.MVC намного лучше отображает P/R/G

Q) как (т.е. какой код) вы перенаправляете на "настоящую" веб-форму aspx?

A) Response.Redirect ("new_page_you_are_redirecting_to.aspx") в методе bbLaunch_Click для old_page_you_are_posting_from.aspx

Q) как (т.е. какой URL) вы перенаправляете на "настоящую" веб-форму aspx? В вопросе об отношении упоминается Response.Redirect(Request.RawUrl);

А) см. Выше

Q) когда (то есть, в каком обработчике событий) вы перенаправляете на "настоящую" веб-форму aspx?

A) После того, как вы обработали нажатие кнопки, сохранили данные в БД (или в сеансе и т. Д.), И до того, как что-то еще записали в поток ответа.

Q) связанные вопросы поднимают вопросы о том, как вы публикуете данные формы. Подразумевается, что формы HTML нельзя использовать - и все данные формы должны быть добавлены в строку запроса. Это правда?

A) Нет - нажатие кнопки в ASP.NET WebForms вернет страницу обратно на страницу.

Q) Если так, то почему? Если нет, то почему нет?

А) Это проще, чем это, поэтому нет. Отображение двух страниц: first_page.asp и second_page.aspx. На First_page.aspx есть кнопка (наряду с другими веб-элементами управления ASP.NET, такими как текстовые поля и т. Д., Которые заполнил пользователь.) Когда они нажимают кнопку, выполняется POST для first_page.aspx. После обработки данных (которые, вероятно, находятся внутри viewstate, хотя это абстрагировано), вы перенаправляете пользователя на second_page.aspx, используя Response.redirect. Second_page.aspx может отображать то, что вы хотите. Если вы хотите (или должны) отображать пользовательский интерфейс, который похож на то, что было на first_page.aspx, включая элементы управления и то, что они вводили, вы должны сохранить его в сеансе, файл cookie, URL-адрес в качестве параметров строки запроса, чтобы установить эти элементы управления на second_page.aspx. (Но вам может не потребоваться отображать что-либо на second_page.aspx, похожее на first_page.aspx - поэтому здесь нет общего правила.)

В) Может ли браузер поместить данные формы в строку запроса?

А) Да, если вы установите метод GET вместо POST. Вы не можете переопределить WebForms, чтобы сделать это, и это не требуется для PRG

Q) в связанном вопросе упоминается Server.Transfer. Использование Server.Transfer совершенно неверно и никоим образом не решает проблему Post-Redirect-Get (потому что Redirect не существует). Правильный?

А) по сути

Q) какое изменение кода должно произойти в файле aspx или aspx.cs для поддержки PRG? Предположительно, по крайней мере, код должен быть изменен, чтобы публиковать где-то помимо MyPage.aspx.

A) Код должен все еще отправлять обратно (как упомянуто выше.) Но тогда Mypage.aspx должен перенаправить на новую страницу в обработчике кнопки.

Именно шаги Get Postirect Redirect:

У вас есть форма, которую вы заполняете данными, и после вашей действительной отправки (POST) вы вставляете их в свою базу данных и даете им идентификатор подтверждения, а затем перенаправляете пользователя на страницу с этим идентификатором подтверждения в качестве параметра URL, который используется. как (GET) После перенаправления каждое F5-обновление только читает данные и не вставляет их снова.

Код для вставки отличается от кода, который показывает подтверждение, вы можете даже сделать их разными страницами - вы можете сделать одну и ту же страницу с текстовыми полями только для чтения.

Перенаправление просто Responce.Redirect функция asp.net

После POST и создания перенаправления единственная мысль, которая связывает вас с предыдущим действием, - это код подтверждения (не состояние просмотра)

Минус этого метода в том, что на самом деле он не распознает обновление, просто делает дополнительный шаг, чтобы обновление не вставляло те же данные, но требует дополнительного кода для получения данных.

Альтернатива - распознать обновление и не выполнять перенаправление. Распознав обновление по обратной записи, вы можете избежать вставки одних и тех же данных пользователю в одно сообщение. В Интернете есть несколько примеров для этого, и я с успехом внедрил один.

Один пример: http://www.codeproject.com/Tips/319955/How-to-prevent-Re-Post-action-caused-by-pressing-b

Шаблон Post-Redirect-Get можно использовать в веб-формах. Я показал, как это можно сделать, преобразовав приложение MVC NerdDinner в веб-формы, http://navigationnerddinner.codeplex.com/. Я сохранил детали навигации точно так же, поэтому есть много примеров паттерна PRG.

Однако есть еще один способ избежать проблемы F5/Refresh. Если вы оберните свою страницу в UpdatePanel (часть ASP.NET Ajax), тогда все обратные ссылки будут преобразованы в частичные запросы страниц. Это означает, что при нажатии клавиши F5 он будет обновлять только исходный запрос GET (поскольку не было никаких последующих POST), и поэтому вы не получите предупреждение. (Примечание. Если JavaScript отключен, предупреждение все равно будет отображаться).

Вы можете вызвать метод Response.Redirect, чтобы перейти в другое место.

Есть несколько вещей, которые входят в это.

  1. Установите атрибут действия формы на главной странице (назовем его LaunchForm.aspx) равным URL-адресу страницы "proxy" (ProxyLaunchForm.aspx).

  2. (необязательно) Добавьте скрытый ввод с именемredirectUrl в форму и укажите URL-адрес, который сообщает ProxyLaunchForm.aspx, куда перенаправлять после завершения запуска (часть R PRG).

  3. Теперь в ProxyLaunchForm.aspx реализация должна происходить внутри обработчика события Page_Load, потому что у него есть доступ к данным поста формы. Выполните запуск здесь.

  4. Затем (также в Page_Load) выполните перенаправление (либо используя redirectUrl из #2, либо просто используя URL-адрес ссылающейся страницы):

    Response.Redirect (Request.Params ["redirectUrl"]?? Request.UrlReferrer.AbsoluteUri);

    Там еще вопрос о состоянии просмотра. Я думаю, что самый простой способ справиться с этим - это изменить способ сохранения состояния представления. Обычно он сохраняется в скрытом элементе ввода на странице и извлекается при обратной передаче (что, конечно, означает, что он будет потерян после перенаправления из-за природы HTTP без сохранения состояния). Однако вы можете переопределить методы, которые использует ASP.net, и использовать вместо него сеанс (таким образом, он все равно будет присутствовать даже после действия прокси PRG). Итак, наконец...

  5. В LaunchForm.aspx.cs используйте в качестве базового класса подклассную страницу, которая переопределяет методы SavePageStateToPersistenceMedium и LoadPageStateFromPersistenceMedium для хранения / извлечения их из сеанса, а не из скрытого поля формы. Смотрите ниже (и здесь больше информации о том, как это работает.).

*

public class PersistViewStateToSession : Page
{
    protected override void SavePageStateToPersistenceMedium(object viewState)
    {
        // serialize the view state into a base-64 encoded string
        LosFormatter los = new LosFormatter();
        StringWriter writer = new StringWriter();
        los.Serialize(writer, viewState);
        // save the string to session
        Session["LaunchViewState"] = writer.ToString();
    }

    protected override object LoadPageStateFromPersistenceMedium()
    {
       if (!Session["LaunchViewState"] == null)
           return null;
       else
       {
          string sessionString = (string)Session["LaunchViewState"];
          // deserialize the string
          LosFormatter los = new LosFormatter();
          return los.Deserialize(viewStateString);
       }
    }
}
Другие вопросы по тегам