Apakah Response.End () dianggap berbahaya?

198

Artikel KB ini mengatakan bahwa ASP.NET Response.End()membatalkan utas.

Reflektor menunjukkan bahwa tampilannya seperti ini:

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();
        }
    }
}

Bagi saya ini agak kasar. Seperti yang dikatakan artikel KB, kode apa pun dalam aplikasi berikut Response.End()ini tidak akan dieksekusi, dan itu melanggar prinsip paling tidak heran. Ini hampir seperti Application.Exit()di aplikasi WinForms. Pengecualian utas dibatalkan yang disebabkan oleh Response.End()tidak dapat ditangkap, jadi mengelilingi kode dalam try... finallytidak akan memuaskan.

Itu membuat saya bertanya-tanya apakah saya harus selalu menghindari Response.End().

Adakah yang bisa menyarankan, kapan saya harus menggunakan Response.End(), kapan Response.Close()dan kapan HttpContext.Current.ApplicationInstance.CompleteRequest()?

ref: entri blog Rick Strahl .


Berdasarkan input yang saya terima, jawaban saya adalah, Ya, Response.Endberbahaya , tetapi berguna dalam beberapa kasus terbatas.

  • gunakan Response.End()sebagai lemparan yang tidak dapat ditandingi, untuk segera mengakhiri HttpResponsedalam kondisi luar biasa. Dapat bermanfaat saat debugging juga. Hindari Response.End()untuk melengkapi respons rutin .
  • gunakan Response.Close()untuk segera menutup koneksi dengan klien. Per posting blog MSDN ini , metode ini tidak dimaksudkan untuk pemrosesan permintaan HTTP normal. Sangat tidak mungkin Anda memiliki alasan yang bagus untuk memanggil metode ini.
  • gunakan CompleteRequest()untuk mengakhiri permintaan normal. CompleteRequestmenyebabkan pipa ASP.NET melompat ke depan ke EndRequestacara, setelah HttpApplicationacara saat ini selesai. Jadi, jika Anda menelepon CompleteRequest, maka tulis sesuatu lebih ke respons, tulis itu akan dikirim ke klien.

Edit - 13 April 2011

Kejelasan lebih lanjut tersedia di sini:
- Posting yang berguna di Blog MSDN
- Analisis yang berguna oleh Jon Reid

Cheeso
sumber
2
tidak tahu apa yang berubah sejak jawaban ini, tetapi saya menangkap Response.End ThreadAbortExceptionbaik-baik saja.
Maslow
1
Ingat juga itu Response.Redirectdan Server.Transferkeduanya memanggil Response.Enddan juga harus dihindari.
Owen Blacker

Jawaban:

66

Jika Anda telah menggunakan logger pengecualian pada aplikasi Anda, itu akan dipermudah dengan ThreadAbortExceptions dari Response.End()panggilan - panggilan jinak ini . Saya pikir ini adalah cara Microsoft untuk mengatakan "Hentikan!".

Saya hanya akan menggunakan Response.End()jika ada kondisi luar biasa dan tidak ada tindakan lain yang mungkin. Mungkin kemudian, mencatat pengecualian ini mungkin benar-benar menunjukkan peringatan.

spoulson
sumber
107

TL; DR

Awalnya saya merekomendasikan agar Anda cukup mengganti semua panggilan Anda ke [Response.End] dengan [...] CompleteRequest () panggilan, tetapi jika Anda ingin menghindari pemrosesan postback dan rendering html Anda harus menambahkan [.. .] menimpa juga.

Jon Reid , "Analisis Akhir"


Per MSDN, Jon Reid , dan Alain Renon:

Kinerja ASP.NET - Manajemen Pengecualian - Menulis Kode yang Menghindari Pengecualian

Metode Server.Transfer, Response.Redirect, Response.End semua meningkatkan pengecualian. Masing-masing metode ini secara internal memanggil Response.End. Panggilan ke Response.End, pada gilirannya, menyebabkan pengecualian ThreadAbortException .

Solusi ThreadAbortException

HttpApplication.CompleteRequest () menetapkan variabel yang menyebabkan utas untuk melewati sebagian besar peristiwa dalam pipa peristiwa HttpApplication [-] bukan rantai acara Halaman tetapi rantai acara Aplikasi.

...

buat variabel tingkat kelas yang menandai jika Halaman harus diakhiri dan kemudian periksa variabel sebelum memproses acara Anda atau merender halaman Anda. [...] Saya akan merekomendasikan hanya mengganti metode RaisePostBackEvent dan Render

Response.End dan Response.Close tidak digunakan dalam pemrosesan permintaan normal ketika kinerja penting. Response.End adalah cara yang mudah dan berat untuk menghentikan pemrosesan permintaan dengan penalti kinerja terkait. Response.Close adalah untuk penghentian segera tanggapan HTTP di tingkat IIS / socket dan menyebabkan masalah dengan hal-hal seperti KeepAlive.

Metode yang disarankan untuk mengakhiri permintaan ASP.NET adalah HttpApplication.CompleteRequest. Perlu diingat bahwa rendering ASP.NET harus dilewati secara manual sejak HttpApplication.CompleteRequest melompati sisa pipa aplikasi IIS / ASP.NET, bukan pipeline Halaman ASP.NET (yang merupakan satu tahap dalam pipeline aplikasi).


Kode

Hak Cipta © 2001-2007, C6 Software, Inc sebaik yang saya tahu.


Referensi

HttpApplication.CompleteRequest

Menyebabkan ASP.NET memintas semua peristiwa dan memfilter dalam rantai eksekusi HTTP pipeline dan langsung menjalankan acara EndRequest.

Respon

Metode ini disediakan hanya untuk kompatibilitas dengan ASP —yaitu, untuk kompatibilitas dengan teknologi pemrograman-Web berbasis COM yang mendahului ASP.NET. ASP.NET sebelumnya. [Penekanan ditambahkan]

Respon. Tutup

Metode ini mengakhiri koneksi ke klien secara mendadak dan tidak dimaksudkan untuk pemrosesan permintaan HTTP normal . [Penekanan ditambahkan]

user423430
sumber
4
> Perlu diingat bahwa rendering ASP.NET harus dilewati secara manual sejak HttpApplication.CompleteRequest melompati sisa pipeline aplikasi IIS / ASP.NET, bukan pipeline Halaman ASP.NET (yang merupakan satu tahap dalam pipeline aplikasi). Dan bagaimana Anda mencapai ini?
PilotBob
1
Lihat tautan ke kode tempat Jon Reid mendemonstrasikan cara mengatur bendera dan mengganti metode RaisePostBackEvent dan Render Halaman untuk melewati implementasi normal saat diinginkan. (Anda mungkin akan melakukan ini di kelas dasar semua halaman aplikasi Anda harus mewarisi dari.) Web.archive.org/web/20101224113858/http://www.c6software.com/…
user423430
4
Hanya untuk menyatakan kembali: HttpApplication.CompleteRequest tidak menghentikan respons sebagai Response.End tidak.
Glen Little
2
HttpApplication.CompleteRequest juga tidak menghentikan aliran kode, sehingga baris berikutnya tetap berjalan. Itu mungkin tidak memengaruhi apa yang dilihat browser, tetapi jika garis-garis itu melakukan pemrosesan lain, itu bisa sangat membingungkan.
Joshua Frank
3
Saya tidak bisa berpikir tetapi Formulir Web itu rusak karena desain. Apa yang lebih merendahkan kinerja, memanggil Response.End () atau membiarkan halaman memuat semuanya dan kemudian menekan respons? Saya tidak bisa melihat di mana Response.End () "lebih" berbahaya di sini. Selain itu, Microsoft memperlakukan `ThreadAbortedException 'sebagai peristiwa normal sebagaimana terbukti dari kode ini: Referenceource.microsoft.com/#System.Web/UI/Page.cs,4875 Satu hal yang bertentangan dengan Response.End () adalah bahwa hal itu mungkin gagal batalkan respons, yang mungkin mengakibatkan respons sesekali ditampilkan.
Ghasan
99

Pertanyaan ini muncul di dekat bagian atas semua pencarian google untuk informasi tentang respons. . (mengganti metode render terlalu rumit untuk tugas sederhana IMO)

// 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()
Jay Zelos
sumber
1
Anda seharusnya tidak menggunakan halaman APSX untuk melakukan ini. Ini banyak usaha yang sia-sia. Anda seharusnya menggunakan ASMX atau Layanan Web, apa pun selain halaman ASPX.
mattmanser
19
Ini sepertinya menjadi jawaban dengan implementasi termudah. Kuncinya adalah Response.SuppressContent = True.
Chris Weber
3
@mattmanser - Tidak selalu mudah / terbaik / disarankan untuk memiliki halaman terpisah untuk representasi berbeda dari sumber daya yang sama. Pikirkan tentang REST, dll. Jika klien mengindikasikan mereka menginginkan csv, xml melalui header atau param, metode ini tentu akan menjadi yang terbaik, sambil tetap memberikan dukungan html melalui fasilitas rendering normal asp.net.
Chris Weber
1
Ini tidak berhasil untuk saya. Saya memiliki halaman yang berfungsi dengan Response.End (), tetapi menggunakan semua jenis kombinasi dari Response.Close (), Response.Flush (). HttpContext.Current.ApplicationInstance.CompleteRequest () dan berbagai hal lainnya tidak berfungsi jika saya memiliki filter GzipStream pada Respons. Apa yang tampaknya terjadi adalah bahwa halaman tersebut masih di-output bersama dengan file saya. Saya akhirnya mengesampingkan fungsi Render () (menjadi kosong) dan itu menyelesaikannya untuk saya.
Aerik
1
CompleteRequest melompati sebagian dari pipeline aplikasi tetapi masih akan berjalan melalui sisa proses rendering halaman, ini bukan penghentian langsung seperti response.end, lebih anggun. Ada lebih banyak penjelasan mendalam mengapa dalam jawaban lain di halaman ini.
Jay Zelos
11

Pada pertanyaan "Saya masih tidak tahu perbedaan antara Response.Close dan CompleteRequest ()" Saya akan mengatakan:

Lebih suka CompleteRequest (), jangan gunakan Response.Close ().

Lihat artikel berikut untuk ringkasan yang dilakukan dengan baik dari kasus ini.

Ketahuilah bahwa bahkan setelah memanggil CompleteRequest () beberapa teks (mis. Redndered dari kode ASPX) akan ditambahkan ke aliran output respons. Anda dapat mencegahnya dengan mengganti metode Render dan RaisePostBackEvent seperti yang dijelaskan dalam artikel berikut .

BTW: Saya setuju dengan pencegahan menggunakan Response.End (), terutama ketika menulis data ke aliran http untuk meniru unduhan file. Kami telah menggunakan Response.End () di masa lalu hingga file log kami menjadi penuh dengan ThreadAbortExceptions.

Jan Šotola
sumber
Saya tertarik mengganti Render seperti yang Anda gambarkan, tetapi tautan ke "artikel berikut" sudah mati. Mungkin Anda dapat memperbarui entri Anda?
paqogomez
Maaf atas jawaban yang terlambat. Saya tidak ingat persis, apa yang ada di artikel itu. Namun, saya menemukannya di webarchive.org: web.archive.org/web/20101224113858/http://www.c6software.com/…
Jan Šotola
9

Saya tidak setuju dengan pernyataan " Response.End berbahaya ". Jelas tidak berbahaya. Respon. Dan melakukan apa yang dikatakannya; itu mengakhiri eksekusi halaman. Menggunakan reflektor untuk melihat bagaimana penerapannya seharusnya hanya dipandang sebagai pelajaran.


Rekomendasi 2cent saya
HINDARI digunakan Response.End()sebagai aliran kontrol.
JANGAN gunakan Response.End()jika Anda perlu menghentikan eksekusi permintaan dan sadarilah bahwa (biasanya) * tidak ada kode yang akan dieksekusi melewati titik itu.


* Response.End()dan ThreadAbortException s.

Response.End() melempar ThreadAbortException sebagai bagian dari implementasi saat ini (seperti dicatat oleh OP).

ThreadAbortException adalah pengecualian khusus yang dapat ditangkap, tetapi secara otomatis akan dinaikkan lagi di akhir blok tangkapan.

Untuk melihat cara menulis kode yang harus berurusan dengan ThreadAbortExceptions, lihat @ Mehrdad membalas SO Bagaimana saya bisa mendeteksi threadabortexception di blok akhirnya di mana ia mereferensikan RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup Method dan Daerah Eksekusi yang Terkendala


Artikel Rick Strahl yang disebutkan adalah instruktif, dan pastikan untuk membaca komentar juga. Perhatikan bahwa masalah Strahl spesifik. Dia ingin mendapatkan data ke klien (gambar) dan kemudian memproses pembaruan basis data pelacakan-pelacakan yang tidak memperlambat penyajian gambar, yang menjadikannya masalah melakukan sesuatu setelah Respons. Akhir telah dipanggil.

Robert Paulson
sumber
Kami melihat posting ini stackoverflow.com/questions/16731745/... menyarankan menggunakan Response.SuppressContent = True HttpContext.Current.ApplicationInstance.CompleteRequest (), bukannya Response.End ()
jazzBox
3

Saya tidak pernah mempertimbangkan menggunakan Response.End () untuk mengontrol aliran program.

Namun Response.End () dapat berguna misalnya saat menyajikan file ke pengguna.

Anda telah menulis file ke respons dan Anda tidak ingin hal lain ditambahkan ke respons karena dapat merusak file Anda.

Kue ikan
sumber
1
Saya memahami perlunya API untuk mengatakan "responsnya selesai". Tapi Response.End () juga membatalkan utas. Ini adalah inti dari pertanyaan. Kapan ide yang baik untuk memasangkan kedua hal itu?
Cheeso
2

Saya telah menggunakan Response.End () di kedua .NET dan Classic ASP untuk secara paksa mengakhiri sesuatu sebelumnya. Misalnya, saya menggunakannya ketika ada sejumlah upaya login yang pasti. Atau ketika halaman aman diakses dari login yang tidak diautentikasi (contoh kasar):

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

Saat menyajikan file ke pengguna saya akan menggunakan Flush, Akhir dapat menyebabkan masalah.

Tim Meers
sumber
Perlu diingat, Flush () bukan "ini akhirnya". Hanya saja "siram semuanya sejauh ini." Alasan Anda mungkin menginginkan "ini akhir" adalah untuk membiarkan klien menyadari bahwa ia memiliki semua konten, sementara server dapat pergi dan melakukan hal-hal lain - perbarui file log, kueri penghitung basis data, atau apa pun. Jika Anda memanggil Response.Flush dan kemudian melakukan salah satu dari hal-hal itu, klien dapat terus menunggu lebih banyak. Jika Anda memanggil Response.End () maka kontrol melompat keluar dan DB tidak mendapatkan pertanyaan, dll.
Cheeso
Anda juga dapat menggunakan Response.Redirect yang menimpa ("....", true) di mana bool adalah 'endResponse: Menunjukkan apakah eksekusi halaman saat ini harus diakhiri "
Robert Paulson
Itu selalu lebih baik untuk menggunakan kerangka kerja Formulir Otentikasi untuk melindungi halaman yang dimaksudkan untuk diamankan oleh kredensial login.
Robert Paulson
3
Sebenarnya, untuk memperbaiki diri saya, saya percaya default dari Response.Redirect dan Server.Transfer adalah untuk memanggil Response.End secara internal kecuali jika Anda memanggil override dan meneruskan 'false' in. Cara kode Anda ditulis sebagai Response.End tidak pernah dipanggil ,
Robert Paulson
1
Response.end bekerja sangat berbeda di .net daripada di ASP klasik. Dalam .net itu menyebabkan sebuah threadabortexception, yang bisa sangat jahat.
Andy
2

Saya hanya menggunakan Response.End () sebagai mekanisme pengujian / debugging

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

Menilai dari apa yang telah Anda posting dalam hal penelitian, saya akan mengatakan itu akan menjadi desain yang buruk jika diperlukan Response.End

Nathan Koop
sumber
0

Pada asp klasik, saya memiliki TTFB (Time To First Byte) dari 3 hingga 10 detik pada beberapa panggilan ajax, jauh lebih besar daripada TTFB pada halaman biasa dengan lebih banyak panggilan SQL.

Ajax yang dikembalikan adalah segmen HTML yang akan disuntikkan ke halaman.

TTFB beberapa detik lebih lama dari waktu render.

Jika saya menambahkan response.end setelah render, TTFB sangat berkurang.

Saya bisa mendapatkan efek yang sama dengan memancarkan "</body> </html>", tetapi ini mungkin tidak berfungsi saat mengeluarkan json atau xml; di sini response.end diperlukan.

Leif Neland
sumber
Saya tahu ini adalah jawaban lama, tetapi sekali lagi, asp klasik sudah tua. Saya menemukan itu berguna ;-)
Leif Neland