@kotyのブログ

PythonとかAWSとか勉強会のこととかを、田舎者SEがつづります。記事のライセンスは"CC BY"でお願いします。

Server.Transferで画面遷移が無限ループ

ハマったのでメモ。

一度のリクエストの中で、Server.Transferを使ってA→B→A(異常系に多い画面遷移)という風に画面遷移をすると、画面遷移が無限ループした。B→Aの遷移でAに来たときに、btnTransfer_Clickが発火してしまう。そして再度Server.Transferが呼ばれるという状況。
コード例:
■A.aspx.cs (A.aspxは、ボタンが一個置いてあるだけ)

public partial class A : System.Web.UI.Page
{
  protected void Page_Load(object sender, EventArgs e)
  {
  }

  protected void btnTransfer_Click(object sender, EventArgs e)
  {
    this.Server.Transfer("B.aspx", true);
  }
}

■B.aspx.cs (B.aspxにはコントロールは何も置いてない)

public partial class B : System.Web.UI.Page
{
  protected void Page_Load(object sender, EventArgs e)
  {
    //this.Server.Transfer("A.aspx");だとループしない
    this.Server.Transfer("A.aspx", true);
  }
}

第二引数無しのServer.Transferだとループしない。preserveFormがTrueのときはポストパラメータが保存されるけど、一度のリクエストの中で元の画面が再度呼ばれたときはポストパラメータが消えるようにASP.NETの内部で制御している模様。しかし第二引数にtrueを指定すると、ポストパラメータが残っており、クリックイベントが発火してしまう。

this.Server.Transfer("A.aspx"); //OK

this.Server.Transfer("A.aspx", true); //NG

MSDNを見る限り等価なように思えるが、そうではないようだ。connectにそれっぽいのがあったけど、詳しい話が書いてあるであろうリンク先が消えていた。まあたぶん同じ現象なんだろう。どうやら.NET1.1からある話のようだ。

というわけで、

public static void MyTransfer(Page page, string Url, bool preserveForm)
{
  if (preserveForm)
  {
    page.Server.Transfer(Url);
  }
  else
  {
    page.Server.Transfer(Url, false)
  }
}

みたいなパッと見は意味不明なラッパを用意すればいいかな、という結論になった。ということの調査に一日を費やした。。。

ググってもあんま情報のってなかったんだけど、みんなハマることはないんだろうか。それとも、ASP.NET Web Formなんていう、おわこんなものを使っているのはうちだけだからか。。。