mvc method asp.net post-redirect-get redirect-after-post

asp.net - method - redirecttoaction post



Post-Redirect-Get con ASP.NET (6)

El patrón Post-Redirect-Get se puede usar en formularios web. He mostrado cómo se puede hacer esto al convertir la aplicación MVC NerdDinner a formularios web, http://navigationnerddinner.codeplex.com/ . Mantuve los detalles de navegación exactamente iguales, así que hay muchos ejemplos del patrón PRG.

Sin embargo, hay otra forma de evitar el problema F5 / Actualizar. Si ajusta su página en un UpdatePanel (parte de ASP.NET Ajax), todas las publicaciones posteriores se convertirán en solicitudes parciales de página. Esto significa que cuando se presiona F5, solo actualizará la solicitud GET original (ya que no ha habido POST posteriores), por lo que no recibirá la advertencia. (Nota: si JavaScript está desactivado, la advertencia seguirá apareciendo).

¿Cómo puedo implementar el patrón Post-Redirect-Get con ASP.NET?

Un clic de botón realiza algún procesamiento:

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

El usuario hace clic en el botón, se lanza la nave espacial, se vuelve a mostrar la página web. Si el usuario presiona F5, recibe la advertencia:

La solución al problema es el patrón Post-Redirect-Get .

¿Cuál es el método mediante el cual se puede implementar Post-Redirect-Get en ASP.NET?

La pregunta se centra en los problemas de:

  • ¿cómo puede el <asp:Button> realizar una POST a un lugar que no es su forma original?
  • ¿Qué sucede con ViewState cuando publica en un formulario que no lee estado de vista?
  • ¿Qué pasa con el ViewState cuando se redirige al formulario web aspx "real"?
  • ¿ ViewState es fundamentalmente incompatible con ASP.net Post-Redirect-Get?
  • es ASP.net fundamentalmente incompatible con Post-Redirect - Get ?
  • ¿cómo (es decir, qué código) redirecciona al formulario web aspx "real"?
  • ¿cómo (es decir, qué url) redirecciona al formulario web aspx "real"? Una pregunta de relación menciona Response.Redirect(Request.RawUrl);
  • ¿Cuándo (es decir, en qué controlador de eventos) redirige al formulario web aspx "real"?
  • las preguntas relacionadas plantean problemas de cómo publica datos de formularios. Existe la implicación de que los formularios HTML no se pueden usar, y todos los datos del formulario se deben agregar a la cadena de consulta. ¿Es esto cierto? Si es así, ¿por qué? ¿Si no, porque no? ¿Puede un navegador poner datos de formulario en una cadena de consulta?
  • una pregunta relacionada menciona Server.Transfer . El uso de Server.Transfer es completamente incorrecto, y de ninguna manera resuelve el problema de Post-Redirect-Get (porque no hay redirección ). ¿Correcto?
  • ¿Qué cambio de código tiene que suceder en el archivo aspx o aspx.cs para admitir PRG? Presumiblemente, como mínimo, el código se debe cambiar para post algún lugar además de MyPage.aspx .

En otras palabras: ¿Cómo se hace Post-Redirect-Get en ASP.net?

Nota : ASP.net (es decir, no ASP.net MVC)

Ver también


Hay un par de cosas que entran en esto.

  1. Establezca el atributo de acción del formulario en la página principal (llamémoslo LaunchForm.aspx ) igual a la URL de la página "proxy" ( ProxyLaunchForm.aspx ).

    <form id = "form1" runat = "server" action = "ProxyLaunchForm.aspx" method = "POST">

  2. (opcional) Agregue una entrada oculta con el nombre redirectUrl al formulario y valore la URL que le dice a ProxyLaunchForm.aspx dónde redirigir una vez que finaliza la ejecución (la parte R de PRG).

  3. Ahora en ProxyLaunchForm.aspx , la implementación debería tener lugar dentro del controlador de eventos Page_Load , porque eso tiene acceso a los datos de formulario de publicación. Ejecute el lanzamiento aquí.

  4. Posteriormente (también en Page_Load ), realice el redireccionamiento (ya sea utilizando el redirectUrl desde el n. ° 2, o simplemente utilizando la URL de la página de referencia):

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

    Todavía está la cuestión del estado de visualización. Creo que la forma más sencilla de lidiar con esto es cambiar la forma en que persiste el estado de la vista. Normalmente, se guarda en un elemento de entrada oculto en la página y se recupera en la devolución de datos (lo que por supuesto significa que se perderá después de la redirección debido a la naturaleza sin estado de HTTP). Sin embargo, puede anular los métodos que utiliza ASP.net, y hacer que use la Sesión en su lugar (de esa manera aún estará presente incluso después de la acción del proxy PRG). Así que finalmente...

  5. En LaunchForm.aspx.cs , use como clase base una Página subclase que anule los métodos SavePageStateToPersistenceMedium y LoadPageStateFromPersistenceMedium para almacenarlos / recuperarlos de la sesión, en lugar de hacerlo desde un campo de formulario oculto. Vea a continuación (y aquí hay más información sobre cómo funciona esto ).

*

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); } } }


Los pasos exactos del Get Redirect Get son:

http://www.planethost.gr/PostRedirectGet.jpg

Tiene el formulario que completa con datos, y después de su envío válido (POST) los inserta en su base de datos y les da un ID de confirmación, luego redirige al usuario a la página con este ID de confirmación como parámetro de URL que se utiliza como (GET) Después de la redirección, cada actualización de F5 solo lee los datos y no los inserta de nuevo.

El código para insertar es diferente al código que muestra la confirmación, incluso puede hacer que sean páginas diferentes; puede hacer la misma página con cuadros de texto de solo lectura.

La redirección es simple la función Responce.Redirect de asp.net

Después del POST y la realización del redireccionamiento, el único pensamiento que lo conecta con la acción anterior es el código de confirmación (no el estado de visualización)

Lo negativo de este método es que en realidad no se reconoce la actualización, solo se realiza un paso adicional que hace que la actualización no vuelva a insertar los mismos datos, pero necesita un código adicional para obtener datos.

La alternativa es reconocer la actualización y no redirigir. Al reconocer la actualización en la publicación posterior, puede evitar insertar los mismos datos con un solo mensaje para el usuario. Hay algunos ejemplos en Internet para eso, y he implementado uno con éxito.

Un ejemplo: http://www.codeproject.com/Tips/319955/How-to-prevent-Re-Post-action-caused-by-pressing-b


Normalmente, harías esto al hacer un formulario web aspx que utiliza la cadena de consulta para indicar qué registro cargar / procesar.

Supongamos que tiene una página que le permite actualizar cierta información del cliente:

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

Debería cargar el formulario usando una identificación en la cadena de consulta:

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

En el código subyacente, tendría algo como esto:

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 } } }

Luego, en algún lugar de tu página, tendrías un botón que guarda los cambios. Ese botón tendría un controlador OnClick en el código detrás:

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()); }

Eso debería ser básicamente eso. La redirección hará que el navegador emita una nueva solicitud GET para la url en el redireccionamiento (...). if (!IsPostBack) la página, se ejecutará if (!IsPostBack) e inicializará la página con los nuevos valores que acaba de guardar en la publicación anterior.

Para todo este proceso, el tráfico entre el navegador y el servidor se vería así:

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)

En el paso intermedio, el servidor básicamente dice:

"Esa solicitud postal que me enviaste, he terminado con eso. Ahora por favor ve a esta otra página aquí ..."

El hecho de que la URL de hecho se refiere a la misma página no es importante.

Algunas reflexiones en respuesta a su lista de preguntas:

  • ¿Cómo se puede realizar una POST a un lugar que no es su forma original?

Puede hacer esto configurando el atributo de action en el formulario, o puede establecer PostBackUrl en el botón.

  • ¿Qué sucede con ViewState cuando publica en un formulario que no lee estado de vista?

Depende Si simplemente publica el formulario en una página diferente, puede usar la directiva <% @ PreviousPageType ... /> para indicarle a la página "nueva" de dónde provino la publicación. Esto simplemente funcionará con los datos publicados en la nueva página. Vea este enlace para más detalles .

  • ¿Qué pasa con el ViewState cuando se redirige al formulario web aspx "real"?

El estado de vista se envía en la solicitud posterior. Al redireccionar, el navegador cargará una nueva página y creará su propio estado.

  • ¿ViewState es fundamentalmente incompatible con ASP.net Post-Redirect-Get?

Depende de cómo lo mires. Después de la redirección, la nueva página no tendrá acceso al estado de visualización de la página anterior.

  • es ASP.net fundamentalmente incompatible con Post-Redirect - Get?

No. Ver ejemplo arriba.

  • ¿cómo (es decir, qué código) redirecciona al formulario web aspx "real"?

Response.Redirect (url). Esto enviará una respuesta al navegador, diciéndole que haga una nueva solicitud de obtención.

  • ¿Cuándo (es decir, en qué controlador de eventos) redirige al formulario web aspx "real"?

Cuando haya realizado todo el trabajo necesario para procesar la solicitud posterior.

  • las preguntas relacionadas plantean problemas de cómo publica datos de formularios. Existe la implicación de que los formularios HTML no se pueden usar, y todos los datos del formulario se deben agregar a la cadena de consulta. ¿Es esto cierto? Si es así, ¿por qué? ¿Si no, porque no? ¿Puede un navegador poner datos de formulario en una cadena de consulta?

Redirigir una solicitud de publicación no está bien soportado y probablemente deba evitarse. Se puede hacer (con un navegador) utilizando la respuesta http 307. Al hacerlo, el servidor le dice al navegador efectivamente que " No procesaré su solicitud posterior, por favor publíquela en esta otra página ".

  • una pregunta relacionada menciona Server.Transfer. El uso de Server.Transfer es completamente incorrecto, y de ninguna manera resuelve el problema de Post-Redirect-Get (porque no hay redirección). ¿Correcto?

Server.Transfer (...) es algo que está sucediendo en el lado del servidor. El navegador no lo sabe. Básicamente, una página puede usar Server.Transfer para hacer que otra página realice algún procesamiento, y esa página será responsable de enviar una respuesta al navegador. Pero el navegador pensará que fue la página original la que respondió.

  • ¿Qué cambio de código tiene que suceder en el archivo aspx o aspx.cs para admitir PRG? Presumiblemente, como mínimo, el código se debe cambiar para publicar en algún lugar además de MyPage.aspx.

No, se puede usar una publicación posterior normal. El truco es tener uno (o algunos) manejadores de eventos específicos en la página que hace un Repsonse.Redirect después de procesar los datos publicados.


P) ¿Cómo se puede realizar una POST a un lugar que no es su forma original?

A) Con PRG, no POSTAS a una página diferente, publicas de nuevo en la misma página (mira el diagrama en la página de wikipedia a la que vinculaste). Pero la respuesta de esa página DEBE SER una respuesta 30X (típicamente un 302 .)

P) ¿Qué sucede con ViewState cuando publica en un formulario que no lee estado de vista?

A) El estado de la vista está allí cuando PUBLICAS, pero allí el estado de la vista no estará allí para la nueva página en la que estás haciendo un GET.

P) ¿Qué sucede con ViewState cuando se redirige al formulario web aspx "real"?

A) Por encima, no hay más estado de vista redirigido a la página.

Q) es ViewState fundamentalmente incompatible con ASP.net?

A) ViewState no es incompatible con ASP.NET. Es (en su mayoría) inútil para P / R / G para representar la página a la que se le redirige.

Q) es ASP.net fundamentalmente incompatible con Post-Redirect - Get?

A) No, pero no se puede confiar demasiado en el uso de una página y mantener todo su estado en viewstate, como se indicó anteriormente. Dicho esto, ASP.MVC es un mapa mucho mejor para P / R / G

P) ¿cómo (es decir, qué código) redirecciona al formulario web aspx "real"?

A) Response.Redirect ("new_page_you_are_redirecting_to.aspx") en el método bbLaunch_Click de old_page_you_are_posting_from.aspx

P) ¿cómo (es decir, qué url) redirecciona al formulario web aspx "real"? Una pregunta de relación menciona Response.Redirect (Request.RawUrl);

A) Ver arriba

Q) cuando (es decir, en qué controlador de eventos) redirige al formulario web aspx "real"?

A) Después de procesar el botón, presione, guardó los datos en DB (o sesión, etc.) y antes de haber escrito algo más en la secuencia de respuesta.

P) las preguntas relacionadas plantean problemas sobre la forma en que publica los datos del formulario. Existe la implicación de que los formularios HTML no se pueden usar, y todos los datos del formulario se deben agregar a la cadena de consulta. ¿Es esto cierto?

A) No: la pulsación de un botón en ASP.NET WebForms volverá a la página POST.

P) Si es así, ¿por qué? ¿Si no, porque no?

A) Es más simple que esto, ¿por qué no? Imágenes de dos páginas: first_page.asp y second_page.aspx. First_page.aspx tiene el botón (junto con otros controles web de ASP.NET, como cuadros de texto, etc. que el usuario ha rellenado). Cuando presionan el botón, se realiza una POST en first_page.aspx. Después de procesar los datos (lo cual es probable dentro de viewstate, aunque esto se abstraiga), se redirige al usuario a second_page.aspx usando Response.redirect. Second_page.aspx puede mostrar lo que quieras. Si desea (o necesita) mostrar UI que sea similar a lo que estaba en first_page.aspx, incluidos los controles y lo que ingresaron, le conviene almacenar eso en la sesión, una cookie, la URL como parámetros querystring, para configurar esos controles en second_page.aspx. (Pero puede que no necesite mostrar nada en second_page.aspx que sea similar a first_page.aspx, por lo que no hay una regla general aquí).

P) ¿Puede un navegador poner datos de formulario en una cadena de consulta?

A) Sí, si configuras el método en GET en lugar de POST. No puede anular WebForms para hacer esto, y esto no es necesario para PRG

Q) una pregunta relacionada menciona Server.Transfer. El uso de Server.Transfer es completamente incorrecto, y de ninguna manera resuelve el problema de Post-Redirect-Get (porque no hay redirección). ¿Correcto?

A) Esencialmente

P) ¿Qué cambio de código debe ocurrir en el archivo aspx o aspx.cs para admitir PRG? Presumiblemente, como mínimo, el código se debe cambiar para publicar en algún lugar además de MyPage.aspx.

A) El código aún se debe publicar de nuevo (como se mencionó anteriormente). Pero luego Mypage.aspx debería redireccionarse a una nueva página en el controlador de botones.