Lorsque j'utilise Response.Redirect (...) pour rediriger mon formulaire vers une nouvelle page, le message d'erreur suivant s'affiche:
Une exception de première chance du 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é gérée dans le code utilisateur.
Si j'ai bien compris, l'erreur provient du fait que le serveur Web a abandonné le reste de la page sur laquelle le fichier response.redirect a été appelé.
Je sais que je peux ajouter un deuxième paramètre à Response.Redirect
, appelé endResponse. Si je mets endResponse à True, j'obtiens toujours l'erreur mais si je la mets à False, je ne le fais pas. Je suis à peu près sûr que cela signifie que le serveur Web exécute le reste de la page que je redirige. Ce qui semble être inefficace pour le moins. Y a-t-il une meilleure manière de faire cela? Quelque chose d'autre que Response.Redirect
ou existe-t-il un moyen de forcer l'ancienne page à cesser de charger sans obtenir un ThreadAbortException
?
Le modèle correct consiste à appeler la surcharge de redirect avec endResponse = false et à appeler le pipeline IIS pour lui indiquer qu'il doit passer directement à l'étape EndRequest une fois que vous avez renvoyé le contrôle:
Response.Redirect(url, false);
Context.ApplicationInstance.CompleteRequest();
Cet article de blog de Thomas Marquardt fournit des détails supplémentaires, y compris comment gérer le cas particulier de redirection dans un gestionnaire Application_Error.
Il existe non une solution simple et élégante au problème Redirect
dans ASP.Net WebForms. Vous pouvez choisir entre la solution sale et la solution fastidieuse
Dirty: Response.Redirect(url)
envoie une redirection au navigateur, puis lance un ThreadAbortedException
pour mettre fin au thread actuel. Donc, aucun code n'est exécuté après l'appel à Redirect (). Inconvénients: c'est une mauvaise pratique et des implications en termes de performances de tuer des threads comme celui-ci. De plus, ThreadAbortedExceptions
apparaîtra dans la journalisation des exceptions.
fastidieux: La méthode recommandée consiste à appeler Response.Redirect(url, false)
puis Context.ApplicationInstance.CompleteRequest()
Cependant, l'exécution du code se poursuivra et le reste des gestionnaires d'événements du cycle de vie de la page sera toujours exécuté. (Par exemple, si vous effectuez la redirection dans Page_Load, non seulement le reste du gestionnaire sera exécuté, Page_PreRender, etc., sera également appelé - la page rendue ne sera tout simplement pas envoyée au navigateur. Vous pouvez éviter le traitement supplémentaire en 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 qu'elle " force ASP.NET à ignorer tous les événements et à filtrer dans la chaîne d'exécution du pipeline HTTP ". Cela peut facilement être mal compris: il ignore d'autres filtres et modules HTTP, mais pas d'autres événements dans le cycle de vie actuel de la page .)
Le problème plus profond est que WebForms manque d'un 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 car vous arrêtez une page partiellement générée afin de générer une page différente. MVC n'a pas ce problème puisque le flux de contrôle est séparé des vues de rendu. Vous pouvez donc effectuer une redirection en clair en renvoyant simplement un 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 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
En réponse au commentaire de @ Kiquenet, voici ce que je ferais comme alternative à l'insertion 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 exécute les actions demandées et définit une valeur de "résultat" pour indiquer le succès ou l'échec des actions.
La deuxième étape en dehors du bloc Try ... Catch effectue la redirection (ou ne le fait pas) en fonction de la valeur du "résultat".
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 (String.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 annuler la demande en cours.
Cet article KB décrit ce comportement (également pour les méthodes Request.End()
et Server.Transfer()
).
Pour Response.Redirect()
il existe une surcharge:
Response.Redirect(String url, bool endResponse)
Si vous transmettez endResponse = false , l'exception n'est pas levée (mais le moteur d'exécution continue de 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 est immédiatement terminée.
C’est ainsi que fonctionne Response.Redirect (url, true). Il lève l'exception ThreadAbortException pour abandonner le thread. Ignorez cette exception. (Je suppose que c'est un gestionnaire d'erreurs global/enregistreur où vous le voyez?)
Une discussion connexe intéressante Response.End () est-il considéré comme dangereux?
Voici le ligne officielle sur le problème (je ne pouvais pas trouver le dernier, mais je ne pense pas que la situation a changé pour les versions ultérieures de .net)
j'ai même essayé d'éviter cela, juste au cas où faire l'abandon sur le fil manuellement, mais je préfère le laisser avec le "CompleteRequest" et continuer - mon code a des commandes de retour après les redirections de toute façon. Donc cela peut être fait
public static void Redirect(string VPathRedirect, global::System.Web.UI.Page Sender)
{
Sender.Response.Redirect(VPathRedirect, false);
global::System.Web.UI.HttpContext.Current.ApplicationInstance.CompleteRequest();
}
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, string iUrl)
{
ResponseRedirect(iResponse, iUrl, HttpContext.Current);
}
public static void ResponseRedirect(HttpResponse iResponse, string 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
}
Ce que je fais, c'est intercepter cette exception, ainsi que d'autres exceptions possibles. J'espère que cela aidera quelqu'un.
catch (ThreadAbortException ex1)
{
writeToLog(ex1.Message);
}
catch(Exception ex)
{
writeToLog(ex.Message);
}
J'ai eu ce problème aussi. Essayez d'utiliser Server.Transfer au lieu de Response.Redirect Travaillé pour moi