Как избежать 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
   {                
   }
}
user3171957
источник
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.
user3412640
источник
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();
}
user2265251
источник
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 (), если вы создаете обработчик файлов

SoliQuiD
источник
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 !!!

Nunopacheco
источник
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

сбросить ответ клиенту перед response.end ()

Подробнее о методе Response.Flush

Поэтому используйте приведенный ниже код перед response.End();

response.Flush();  
справедливость
источник
0

Я использовал все вышеупомянутые изменения, но все же у меня возникала такая же проблема в моем веб-приложении.

Затем я связался со своим провайдером хостинга и попросил их проверить, не блокирует ли какое-либо программное обеспечение или антивирус наши файлы для передачи через HTTP. или Интернет-провайдер / сеть не разрешает передачу файла.

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

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

Сушил Джадхав
источник
Хотя это может сработать, это не кажется надежным решением. Вы говорите, что брандмауэр полностью отключен? Это было бы большим «нет». Или он настроен для вашего приложения? Также странно видеть исключение ThreadAbortException на том, что блокирует брандмауэр центра обработки данных ... Другими словами, это не ответ на вопрос?
Майкл
0

Я нашел причину. Если вы удалите панели обновления, все работает нормально!

WSJayaruwan Sumathirathne
источник
4
должен быть в комментарии
TarangP
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)
        {
        }
    }
that_roy
источник
0

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

protected void Page_Init(object sender, EventArgs e)
{
    ScriptManager.GetCurrent(this.Page).RegisterPostBackControl(btnMyExport);
}
пользователь13938019
источник