HttpResponse.Fin vs HttpResponse.Fermer vs HttpResponse.SuppressContent
Dans une page ASPX, je veux terminer la réponse à des points spécifiques (pas en raison d'une condition d'erreur), en fonction du chemin de code, de sorte que rien d'autre ne soit renvoyé dans le flux. Donc naturellement utilisé:
Response.End();
Il en résulte une ThreadAbortException, qui est par conception .
Ce qui suit semble fonctionner mais ne ressemble pas à la bonne approche selon cette question SO :
Response.Flush();
Response.Close();
Alors, que dis-tu de ça?
Response.Flush();
Response.SuppressContent = true
Et puis laissez la page terminer normalement.
Je pourrais juste gérer et avaler L'exception ThreadAbortException, mais je veux juste savoir s'il y a quelque chose de mal/gotchas avec L'approche SuppressContent?
Modifier: Pour donner un peu plus d'un exemple. Disons que j'ai une page ASPX par laquelle je peux changer le type de contenu à l'une des nombreuses possibilités. Selon le type de contenu et le scénario, à un moment donné dans le code, je veux empêcher tout contenu supplémentaire d'être envoyé au client. Assumer après SuppressContent a été défini sur true, qu'il n'y a aucun problème avec tout autre code côté serveur en cours d'exécution. Je ne veux rien d'autre à envoyer au client.
Modifier 2: MyPage.aspx-a une page maître qui peut inclure du contenu standard, des en-têtes, des pieds de page, etc. Cette page peut simplement être rendue comme une page normale. Il peut également simplement écrire un document XML (par exemple) à télécharger. Si vous écrivez un document XML (déterminé lors du chargement de la page), il effacera la sortie, définira le content-Tapez en XML, écrivez tout le XML et si vous le laissez normalement, vous vous retrouvez avec le reste du rendu de la page ASPX qui est cloué à la fin - ce n'est évidemment pas nécessaire/casse le XML.
Modifier 3: Pour l'instant, j'utilise L'approche SuppressContent. Pour essayer de clore cette question, je lève une prime et poserai la question d'une autre manière: Quand devriez-vous utiliser SuppressContent? Pourquoi voudriez-vous utiliser à la place de Réponse.Fin?
Veuillez voir la réponse que j'ai fournie ci-dessous pour la solution que j'ai trouvée car j'ai finalement trouvé un moyen d'éviter L'exception ThreadAbortException lors de l'utilisation de Response.Fin. J'avais déjà exclu une réponse de ce point.
7 réponses
Mise à jour-avertissement: il y a une meilleure méthode, ne l'utilisez pas, voir la réponse D'Ethan à la place!
Je ne dirais pas qu'il y a une raison valable d'éviter la réponse.Fin. Vouloir éviter le coût de L'exception ThreadAbortException, en laissant le cycle de demande de page continuer et lui faire faire un travail supplémentaire qui n'est pas nécessaire ne semble pas correct.
ThreadAbortException est un type spécial d'exception destiné à arrêter l'exécution d'un thread (il est relancé automatiquement même s'il est intercepté). Que dit, il existe certains scénarios où cela pourrait nuire (voir le contenu de la communauté ajouté à la fin de ThreadAbortException ).
Sauf si vous êtes dans l'un de ces scénarios, vous devriez vous en tenir à la réponse.Fin. Notez que certains usages autour, faire un SuppressContent & réponse.Fin, je suppose que dans les cas où vous voulez éviter des choses qui proviendraient de la réponse interne.Flush.
Je sais que c'est une vieille question, mais j'inclus cela pour le bénéfice de tous ceux qui pourraient tomber dans ce post. J'ai poursuivi un bug qui m'a conduit à revoir mon utilisation de la réponse.Fin, et découvert un post MSDN d'un an après cette question qui pourrait être résumée comme "Jamais, Jamais utiliser la réponse.Fin". Voici ce que dit Thomas Marquardt, qui a conçu le Pipeline intégré pour IIS7:
La méthode End est également sur ma liste "ne jamais utiliser". Wells façon d'arrêter la demande est d'appeler HttpApplication.CompleteRequest. La méthode End n'est là que parce que nous avons essayé d'être compatible avec ASP classique lors de la sortie de 1.0. ASP classique a une réponse.Méthode End qui termine le traitement du script ASP. Pour imiter ce comportement, ASP.NET la méthode End tente de déclencher une exception ThreadAbortException. Si cela réussit, le thread appelant sera abandonné (très coûteux, pas bon pour les performances) et le pipeline passera à la demande finale événement. L'exception ThreadAbortException, en cas de succès, signifie Bien sûr que le thread se déroule avant de pouvoir appeler plus de code, donc appeler End signifie que vous n'appellerez plus de code après cela. Si la méthode End n'est pas capable de déclencher une exception ThreadAbortException, elle videra plutôt les octets de réponse au client, mais elle le fait de manière synchrone, ce qui est vraiment mauvais pour les performances, et lorsque le code utilisateur après L'exécution de End est terminé, le pipeline passe à la notification EndRequest. L'écriture d'octets pour le client est une opération très coûteuse, surtout si le client est à mi-chemin dans le monde et en utilisant un modem 56k, il est donc préférable d'envoyer les octets de manière asynchrone, ce que nous faisons lorsque la requête se termine normalement. Flushing synchrone est vraiment mauvais. Donc, pour résumer, vous ne devriez pas utiliser End, mais utiliser CompleteRequest est parfaitement bien. La documentation de End doit indiquer que CompleteRequest est un meilleur moyen de passer à la notification EndRequest et de compléter le demande.
J'ai finalement trouvé une solution simple pour utiliser la réponse.End() sans obtenir une ThreadAbortException.
Response.Flush();
Response.End();
De ma question initiale, j'avais toujours essayé juste une réponse.End() après avoir envoyé du contenu au flux de réponse.
Il semble que s'il y a du contenu unflushed lorsque vous faites une réponse.End (), vous obtenez L'exception ThreadAbortException. En faisant le rinçage immédiatement avant la fin, une ThreadAbortException n'est pas réellement lancée.
Semble fonctionner Génial - aucune ThreadAbortException n'est lancée maintenant quand j'utilise Response.Fin
C'est une question très courante. Et c'est presque toujours une erreur d'appeler n'importe quoi sauf Response.End()
. Voici la description de End () de MSDN:
Envoie toutes les sorties actuellement mises en mémoire tampon au client, arrête l'exécution de la page et déclenche L'événement EndRequest.
Cela semble être exactement ce que vous voulez faire. Et vous remarquerez dans la dernière partie qu'il déclenche L'événement EndRequest. Cela signifie qu'après L'appel de End (), toutes les données sont vidées client qui a été écrit avant la fin (), le socket est fermé, et les ressources sont libérées, et votre programme cesse de traiter la demande tout de suite.
Que faire si, après avoir appelé Response.SuppressContent = true
votre page continue à apporter des modifications à un enregistrement dans la base de données?
Pour autant que je puisse comprendre le code lors de la réflexion HttpResponse en utilisant L'approche Flush/SuppressContent vous rendra vulnérable au code essayant de faire des changements d'en-tête après le flush. Changer un en-tête après le vidage donnera une exception HttpException.
J'utiliserais la réponse.Fin() pour être absolument sûr que rien d'autre ne pourrait interférer avec la réponse.
Si vous voulez continuer l'exécution mais aussi court-circuiter le pipeline http, envisagez D'utiliser Response.Flush () et HttpContext.Actuel.ApplicationInstance.CompleteRequest () comme réponse.Fin() lorsque le contexte n'est pas dans un résiliable période.
Êtes-vous sûr que la stratégie de conception est correcte? Quel pré-traitement Pouvez-vous faire pour vous assurer que les en-têtes corrects sont envoyés, puis s'y tenir jusqu'à ce que le script ait distribué ses objectifs?