misc.log

日常茶飯事とお仕事と

Response.EndでThreadAbortExceptionが起きる

下記エントリで書いていたコードに、実行ログを出力させよう!とlog4net出力コードを埋め込み、さらに「エラー処理も(エラー起きないだろうけど)やっておこう!」と張り切ってTry/Catchで囲ったら……エラー出てるし……

www.backyrd.net

エラー内容

出てるエラーはこんな感じ

2015-04-14 19:09:33,119 [10] INFO  - ■ Button_Click 開始
2015-04-14 19:09:33,146 [10] ERROR - エラー発生
System.Threading.ThreadAbortException: スレッドを中止しようとしました。
   場所 System.Threading.Thread.AbortInternal()
   場所 System.Threading.Thread.Abort(Object stateInfo)
   場所 System.Web.HttpResponse.End()
   場所 OfficeFileDownloadTest._Default.Button_Click(Object sender, EventArgs e) 
      場所 C:\Users\test\Documents\Visual Studio 2008\Projects\Test\Test\Default.aspx.cs:行 248

なんなのこれ?と思い、軽く検索するとこんなのが引っかかった。あとで詳細調べます。

PRB/ ThreadAbortException Occurs If You Use Response.End, Response.Redirect, or Server.Transfer
https://support.microsoft.com/en-us/kb/312629/

とりあえず、Response.Endの代わりにこれを書いて回避してみます。

HttpContext.Current.ApplicationInstance.CompleteRequest();

CompleteRequesetもダメだ

エラーは消えましたが、TransmitFileでファイルをダウンロードしたほうは、どうもファイル内に余計なタグがついたか何かでファイル表示時に修復の問い合わせがでるように。

また、Response.WriteでHTMLを返していた方は、なんとダウンロードされる内容がASP.NETが作ったページそのままをコピーしたExcelファイルに。HTMLの記述内容はどこかに行ってしまいました。

前者はおそらくこれです。

HttpResponse.WriteとかWriteFileするとデフォルトで付いてしまう
https://social.msdn.microsoft.com/Forums/ja-JP/b7b5e136-e8bd-457b-8993-aaa9893902ae/httpresponsewritewritefiledoctype-html-public-w3cdtd-?forum=aspnetja

上記のフォーラム内で「aspxを使わずに、ashxファイルつかってProcessRequestの中で同じことやればいいように思いますが。」といったコメントがあるので、このあたりを調べてみます。

いずれにしても、現時点ではResponseオブジェクトによるデータ返送の仕組みを調べるのは完全に脱線で、Excelデータをダウンロードするテストページを作ることがもくてきなので、とりあえずエラートラップをはずしてResponse.Endでやって行こうと思います。

分かりやすい説明があった

ここにわかりやすく書いてありました。もう少し噛み砕いてみますが、すこしすっきり。

ThreadAbortExceptionの回避策について
http://www.ailight.jp/BBSDetail/Index/08988dba-817c-4d2d-a64e-98159ccfd47c

参考: KB 312629 内容

マイクロソフトのリンク先が消える可能性を考慮して、概要を転記しておきます。

ThreadAbortException occurs if you use Response.End, Response.Redirect, or Server.Transfer

This article helps you resolve the ThreadAbortException error that occurs if you use Response.End, Response.Redirect, or Server.Transfer.

Symptmons

If you use the Response.End, Response.Redirect, or Server.Transfer method, a ThreadAbortException exception occurs. You can use a try-catch statement to catch this exception.

Cause

The Response.End method ends the page execution and shifts the execution to the Application_EndRequest event in the application's event pipeline. The line of code that follows Response.End is not executed.

This problem occurs in the Response.Redirect and Server.Transfer methods because both methods call Response.End internally.

Resolution

To work around this problem, use one of the following methods:

  • For Response.End , call the HttpContext.Current.ApplicationInstance.CompleteRequest method instead of Response.End to bypass the code execution to the Application_EndRequest event.
  • For Response.Redirect, use an overload, Response.Redirect(String url, bool endResponse) that passes false for the endResponse parameter to suppress the internal call to Response.End. For example:
 Response.Redirect ("nextpage.aspx", false);

If you use this workaround, the code that follows Response.Redirect is executed.

  • For Server.Transfer, use the Server.Execute method instead.

Although ASP.NET handles this exception, you can use the try-catch statement to catch this exception. For example:

try
{
    Response.Redirect("nextpage.aspx");
}
catch (Exception ex)
{
    Response.Write (ex.Message);
}

Add a breakpoint on the Response.Write line, and notice that this breakpoint is hit. When you examine the exception, notice that the ThreadAbortException exception occurs.