วิธีหลีกเลี่ยงการตอบกลับ End () ข้อยกเว้น“ เธรดถูกยกเลิก” ระหว่างการดาวน์โหลดไฟล์ Excel


99

ฉันพยายามแปลงชุดข้อมูลของฉันเป็น excel และดาวน์โหลด excel นั้นฉันได้รับไฟล์ excel ที่ต้องการ แต่ System.Threading.ThreadAbortException ถูกเพิ่มขึ้นทุกการดาวน์โหลด excel จะแก้ไขปัญหานี้อย่างไร? .. โปรดช่วยฉันด้วย ...

ฉันเรียกวิธีนี้ในหน้าจอ aspx ของฉันนอกจากนี้ยังมีข้อยกเว้นเช่นเดียวกันกับวิธีนี้

ฉันเรียกมันว่าฟังก์ชัน ExportDataSet (DataSet ds) ที่เป็นโมฆะสาธารณะในหลาย ๆ หน้าจอ aspx และฉันยังคงรักษาวิธีการบันทึกข้อผิดพลาดสำหรับข้อยกเว้นที่เพิ่มขึ้นในรันไทม์ที่ถูกต้องข้อยกเว้นเหล่านั้นจะถูกเขียนลงในไฟล์. txt ดังนั้นข้อยกเว้นเดียวกันนี้จึงถูกบันทึกในไฟล์ txt ของหน้าจอ aspx ทั้งหมดฉันแค่ต้องการหลีกเลี่ยงข้อยกเว้นนี้ที่โยนจากไฟล์คลาสที่ประกาศไปยังวิธี aspx ฉันแค่ต้องการจัดการข้อยกเว้นนี้ที่ไฟล์คลาสการประกาศเมธอดของฉันเอง

ASPX File Method เรียก: 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.Endดูstackoverflow.com/a/3917180/2864740 (และคำตอบอื่น ๆ ) โปรดทราบว่าข้อยกเว้นคือ "เป็นที่คาดหวัง" เนื่องจากเป็นวิธีคลายสแต็ก (ดังนั้นอย่าจับข้อยกเว้นนั้น) หากคุณยังต้องการจับข้อยกเว้น [อื่น ๆ ] ให้ใช้:.. catch (ThreadAbortException) { throw; /* propagate */ } catch (Exception ex) { .. }
user2864740

เพียงแค่อยากรู้ว่าคุณใช้คนตัดไม้อะไร
rogue39nin

คำตอบ:


203

ฉันค้นคว้าข้อมูลทางออนไลน์และเห็นว่า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 ในกรณีของฉัน w3wp.exe ของฉันเพิ่งล้มเหลวหากมี ThreadAbortException มากเกินไป
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

3
ไม่ได้ผลสำหรับฉัน ดูคำตอบจริงๆ ถ้าResponse.End()ไม่ได้ผลทำไมคำตอบที่แนะนำจึงResponse.End()อยู่ที่บรรทัดสุดท้ายด้วย? แทนคำตอบจาก @Binny (ด้านล่าง) ช่วยด้วย!
user3454439

1
ตามเอกสารที่docs.microsoft.com/en-us/dotnet/api/system.web.httpresponse.end Request.End ได้รับการสนับสนุนสำหรับความเข้ากันได้แบบย้อนหลังเท่านั้น แนะนำให้ใช้ CompleteRequest แทน
Rudolf Dvoracek

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

1
สาเหตุที่คุณกำลังจับและซ่อนข้อยกเว้น
Dan Friedman

3
ช่างเป็นทางออกที่น่าสยดสยอง
มีดโกน

4

ดูเหมือนจะเป็นคำถามเดียวกันกับ:

เมื่อเรียกใช้ ASP.NET System.Web.HttpResponse.End () เธรดปัจจุบันจะถูกยกเลิก?

ดังนั้นจึงเป็นไปตามการออกแบบ คุณต้องเพิ่มการจับสำหรับข้อยกเว้นนั้นและ "ละเว้น" อย่างสง่างาม


ฉันเรียกมันว่าฟังก์ชัน ExportDataSet (DataSet ds) ที่เป็นโมฆะสาธารณะในหลาย ๆ หน้าจอ aspx และฉันยังคงรักษาวิธีการบันทึกข้อผิดพลาดสำหรับข้อยกเว้นที่เพิ่มขึ้นในรันไทม์ที่ถูกต้องข้อยกเว้นเหล่านั้นจะถูกเขียนลงในไฟล์. txt ดังนั้นข้อยกเว้นเดียวกันนี้จึงถูกบันทึกในไฟล์ txt ของหน้าจอ aspx ทั้งหมดฉันแค่ต้องการหลีกเลี่ยงข้อยกเว้นนี้ที่โยนจากไฟล์คลาสที่ประกาศไปยังวิธี aspx ฉันแค่ต้องการจัดการข้อยกเว้นนี้ที่ไฟล์คลาสการประกาศเมธอดของฉันเอง
user3171957

ตามความคิดเห็นจากผู้ใช้ในคำถามของคุณเพียงแค่จับ TheadAbortException -> catch (ThreadAbortException) {}
robnick

ใช่จับข้อยกเว้นนั้นในไฟล์คลาสการประกาศเมธอดด้วยตนเอง
user3171957

4

ย้าย Response.End () ไปที่ด้านนอกของบล็อก Try / Catch and Using

สมมติว่าคุณโยนข้อยกเว้นเพื่อข้ามส่วนที่เหลือของคำขอคุณก็ไม่คิดว่าจะจับได้

bool endRequest = false;

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

if (endRequest)
    Resonse.End();

ทำไมไม่วางไว้ในบล็อกสุดท้ายมันจึงถูกเรียกใช้งานเสมอ?
GoldBishop

คุณสามารถทำได้โดยเฉพาะอย่างยิ่งถ้าคุณมีคำสั่ง return ใน try block แต่ถ้าคุณพยายาม / จับ / เพิกเฉยคุณก็ไม่จำเป็นต้องใช้ในที่สุด สิ่งสำคัญคือคุณไม่ควรจับ ThreadAbortException
Steve

จริงอยู่ TAE เป็น PITA สำหรับการตอบกลับที่ประสบความสำเร็จ
GoldBishop

3

เพียงแค่ใส่ไฟล์

Response.End();

ภายในบล็อกสุดท้ายแทนที่จะอยู่ในบล็อกลอง

ได้ผลสำหรับฉัน !!!.

ฉันมีโครงสร้างโค้ดที่มีปัญหาต่อไปนี้ (พร้อมข้อยกเว้น)

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

   return;

 } 

 some_more_code...

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

}
catch(Exception){
}
finally{}

และมันพ่นข้อยกเว้น ฉันสงสัยว่ามีการยกเว้น Exception ที่มีรหัส / งานที่ต้องดำเนินการหลังจากการตอบสนอง End (); . ในกรณีของฉันรหัสพิเศษเป็นเพียงการส่งคืนเท่านั้น

เมื่อฉันเพิ่งย้ายการตอบกลับ End (); ไปยังบล็อกสุดท้าย (และปล่อยให้ผลตอบแทนกลับมาแทนที่ - ซึ่งทำให้ข้ามส่วนที่เหลือของโค้ดในบล็อกลองและข้ามไปที่บล็อกสุดท้าย (ไม่ใช่แค่ออกจากฟังก์ชันที่มี)) ข้อยกเว้นจะหยุดลง

ต่อไปนี้ทำงานได้ดี:

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

   return;

 } 

 some_more_code...

 Reponse.Write(...);

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

3

ใช้บล็อกจับพิเศษสำหรับข้อยกเว้นของเมธอดResponse.End ()

{
    ...
    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 ()ถ้าคุณสร้าง filehandler


2

สำหรับฉันใช้งานได้เท่านั้น

HttpContext.Current.ApplicationInstance.CompleteRequest ()

https://stackoverflow.com/a/21043051/1828356


1
ตามเอกสารที่docs.microsoft.com/en-us/dotnet/api/system.web.httpresponse.end Request.End ได้รับการสนับสนุนสำหรับความเข้ากันได้แบบย้อนหลังเท่านั้น แนะนำให้ใช้ CompleteRequest แทน
Rudolf Dvoracek


1

ข้อผิดพลาดสำหรับ Response.END (); เป็นเพราะคุณใช้แผงการอัปเดต asp หรือการควบคุมใด ๆ ที่ใช้จาวาสคริปต์ให้ลองใช้การควบคุมเนทีฟจาก asp หรือ html โดยไม่ใช้จาวาสคริปต์หรือโปรแกรมจัดการสคริปต์หรือสคริปต์แล้วลองอีกครั้ง


1

นี่ไม่ใช่ปัญหา แต่เกิดจากการออกแบบ สาเหตุหลักมีอธิบายไว้ในหน้าการสนับสนุนของ Microsoft

เมธอด Response.End จะสิ้นสุดการเรียกใช้เพจและเลื่อนการดำเนินการเป็นเหตุการณ์ Application_EndRequest ในไปป์ไลน์เหตุการณ์ของแอ็พพลิเคชัน บรรทัดของโค้ดที่ตามหลัง Response.End จะไม่ดำเนินการ

โซลูชันที่ให้มาคือ:

สำหรับ Response.End เรียกเมธอด HttpContext.Current.ApplicationInstance.CompleteRequest แทน Response.End เพื่อข้ามการเรียกใช้โค้ดไปยังเหตุการณ์ Application_EndRequest

นี่คือลิงค์: https://support.microsoft.com/en-us/help/312629/prb-threadabortexception-occurs-if-you-use-response-end--response-redi



0

ฉันใช้การเปลี่ยนแปลงข้างต้นทั้งหมด แต่ก็ยังคงได้รับปัญหาเดียวกันกับเว็บแอปพลิเคชันของฉัน

จากนั้นฉันติดต่อโฮสต์ของฉันและขอให้พวกเขาตรวจสอบว่าซอฟต์แวร์หรือโปรแกรมป้องกันไวรัสใด ๆ ที่บล็อกไฟล์ของเราเพื่อถ่ายโอนผ่าน HTTP หรือ ISP / เครือข่ายไม่อนุญาตให้ถ่ายโอนไฟล์

พวกเขาตรวจสอบการตั้งค่าเซิร์ฟเวอร์และข้าม "Data Center Shared Firewall" สำหรับเซิร์ฟเวอร์ของฉันและตอนนี้แอปพลิเคชันของเราสามารถดาวน์โหลดไฟล์ได้แล้ว

หวังว่าคำตอบนี้จะช่วยใครบางคนนี่คือสิ่งที่ได้ผลสำหรับฉัน


แม้ว่าอาจใช้งานได้ แต่ก็ไม่ได้เป็นวิธีแก้ปัญหาที่มั่นคง คุณกำลังบอกว่าไฟร์วอลล์ถูกปิดใช้งานอย่างสมบูรณ์หรือไม่? นั่นจะเป็น "ไม่" ที่ยิ่งใหญ่ หรือปรับแต่งสำหรับแอปพลิเคชันของคุณหรือไม่ ยังแปลกที่เห็น ThreadAbortException ในบางสิ่งที่ไฟร์วอลล์ดาต้าเซ็นเตอร์บล็อก ... กล่าวอีกนัยหนึ่งไม่ใช่คำตอบสำหรับคำถาม?
Michael


0

ฉันแนะนำวิธีแก้ปัญหานี้:

  1. อย่าใช้ response.End();

  2. ประกาศตัวแปรทั่วโลกนี้: bool isFileDownLoad;

  3. หลังจากที่คุณ (response.Write(sw.ToString());) set ==> isFileDownLoad = true;

  4. แทนที่ Render ของคุณเช่น:

    /// 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.