ASP.NETで Post-Redirect-Get パターンを実装するにはどうすればよいですか?
ボタンをクリックすると、いくつかの処理が実行されます。
_<asp:Button id="bbLaunch" OnCommand="bbLaunch_Click" />
_
ユーザーがボタンをクリックすると、宇宙船が打ち上げられ、Webページが再表示されます。ユーザーがF5キーを押すと、警告が表示されます。
この問題の解決策は Post-Redirect-Get パターンです。
[〜#〜] prg [〜#〜] をASP.NETに実装する方法は何ですか?
問題の中心は次のとおりです。
<asp:Button>
_は、元の形式ではない場所に対してPOST
をどのように実行できますか?Response.Redirect(Request.RawUrl);
について言及していますServer.Transfer
_について言及しています。 _Server.Transfer
_の使用は完全に間違っており、Post-Redirect-Getの問題を解決する方法はありません(Redirectがないため)。正しい?aspx
または_aspx.cs
_ファイルでどのコード変更を行う必要がありますか?おそらく、少なくとも、コードは_MyPage.aspx
_以外のどこかでpost
に変更する必要があります。つまり、ASP.netでPost-Redirect-Getをどのように実行しますか?
注:ASP.net(つまり、ASP.net MVCではありません)
通常、これは、クエリ文字列を使用してどのレコードをロード/処理するかを通知するaspx Webフォームを作成することによって行います。
顧客情報を更新できるページがあるとします。
_http://www.mysite.com/customer.aspx
_
クエリ文字列でIDを使用してフォームをロードします。
_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());
}
_
それは基本的にそれであるはずです。リダイレクトにより、ブラウザはRedirect(...)のURLに対して新しいGETリクエストを発行します。ページが読み込まれ、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が実際に同じページを参照しているという事実は重要ではありません。
質問の箇条書きリストに対応するいくつかの考察:
これを行うには、フォームにaction
属性を設定するか、ボタンにPostBackUrl
を設定します。
依存します。フォームを別のページに投稿するだけの場合は、<%@ PreviousPageType ... />ディレクティブを使用して、投稿の送信元を「新しい」ページに通知できます。これにより、新しいページに投稿されたデータを操作することが簡単になります。 詳細はこのリンク を参照してください。
表示状態は投稿リクエストで送信されます。リダイレクトすると、ブラウザは新しいページをロードし、独自のビューステートを作成します。
見方次第です。リダイレクト後、新しいページは以前のページのビューステートにアクセスできなくなります。
いいえ。上の例を参照してください。
Response.Redirect(url)。これにより、ブラウザーに応答が送信され、新しいget要求を実行するよう指示されます。
投稿リクエストの処理に必要なすべての作業を実行したとき。
投稿リクエストのリダイレクトは十分にサポートされておらず、おそらく回避する必要があります。これは、http応答307を使用して(一部のブラウザーで)行うことができます。その際、サーバーはブラウザーに「私は要求を処理しません。これに投稿してください。代わりに他のページ」。
Server.Transfer(...)はサーバー側で実行されているものです。ブラウザはそれを認識していません。基本的に、ページはServer.Transferを使用して他のページに処理を実行させることができ、そのページはブラウザに応答を送信する必要があります。しかし、ブラウザはそれが応答された元のページだったと考えます。
いいえ、通常のポストバックを使用できます。秘訣は、投稿されたデータを処理した後にRepsonse.Redirectを実行する1つ(またはいくつか)の特定のイベントハンドラーをページに配置することです。
Q)元の形式ではない場所にPOSTを実行するにはどうすればよいですか?
A)PRGでは、POSTを別のページに送信するのではなく、同じページにポストバックします(リンク先のWikipediaページの図を参照してください。)しかし、そのページからの応答30X応答である必要があります(通常は302)。
Q)ビューステートを読み取らないフォームに投稿すると、ViewStateはどうなりますか?
A)POSTするとビューステートが表示されますが、GETを実行している新しいページのビューステートは表示されません。
Q) "実際の" aspx Webフォームにリダイレクトすると、ViewStateはどうなりますか?
A)上記のとおり、ページにリダイレクトされるビューステートはありません。
Q)ViewStateは基本的にASP.netと互換性がありませんか?
A)ViewStateはASP.NETと互換性がありません。リダイレクト先のページをレンダリングするためのP/R/Gには(ほとんど)役に立たない。
Q)ASP.netはPost-Redirect--Getと基本的に互換性がありませんか?
A)いいえ。ただし、上記のように、1つのページを使用してすべての状態をビューステートに維持することに過度に依存することはできません。とはいえ、ASP.MVCはP/R/Gにはるかによく対応しています
Q)「実際の」aspx Webフォームにどのように(つまりどのコードを)リダイレクトしますか?
A)old_page_you_are_posting_from.aspxのbbLaunch_ClickメソッドのResponse.Redirect( "new_page_you_are_redirecting_to.aspx")
Q)「実際の」aspx Webフォームにどのように(つまり、どのURLに)リダイレクトしますか?関係の質問はResponse.Redirect(Request.RawUrl);について言及しています。
A)上記を参照
Q)いつ(つまり、どのイベントハンドラーで) "実際の" aspx Webフォームにリダイレクトしますか?
A)ボタンを押して処理した後、データをDB(またはセッションなど)に保存し、それ以外に応答ストリームに何かを書き込む前。
Q)関連する質問により、フォームデータの投稿方法に関する問題が発生します。 HTMLフォームを使用できないという意味があり、すべてのフォームデータをクエリ文字列に追加する必要があります。これは本当ですか?
A)いいえ-ASP.NET Webフォームでボタンを押すと、ページに戻りますPOST.
Q)その場合、なぜですか?そうでない場合、なぜでしょうか?
A)これよりも簡単です。それが理由です。 2つのページのイメージング:first_page.aspおよびsecond_page.aspx。 First_page.aspxにはボタンがあります(ユーザーが入力したテキストボックスなどの他のASP.NET Webコントロールと一緒に)。ボタンを押すと、POSTが作成されますデータを処理した後(ビューステート内にある可能性がありますが、これは抽象化されています)、Response.redirectを使用してユーザーをsecond_page.aspxにリダイレクトします。Second_page.aspxは必要なものを表示できます。必要に応じて(または必要性)コントロールとそれらが入力したものを含め、first_page.aspxにあるものと同様のUIを表示するには、セッション、Cookie、クエリ文字列パラメーターとしてのURLに保存して、second_pageにこれらのコントロールを設定します.aspx(ただし、first_page.aspxと同様に、second_page.aspxに何も表示する必要がない場合があるため、ここでは一般的なルールはありません。)
Q)ブラウザはフォームデータをクエリ文字列に入れることができますか?
A)はい、メソッドをPOSTではなくGETに設定した場合。これを行うためにWebFormsをオーバーライドすることはできません。これはPRGには必要ありません。
Q)関連する質問でServer.Transferについて言及しています。 Server.Transferの使用は完全に間違っており、Post-Redirect-Get問題を解決する方法はありません(リダイレクトがないため)。正しい?
A)本質的に
Q)PRGをサポートするには、aspxまたはaspx.csファイルでどのコード変更を行う必要がありますか?おそらく、少なくとも、MyPage.aspx以外の場所に投稿するようにコードを変更する必要があります。
A)(上記のように)コードは引き続きポストバックする必要がありますが、Mypage.aspxはボタンハンドラーの新しいページにリダイレクトする必要があります。
Post-Redirect-Getパターンは、Webフォームで使用できます。 MVC NerdDinnerアプリケーションをWebフォーム http://navigationnerddinner.codeplex.com/ に変換することによって、これを行う方法を示しました。ナビゲーションの詳細はまったく同じにしたので、PRGパターンの例はたくさんあります。
ただし、F5 /更新の問題を回避する別の方法があります。ページをUpdatePanel(ASP.NET Ajaxの一部)でラップすると、すべてのポストバックが部分的なページリクエストに変換されます。つまり、F5を押すと、元のGETリクエストのみが更新され(後続のPOSTがなかったため)、警告は表示されません。 (注、JavaScriptが無効になっている場合でも警告が表示されます)。
Post Redirect Getの正確な手順は次のとおりです。
データを入力するフォームがあり、有効な送信(POST)の後、それらをデータベースに挿入し、確認IDを付与した後、この確認IDを使用するページにユーザーをリダイレクトします。 (GET)としてリダイレクト後、すべてのF5-refreshはデータを読み取るだけで、再度挿入することはありません。
挿入のコードは、確認を示すコードとは異なり、別のページにすることもできます-読み取り専用のテキストボックスで同じページを作成できます。
リダイレクトは単純ですResponce.Redirect
asp.netの関数
POSTとリダイレクトの作成後、前のアクションに接続すると考えるのは確認コード(viewstateではない)だけです)
このメソッドのマイナス点は、実際には更新を認識せず、更新が同じデータを再度挿入しないようにする追加の手順を実行するだけですが、Getデータに追加のコードが必要なことです。
代替方法は、更新を認識し、リダイレクトを行わないことです。ポストバックの更新を認識することにより、ユーザーへの単一のメッセージで同じデータを挿入することを回避できます。そのためにインターネット上にいくつかの例があり、私は成功したものを実装しました。
1つの例: http://www.codeproject.com/Tips/319955/How-to-prevent-Re-Post-action-caused-by-pressing-b
Response.Redirect メソッドを呼び出して、別の場所に移動できます。
これにはいくつかの事柄があります。
メインページでフォームのaction属性を設定します(これをと呼びましょう)LaunchForm.aspx)「プロキシ」ページのURLに等しい(ProxyLaunchForm.aspx)。
<form id = "form1" runat = "server" action = "ProxyLaunchForm.aspx" method = "POST">
(オプション)名前に非表示の入力redirectUrlをフォームに追加し、ProxyLaunchForm.aspxに通知するURLの値を設定します起動の実行が終了したらリダイレクトする場所(PRGのR部分)。
ProxyLaunchForm.aspxでは、実装は Page_Load イベントハンドラ。フォームの投稿データにアクセスできるためです。ここで起動を実行します。
その後(また Page_Load)、リダイレクトを実行します(#2のredirectUrlを使用するか、単に参照ページのURLを使用します):
Response.Redirect(Request.Params ["redirectUrl"] ?? Request.UrlReferrer.AbsoluteUri);
ビューステートの問題はまだあります。これに対処する最も簡単な方法は、ビューステートが永続化される方法を変更することだと思います。通常、これはページの非表示の入力要素に保存され、ポストバック時に取得されます(もちろん、HTTPのステートレスな性質により、リダイレクト後に失われます)。ただし、ASP.netが使用するメソッドをオーバーライドして、代わりにSessionを使用させることができます(そのようにして、PRGの後でさえ存在しますプロキシアクション)。だから、最後に...
LaunchForm.aspx.csでは、基本クラスとしてサブクラス化されたPageSavePageStateToPersistenceMediumおよび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);
}
}
}