Come evitare Response.End () "Il thread è stato interrotto" Eccezione durante il download del file Excel


96

Ho provato a convertire il mio set di dati in Excel e scaricare quell'Excel. Ho ottenuto il mio file Excel richiesto. Ma System.Threading.ThreadAbortException è stata sollevata ogni download di Excel. Come risolvere questo problema? .. Per favore aiutami ...

Chiamo questo metodo nella mia schermata aspx. C'è anche la stessa eccezione generata da questo metodo.

Chiamo quella funzione public void ExportDataSet (DataSet ds) in molte schermate aspx e inoltre sto mantenendo il metodo di registrazione degli errori per le eccezioni che vengono sollevate in fase di esecuzione, proprio quelle eccezioni vengono scritte in un file .txt. Quindi la stessa eccezione viene registrata in tutti i file txt dello schermo aspx.Voglio solo evitare che questa eccezione venga lanciata dal file di classe dichiarato dal metodo ad aspx. Semplicemente voglio solo gestire questa eccezione nel file della classe di dichiarazione del metodo stesso.

Chiamata al metodo file ASPX: excel.ExportDataSet (dsExcel);

Definizione del metodo:

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
Non utilizzare Response.Endvedi stackoverflow.com/a/3917180/2864740 (e le altre risposte); nota che l'eccezione è "prevedibile" poiché è il modo in cui la pila viene srotolata (quindi non catturare quell'eccezione). Se desideri ancora .. catch (ThreadAbortException) { throw; /* propagate */ } catch (Exception ex) { .. }
rilevare

Solo per curiosità quale logger stai usando
rogue39nin

Risposte:


194

Ho cercato online e ho visto che il file Response.End() genera sempre un'eccezione.

Sostituisci questo: HttpContext.Current.Response.End();

Con questo:

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 una manna dal cielo. Mi ha fatto risparmiare ore di debug utilizzando WinDbg. Nel mio caso, il mio w3wp.exe si è arrestato in modo anomalo se ci sono troppe ThreadAbortException
Dio Phung

Grazie. Questo pezzo di codice è davvero utile se vuoi aggiungere un po 'di controllo di autorizzazione al costruttore del servizio asmx
vadim

Questo ha funzionato per me. Ho sostituito .End () con il codice suggerito e ora funziona senza eccezioni. Grazie, il mio codice funzionante ora è: Response.ContentType = "text / csv"; Response.AddHeader ("Content-Disposition", string.Format ("attachment; 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
No. Non funziona per me. In realtà guarda la risposta. Se Response.End()non non funziona, perché la risposta suggerita ha anche Response.End()l'ultima riga? Invece la risposta di @Binny (sotto) aiuta!
user3454439

1
Secondo la documentazione su docs.microsoft.com/en-us/dotnet/api/system.web.httpresponse.end Request.End è supportato solo per compatibilità con le versioni precedenti. Si consiglia l'utilizzo di CompleteRequest in sostituzione
Rudolf Dvoracek

11

Questo mi ha aiutato a gestire l' Thread was being abortedeccezione,

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

se usi il seguente codice al posto di HttpContext.Current.Response.End(), otterrai Server cannot append header after HTTP headers have been sentun'eccezione.

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

Spero che sia d'aiuto


1
Per me va bene. Quanto sopra non lo fa. In realtà è divertente che mentre Response.End()non funziona, ma il metodo suggerito ha anche Response.End()l'ultima riga?
user3454439

1
Perché stai catturando e nascondendo l'eccezione.
Dan Friedman

3
Che soluzione orribile
Razor

4

Sembra essere la stessa domanda di:

Quando viene chiamato un System.Web.HttpResponse.End () ASP.NET, il thread corrente viene interrotto?

Quindi è in base alla progettazione. È necessario aggiungere una cattura per quell'eccezione e "ignorarla" con garbo.


Chiamo quella funzione public void ExportDataSet (DataSet ds) in molte schermate aspx e inoltre sto mantenendo il metodo del logger degli errori per le eccezioni che vengono sollevate in fase di esecuzione a destra quelle eccezioni sono scritte in un file .txt. Quindi la stessa eccezione viene registrata in tutti i file txt dello schermo aspx.Voglio solo evitare che questa eccezione venga lanciata dal file di classe dichiarato dal metodo ad aspx. Semplicemente voglio solo gestire questa eccezione nel file della classe di dichiarazione del metodo stesso.
user3171957

Per commento dell'utente nella tua domanda, prendi semplicemente TheadAbortException -> catch (ThreadAbortException) {}
robnick

Sì, cattura l'eccezione con nel file di classe di dichiarazione del metodo stesso.
user3171957

4

Spostare Response.End () all'esterno dei blocchi Try / Catch e Using.

Si suppone di lanciare un'eccezione per bypassare il resto della richiesta, semplicemente non si supponeva di catturarla.

bool endRequest = false;

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

if (endRequest)
    Resonse.End();

perché non metterlo in un blocco Infine, in modo che venga sempre eseguito?
GoldBishop

potresti farlo, specialmente se hai un'istruzione return nel blocco try. Ma se provi / prendi / ignori, non hai nemmeno bisogno del file finalmente. la cosa importante è che non dovresti catturare ThreadAbortException.
Steve il

È vero, il TAE è un PITA per la restituzione di una risposta di successo.
GoldBishop

3

Metti solo il file

Response.End();

all'interno di un blocco finalmente invece che all'interno del blocco try.

Questo ha funzionato per me!!!.

Ho avuto la seguente struttura di codice problematica (con l'eccezione)

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

   return;

 } 

 some_more_code...

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

}
catch(Exception){
}
finally{}

e lancia l'eccezione. Sospetto che l'eccezione venga lanciata dove c'è codice / lavoro da eseguire dopo response.End (); . Nel mio caso il codice extra era solo il ritorno stesso.

Quando ho appena spostato la risposta.End (); al blocco finalmente (e ha lasciato il ritorno al suo posto - il che fa saltare il resto del codice nel blocco try e saltare al blocco finalmente (non solo uscire dalla funzione contenitore)) l'eccezione ha cessato di avere luogo.

Il seguente funziona bene:

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

   return;

 } 

 some_more_code...

 Reponse.Write(...);

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

3

Utilizzare un blocco catch speciale per l'eccezione del metodo 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);
}

Oppure rimuovi semplicemente Response.End () se stai creando un filehandler



2

Ho rimosso il linkbutton dal UpdatePanel e ho anche commentato il Response.End () Success !!!


1

l'errore per Response.END (); è perché stai utilizzando un pannello di aggiornamento asp o qualsiasi controllo che utilizza javascript, prova a utilizzare il controllo nativo da asp o html senza javascript o scriptmanager o script e riprova


1

Questo non è un problema, ma è di progettazione. La causa principale è descritta nella pagina di supporto Microsoft.

Il metodo Response.End termina l'esecuzione della pagina e sposta l'esecuzione all'evento Application_EndRequest nella pipeline degli eventi dell'applicazione. La riga di codice che segue Response.End non viene eseguita.

La soluzione fornita è:

Per Response.End, chiama il metodo HttpContext.Current.ApplicationInstance.CompleteRequest invece di Response.End per ignorare l'esecuzione del codice all'evento Application_EndRequest

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


0

scarica la risposta al client prima di response.end ()

Di più metodo Response.Flush

Quindi usa il codice sotto menzionato prima response.End();

response.Flush();  

0

Ho utilizzato tutte le modifiche di cui sopra, ma continuavo a riscontrare lo stesso problema sulla mia applicazione web.

Quindi ho contattato il mio fornitore di hosting e ho chiesto loro di controllare se qualche software o antivirus bloccava i nostri file da trasferire tramite HTTP. o l'ISP / rete non consente il trasferimento del file.

Hanno controllato le impostazioni del server e bypassato il "Data Center Shared Firewall" per il mio server e ora la nostra applicazione è in grado di scaricare il file.

Spero che questa risposta possa aiutare qualcuno. Questo è ciò che ha funzionato per me


Anche se potrebbe funzionare, non sembra una soluzione solida. Stai dicendo che il firewall è completamente disabilitato? Sarebbe un grande "no". O è personalizzato per la tua applicazione? È anche strano vedere un'eccezione ThreadAbortException su qualcosa che il firewall del datacenter blocca ... In altre parole, non una risposta alla domanda?
Michael


0

Consiglio questa soluzione:

  1. Non usare response.End();

  2. Dichiara questa var globale: bool isFileDownLoad;

  3. Subito dopo il tuo (response.Write(sw.ToString());) set ==> isFileDownLoad = true;

  4. Sostituisci il tuo rendering come:

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

0

Ho scoperto che quanto segue ha funzionato meglio ...

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

0

Per me è stato utile registrare un pulsante che chiama il codice dietro il codice come controllo di postback.

protected void Page_Init(object sender, EventArgs e)
{
    ScriptManager.GetCurrent(this.Page).RegisterPostBackControl(btnMyExport);
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.