如何避免Response.End()“线程被中止” Excel文件下载过程中的异常


96

我试图将数据集转换为excel并下载该excel。我获得了所需的excel文件。但是每次excel下载都会引发System.Threading.ThreadAbortException。如何解决此问题?..请帮助我...

我在aspx屏幕上调用此方法。此方法也引发了相同的异常。

我在许多aspx屏幕中都将其称为public void ExportDataSet(DataSet ds)函数,并且我还在为运行时引发的异常维护错误记录器方法,将这些异常写入.txt文件中。因此,相同的异常记录在所有aspx屏幕的txt文件中。我只是想在方法声明类文件本身中处理此异常。

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.End请参阅stackoverflow.com/a/3917180/2864740(和其他答案);请注意,该异常是“可以预料的”,因为它是取消堆栈堆栈的方式(因此请不要捕获该异常)。如果您仍然想捕获[other]例外,请使用:.. catch (ThreadAbortException) { throw; /* propagate */ } catch (Exception ex) { .. }
2014年

出于好奇,您正在使用什么记录器
rogue39nin

Answers:


195

我在网上进行了调查,发现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服务构造函数添加一些授权检查,那么这段代码非常有用
vadim

这对我有用。我用建议的代码替换了.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/zh-cn/dotnet/api/system.web.httpresponse.end上的文档,Request.End仅受向后兼容性支持。建议使用CompleteRequest作为替代品
Rudolf Dvoracek '18年

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
因为您正在捕获并隐藏异常。
丹·弗里德曼

3
多么可怕的解决方案
Razor

4

看起来与以下问题相同:

当调用ASP.NET System.Web.HttpResponse.End()时,当前线程是否中止?

所以这是设计使然。您需要为该异常添加一个捕获并优雅地“忽略”它。


我在许多aspx屏幕中都将其称为public void ExportDataSet(DataSet ds)函数,并且我还在为运行时引发的异常维护错误记录器方法,将这些异常写入.txt文件中。因此,相同的异常记录在所有aspx屏幕的txt文件中。我只想避免此异常从方法声明的类文件抛出到aspx。我只是想在我的方法声明类文件本身中处理此异常。
user3171957

根据用户对您问题的评论,只需捕获TheadAbortException-> catch(ThreadAbortException){}
robnick

是的,可以在Method声明类文件self中捕获该异常。
user3171957年

4

将Response.End()移到Try / Catch和Using块之外。

假设抛出一个Exception来绕过请求的其余部分,而您只是没有想到要捕获它。

bool endRequest = false;

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

if (endRequest)
    Resonse.End();

为什么不将其放在Final块中,以便始终执行?
GoldBishop

您可以这样做,尤其是在try块中有return语句的情况下。但是,如果您尝试/捕获/忽略,那么您甚至不需要finally。重要的是您不应该捕获ThreadAbortException。
史蒂夫·

的确,TAE是用于返回成功响应的PITA。
GoldBishop

3

只是把

Response.End();

在finally块中而不是try块中。

这对我有用!!

我有以下有问题的代码(带有异常)

...
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块(并将返回值留在原处-这会导致跳过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()



2

我从UpdatePanel中删除了linkbutton,还评论了Response.End()成功!!!


1

Response.END()的错误;是因为您使用的是ASP更新面板或使用javascript的任何控件,请尝试使用无javascript,scriptmanager或脚本编写的来自asp或html的控件,然后重试


1

这不是问题,但这是设计使然。根本原因在Microsoft支持页面中进行了描述。

Response.End方法结束页面执行,并将执行转移到应用程序的事件管道中的Application_EndRequest事件。未执行Response.End之后的代码行。

提供的解决方案是:

对于Response.End,请调用HttpContext.Current.ApplicationInstance.CompleteRequest方法而不是Response.End,以将代码执行绕过Application_EndRequest事件

这是链接:https : //support.microsoft.com/zh-cn/help/312629/prb-threadabortexception-occurs-if-you-use-response-end--response-redi


0

在response.end()之前将响应刷新到客户端

有关Response.Flush方法的更多信息

所以在使用下面的代码之前 response.End();

response.Flush();  

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);
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.