Excelファイルのダウンロード中にResponse.End()の「スレッドが中止されました」例外を回避する方法


96

データセットをExcelに変換し、そのExcelをダウンロードしようとしました。必要なExcelファイルを取得しましたが、System.Threading.ThreadAbortExceptionがExcelのダウンロードごとに発生しました。この問題の解決方法?..助けてください...

このメソッドをaspx画面で呼び出します。このメソッドによって同じ例外がスローされました。

多くのaspx画面でそのpublic void ExportDataSet(DataSet ds)関数を呼び出し、実行時に発生する例外のエラーロガーメソッドを維持しています。これらの例外は.txtファイルに書き込まれます。そのため、同じ例外がすべてのaspx画面のtxtファイルに記録されます。メソッド宣言クラスファイルからaspxへのこの例外のスローを回避したいだけです。単に、この例外をメソッド宣言クラスファイル自体で処理したいだけです。

ASPXファイルメソッド呼び出し:excel.ExportDataSet(dsExcel);

メソッド定義:

public void ExportDataSet(DataSet ds)
{

   try
   {
      string filename = "ExcelFile.xls";
      HttpResponse response = HttpContext.Current.Response;
      response.Clear();
      response.Charset = "";
      response.ContentType = "application/vnd.ms-excel";
      response.AddHeader("Content-Disposition", "attachment;filename=\"" + filename + "\"");
      using (StringWriter sw = new StringWriter())
      {
         using (HtmlTextWriter htw = new HtmlTextWriter(sw))
         {
             GridView dg = new GridView();
             dg.DataSource = ds.Tables[0];
             dg.DataBind();
             dg.RenderControl(htw);
             // response.Write(style);
             response.Write(sw.ToString());                                                
             response.End();                    // Exception was Raised at here
         }
      }
   }
   catch (Exception ex)
   {
      string Err = ex.Message.ToString();
      EsHelper.EsADLogger("HOQCMgmt.aspx ibtnExcelAll_Click()", ex.Message.ToString());
   }
   finally
   {                
   }
}

2
使用しないでくださいResponse.Endstackoverflow.com/a/3917180/2864740(および他の回答を)。例外はスタックが解かれる方法であるため、「予期される」ことに注意してください(その例外をキャッチしないでください)。あなたはまだキャッチしたい場合は、[その他]の例外、使用:.. catch (ThreadAbortException) { throw; /* propagate */ } catch (Exception ex) { .. }
user2864740

ちょうどあなたのロガーが何を使っているのか好奇心を
かき立てる

回答:


194

オンラインで調べたところ、Response.End()常に例外がスローされることがわかりました。

これを交換してください: HttpContext.Current.Response.End();

これとともに:

HttpContext.Current.Response.Flush(); // Sends all currently buffered output to the client.
HttpContext.Current.Response.SuppressContent = true;  // Gets or sets a value indicating whether to send HTTP content to the client.
HttpContext.Current.ApplicationInstance.CompleteRequest(); // Causes ASP.NET to bypass all events and filtering in the HTTP pipeline chain of execution and directly execute the EndRequest event.

2
うわー、天の恵み。WinDbgを使用してデバッグする時間を節約できました。私の場合、ThreadAbortExceptionが多すぎると、w3wp.exeがクラッシュしました
Dio Phung

ありがとう。コードのこの作品、あなたがASMXサービスのコンストラクタにいくつかの承認チェックを追加したい場合は本当に便利です
ヴァディム

これでうまくいきました。.End()を推奨されたコードに置き換えたところ、現在は例外なく動作します。ありがとう、私の作業コードは次のとおりです。Response.ContentType= "text / csv"; Response.AddHeader( "Content-Disposition"、string.Format( "attachment; filename = \" {0} \ ""、Path.GetFileName(filePath))); Response.TransmitFile(filePath); //Response.End(); HttpContext.Current.Response.Flush(); HttpContext.Current.Response.SuppressContent = true; HttpContext.Current.ApplicationInstance.CompleteRequest();
Nour Lababidi 2016年

3
いいえ、機能しません。実際に答えを見てください。Response.End()うまくいかない場合、提案された回答がResponse.End()最後の行にもあるのはなぜですか?代わりに、@ Binny(以下)からの回答が役立ちます!
user3454439 2017

1
docs.microsoft.com/en-us/dotnet/api/system.web.httpresponse.endのドキュメントによると、Request.Endは下位互換性のためにのみサポートされています。代わりにCompleteRequestの使用をお勧めします
Rudolf Dvoracek 2018

11

これは私がThread was being aborted例外を処理するのに役立ちました、

try
{
   //Write HTTP output
    HttpContext.Current.Response.Write(Data);
}  
catch (Exception exc) {}
finally {
   try 
    {
      //stop processing the script and return the current result
      HttpContext.Current.Response.End();
     } 
   catch (Exception ex) {} 
   finally {
        //Sends the response buffer
        HttpContext.Current.Response.Flush();
        // Prevents any other content from being sent to the browser
        HttpContext.Current.Response.SuppressContent = true;
        //Directs the thread to finish, bypassing additional processing
        HttpContext.Current.ApplicationInstance.CompleteRequest();
        //Suspends the current thread
        Thread.Sleep(1);
     }
   }

の代わりに次のコードを使用HttpContext.Current.Response.End()すると、Server cannot append header after HTTP headers have been sent例外が発生します。

            HttpContext.Current.Response.Flush();
            HttpContext.Current.Response.SuppressContent = True;
            HttpContext.Current.ApplicationInstance.CompleteRequest();

それが役に立てば幸い


1
私のために働く。上記はそうではありません。実際にはそれがResponse.End()うまくいかないのは面白いですが、提案された方法はResponse.End()最後の行にもありますか?
user3454439 2017

1
例外をキャッチして非表示にしている原因。
Dan Friedman

3
なんて恐ろしいソリューション
Razor

4

同じ質問のようです:

ASP.NET System.Web.HttpResponse.End()が呼び出されると、現在のスレッドは中止されますか?

したがって、仕様によるものです。その例外のキャッチを追加して、優雅に「無視」する必要があります。


多くのaspx画面でそのpublic void ExportDataSet(DataSet ds)関数を呼び出し、実行時に発生する例外のエラーロガーメソッドを維持しています。これらの例外は.txtファイルに書き込まれます。そのため、同じ例外がすべてのaspx画面のtxtファイルに記録されます。このメソッド例外がクラスファイルからaspxにスローされるのを回避したいだけです。単に、この例外をメソッド宣言クラスファイル自体で処理したいだけです。
user3171957 2014年

質問のユーザーからのコメントごとに、TheadAbortException-> catch(ThreadAbortException){}をキャッチするだけです
robnick

はい、メソッド宣言クラスファイルでそれ自体を例外としてキャッチします。
user3171957 2014年

4

Response.End()をTry / CatchおよびUsingブロックの外側に移動します。

例外をスローして残りのリクエストをバイパスすることが想定されていますが、それをキャッチすることは想定されていませんでした。

bool endRequest = false;

try
{
    .. do stuff
    endRequest = true;
}
catch {}

if (endRequest)
    Resonse.End();

それをfinallyブロックに入れて、常に実行されるのはなぜですか?
GoldBishop 2017年

特にtryブロックにreturnステートメントがある場合は、そうすることができます。しかし、あなたがしよう/キャッチ/無視するなら、あなたは最終的にさえ必要としません。重要なことは、ThreadAbortExceptionをキャッチしてはならないということです。
Steve

確かに、TAEは成功した応答を返すためのPITAです。
GoldBishop 2017年

3

置くだけ

Response.End();

tryブロック内ではなく、finallyブロック内。

これは私のために働いた!!!。

次の問題のある(例外あり)コード構造がありました

...
Response.Clear();
...
...
try{
 if (something){
   Reponse.Write(...);
   Response.End();

   return;

 } 

 some_more_code...

 Reponse.Write(...);
 Response.End();

}
catch(Exception){
}
finally{}

そしてそれは例外を投げます。response.End();の後に実行するコード/作業がある場合、例外がスローされると思います。。私の場合、追加のコードは戻り値そのものでした。

response.End();を移動したとき finallyブロックに(そしてreturnをその場所に残しました-これにより、tryブロックの残りのコードがスキップされ、finallyブロックにジャンプします(含まれる関数を終了するだけではありません))例外が発生しなくなりました。

以下は正常に動作します:

...
Response.Clear();
...
...
try{
 if (something){
   Reponse.Write(...);

   return;

 } 

 some_more_code...

 Reponse.Write(...);

}
catch(Exception){
}
finally{
    Response.End();
}

3

Response.End()メソッドの例外には特別なcatchブロックを使用します

{
    ...
    context.Response.End(); //always throws an exception

}
catch (ThreadAbortException e)
{
    //this is special for the Response.end exception
}
catch (Exception e)
{
     context.Response.ContentType = "text/plain";
     context.Response.Write(e.Message);
}

または、ファイルハンドラを構築している場合は、単にResponse.End()を削除します




1

Response.END();のエラー あなたはASPアップデートパネルまたはJavaScriptを使用する任意のコントロールを使用しているため、JavaScriptまたはScriptManagerまたはスクリプトを使用せずにASPまたはHTMLからネイティブのコントロールを使用して、再試行してください


1

これは問題ではありませんが、これは仕様によるものです。根本的な原因は、マイクロソフトサポートページに記載されています。

Response.Endメソッドは、ページの実行を終了し、実行をアプリケーションのイベントパイプラインのApplication_EndRequestイベントにシフトします。Response.Endに続くコード行は実行されません。

提供されるソリューションは次のとおりです。

Response.Endの場合は、Response.EndではなくHttpContext.Current.ApplicationInstance.CompleteRequestメソッドを呼び出して、Application_EndRequestイベントへのコード実行をバイパスします。

ここにリンクがあります:https : //support.microsoft.com/en-us/help/312629/prb-threadabortexception-occurs-if-you-use-response-end--response-redi



0

上記のすべての変更を使用しましたが、それでもWebアプリケーションで同じ問題が発生しました。

次に、ホスティングサービスに連絡し、HTTP経由で転送するファイルをブロックしているソフトウェアまたはウイルス対策があるかどうかを確認するように依頼しました。またはISP /ネットワークがファイルの転送を許可していません。

彼らはサーバー設定をチェックし、私のサーバーの「データセンター共有ファイアウォール」をバイパスしました。これで、アプリケーションがファイルをダウンロードできるようになりました。

この答えが誰かを助けることを願っていますこれは私のために働いたものです


それは機能するかもしれませんが、固い解決策として聞こえません。ファイアウォールが完全に無効になっていると言いますか?それは大きな「いいえ」でしょう。それとも、アプリケーションに合わせてカスタマイズされていますか?また、データセンターのファイアウォールがブロックするものでThreadAbortExceptionが表示されるのはおかしい…言い換えれば、質問への回答ではないのか。
マイケル


0

私はこの解決策をお勧めします:

  1. 使わない response.End();

  2. このグローバル変数を宣言します。 bool isFileDownLoad;

  3. あなたの直後 (response.Write(sw.ToString());) set ==> isFileDownLoad = true;

  4. 次のようにレンダリングをオーバーライドします。

    /// AEG : Very important to handle the thread aborted exception
    
    override protected void Render(HtmlTextWriter w)
    {
         if (!isFileDownLoad) base.Render(w);
    } 

0

次の方がうまくいくことがわかりました...

   private void EndResponse()
    {
        try
        {
            Context.Response.End();
        }
        catch (System.Threading.ThreadAbortException err)
        {
            System.Threading.Thread.ResetAbort();
        }
        catch (Exception err)
        {
        }
    }

0

私にとって、コードビハインドコードをポストバックコントロールとして呼び出すボタンを登録するのに役立ちました。

protected void Page_Init(object sender, EventArgs e)
{
    ScriptManager.GetCurrent(this.Page).RegisterPostBackControl(btnMyExport);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.