Comment éviter Response.End () "Le thread était en cours d'abandon" Exception lors du téléchargement du fichier Excel

96

J'ai essayé de convertir mon ensemble de données en Excel et de télécharger cet excel. J'ai obtenu mon fichier Excel requis, mais System.Threading.ThreadAbortException a été soulevé à chaque téléchargement Excel. Comment résoudre ce problème? .. Aidez-moi s'il vous plaît ...

J'appelle cette méthode dans mon écran aspx. La même exception a également été levée par cette méthode.

J'appelle cette fonction publique void ExportDataSet (DataSet ds) dans de nombreux écrans aspx et je maintiens également la méthode d'enregistrement des erreurs pour les exceptions qui sont déclenchées au moment de l'exécution, ces exceptions sont écrites dans des fichiers .txt. Donc, cette même exception est enregistrée dans tous les fichiers txt de l'écran aspx.Je veux juste éviter que cette exception ne soit lancée depuis le fichier de classe déclaré par la méthode vers aspx. Je veux simplement gérer cette exception dans mon fichier de classe de déclaration de méthode lui-même.

Appel de méthode de fichier ASPX: excel.ExportDataSet (dsExcel);

Définition de la méthode:

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
la source
2
N'utilisez pas Response.Endvoir stackoverflow.com/a/3917180/2864740 (et les autres réponses); notez que l'exception est "à prévoir" car c'est la façon dont la pile est déroulée (donc n'attrapez pas cette exception). Si vous souhaitez toujours intercepter [autres] exceptions, utilisez:.. catch (ThreadAbortException) { throw; /* propagate */ } catch (Exception ex) { .. }
user2864740
Juste par curiosité quel enregistreur est-ce que vous utilisez
rogue39nin

Réponses:

194

J'ai fait des recherches en ligne et j'ai vu que le Response.End()jette toujours une exception.

Remplacez ceci: HttpContext.Current.Response.End();

Avec ça:

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.
utilisateur3412640
la source
2
Wow une aubaine. Cela m'a sauvé des heures de débogage en utilisant WinDbg. Dans mon cas, mon w3wp.exe vient de planter s'il y a trop de ThreadAbortException
Dio Phung
Merci. Ce morceau de code est vraiment utile si vous souhaitez ajouter une vérification d'autorisation au constructeur de service
asmx
Cela a fonctionné pour moi. J'ai remplacé .End () par le code suggéré et cela fonctionne sans exception maintenant. Merci, Mon code de travail est maintenant: 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
Non, ça ne marche pas pour moi. En fait, regardez la réponse. Si Response.End()cela ne fonctionne pas , pourquoi la réponse suggérée a également Response.End()à la dernière ligne? Au lieu de cela, la réponse de @Binny (ci-dessous) aide!
user3454439
1
Selon la documentation sur docs.microsoft.com/en-us/dotnet/api/system.web.httpresponse.end Request.End est pris en charge uniquement pour la compatibilité descendante. L'utilisation de CompleteRequest est recommandée en remplacement
Rudolf Dvoracek
11

Cela m'a aidé à gérer l' Thread was being abortedexception,

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

si vous utilisez le code suivant au lieu de HttpContext.Current.Response.End(), vous obtiendrez une Server cannot append header after HTTP headers have been sentexception.

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

J'espère que ça aide

Binny
la source
1
Travaille pour moi. Ce n'est pas le cas. En fait, il est drôle que tout Response.End()ne fonctionne pas, mais la méthode suggérée a également Response.End()à la dernière ligne?
user3454439
1
Parce que vous attrapez et cachez l'exception.
Dan Friedman
3
Quelle horrible solution
Razor
4

Cela semble être la même question que:

Lorsqu'un ASP.NET System.Web.HttpResponse.End () est appelé, le thread actuel est abandonné?

C'est donc par conception. Vous devez ajouter une capture pour cette exception et "l'ignorer" gracieusement.

Robnick
la source
J'appelle cette fonction publique void ExportDataSet (DataSet ds) dans de nombreux écrans aspx et je gère également la méthode de journalisation des erreurs pour les exceptions qui sont déclenchées au moment de l'exécution, ces exceptions sont écrites dans des fichiers .txt. Donc, cette même exception est enregistrée dans tous les fichiers txt de l'écran aspx.Je veux juste éviter que cette exception ne jette du fichier de classe déclaré de méthode à aspx. Je veux simplement gérer cette exception dans mon fichier de classe de déclaration de méthode lui-même.
user3171957
Par commentaire de l'utilisateur dans votre question, attrapez simplement l'exception TheadAbortException -> catch (ThreadAbortException) {}
robnick
Oui, attrapez cette exception avec le fichier de classe de déclaration de méthode lui-même.
user3171957
4

Déplacez le Response.End () vers l'extérieur des blocs Try / Catch et Using.

Il est supposé lancer une exception pour contourner le reste de la requête, vous n'étiez simplement pas supposé l'attraper.

bool endRequest = false;

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

if (endRequest)
    Resonse.End();
Steve
la source
pourquoi ne pas placer cela dans un bloc Enfin, pour qu'il soit toujours exécuté?
GoldBishop
vous pouvez le faire, surtout si vous avez une instruction return dans le bloc try. Mais si vous essayez / attrapez / ignorez, vous n'avez même pas besoin du enfin. la chose importante est que vous ne devez pas attraper le ThreadAbortException.
Steve
Certes, le TAE est un PITA pour renvoyer une réponse réussie.
GoldBishop
3

Il suffit de mettre le

Response.End();

dans un bloc finally plutôt que dans le bloc try.

Cela a fonctionné pour moi !!!.

J'ai eu la structure de code problématique suivante (avec l'exception)

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

   return;

 } 

 some_more_code...

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

}
catch(Exception){
}
finally{}

et il jette l'exception. Je soupçonne que l'exception est lancée là où il y a du code / travail à exécuter après response.End (); . Dans mon cas, le code supplémentaire n'était que le retour lui-même.

Quand je viens de déplacer la réponse.End (); au bloc finally (et a laissé le retour à sa place - ce qui provoque le saut du reste du code dans le bloc try et le saut vers le bloc finally (pas seulement la sortie de la fonction contenant)), l'exception a cessé d'avoir lieu.

Ce qui suit fonctionne bien:

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

   return;

 } 

 some_more_code...

 Reponse.Write(...);

}
catch(Exception){
}
finally{
    Response.End();
}
user2265251
la source
3

Utilisez un bloc catch spécial pour l'exception de la méthode 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);
}

Ou supprimez simplement Response.End () si vous créez un gestionnaire de fichiers

SoliQuiD
la source
2

J'ai supprimé le linkbutton de UpdatePanel et j'ai également commenté le succès Response.End () !!!

Nunopacheco
la source
1

l'erreur pour Response.END (); est parce que vous utilisez un panneau de mise à jour asp ou tout contrôle utilisant javascript, essayez d'utiliser le contrôle natif d'asp ou html sans javascript ou scriptmanager ou script et réessayez

Ivan Renteria Vidal
la source
1

Ce n'est pas un problème, mais c'est par conception. La cause première est décrite dans la page de support Microsoft.

La méthode Response.End met fin à l'exécution de la page et décale l'exécution vers l'événement Application_EndRequest dans le pipeline d'événements de l'application. La ligne de code qui suit Response.End n'est pas exécutée.

La solution fournie est:

Pour Response.End, appelez la méthode HttpContext.Current.ApplicationInstance.CompleteRequest au lieu de Response.End pour contourner l'exécution du code à l'événement Application_EndRequest

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

Anjani
la source
0

vider la réponse au client avant response.end ()

En savoir plus sur la méthode Response.Flush

Utilisez donc le code ci-dessous avant response.End();

response.Flush();  
thejustv
la source
0

J'ai utilisé tous les changements ci-dessus mais j'obtenais toujours le même problème sur mon application Web.

Ensuite, j'ai contacté mon fournisseur d'hébergement et leur ai demandé de vérifier si un logiciel ou un antivirus bloquait nos fichiers à transférer via HTTP. ou le FAI / le réseau n'autorise pas le transfert de fichier.

Ils ont vérifié les paramètres du serveur et contourné le "Pare-feu partagé du centre de données" pour mon serveur et maintenant notre application est capable de télécharger le fichier.

J'espère que cette réponse aidera quelqu'un.C'est ce qui a fonctionné pour moi

Sushil Jadhav
la source
Bien que cela puisse fonctionner, cela ne semble pas être une solution solide. Êtes-vous en train de dire que le pare-feu est complètement désactivé? Ce serait un grand "non". Ou est-il personnalisé pour votre application? Aussi bizarre de voir une ThreadAbortException sur quelque chose que le pare-feu du centre de données bloque… En d'autres termes, pas de réponse à la question?
Michael
0

J'ai trouvé la raison. Si vous supprimez les panneaux de mise à jour, tout fonctionne bien!

WSJayaruwan Sumathirathne
la source
4
devrait être en commentaire
TarangP
0

Je recommande cette solution:

  1. Ne pas utiliser response.End();

  2. Déclarez cette variable globale: bool isFileDownLoad;

  3. Juste après votre (response.Write(sw.ToString());) set ==> isFileDownLoad = true;

  4. Remplacez votre rendu comme:

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

J'ai trouvé que ce qui suit fonctionnait mieux ...

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

Pour moi, cela m'a aidé à enregistrer un bouton qui appelle le code derrière le code en tant que contrôle de publication.

protected void Page_Init(object sender, EventArgs e)
{
    ScriptManager.GetCurrent(this.Page).RegisterPostBackControl(btnMyExport);
}
user13938019
la source