web-dev-qa-db-ja.com

ASP.NETによるPost-Redirect-Get

ASP.NETで Post-Redirect-Get パターンを実装するにはどうすればよいですか?

ボタンをクリックすると、いくつかの処理が実行されます。

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

ユーザーがボタンをクリックすると、宇宙船が打ち上げられ、Webページが再表示されます。ユーザーがF5キーを押すと、警告が表示されます。

enter image description here

この問題の解決策は Post-Redirect-Get パターンです。

[〜#〜] prg [〜#〜] をASP.NETに実装する方法は何ですか?


問題の中心は次のとおりです。

  • _<asp:Button>_は、元の形式ではない場所に対してPOSTをどのように実行できますか?
  • ビューステートを読み取らないフォームに投稿すると、ViewStateはどうなりますか?
  • 「実際の」aspx Webフォームにリダイレクトすると、ViewStateはどうなりますか?
  • ViewStateと基本的に互換性がありません ASP.net リダイレクト後取得?
  • aSP.netは基本的にPost-Redirect--Getと互換性がありませんか?
  • how(つまり、どのコード)「本物の」aspx Webフォームにリダイレクトしますか?
  • how(つまり、どのようなURL)「実際の」aspx Webフォームにリダイレクトしますか?関係の質問でResponse.Redirect(Request.RawUrl);について言及しています
  • when(つまり、どのイベントハンドラー内)で、「実際の」aspx Webフォームにリダイレクトしますか?
  • 関連する質問は、フォームデータを投稿する方法の問題を引き起こします。 HTMLformsは使用できないという意味があり、すべてのフォームデータをクエリ文字列に追加する必要があります。これは本当ですか?もしそうなら、なぜですか?そうでない場合、なぜでしょうか? ブラウザはフォームデータをクエリ文字列に入れることができますか
  • 関連する質問は_Server.Transfer_について言及しています。 _Server.Transfer_の使用は完全に間違っており、Post-Redirect-Getの問題を解決する方法はありません(Redirectがないため)。正しい?
  • pRGをサポートするには、aspxまたは_aspx.cs_ファイルでどのコード変更を行う必要がありますか?おそらく、少なくとも、コードは_MyPage.aspx_以外のどこかでpostに変更する必要があります。

つまり、ASP.netでPost-Redirect-Getをどのように実行しますか?

:ASP.net(つまり、ASP.net MVCではありません)

こちらもご覧ください

41
Ian Boyd

通常、これは、クエリ文字列を使用してどのレコードをロード/処理するかを通知する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が実際に同じページを参照しているという事実は重要ではありません。


質問の箇条書きリストに対応するいくつかの考察:

  • 元の形式ではない場所でPOSTを実行するにはどうすればよいですか?

これを行うには、フォームにaction属性を設定するか、ボタンにPostBackUrlを設定します。

  • ビューステートを読み取らないフォームに投稿すると、ViewStateはどうなりますか?

依存します。フォームを別のページに投稿するだけの場合は、<%@ PreviousPageType ... />ディレクティブを使用して、投稿の送信元を「新しい」ページに通知できます。これにより、新しいページに投稿されたデータを操作することが簡単になります。 詳細はこのリンク を参照してください。

  • "実際の" aspx Webフォームにリダイレクトすると、ViewStateはどうなりますか?

表示状態は投稿リクエストで送信されます。リダイレクトすると、ブラウザは新しいページをロードし、独自のビューステートを作成します。

  • viewStateは基本的にASP.net Post-Redirect-Getと互換性がありませんか?

見方次第です。リダイレクト後、新しいページは以前のページのビューステートにアクセスできなくなります。

  • aSP.netはPost-Redirect--Getと基本的に互換性がありませんか?

いいえ。上の例を参照してください。

  • 「実際の」aspx Webフォームにどのように(つまりどのコードを)リダイレクトしますか?

Response.Redirect(url)。これにより、ブラウザーに応答が送信され、新しいget要求を実行するよう指示されます。

  • いつ(つまり、どのイベントハンドラーで) "実際の" aspx Webフォームにリダイレクトしますか?

投稿リクエストの処理に必要なすべての作業を実行したとき。

  • 関連する質問により、フォームデータの投稿方法に関する問題が発生します。 HTMLフォームを使用できないという意味があり、すべてのフォームデータをクエリ文字列に追加する必要があります。これは本当ですか?もしそうなら、なぜですか?そうでない場合、なぜでしょうか?ブラウザはフォームデータをクエリ文字列に入れることができますか?

投稿リクエストのリダイレクトは十分にサポートされておらず、おそらく回避する必要があります。これは、http応答307を使用して(一部のブラウザーで)行うことができます。その際、サーバーはブラウザーに「私は要求を処理しません。これに投稿してください。代わりに他のページ」。

  • 関連する質問は、Server.Transferについて言及しています。 Server.Transferの使用は完全に間違っており、Post-Redirect-Get問題を解決する方法はありません(リダイレクトがないため)。正しい?

Server.Transfer(...)はサーバー側で実行されているものです。ブラウザはそれを認識していません。基本的に、ページはServer.Transferを使用して他のページに処理を実行させることができ、そのページはブラウザに応答を送信する必要があります。しかし、ブラウザはそれが応答された元のページだったと考えます。

  • pRGをサポートするには、aspxまたはaspx.csファイルでどのコード変更を行う必要がありますか?おそらく、少なくとも、MyPage.aspx以外の場所に投稿するようにコードを変更する必要があります。

いいえ、通常のポストバックを使用できます。秘訣は、投稿されたデータを処理した後にRepsonse.Redirectを実行する1つ(またはいくつか)の特定のイベントハンドラーをページに配置することです。

36
user1429080

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はボタンハンドラーの新しいページにリダイレクトする必要があります。

7
Keith Ballinger

Post-Redirect-Getパターンは、Webフォームで使用できます。 MVC NerdDinnerアプリケーションをWebフォーム http://navigationnerddinner.codeplex.com/ に変換することによって、これを行う方法を示しました。ナビゲーションの詳細はまったく同じにしたので、PRGパターンの例はたくさんあります。

ただし、F5 /更新の問題を回避する別の方法があります。ページをUpdatePanel(ASP.NET Ajaxの一部)でラップすると、すべてのポストバックが部分的なページリクエストに変換されます。つまり、F5を押すと、元のGETリクエストのみが更新され(後続のPOSTがなかったため)、警告は表示されません。 (注、JavaScriptが無効になっている場合でも警告が表示されます)。

5
graham mendick

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

5
Aristos

Response.Redirect メソッドを呼び出して、別の場所に移動できます。

4
Bas

これにはいくつかの事柄があります。

  1. メインページでフォームのaction属性を設定します(これをと呼びましょう)LaunchForm.aspx)「プロキシ」ページのURLに等しい(ProxyLaunchForm.aspx)。

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

  2. (オプション)名前に非表示の入力redirectUrlをフォームに追加し、ProxyLaunchForm.aspxに通知するURLの値を設定します起動の実行が終了したらリダイレクトする場所(PRGのR部分)。

  3. ProxyLaunchForm.aspxでは、実装は Page_Load イベントハンドラ。フォームの投稿データにアクセスできるためです。ここで起動を実行します。

  4. その後(また Page_Load)、リダイレクトを実行します(#2のredirectUrlを使用するか、単に参照ページのURLを使用します):

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

    ビューステートの問題はまだあります。これに対処する最も簡単な方法は、ビューステートが永続化される方法を変更することだと思います。通常、これはページの非表示の入力要素に保存され、ポストバック時に取得されます(もちろん、HTTPのステートレスな性質により、リダイレクト後に失われます)。ただし、ASP.netが使用するメソッドをオーバーライドして、代わりにSessionを使用させることができます(そのようにして、PRGの後でさえ存在しますプロキシアクション)。だから、最後に...

  5. 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);
       }
    }
}
2
McGarnagle