Pourquoi La Réponse.La redirection provoque le système.Le filetage.ThreadAbortException?

quand j'utilise Response.Rediriger.(..) pour rediriger mon formulaire vers une nouvelle page, j'obtiens l'erreur:

Une exception de première chance de type 'System.Le filetage.ThreadAbortException s'est produite dans mscorlib.dll

Une exception de type 'System.Le filetage.ThreadAbortException s'est produite dans mscorlib.dll mais n'a pas été traité par l'utilisateur code

Ma compréhension de cette est que l'erreur est causée par le serveur web de stopper le reste de la page de la réponse.redirection a été appelé.

je sais que je peux ajouter un second paramètre à Response.Redirect qui s'appelle endResponse. Si je mets endResponse à True j'obtiens toujours l'erreur mais si je mets à False alors je ne le fais pas. Je suis assez sûr que cela signifie que le serveur web exécute le reste de la page que j'ai redirigé loin de. Ce qui semble être inefficace pour dire le moins. Est-il une meilleure façon de le faire? Quelque autre que Response.Redirect ou y a-t-il un moyen de forcer la vieille page à arrêter le chargement où je n'obtiendrai pas un ThreadAbortException ?

212
demandé sur Kiquenet 2010-05-06 02:02:43

10 réponses

le modèle correct est d'appeler la surcharge de redirection avec endResponse=false et de faire un appel pour dire au pipeline IIS qu'il devrait avancer directement à L'étape de la demande finale une fois que vous retournez 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 la façon de gérer le cas spécial de redirection à l'intérieur d'un gestionnaire Application_Error.

309
répondu Joel Fillmore 2010-05-05 22:28:24

Il y a non solution simple et élégante à la Redirect problème ASP.Net WebForms. Vous pouvez choisir entre la solution Sale et la solution fastidieuse solution

Dirty : Response.Redirect(url) envoie une redirection vers le navigateur, puis lance un ThreadAbortedException pour terminer le fil courant. Donc aucun code n'est exécuté après L'appel Redirect () -. Inconvénients: Il est mauvais s'entraîner et avoir des implications de performance pour tuer des fils comme celui-ci. De plus, ThreadAbortedExceptions apparaîtra dans exception logging.

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 le reste des gestionnaires d'événements dans le cycle de vie de la page sera encore exécuté. (P. ex. si vous exécutez la redirection dans Page_Load, non seulement le reste du gestionnaire sera exécuté, Page_PreRender et ainsi on sera également appelé - la page rendue ne sera tout simplement pas envoyé au navigateur. Vous pouvez éviter le traitement supplémentaire en mettant par exemple un drapeau sur la page, puis laisser les gestionnaires d'événements suivants vérifier ce drapeau avant de faire n'importe quel traitement.

(la documentation à CompleteRequest indique qu'il " Causes ASP.NET pour contourner tous les événements et le filtrage dans la chaîne D'exécution de pipeline HTTP ". Cela peut facilement être mal compris. Il ne dérivation d'autres filtres et modules HTTP, mais il ne contourne pas d'autres événements dans l'actuel page cycle de vie.)

le problème le plus profond est que les formes Web manquent d'un niveau d'abstraction. Lorsque vous êtes dans un gestionnaire d'événements, vous êtes déjà en train de construire une page à la sortie. Rediriger dans un handler d'événement est laid parce que vous terminez 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 le flux de contrôle est séparé du rendu des vues, de sorte que vous pouvez faire une redirection nette en retournant simplement un RedirectAction dans le contrôleur, sans générer de vue.

143
répondu JacquesB 2012-10-18 15:23:55

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 .

N'a jamais répondu.Rediriger dans un essai...Bloc Catch. C'est une mauvaise pratique

Modifier

en réponse au commentaire de @Kiquenet, voici ce que je ferais comme alternative à la réponse.Redirection dans le coup d'Essayer...Bloc Catch.

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

première étape dans L'essai...Catch block exécute les actions demandées et définit une valeur "résultat" pour indiquer le succès ou l'échec des actions.

deuxième étape en dehors de L'essai...Le bloc de capture fait la redirection (ou ne fait pas) en fonction de ce qu'est la valeur "résultat".

ce code est loin d'être parfait et ne devrait probablement pas être copié puisque 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.
    }
}
28
répondu Ortund 2017-07-10 11:19:26

Response.Redirect() lance une exception pour annuler la requête actuelle.

Ce l'article décrit ce comportement (aussi pour la Request.End() et Server.Transfer() méthodes).

pour Response.Redirect() il existe une surcharge:

Response.Redirect(String url, bool endResponse)

si vous passez endResponse=false , alors l'exception n'est pas lancée (mais l'exécution va continuer à traiter la requête actuelle).

si endResponse=true (ou si l'autre surcharge est utilisée), l'exception est lancée et la requête courante sera immédiatement terminée.

8
répondu M4N 2010-05-05 22:11:21

C'est comme ça Qu'on réagit.Redirection(url, true) fonctionne. Il lance la ThreadAbortException pour annuler le fil. Il suffit de les ignorer cette exception. (Je suppose que c'est un gestionnaire d'erreurs global où vous le voyez?)

Une intéressante discussion Est la Réponse.Fin() considéré comme dangereux?

7
répondu Martin Smith 2017-05-23 11:33:25

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

6
répondu spender 2010-05-05 22:08:47

j'ai même essayé d'éviter cela, juste au cas où faire L'avortement sur le thread manuellement, mais je le laisse plutôt avec le" CompleteRequest " et je passe à autre chose - mon code a des commandes de retour après redirection 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();
}
2
répondu SammuelMiranda 2015-09-03 19:52:30

ce que je fais c'est attraper cette exception, avec une autre exception possible. Espérons que cela aide quelqu'un.

 catch (ThreadAbortException ex1)
 {
    // do nothing
 }
 catch(Exception ex)
 {
     writeToLog(ex.Message);
 }
1
répondu Jorge 2013-02-28 17:18:02

aussi j'ai essayé une autre solution, mais une partie du code exécuté après 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 du code après redirection

try
{
   //other code
   Response.Redirect("")
  // code not to be executed
}
catch(ThreadAbortException){}//do there id nothing here
catch(Exception ex)
{
  //Logging
}
1
répondu Maxim Lavrov 2014-01-17 17:37:09

j'ai eu ce problème aussi. Essayez d'utiliser de Serveur.Transférer au lieu de répondre.Rediriger A travaillé pour moi

0
répondu Marko 2015-10-05 09:07:10