Як уникнути відповіді. End () Виняток “Нитка перервана” під час завантаження файлу Excel


96

Я спробував перетворити свій набір даних в Excel і завантажити цей Excel. Я отримав необхідний файл Excel. Але System.Threading.ThreadAbortException піднімався під час кожного завантаження Excel. Як вирішити цю проблему? .. Будь ласка, допоможіть мені ...

Я викликаю цей метод на моєму екрані aspx.Також цей же виняток викликав цей метод.

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

Просто з цікавості, який саме реєстратор ви використовуєте
rogue39nin

Відповіді:


194

Я досліджував в Інтернеті і побачив, що 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
vadim

Це працювало для мене. Я замінив .End () на запропонований код, і він працює без винятку зараз. Дякую, мій робочий код зараз: Response.ContentType = "text / csv"; Response.AddHeader ("Content-Disposition", string.Format ("вкладення; ім'я файлу = \" {0} \ "", Path.GetFileName (filePath))); Response.TransmitFile (filePath); //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
Яке жахливе рішення
Бритва

4

Схоже, це саме питання:

Коли викликається ASP.NET System.Web.HttpResponse.End (), поточний потік перервано?

Так це за задумом. Вам потрібно додати лову для цього винятку і витончено «ігнорувати» його.


Я називаю цю публічну порожню функцію ExportDataSet (DataSet ds) на багатьох екранах aspx, а також я підтримую метод реєстрації помилок для винятків, які виникають під час виконання, ці винятки записуються у файли .txt. Отже, той самий виняток реєструється у всіх txt-файлах екрана aspx. Я просто хочу уникнути цього винятку, коли файли класу методу оголошені в aspx. Просто я просто хочу обробити цей виняток у самому файлі класу моєї декларації методу.
user3171957

На коментар користувача до вашого запитання, просто впіймайте TheadAbortException -> catch (ThreadAbortException) {}
Робнік

Так, вийміть цей виняток із файлом класу декларації методу, який він сам.
user3171957

4

Перемістіть Response.End () за межі блоків Try / Catch і Use.

Припустимо, кинути виняток, щоб обійти решту запиту, ви просто не повинні були його вловити.

bool endRequest = false;

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

if (endRequest)
    Resonse.End();

чому б не помістити це в блок нарешті, щоб він завжди виконувався?
GoldBishop

Ви могли б це зробити, особливо якщо у вас є оператор return у блоці try. Але якщо ви спробуєте / зловити / проігнорувати, то вам навіть не потрібно нарешті. важливим є те, що ви не повинні ловити ThreadAbortException.
Стів

Правда, 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{}

і викидає виняток. Я підозрюю, що виняток викидається там, де є код / ​​робота для виконання після відповіді.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 (), якщо ви створюєте обробник файлів


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 () Успіх !!!


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

Я рекомендую таке рішення:

  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.