Jak uniknąć Response.End () „Wątek został przerwany” Wyjątek podczas pobierania pliku Excel


96

Próbowałem przekonwertować mój zestaw danych do programu Excel i pobrać ten plik Excel. Otrzymałem wymagany plik programu Excel, ale System.Threading.ThreadAbortException był podnoszony przy każdym pobieraniu programu Excel. Jak rozwiązać ten problem? .. Pomóż mi ...

Wywołuję tę metodę na moim ekranie aspx.There także ten sam wyjątek został zgłoszony przez tę metodę.

Wywołuję tę publiczną funkcję void ExportDataSet (DataSet ds) na wielu ekranach aspx, a także utrzymuję metodę rejestratora błędów dla wyjątków, które są zgłaszane w czasie wykonywania, a te wyjątki są zapisywane w plikach .txt. Tak więc ten sam wyjątek jest rejestrowany we wszystkich plikach txt ekranu aspx.I chcę tylko uniknąć tego wyjątku zgłasza z pliku klasy zadeklarowanej metody do aspx. Po prostu chcę obsłużyć ten wyjątek w moim pliku klasy deklaracji metody.

Wywołanie metody pliku ASPX: excel.ExportDataSet (dsExcel);

Definicja metody:

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
Nie używaj Response.Endzobaczyć stackoverflow.com/a/3917180/2864740 (i innych wskazań); zwróć uwagę, że wyjątek jest „oczekiwany”, ponieważ jest to sposób rozwijania stosu (więc nie łapaj tego wyjątku). Jeśli nadal chcesz złapać [inne] wyjątki, użyj:.. catch (ThreadAbortException) { throw; /* propagate */ } catch (Exception ex) { .. }
user2864740

Tylko ciekawość, jakiego loggera używasz
rogue39nin

Odpowiedzi:


195

Poszukałem informacji w Internecie i zobaczyłem, że Response.End()zawsze rzuca wyjątek.

Zastąp to: HttpContext.Current.Response.End();

Z tym:

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, wybawienie. Zaoszczędziło mi to godzin debugowania przy użyciu WinDbg. W moim przypadku mój w3wp.exe właśnie się zawiesił, jeśli jest zbyt wiele ThreadAbortException
Dio Phung

Dzięki. Ten fragment kodu jest naprawdę pomocny, jeśli chcesz dodać sprawdzanie autoryzacji do konstruktora usługi asmx
vadim

To zadziałało dla mnie. Zastąpiłem .End () sugerowanym kodem i teraz działa bez wyjątku. Dziękuję! Mój działający kod to teraz: Response.ContentType = "text / csv"; Response.AddHeader ("Content-Disposition", string.Format ("załącznik; 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
Nie. Nie działa na mnie. Właściwie spójrz na odpowiedź. Jeśli Response.End()nie nie działa, dlaczego proponowana odpowiedź również Response.End()w ostatniej linii? Zamiast tego pomaga odpowiedź od @Binny (poniżej)!
user3454439

1
Zgodnie z dokumentacją pod adresem docs.microsoft.com/en-us/dotnet/api/system.web.httpresponse.end Request.End jest obsługiwane tylko w celu zapewnienia zgodności z poprzednimi wersjami. Zalecane jest użycie CompleteRequest jako zamiennika
Rudolf Dvoracek

11

To pomogło mi poradzić sobie z Thread was being abortedwyjątkiem,

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

jeśli zamiast tego HttpContext.Current.Response.End()użyjesz następującego kodu , otrzymasz Server cannot append header after HTTP headers have been sentwyjątek.

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

Mam nadzieję, że to pomoże


1
Pracuje dla mnie. Powyższe nie. Właściwie to zabawne, że co Response.End()prawda nie działa, ale sugerowana metoda działa też Response.End()w ostatniej linijce?
user3454439

1
Ponieważ łapiesz i ukrywasz wyjątek.
Dan Friedman,

3
Co za okropne rozwiązanie
Razor

4

Wygląda na to samo pytanie, co:

Gdy wywoływana jest metoda ASP.NET System.Web.HttpResponse.End (), bieżący wątek jest przerywany?

Więc to jest zgodne z projektem. Musisz dodać haczyk dla tego wyjątku i wdzięcznie go „zignorować”.


Wywołuję tę publiczną funkcję void ExportDataSet (DataSet ds) na wielu ekranach aspx, a także utrzymuję metodę rejestratora błędów dla wyjątków, które są zgłaszane w czasie wykonywania, a te wyjątki są zapisywane w plikach .txt. Tak więc ten sam wyjątek jest rejestrowany we wszystkich plikach txt ekranu aspx. Chcę tylko uniknąć tego wyjątku zgłasza z pliku klasy zadeklarowanej metody do aspx. Po prostu chcę obsłużyć ten wyjątek w moim pliku klasy deklaracji metody.
user3171957

Za komentarz użytkownika w swoim pytaniu, po prostu złap TheadAbortException -> catch (ThreadAbortException) {}
robnick

Tak, złap ten wyjątek w pliku klasy deklaracji metody.
user3171957

4

Przenieś Response.End () poza bloki Try / Catch i Using.

Przypuszcza się, że rzuca wyjątek, aby ominąć resztę żądania, po prostu nie miałeś go złapać.

bool endRequest = false;

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

if (endRequest)
    Resonse.End();

dlaczego nie umieścić tego w bloku Final, aby zawsze był wykonywany?
GoldBishop

mógłbyś to zrobić, zwłaszcza jeśli masz instrukcję return w bloku try. Ale jeśli spróbujesz / złapać / zignorować, nie potrzebujesz nawet ostatecznego. ważne jest, aby nie przechwytywać wyjątku ThreadAbortException.
Steve

To prawda, że ​​TAE to PITA za zwrot pomyślnej odpowiedzi.
GoldBishop

3

Po prostu włóż

Response.End();

w ostatnim bloku zamiast w bloku try.

To zadziałało dla mnie !!!.

Miałem następującą problematyczną (z wyjątkiem) strukturę kodu

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

   return;

 } 

 some_more_code...

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

}
catch(Exception){
}
finally{}

i zgłasza wyjątek. Podejrzewam, że wyjątek jest generowany, gdy istnieje kod / praca do wykonania po odpowiedzi.End (); . W moim przypadku dodatkowym kodem był sam zwrot.

Kiedy właśnie przeniosłem odpowiedź.End (); do ostatniego bloku (i pozostawił powrót na swoim miejscu - co powoduje pominięcie reszty kodu w bloku try i przeskoczenie do ostatniego bloku (a nie tylko wyjście z funkcji zawierającej)) wyjątek przestał mieć miejsce.

Następujące działa OK:

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

   return;

 } 

 some_more_code...

 Reponse.Write(...);

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

3

Użycie specjalnego bloku złapać za wyjątkiem Response.End () Sposób

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

Lub po prostu usuń Response.End (), jeśli budujesz program do obsługi plików



2

Usunąłem linkbutton z UpdatePanel i skomentowałem również Response.End () Success !!!


1

błąd dla Response.END (); Dzieje się tak, ponieważ używasz panelu aktualizacji asp lub dowolnego elementu sterującego, który używa javascript, spróbuj użyć natywnej kontroli z asp lub html bez javascript lub scriptmanager lub skryptów i spróbuj ponownie


1

To nie jest problem, ale jest to zamierzone. Główna przyczyna jest opisana na stronie pomocy technicznej firmy Microsoft.

Metoda Response.End kończy wykonywanie strony i przenosi wykonanie do zdarzenia Application_EndRequest w potoku zdarzeń aplikacji. Wiersz kodu następujący po Response.End nie jest wykonywany.

Dostarczone rozwiązanie to:

W przypadku Response.End wywołaj metodę HttpContext.Current.ApplicationInstance.CompleteRequest zamiast Response.End, aby ominąć wykonanie kodu do zdarzenia Application_EndRequest

Oto link: https://support.microsoft.com/en-us/help/312629/prb-threadabortexception-occurs-if-you-use-response-end--response-redi



0

Wykorzystałem wszystkie powyższe zmiany, ale nadal otrzymywałem ten sam problem w mojej aplikacji internetowej.

Następnie skontaktowałem się z moim dostawcą usług hostingowych i poprosiłem ich o sprawdzenie, czy jakieś oprogramowanie lub program antywirusowy blokuje nasze pliki do przesyłania przez HTTP. lub ISP / sieć nie zezwala na przesyłanie plików.

Sprawdzili ustawienia serwera i ominęli "Data Center Shared Firewall" dla mojego serwera, a teraz nasza aplikacja może pobrać plik.

Mam nadzieję, że ta odpowiedź komuś pomoże. To właśnie zadziałało dla mnie


Choć może działać, nie brzmi jak solidne rozwiązanie. Czy mówisz, że zapora jest całkowicie wyłączona? To byłoby duże „nie”. A może jest dostosowany do Twojej aplikacji? Dziwne jest również zobaczenie wyjątku ThreadAbortException na czymś, co blokuje zapora centrum danych… Innymi słowy, nie ma odpowiedzi na pytanie?
Michael


0

Polecam to rozwiązanie:

  1. Nie używaj response.End();

  2. Zadeklaruj tę zmienną globalną: bool isFileDownLoad;

  3. Zaraz po twoim (response.Write(sw.ToString());) set ==> isFileDownLoad = true;

  4. Zastąp Render jak:

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

0

Okazało się, że poniższe działa lepiej ...

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

0

U mnie pomogło zarejestrowanie przycisku, który wywołuje kod za kodem jako formant ogłaszania zwrotnego.

protected void Page_Init(object sender, EventArgs e)
{
    ScriptManager.GetCurrent(this.Page).RegisterPostBackControl(btnMyExport);
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.