Pourquoi Response.Redirect provoque System.Threading.ThreadAbortException?

Lorsque j’utilise Response.Redirect (…) pour redirect mon formulaire vers une nouvelle page, j’obtiens l’erreur suivante:

Une première exception au hasard de type ‘System.Threading.ThreadAbortException’ s’est produite dans mscorlib.dll
Une exception de type ‘System.Threading.ThreadAbortException’ s’est produite dans mscorlib.dll mais n’a pas été traitée dans le code utilisateur

Ma compréhension de ceci est que l’erreur est provoquée par le serveur Web abandonnant le rest de la page à laquelle la response.redirect a été appelée.

Je sais que je peux append un second paramètre à Response.Redirect appelé endResponse. Si je mets endResponse sur True, je reçois toujours l’erreur, mais si je le définissez sur False, je ne le ferai pas. Je suis presque sûr que cela signifie que le serveur Web exécute le rest de la page que j’ai redirigé. Ce qui semblerait être inefficace, c’est le moins qu’on puisse dire. Y a-t-il une meilleure manière de faire cela? Quelque chose d’autre que Response.Redirect ou y a-t-il un moyen de forcer l’ancienne page à arrêter de charger là où je n’aurai pas une ThreadAbortException ?

Le modèle correct consiste à appeler la surcharge Redirect avec endResponse = false et à appeler le pipeline IIS pour qu’il passe directement à l’étape EndRequest une fois que vous avez renvoyé le contrôle:

 Response.Redirect(url, false); Context.ApplicationInstance.CompleteRequest(); 

Cet article de Thomas Marquardt fournit des détails supplémentaires, notamment sur la gestion du cas particulier de la redirection à l’intérieur d’un gestionnaire Application_Error.

Il n’y a pas de solution simple et élégante au problème de la Redirect dans ASP.Net WebForms. Vous pouvez choisir entre la solution Dirty et la solution Tedious

Sale : Response.Redirect(url) envoie une redirection au navigateur, puis lance une ThreadAbortedException pour terminer le thread en cours. Donc, aucun code n’est exécuté après l’appel de Redirect (). Inconvénients: C’est une mauvaise pratique et cela a des conséquences sur la performance pour tuer des threads comme celui-ci. En outre, ThreadAbortedExceptions apparaîtra dans la journalisation des exceptions.

Fastidieux : la méthode recommandée est d’appeler Response.Redirect(url, false) et ensuite Context.ApplicationInstance.CompleteRequest() Cependant, l’exécution du code se poursuivra et les autres gestionnaires d’événements du cycle de vie de la page seront toujours exécutés. (Par exemple, si vous exécutez la redirection dans Page_Load, non seulement le rest du gestionnaire sera exécuté, le gestionnaire sanction rangera quant à son nom. Grâce à Page_PreRender, la page restituée ne sera pas envoyée au navigateur. Par exemple, définir un indicateur sur la page, puis laisser les gestionnaires d’événements ultérieurs vérifier cet indicateur avant d’effectuer un traitement.

(La documentation de CompleteRequest indique que cela ” amène ASP.NET à contourner tous les événements et à filtrer dans la chaîne d’exécution du pipeline HTTP “. Cela peut facilement être mal compris. Il ignore les autres filtres et modules HTTP, mais événements dans le cycle de vie de la page en cours.)

Le problème le plus profond est que WebForms manque de niveau d’abstraction. Lorsque vous êtes dans un gestionnaire d’événements, vous êtes déjà en train de créer une page à afficher. La redirection dans un gestionnaire d’événements est moche parce que vous terminez une page partiellement générée afin de générer une page différente. MVC ne rencontre pas ce problème car le stream de contrôle est distinct des vues de rendu. Vous pouvez donc effectuer une redirection propre en retournant simplement une RedirectAction dans le contrôleur sans générer de vue.

Je sais que je suis en retard, mais je n’ai jamais eu cette erreur que si mon Response.Redirect est dans un bloc Try...Catch .

Ne mettez jamais un Response.Redirect dans un bloc Try … Catch. C’est une mauvaise pratique

modifier

En réponse au commentaire de @ Kiquenet, voici ce que je ferais comme alternative à la mise en place de Response.Redirect dans le bloc Try … Catch.

Je diviserais la méthode / fonction en deux étapes.

La première étape du bloc Try … Catch effectue les actions demandées et définit une valeur “result” pour indiquer le succès ou l’échec des actions.

La deuxième étape en dehors du bloc Try … Catch effectue la redirection (ou non) en fonction de la valeur “result”.

Ce code est loin d’être parfait et ne devrait probablement pas être copié car je ne l’ai pas testé

 public void btnLogin_Click(UserLoginViewModel model) { bool ValidLogin = false; // this is our "result value" try { using (Context Db = new Context) { User User = new User(); if (Ssortingng.IsNullOrEmpty(model.EmailAddress)) ValidLogin = false; // no email address was entered else User = Db.FirstOrDefault(x => x.EmailAddress == model.EmailAddress); if (User != null && User.PasswordHash == Hashing.CreateHash(model.Password)) ValidLogin = true; // login succeeded } } catch (Exception ex) { throw ex; // something went wrong so throw an error } if (ValidLogin) { GenerateCookie(User); Response.Redirect("~/Members/Default.aspx"); } else { // do something to indicate that the login failed. } } 

Response.Redirect() lève une exception pour abandonner la requête en cours.

Cet article de la base de Server.Transfer() décrit ce comportement (également pour les méthodes Request.End() et Server.Transfer() ).

Pour Response.Redirect() il existe une surcharge:

 Response.Redirect(Ssortingng url, bool endResponse) 

Si vous transmettez endResponse = false , l’exception n’est pas renvoyée (mais le moteur d’exécution continue à traiter la demande en cours).

Si endResponse = true (ou si l’autre surcharge est utilisée), l’exception est levée et la demande en cours sera immédiatement terminée.

C’est comme ça que fonctionne Response.Redirect (url, true). Il jette le ThreadAbortException pour abandonner le thread. Ignorez simplement cette exception. (Je suppose que c’est un gestionnaire / enregistreur d’erreur global là où vous le voyez?)

Une discussion intéressante sur le sujet Response.End () est-il considéré comme dangereux?

Voici la ligne officielle sur le problème (je n’ai pas trouvé la dernière version, mais je ne pense pas que la situation ait changé pour les versions ultérieures de .net)

J’ai même essayé d’éviter cela, juste au cas où Abort serait exécuté manuellement sur le thread, mais je préfère le laisser avec le “CompleteRequest” et continuer – mon code a quand même des commandes de retour après les redirections. Donc cela peut être fait

 public static void Redirect(ssortingng VPathRedirect, global::System.Web.UI.Page Sender) { Sender.Response.Redirect(VPathRedirect, false); global::System.Web.UI.HttpContext.Current.ApplicationInstance.CompleteRequest(); } 

Ce que je fais, c’est attraper cette exception, avec d’autres exceptions possibles. J’espère que cela aidera quelqu’un.

  catch (ThreadAbortException ex1) { // do nothing } catch(Exception ex) { writeToLog(ex.Message); } 

J’ai aussi essayé une autre solution, mais une partie du code a été exécutée après la redirection.

 public static void ResponseRedirect(HttpResponse iResponse, ssortingng iUrl) { ResponseRedirect(iResponse, iUrl, HttpContext.Current); } public static void ResponseRedirect(HttpResponse iResponse, ssortingng iUrl, HttpContext iContext) { iResponse.Redirect(iUrl, false); iContext.ApplicationInstance.CompleteRequest(); iResponse.BufferOutput = true; iResponse.Flush(); iResponse.Close(); } 

Donc, si besoin d’empêcher l’exécution de code après la redirection

 try { //other code Response.Redirect("") // code not to be executed } catch(ThreadAbortException){}//do there id nothing here catch(Exception ex) { //Logging } 

J’ai eu ce problème aussi. Essayez d’utiliser Server.Transfer au lieu de Response.Redirect Travaillé pour moi