Làm thế nào để tránh phản hồi.End () “Luồng đã bị hủy bỏ” Ngoại lệ trong quá trình tải xuống tệp Excel


96

Tôi đã cố gắng chuyển đổi tập dữ liệu của mình thành excel và tải xuống excel đó. Tôi đã nhận được tệp excel cần thiết của mình. Nhưng System.Threading.ThreadAbortException đã được nâng lên sau mỗi lần tải xuống excel. Làm thế nào để giải quyết vấn đề này? .. Xin hãy giúp tôi ...

Tôi gọi phương thức này trong màn hình aspx của mình, cũng có một ngoại lệ tương tự được đưa ra bởi phương thức này.

Tôi gọi hàm public void ExportDataSet (DataSet ds) đó trong nhiều màn hình aspx và tôi cũng đang duy trì phương pháp ghi lỗi cho các ngoại lệ được đưa ra trong thời gian chạy ngay những ngoại lệ đó được ghi vào tệp .txt. Vì vậy, cùng một ngoại lệ đó được đăng nhập vào tất cả các tệp txt của màn hình aspx. Tôi chỉ muốn tránh ngoại lệ này ném từ tệp lớp được khai báo phương thức sang aspx. Đơn giản là tôi chỉ muốn xử lý ngoại lệ này tại chính tệp lớp khai báo phương thức của mình.

Phương thức tệp ASPX gọi: excel.ExportDataSet (dsExcel);

Định nghĩa phương pháp:

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
Không sử dụng Response.Endxem stackoverflow.com/a/3917180/2864740 (và các câu trả lời khác); lưu ý rằng ngoại lệ là "được mong đợi" vì nó là cách ngăn xếp được mở ra (vì vậy đừng nắm bắt ngoại lệ đó). Nếu bạn vẫn muốn bắt [khác] trường hợp ngoại lệ, sử dụng:.. catch (ThreadAbortException) { throw; /* propagate */ } catch (Exception ex) { .. }
user2864740

Chỉ tò mò bạn đang sử dụng trình ghi nhật ký nào
rogue39 trong

Câu trả lời:


194

Tôi nghiên cứu trực tuyến và thấy rằng Response.End()luôn luôn ném ra một ngoại lệ.

Thay thế cái này: HttpContext.Current.Response.End();

Với cái này:

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
Wow một ơn trời. Nó giúp tôi tiết kiệm hàng giờ gỡ lỗi bằng WinDbg. Trong trường hợp của tôi, w3wp.exe của tôi chỉ bị rơi nếu có quá nhiều ThreadAbortException
Dio Phùng

Cảm ơn. Đoạn mã này thực sự hữu ích nếu bạn muốn thêm một số kiểm tra ủy quyền vào phương thức khởi tạo dịch vụ asmx
vadim

Điều này đã làm việc cho tôi. Tôi đã thay thế .End () bằng mã đề xuất và nó hoạt động mà không có ngoại lệ bây giờ. Cảm ơn Bạn, Mã làm việc của tôi bây giờ là: Response.ContentType = "text / csv"; Response.AddHeader ("Nội dung-Bố trí", string.Format ("tệp đính kèm; tên tệp = \" {0} \ "", Path.GetFileName (tệp đường dẫn))); Response.TransmitFile (filePath); //Response.End (); HttpContext.Current.Response.Flush (); HttpContext.Current.Response.SuppressContent = true; HttpContext.Current.ApplicationInstance.CompleteRequest ();
Nour Lababidi

3
Không. Không hiệu quả với tôi. Trên thực tế, hãy nhìn vào câu trả lời. Nếu Response.End()không không làm việc, tại sao câu trả lời gợi ý cũng có Response.End()ở dòng cuối cùng? Thay vào đó, câu trả lời từ @Binny (bên dưới) sẽ hữu ích!
user3454439

1
Theo tài liệu tại docs.microsoft.com/en-us/dotnet/api/system.web.httpresponse.end Request.End chỉ được hỗ trợ để tương thích ngược. CompleteRequest sử dụng được khuyến cáo như là thay thế
Rudolf Dvoracek

11

Điều này đã giúp tôi xử lý Thread was being abortedngoại lệ,

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

nếu bạn sử dụng mã sau thay vì mã sau HttpContext.Current.Response.End(), bạn sẽ nhận được Server cannot append header after HTTP headers have been sentngoại lệ.

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

Hy vọng nó giúp


1
Làm việc cho tôi. Ở trên không. Trên thực tế, thật buồn cười là trong khi Response.End()không hoạt động, nhưng phương pháp gợi ý cũng có Response.End()ở dòng cuối cùng?
user3454439

1
Vì bạn đang bắt và ẩn ngoại lệ.
Dan Friedman

3
Thật là một giải pháp khủng khiếp
Razor

4

Có vẻ như câu hỏi giống như:

Khi một ASP.NET System.Web.HttpResponse.End () được gọi, luồng hiện tại bị hủy bỏ?

Vì vậy, đó là do thiết kế. Bạn cần thêm một lệnh bắt cho ngoại lệ đó và "bỏ qua" nó một cách duyên dáng.


Tôi gọi đó là hàm public void ExportDataSet (DataSet ds) trong nhiều màn hình aspx và tôi cũng đang duy trì phương pháp ghi lỗi cho các ngoại lệ được đưa ra trong thời gian chạy ngay những ngoại lệ đó được ghi vào tệp .txt. Vì vậy, cùng một ngoại lệ đó được đăng nhập vào tất cả các tệp txt của màn hình aspx. Tôi chỉ muốn tránh ngoại lệ này ném từ tệp lớp được khai báo phương thức sang aspx. Đơn giản là tôi chỉ muốn xử lý ngoại lệ này tại chính tệp lớp khai báo phương thức của mình.
user3171957

Mỗi nhận xét từ người dùng trong câu hỏi của bạn, chỉ cần bắt TheadAbortException -> catch (ThreadAbortException) {}
robnick

Có bắt ngoại lệ đó với trong tệp lớp khai báo Phương thức tự nó.
user3171957

4

Di chuyển Response.End () ra bên ngoài các khối Thử / Bắt và Sử dụng.

Giả sử bạn ném một Ngoại lệ để bỏ qua phần còn lại của yêu cầu, bạn chỉ không cho là bắt được nó.

bool endRequest = false;

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

if (endRequest)
    Resonse.End();

tại sao không đặt nó trong khối Cuối cùng để nó luôn được thực thi?
GoldBishop

bạn có thể làm điều đó, đặc biệt nếu bạn có câu lệnh trả về trong khối try. Nhưng nếu bạn cố gắng / bắt / bỏ qua thì bạn thậm chí không cần cuối cùng. điều quan trọng là bạn không nên bắt ThreadAbortException.
Steve

Đúng, TAE là PITA để trả lại một Phản hồi thành công.
GoldBishop

3

Chỉ cần đặt

Response.End();

trong một khối cuối cùng thay vì trong khối thử.

Điều này đã làm việc cho tôi !!!.

Tôi có cấu trúc mã có vấn đề (với ngoại lệ) sau đây

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

   return;

 } 

 some_more_code...

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

}
catch(Exception){
}
finally{}

và nó ném ngoại lệ. Tôi nghi ngờ rằng Ngoại lệ được ném ở nơi có mã / công việc để thực thi sau phản hồi.End (); . Trong trường hợp của tôi, mã bổ sung chỉ là trả về.

Khi tôi vừa di chuyển response.End (); đến khối cuối cùng (và để nguyên giá trị trả về - điều này khiến việc bỏ qua phần còn lại của mã trong khối thử và chuyển đến khối cuối cùng (không chỉ thoát khỏi hàm chứa))) Ngoại lệ không còn diễn ra.

Những điều sau đây hoạt động tốt:

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

   return;

 } 

 some_more_code...

 Reponse.Write(...);

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

3

Sử dụng một khối bắt đặc biệt cho ngoại lệ của phương thức 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);
}

Hoặc chỉ cần loại bỏ Response.End () nếu bạn đang xây dựng một trình xử lý tệp



2

Tôi đã xóa nút liên kết khỏi UpdatePanel và cũng nhận xét Response.End () Thành công !!!


1

lỗi đối với Response.END (); là do bạn đang sử dụng bảng cập nhật asp hoặc bất kỳ điều khiển nào sử dụng javascript, hãy thử sử dụng điều khiển gốc từ asp hoặc html mà không cần javascript hoặc scriptmanager hoặc script và thử lại


1

Đây không phải là vấn đề mà đây là do thiết kế. Nguyên nhân gốc rễ được mô tả trong Trang hỗ trợ của Microsoft.

Phương thức Response.End kết thúc việc thực thi trang và chuyển việc thực thi sang sự kiện Application_EndRequest trong đường dẫn sự kiện của ứng dụng. Dòng mã theo sau Response.End không được thực thi.

Giải pháp được cung cấp là:

Đối với Response.End, hãy gọi phương thức HttpContext.Current.ApplicationInstance.CompleteRequest thay vì Response.End để bỏ qua việc thực thi mã cho sự kiện Application_EndRequest

Đây là liên kết: https://support.microsoft.com/en-us/help/312629/prb-threadabortexception-occurs-if-you-use-response-end--response-redi


0

gửi phản hồi cho máy khách trước khi response.end ()

Tìm hiểu thêm về Phương pháp Response.Flush

Vì vậy, hãy sử dụng mã được đề cập bên dưới trước khi response.End();

response.Flush();  

0

Tôi đã sử dụng tất cả các thay đổi trên nhưng vẫn gặp sự cố tương tự trên ứng dụng web của mình.

Sau đó, tôi đã liên hệ với nhà cung cấp dịch vụ lưu trữ của mình và yêu cầu họ kiểm tra xem có phần mềm hoặc phần mềm chống vi-rút nào chặn tệp của chúng tôi để truyền qua HTTP hay không. hoặc ISP / mạng không cho phép truyền tệp.

Họ đã kiểm tra cài đặt máy chủ & bỏ qua "Tường lửa chia sẻ của Trung tâm dữ liệu" cho máy chủ của tôi và bây giờ ứng dụng của chúng tôi có thể tải xuống tệp.

Hy vọng câu trả lời này sẽ giúp ích cho ai đó. Đây là những gì đã làm việc cho tôi


Mặc dù nó có thể hoạt động, nhưng nó không phải là một giải pháp vững chắc. Bạn nói tường lửa bị vô hiệu hóa hoàn toàn? Đó sẽ là một "không" lớn. Hay nó được tùy chỉnh cho ứng dụng của bạn? Cũng kỳ lạ khi thấy một ThreadAbortException trên thứ mà tường lửa trung tâm dữ liệu chặn… Nói cách khác, không phải là câu trả lời cho câu hỏi?
Michael,


0

Tôi khuyên bạn nên giải pháp này:

  1. Không sử dụng response.End();

  2. Khai báo var toàn cầu này: bool isFileDownLoad;

  3. Chỉ sau của bạn (response.Write(sw.ToString());) set ==> isFileDownLoad = true;

  4. Ghi đè Render của bạn như:

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

0

Tôi thấy rằng cách sau hoạt động tốt hơn ...

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

0

Đối với tôi, nó đã giúp đăng ký một nút gọi mã sau mã như một điều khiển đăng lại.

protected void Page_Init(object sender, EventArgs e)
{
    ScriptManager.GetCurrent(this.Page).RegisterPostBackControl(btnMyExport);
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.