Bagaimana Menghindari Respon.End () Pengecualian "Thread telah dibatalkan" selama download file Excel

96

Saya mencoba mengonversi dataset saya menjadi excel dan mengunduh excel itu. Saya mendapatkan file excel yang saya butuhkan. Tetapi System.Threading.ThreadAbortException dinaikkan setiap unduhan excel. Bagaimana cara mengatasi masalah ini? .. Tolong bantu saya ...

Saya memanggil metode ini di layar aspx saya. Ada juga pengecualian yang sama telah dilemparkan oleh metode ini.

Saya menyebut bahwa fungsi ExportDataSet (DataSet ds) public void di banyak layar aspx dan juga saya mempertahankan metode error logger untuk pengecualian yang dimunculkan pada saat runtime, pengecualian tersebut ditulis ke dalam file .txt. Jadi pengecualian yang sama dicatat di semua file txt layar aspx. Saya hanya ingin menghindari pengecualian ini melempar dari metode file kelas yang dideklarasikan ke aspx. Cukup saya hanya ingin menangani pengecualian ini di file kelas deklarasi metode saya itu sendiri.

Metode File ASPX panggilan: excel.ExportDataSet (dsExcel);

Definisi Metode:

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
   {                
   }
}
pengguna3171957
sumber
2
Jangan gunakan Response.Endlihat stackoverflow.com/a/3917180/2864740 (dan jawaban lainnya); perhatikan bahwa pengecualiannya adalah "diharapkan" karena begitulah cara tumpukan dibatalkan (jadi jangan tangkap pengecualian itu). Jika Anda masih ingin menangkap pengecualian [lainnya], gunakan:.. catch (ThreadAbortException) { throw; /* propagate */ } catch (Exception ex) { .. }
user2864740
Hanya ingin tahu logger apa yang Anda gunakan
rogue39nin

Jawaban:

195

Saya mencari secara online dan melihat bahwa Response.End()selalu ada pengecualian.

Ganti ini: HttpContext.Current.Response.End();

Dengan ini:

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.
pengguna3412640
sumber
2
Wow, berkah. Ini menghemat waktu berjam-jam debug menggunakan WinDbg. Dalam kasus saya, w3wp.exe saya baru saja macet jika ada terlalu banyak ThreadAbortException
Dio Phung
Terima kasih. Potongan kode ini sangat membantu jika Anda ingin menambahkan beberapa pemeriksaan otorisasi ke konstruktor layanan asmx
vadim
Ini berhasil untuk saya. Saya mengganti .End () dengan kode yang disarankan dan berfungsi tanpa kecuali sekarang. Terima kasih, kode kerja saya sekarang adalah: 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
3
Tidak. Tidak bekerja untuk saya. Lihatlah jawabannya. Jika Response.End()tidak tidak bekerja, mengapa jawaban disarankan memiliki juga Response.End()pada baris terakhir? Sebaliknya, jawaban dari @Binny (di bawah) membantu!
pengguna3454439
1
Menurut dokumentasi di docs.microsoft.com/en-us/dotnet/api/system.web.httpresponse.end Request.End hanya didukung untuk kompatibilitas ke belakang. Penggunaan CompleteRequest direkomendasikan sebagai pengganti
Rudolf Dvoracek
11

Ini membantu saya menangani Thread was being abortedpengecualian,

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);
     }
   }

jika Anda menggunakan kode berikut sebagai ganti HttpContext.Current.Response.End(), Anda akan mendapatkan Server cannot append header after HTTP headers have been sentpengecualian.

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

Semoga membantu

Binny
sumber
1
Bekerja untuk saya. Di atas tidak. Sebenarnya lucu bahwa sementara Response.End()tidak berhasil, tetapi metode yang disarankan juga ada Response.End()di baris terakhir?
pengguna3454439
1
Penyebab Anda menangkap dan menyembunyikan pengecualian.
Dan Friedman
3
Solusi yang sangat mengerikan
Razor
4

Tampaknya pertanyaannya sama dengan:

Ketika ASP.NET System.Web.HttpResponse.End () dipanggil, utas saat ini dibatalkan?

Jadi sesuai desain. Anda perlu menambahkan tangkapan untuk pengecualian itu dan dengan anggun "mengabaikan" -nya.

robnick
sumber
Saya menyebut bahwa fungsi ExportDataSet (DataSet ds) public void di banyak layar aspx dan juga saya mempertahankan metode error logger untuk pengecualian yang dimunculkan pada saat runtime, pengecualian tersebut ditulis ke dalam file .txt. Jadi pengecualian yang sama dicatat di semua file txt layar aspx. Saya hanya ingin menghindari pengecualian ini melempar dari metode file kelas yang dideklarasikan ke aspx. Cukup saya hanya ingin menangani pengecualian ini di file kelas deklarasi metode saya sendiri.
user3171957
Per komentar dari pengguna dalam pertanyaan Anda, cukup tangkap TheadAbortException -> catch (ThreadAbortException) {}
robnick
Ya menangkap pengecualian itu dengan dalam file kelas deklarasi Metode itu sendiri.
pengguna3171957
4

Pindahkan Response.End () ke luar blok Try / Catch dan Using.

Ini seharusnya melempar Exception untuk melewati sisa permintaan, Anda tidak seharusnya menangkapnya.

bool endRequest = false;

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

if (endRequest)
    Resonse.End();
Steve
sumber
mengapa tidak menempatkannya di blok Akhirnya, sehingga selalu dieksekusi?
GoldBishop
Anda bisa melakukan itu, terutama jika Anda memiliki pernyataan pengembalian di blok percobaan. Tetapi jika Anda mencoba / menangkap / mengabaikan maka Anda bahkan tidak membutuhkan akhirnya. yang penting adalah Anda tidak boleh menangkap ThreadAbortException.
Steve
Benar, TAE adalah PITA untuk mengembalikan Respons yang berhasil.
GoldBishop
3

Taruh saja

Response.End();

dalam blok terakhir alih-alih dalam blok percobaan.

Ini telah berhasil untuk saya !!!.

Saya memiliki struktur kode bermasalah (dengan Exception) berikut

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

   return;

 } 

 some_more_code...

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

}
catch(Exception){
}
finally{}

dan itu melempar pengecualian. Saya menduga Exception dilemparkan di mana ada kode / pekerjaan untuk dijalankan setelah response.End (); . Dalam kasus saya, kode tambahan hanyalah pengembalian itu sendiri.

Ketika saya baru saja memindahkan respons.End (); ke blok terakhir (dan membiarkan pengembalian pada tempatnya - yang menyebabkan melewatkan sisa kode di blok percobaan dan melompat ke blok terakhir (tidak hanya keluar dari fungsi yang memuat)) Pengecualian berhenti berlangsung.

Berikut ini berfungsi dengan baik:

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

   return;

 } 

 some_more_code...

 Reponse.Write(...);

}
catch(Exception){
}
finally{
    Response.End();
}
pengguna2265251
sumber
3

Gunakan blok catch khusus untuk pengecualian dari Response.End () metode

{
    ...
    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);
}

Atau hapus saja Response.End () jika Anda membuat filehandler

SoliQuiD
sumber
2

Saya menghapus tombol tautan dari UpdatePanel dan juga mengomentari Respons.End () Berhasil !!!

nunopacheco
sumber
1

kesalahan untuk Response.END (); karena Anda menggunakan panel pembaruan asp atau kontrol apa pun yang menggunakan javascript, coba gunakan kontrol asli dari asp atau html tanpa javascript atau scriptmanager atau skrip dan coba lagi

Ivan Renteria Vidal
sumber
1

Ini bukan masalah tapi ini memang disengaja. Akar masalah dijelaskan di Halaman Dukungan Microsoft.

Metode Response.End mengakhiri eksekusi halaman dan menggeser eksekusi ke peristiwa Application_EndRequest di pipeline peristiwa aplikasi. Baris kode yang mengikuti Response.End tidak dijalankan.

Solusi yang disediakan adalah:

Untuk Response.End, panggil metode HttpContext.Current.ApplicationInstance.CompleteRequest alih-alih Response.End untuk melewati eksekusi kode ke acara Application_EndRequest

Ini tautannya: https://support.microsoft.com/en-us/help/312629/prb-threadabortexception-occurs-if-you-use-response-end--response-redi

Anjani
sumber
0

siram respons ke klien sebelum response.end ()

Lebih lanjut tentang Metode Response.Flush

Jadi gunakan kode yang disebutkan di bawah ini sebelumnya response.End();

response.Flush();  
thejustv
sumber
0

Saya menggunakan semua perubahan di atas tetapi saya masih mendapatkan masalah yang sama pada aplikasi web saya.

Kemudian saya menghubungi penyedia hosting saya & meminta mereka untuk memeriksa apakah ada perangkat lunak atau antivirus yang memblokir file kami untuk ditransfer melalui HTTP. atau ISP / jaringan tidak mengizinkan file untuk ditransfer.

Mereka memeriksa pengaturan server & melewati "Data Center Shared Firewall" untuk server saya & sekarang aplikasi kami dapat mengunduh file.

Semoga jawaban ini akan membantu seseorang. Inilah yang berhasil untuk saya

Sushil Jadhav
sumber
Meskipun mungkin berhasil, itu tidak terdengar sebagai solusi yang solid. Apakah Anda mengatakan firewall dinonaktifkan sepenuhnya? Itu akan menjadi "tidak" yang besar. Atau apakah itu disesuaikan untuk aplikasi Anda? Juga aneh melihat ThreadAbortException pada sesuatu yang diblokir firewall pusat data ... Dengan kata lain, bukan jawaban untuk pertanyaan?
Michael
0

Saya menemukan alasannya. Jika Anda menghapus panel pembaruan, itu akan baik-baik saja!

WSJayaruwan Sumathirathne
sumber
4
harus di komentar
TarangP
0

Saya merekomendasikan solusi ini:

  1. Jangan gunakan response.End();

  2. Deklarasikan var global ini: bool isFileDownLoad;

  3. Tepat setelah Anda (response.Write(sw.ToString());) set ==> isFileDownLoad = true;

  4. Ganti Render Anda seperti:

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

Saya menemukan bahwa berikut ini bekerja lebih baik ...

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

Bagi saya itu membantu untuk mendaftarkan tombol yang memanggil kode di belakang kode sebagai kontrol pos balik.

protected void Page_Init(object sender, EventArgs e)
{
    ScriptManager.GetCurrent(this.Page).RegisterPostBackControl(btnMyExport);
}
pengguna13938019
sumber