Response.End () è considerato dannoso?


198

Questo articolo della KB dice che ASP.NET Response.End()interrompe un thread.

Reflector mostra che assomiglia a questo:

public void End()
{
    if (this._context.IsInCancellablePeriod)
    {
        InternalSecurityPermissions.ControlThread.Assert();
        Thread.CurrentThread.Abort(new HttpApplication.CancelModuleException(false));
    }
    else if (!this._flushing)
    {
        this.Flush();
        this._ended = true;
        if (this._context.ApplicationInstance != null)
        {
            this._context.ApplicationInstance.CompleteRequest();
        }
    }
}

Questo mi sembra piuttosto duro. Come dice l'articolo KB, qualsiasi codice nell'app seguente Response.End()non verrà eseguito e ciò viola il principio del minimo stupore. È quasi come Application.Exit()in un'app WinForms. L'eccezione di interruzione del thread causata da Response.End()non è rilevabile, quindi circondare il codice in un try... finallynon è soddisfacente.

Mi chiedo se dovrei sempre evitare Response.End().

Qualcuno può suggerire, quando dovrei usare Response.End(), quando Response.Close()e quando HttpContext.Current.ApplicationInstance.CompleteRequest()?

ref: il blog di Rick Strahl .


Sulla base dell'input che ho ricevuto, la mia risposta è Sì, Response.Endè dannosa , ma è utile in alcuni casi limitati.

  • utilizzare Response.End()come tiro inattaccabile, per terminare immediatamente HttpResponsein condizioni eccezionali. Può essere utile anche durante il debug. Evitare Response.End()di completare le risposte di routine .
  • utilizzare Response.Close()per chiudere immediatamente la connessione con il client. Per questo post sul blog MSDN , questo metodo non è destinato alla normale elaborazione delle richieste HTTP. È altamente improbabile che tu abbia una buona ragione per chiamare questo metodo.
  • utilizzare CompleteRequest()per terminare una richiesta normale. CompleteRequestfa in modo che la pipeline ASP.NET passi EndRequestall'evento dopo il HttpApplicationcompletamento dell'evento corrente . Quindi, se chiami CompleteRequest, quindi scrivi qualcosa in più alla risposta, la scrittura verrà inviata al client.

Modifica - 13 aprile 2011

Ulteriori chiarimenti sono disponibili qui:
- Post utili sul blog MSDN
- Analisi utili di Jon Reid


2
non ho idea di cosa sia cambiato da questa risposta, ma sto prendendo il Response.End ThreadAbortExceptionbene.
Maslow,

1
Tieni presente anche quello Response.Redirected Server.Transferentrambi chiamano Response.Ende dovrebbero anche essere evitati.
Owen Blacker,

Risposte:


66

Se hai utilizzato un registratore di eccezioni sulla tua app, verrà annacquato con le ThreadAbortExceptions di queste Response.End()chiamate benigne . Penso che questo sia il modo in cui Microsoft dice "Smettila!".

Userei solo Response.End()se ci fosse qualche condizione eccezionale e nessun'altra azione fosse possibile. Forse allora, la registrazione di questa eccezione potrebbe effettivamente indicare un avviso.


107

TL; DR

Inizialmente avevo raccomandato di sostituire semplicemente tutte le chiamate a [Response.End] con [...] chiamate CompleteRequest (), ma se si desidera evitare l'elaborazione di postback e il rendering html, è necessario aggiungere [.. .] sostituisce anche.

Jon Reid , "Analisi finale"


Per MSDN, Jon Reid e Alain Renon:

Prestazioni ASP.NET - Gestione delle eccezioni - Scrivi codice che evita le eccezioni

I metodi Server.Transfer, Response.Redirect, Response.End generano eccezioni. Ognuno di questi metodi chiama internamente Response.End. La chiamata a Response.End, a sua volta, provoca un'eccezione ThreadAbortException .

ThreadAbortException Solution

HttpApplication.CompleteRequest () imposta una variabile che fa sì che il thread salti la maggior parte degli eventi nella pipeline degli eventi di HttpApplication [-] non nella catena di eventi Pagina ma nella catena di eventi Applicazione.

...

creare una variabile a livello di classe che contrassegna se la Pagina deve terminare e quindi controllare la variabile prima di elaborare gli eventi o eseguire il rendering della pagina. [...] Consiglierei solo di ignorare i metodi RaisePostBackEvent e Render

Response.End e Response.Close non vengono utilizzati nell'elaborazione della richiesta normale quando le prestazioni sono importanti. Response.End è un mezzo conveniente e pesante per terminare l'elaborazione delle richieste con una penalità di performance associata. Response.Close serve per la terminazione immediata della risposta HTTP a livello di IIS / socket e causa problemi con cose come KeepAlive.

Il metodo consigliato per terminare una richiesta ASP.NET è HttpApplication.CompleteRequest. Tenere presente che il rendering ASP.NET dovrà essere saltato manualmente poiché HttpApplication.CompleteRequest salta il resto della pipeline dell'applicazione IIS / ASP.NET, non la pipeline della pagina ASP.NET (che è uno stadio della pipeline dell'app).


Codice

Copyright © 2001-2007, C6 Software, Inc come meglio potrei dire.


Riferimento

HttpApplication.CompleteRequest

Fa sì che ASP.NET ignori tutti gli eventi e i filtri nella catena di esecuzione della pipeline HTTP ed esegua direttamente l'evento EndRequest.

Response.End

Questo metodo viene fornito solo per la compatibilità con ASP , ovvero per la compatibilità con la tecnologia di programmazione Web basata su COM che ha preceduto ASP.NET.precedente ASP.NET. [Enfasi aggiunta]

Response.Close

Questo metodo interrompe la connessione al client in modo brusco e non è previsto per la normale elaborazione di richieste HTTP . [Enfasi aggiunta]


4
> Tenere presente che il rendering ASP.NET dovrà essere saltato manualmente poiché HttpApplication.CompleteRequest salta il resto della pipeline dell'applicazione IIS / ASP.NET, non la pipeline della pagina ASP.NET (che è una fase della pipeline dell'app). E come ci riesci?
PilotBob,

1
Vedi il link al codice in cui Jon Reid ha dimostrato come impostare un flag e sovrascrivere i metodi RaisePostBackEvent e Render della Pagina per saltare l'implementazione normale quando desiderato. (Si sarebbe probabilmente fare questo in una classe base di tutte le pagine del vostro applicazione dovrebbe ereditare da.) Web.archive.org/web/20101224113858/http://www.c6software.com/...
user423430

4
Solo per ripetere: HttpApplication.CompleteRequest non termina la risposta come Response.End.
Glen Little,

2
Anche HttpApplication.CompleteRequest non arresta il flusso di codice, quindi le righe successive continuano a funzionare. Ciò potrebbe non influire su ciò che il browser vede, ma se quelle linee eseguono qualsiasi altra elaborazione, può essere davvero confuso.
Joshua Frank,

3
Non riesco a pensare, ma che i Web Form sono interrotti dal design. Cosa significa più degrado delle prestazioni, chiamare Response.End () o lasciare che la pagina carichi tutto e quindi sopprimere la risposta? Non riesco a vedere dove Response.End () è "più" dannoso qui. Inoltre, Microsoft considera "ThreadAbortedException" come un normale evento evidente da questo codice: riferimentiource.microsoft.com/#System.Web/UI/Page.cs,4875 Una cosa che è contro Response.End () è che potrebbe non riuscire interruzione della risposta, che potrebbe comportare occasionalmente la visualizzazione della risposta.
Ghasan,

99

Questa domanda appare nella parte superiore di tutte le ricerche di Google per informazioni su response.end quindi per altre ricerche come me che desiderano pubblicare CSV / XML / PDF ecc in risposta a un evento senza eseguire il rendering dell'intera pagina ASPX, ecco come lo faccio . (l'override dei metodi di rendering è eccessivamente complesso per un'attività IMO così semplice)

// Add headers for a csv file or whatever
Response.ContentType = "text/csv"
Response.AddHeader("Content-Disposition", "attachment;filename=report.csv")
Response.AddHeader("Pragma", "no-cache")
Response.AddHeader("Cache-Control", "no-cache")

// Write the data as binary from a unicode string
Dim buffer As Byte()
buffer = System.Text.Encoding.Unicode.GetBytes(csv)
Response.BinaryWrite(buffer)

// Sends the response buffer
Response.Flush()

// Prevents any other content from being sent to the browser
Response.SuppressContent = True

// Directs the thread to finish, bypassing additional processing
HttpContext.Current.ApplicationInstance.CompleteRequest()

1
Non dovresti usare una pagina APSX per farlo. È uno sforzo sprecato. Dovresti usare un ASMX o un servizio Web, tranne una pagina ASPX.
Mattmanser,

19
Questa sembra essere la risposta con l'implementazione più semplice. La chiave è Response.SuppressContent = True.
Chris Weber,

3
@mattmanser - Non è sempre facile / migliore / consigliabile avere una pagina separata per una diversa rappresentazione della stessa risorsa. Pensa a REST, ecc. Se il client indica che vogliono csv, xml tramite un'intestazione o un parametro, questo metodo sarebbe sicuramente il migliore, fornendo comunque supporto html attraverso le normali funzionalità di rendering di asp.net.
Chris Weber,

1
Questo non ha funzionato per me. Ho avuto una pagina che ha funzionato con Response.End (), ma utilizzando tutti i tipi di combinazioni di Response.Close (), Response.Flush (). HttpContext.Current.ApplicationInstance.CompleteRequest () e varie altre cose non funzionavano se avessi un filtro GzipStream sulla risposta. Quello che sembrava accadere era che la pagina fosse ancora in uscita insieme al mio file. Alla fine ho annullato la funzione Render () (per essere vuota) e questo l'ha risolto per me.
Aerik,

1
CompleteRequest salta parti della pipeline dell'applicazione ma continuerà comunque per il resto del processo di rendering della pagina, non è un arresto immediato come response.end, è più grazioso. Ci sono spiegazioni più approfondite sul perché in altre risposte in questa pagina.
Jay Zelos,

11

Alla domanda "Ancora non conosco la differenza tra Response.Close e CompleteRequest ()" Direi:

Preferisci CompleteRequest (), non usare Response.Close ().

Vedere il seguente articolo per un riepilogo ben fatto di questo caso.

Tenere presente che anche dopo aver chiamato CompleteRequest () parte del testo (ad esempio redndered dal codice ASPX) verrà aggiunto al flusso di output della risposta. Puoi prevenirlo sovrascrivendo i metodi Render e RaisePostBackEvent come descritto nel seguente articolo .

A proposito: concordo con la prevenzione dell'uso di Response.End (), in particolare quando scrivo dati nello stream http per emulare il download di file. Abbiamo usato Response.End () in passato fino a quando il nostro file di registro non è diventato pieno di ThreadAbortExceptions.


Sono interessato a scavalcare Render come descrivi, ma il link al "seguente articolo" è morto. Forse puoi aggiornare la tua voce?
paqogomez,

Ci scusiamo per una risposta in ritardo. Non ricordo esattamente cosa c'era in quell'articolo. Tuttavia, l'ho trovato su webarchive.org: web.archive.org/web/20101224113858/http://www.c6software.com/…
Jan Šotola

9

Non sono d'accordo con l'affermazione " Response.End è dannoso ". Non è assolutamente dannoso. Response.End fa quello che dice; termina l'esecuzione della pagina. L'uso del riflettore per vedere come è stato implementato dovrebbe essere considerato solo istruttivo.


La mia raccomandazione 2cent
EVITARE di usare Response.End()come flusso di controllo.
DO uso Response.End()se avete bisogno di fermarsi richiesta di esecuzione e di essere consapevoli del fatto che (di solito) * nessun codice verrà eseguito oltre quel punto.


* Response.End()e ThreadAbortException s.

Response.End() genera una ThreadAbortException come parte della sua implementazione corrente (come notato da OP).

ThreadAbortException è un'eccezione speciale che può essere rilevata, ma verrà automaticamente sollevata nuovamente alla fine del blocco catch.

Per vedere come scrivere il codice che deve gestire ThreadAbortExceptions, vedere la risposta di @ Mehrdad a SO Come posso rilevare un threadabortexception in un blocco finalmente in cui fa riferimento a RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup Method e Vincolo delle regioni di esecuzione


L' articolo di Rick Strahl menzionato è istruttivo e assicurati di leggere anche i commenti. Si noti che il problema di Strahl era specifico. Voleva ottenere i dati al client (un'immagine) e quindi elaborare l'aggiornamento del database di tracciamento dei risultati che non rallentava la pubblicazione dell'immagine, il che gli rendeva il problema di fare qualcosa dopo che Response.End era stato chiamato.


Abbiamo visto questo post stackoverflow.com/questions/16731745/… suggerendo di usare Response.SuppressContent = True HttpContext.Current.ApplicationInstance.CompleteRequest () invece di Response.End ()
jazzBox

3

Non ho mai considerato l'utilizzo di Response.End () per controllare il flusso del programma.

Tuttavia Response.End () può essere utile, ad esempio, quando si forniscono file a un utente.

Hai scritto il file nella risposta e non vuoi aggiungere altro alla risposta poiché potrebbe corrompere il file.


1
Comprendo la necessità di un'API per dire "la risposta è completa". Ma Response.End () inoltre interrompe un thread. Questo è il nocciolo della domanda. Quando è una buona idea accoppiare queste due cose?
Cheeso,

2

Ho usato Response.End () in .NET e ASP classico per terminare forzatamente le cose prima. Ad esempio, lo uso quando c'è una quantità certa di tentativi di accesso. O quando si accede a una pagina protetta da un accesso non autenticato (esempio approssimativo):

    if (userName == "")
    {
        Response.Redirect("......");
        Response.End();
    }
    else
    {
      .....

Quando offro file a un utente, uso un Flush, l'End può causare problemi.


Tieni presente che Flush () non è "questa è la fine". È solo "scarica tutto finora". Il motivo per cui potresti voler "questo è il fine" è far sapere al client che ha tutto il contenuto, mentre il server può andare e fare altre cose: aggiornare un file di registro, eseguire una query su un contatore di database o altro. Se si chiama Response.Flush e quindi si esegue una di queste operazioni, il client potrebbe continuare ad attendere di più. Se si chiama Response.End (), il controllo salta fuori e il DB non riceve query, ecc.
Cheeso

In alternativa, è possibile utilizzare l'override Response.Redirect ("....", true) in cui il bool è 'endResponse: indica se l'esecuzione corrente della pagina deve terminare "
Robert Paulson,

È sempre meglio utilizzare il framework Autenticazione moduli per proteggere le pagine che devono essere protette dalle credenziali di accesso.
Robert Paulson,

3
In realtà, per correggermi, credo che il valore predefinito di Response.Redirect e Server.Transfer sia chiamare Response.End internamente a meno che tu non chiami l'override e passi 'false'. Il modo in cui il tuo codice è scritto Response.End non viene mai chiamato ,
Robert Paulson,

1
Response.end funziona in modo molto diverso in .net rispetto a ASP classico. In .net provoca un threadabortexception, che può essere piuttosto brutto.
Andy,

2

Ho usato Response.End () solo come meccanismo di test / debugging

<snip>
Response.Write("myVariable: " + myVariable.ToString());
Response.End();
<snip>

A giudicare da ciò che hai pubblicato in termini di ricerca, direi che sarebbe un cattivo progetto se richiedesse Response.End


0

Su ASP classico, ho avuto un TTFB (Time To First Byte) da 3 a 10 secondi su alcune chiamate ajax, molto più grande del TTFB su pagine normali con molte più chiamate SQL.

L'ajax restituito era un segmento di HTML da iniettare nella pagina.

Il TTFB era più lungo di alcuni secondi rispetto al tempo di rendering.

Se ho aggiunto un response.end dopo il rendering, il TTFB è stato notevolmente ridotto.

Potrei ottenere lo stesso effetto emettendo un "</body> </html>", ma probabilmente questo non funziona quando si genera json o xml; qui è necessario response.end.


So che questa è una vecchia risposta, ma ancora una volta, la classica asp è vecchia. L'ho trovato utile ;-)
Leif Neland
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.