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
   {                
   }
}
user3171957
źródło
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.
user3412640
źródło
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

Binny
źródło
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ć”.

robnick
źródło
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();
Steve
źródło
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();
}
user2265251
źródło
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

SoliQuiD
źródło
2

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

nunopacheco
źródło
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

Ivan Renteria Vidal
źródło
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

Anjani
źródło
0

opróżnij odpowiedź do klienta przed response.end ()

Więcej o metodzie Response.Flush

Więc użyj wcześniej wymienionego poniżej kodu response.End();

response.Flush();  
thejustv
źródło
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

Sushil Jadhav
źródło
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

Znalazłem powód. Jeśli usuniesz panele aktualizacji, wszystko będzie dobrze!

WSJayaruwan Sumathirathne
źródło
4
powinien być w komentarzu
TarangP
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);
    } 
Abdelrahman ELGAMAL
źródło
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)
        {
        }
    }
that_roy
źródło
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);
}
user13938019
źródło