Как избежать Response.End () Исключение «Поток прерван» во время загрузки файла Excel


96

Я попытался преобразовать свой набор данных в Excel и загрузить этот Excel. Я получил требуемый файл Excel. Но System.Threading.ThreadAbortException возникала при каждой загрузке Excel. Как решить эту проблему? .. Помогите, пожалуйста ...

Я вызываю этот метод на моем экране aspx. Он также вызывает такое же исключение.

Я вызываю эту общедоступную функцию void ExportDataSet (DataSet ds) на многих экранах aspx, а также поддерживаю метод регистрации ошибок для исключений, которые возникают во время выполнения, и эти исключения записываются в файлы .txt. То же самое исключение регистрируется во всех текстовых файлах экрана aspx. Я просто хочу, чтобы это исключение не генерировалось из файла класса, объявленного методом, в 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.Endсм. Stackoverflow.com/a/3917180/2864740 (и другие ответы); обратите внимание, что исключение «ожидаемо», поскольку именно так раскручивается стек (так что не перехватывайте это исключение). Если вы по-прежнему хотите перехватывать [другие] исключения, используйте:.. catch (ThreadAbortException) { throw; /* propagate */ } catch (Exception ex) { .. }
— user2864740

Просто из любопытства, какой регистратор вы используете
— rogue39nin

Ответы:


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. В моем случае мой w3wp.exe просто вылетел из-за слишком большого количества исключений ThreadAbortException
— Дио Фунг,

Спасибо. Этот фрагмент кода действительно полезен, если вы хотите добавить некоторую проверку авторизации в конструктор службы asmx
— вадим,

Это сработало для меня. Я заменил .End () предложенным кодом, и теперь он работает без исключения. Спасибо, у меня сейчас рабочий код: Response.ContentType = "text / csv"; Response.AddHeader ("Content-Disposition", string.Format ("attachment; filename = \" {0} \ "", Path.GetFileName (filePath))); Response.TransmitFile (путь к файлу); //Response.End (); HttpContext.Current.Response.Flush (); HttpContext.Current.Response.SuppressContent = true; HttpContext.Current.ApplicationInstance.CompleteRequest ();
— Нур Лабабиди

3
Нет. У меня не работает. Собственно посмотрите ответ. Если Response.End()это не работает, почему предложенный ответ имеет также Response.End()в последней строке? Вместо этого помогает ответ от @Binny (ниже)!
— user3454439

1
Согласно документации на docs.microsoft.com/en-us/dotnet/api/system.web.httpresponse.end Request.End поддерживается только для обратной совместимости. В качестве замены рекомендуется использовать CompleteRequest
— Рудольф Дворачек

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 (), текущий поток прерывается?

Так что это задумано. Вам нужно добавить уловку для этого исключения и изящно «игнорировать» его.


Я вызываю эту общедоступную функцию void ExportDataSet (DataSet ds) на многих экранах aspx, а также поддерживаю метод регистрации ошибок для исключений, которые возникают во время выполнения, и эти исключения записываются в файлы .txt. То же самое исключение регистрируется во всех текстовых файлах экрана aspx. Я просто хочу, чтобы это исключение не генерировалось из файла класса, объявленного методом, в aspx. Просто я просто хочу обработать это исключение в самом файле класса объявления метода.
— user3171957 08

За комментарий пользователя в вашем вопросе просто перехватите TheadAbortException -> catch (ThreadAbortException) {}
— robnick

Да, поймать это исключение с помощью файла класса объявления метода.
— user3171957 08

4

Переместите Response.End () за пределы блоков Try / Catch и Using.

Предполагается, что было выбрано исключение, чтобы обойти остальную часть запроса, вы просто не могли его поймать.

bool endRequest = false;

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

if (endRequest)
    Resonse.End();

почему бы не поместить это в блок finally, чтобы он всегда выполнялся?
— GoldBishop

вы могли бы это сделать, особенно если у вас есть оператор return в блоке try. Но если вы попробуете / поймать / проигнорировать, вам даже не понадобится файл finally. Важно то, что вы не должны ловить ThreadAbortException.
— Стив

Правда, TAE - это PITA для возврата успешного ответа.
— GoldBishop 08

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 (и оставил return на своем месте - что приводит к пропуску остальной части кода в блоке try и переходу к блоку finally (а не только к выходу из содержащей функции)) исключение перестало иметь место.

Следующее работает нормально:

...
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 (), если вы создаете обработчик файлов


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
— Рудольф Дворачек

2

Я удалил кнопку ссылки из UpdatePanel, а также прокомментировал Response.End () Success !!!


1

ошибка Response.END (); потому что вы используете панель обновления asp или любой элемент управления, использующий javascript, попробуйте использовать собственный элемент управления из asp или html без javascript или scriptmanager или сценариев и повторите попытку


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. или Интернет-провайдер / сеть не разрешает передачу файла.

Они проверили настройки сервера и обошли «общий брандмауэр центра обработки данных» для моего сервера, и теперь наше приложение может загрузить файл.

Надеюсь, этот ответ кому-то поможет. Это сработало для меня.


Хотя это может сработать, это не кажется надежным решением. Вы говорите, что брандмауэр полностью отключен? Это было бы большим «нет». Или он настроен для вашего приложения? Также странно видеть исключение 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);
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.