2005.08.30

Response.End、Response.Redirect、または Server.Transfer メソッドを使用すると ThreadAbortException が発生する

表題のマイクロソフトのサポート技術情報があることを知った。
http://support.microsoft.com/default.aspx?scid=kb;ja;JP312629

ASP.netで 例えばログインの処理などで、
 パスワードが正しければ“メニュー”を表示するが
 間違ったパスワードだとログイン画面を表示したまま。
なんて処理はたぶんにあると思う。

そこになにげなく

  Response.Redirect("Menu.aspx")

と書いたりすることもあるだろう。

結果、画面は新たな遷移先の画面内容が表示されるので、
気が付くことはないのだけれども、
実は知らない間に裏でこっそり ThreadAbortException が発生していたというのだ。ひー。

試しに、こうして実行してみよう。

Try
  Response.Redirect("Menu.aspx")
Catch ex As Exception
  System.Diagnostics.Debug.WriteLine(ex.ToString)
End Try

速度にどの程度まで影響しているか等は調べていないのだけれど、
もともと Exceptionがうんちゃらという画面が出るわけでもないので、
そのまま無視して使うというのも手だと思う。
この症状を気にして回避する場合には、以下のようにするらしい。

  Response.Redirect("Menu.aspx", False)


是非はともかく、この動作はマイクロソフトによると『仕様』なのだそうだ。
 
 
 
さて、ここまでは前置き。

通常 Webアプリケーションで CSVダウンロードをしたり、動的に画像を作成/選択して
表示したりする場合には最後に Response.End を使うことになるというのが一般とされている。
ただ、実はこの Response.End でも ThreadAbortException が発生する。

で、ファイルの読み書き処理や、データベースアクセス処理なんかに
はしょって大雑把な Try / Catch を仕掛けている場合、ファイルや DBのアクセス時ではなく
Response.End で Exception が発生したりするのだな。

もう一度。
>是非はともかく、この動作はマイクロソフトによると『仕様』なのだそうだ!!


というわけで、Response.End における ThreadAbortException の扱いは、以下。

1.ThreadAbortException は catch しても無視する。
 ただしこの ThreadAbortException は、キャッチできても、 catch ブロックの末尾で
 もう一度自動的に発生する特殊な例外(by Help)、
とのことで呼び出し側のメソッドにも Try / Catch がある場合は再度 catch されてしまうゆえ
無視し続けなくてはいけない。

2.Try / Catch ブロック中に Response.End を入れない。
 Response.End だけを除外するにはかなり高度なテクが必要でわ?

3.Response.End の代わりに、HttpContext.Current.ApplicationInstance.CompleteRequest メソッドを呼び出す。
(by サポート技術情報)
よくわかりませんが、こんなん使って良いんですか?(日本語情報が無さすぎ)

---投稿者一言コメント----------
(2005/08/31:追記) ただし困ったことに   HttpContext.Current.ApplicationInstance.CompleteRequest

は、Response.Endと等価ではなく、処理が途中で終わるわけではない。

例えば Postbackしたままの画面でダウンロード処理を行い、上記メソッドを呼び出すと
ダウンロードするデータの内容の末尾に、本来 Postback後に表示されるはずの
画面内容(HTML)が付け足しで送って来られてしまう。非常にいらん。
 
 
 
ということで、考えられる回避策、

その1.そんな設計(画面遷移)をするな。
 JavaScript:window.open(~) とかしてから呼べ?

その2.HttpContext.Current.ApplicationInstance.CompleteRequest の後に
 Response.Closeをしろ。
とりあえずブラウザとの接続を切っちゃえば送ってこられなくなる。
(なんか問題の解決を間違っているような気も)

その3.やっぱり Response.End を使う。
 ひゃー

その4.Render系のイベントをごにょごにょする(???)

コメントを投稿

(いままで、ここでコメントしたことがないときは、コメントを表示する前にこのブログのオーナーの承認が必要になることがあります。承認されるまではコメントは表示されません。そのときはしばらく待ってください。)

photo
ichikawa