Response.End () zararlı kabul edilir mi?


198

Bu KB makalesi , ASP.NET'in Response.End()bir iş parçacığını iptal ettiğini söylüyor .

Reflektör, şuna benzediğini gösterir:

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

Bu bana çok sert geliyor. KB makalesinde belirtildiği gibi, aşağıdaki uygulamada herhangi bir kod Response.End()yürütülmez ve bu en az şaşkınlık ilkesini ihlal eder. Neredeyse Application.Exit()bir WinForms uygulamasında olduğu gibi. Neden olduğu iş parçacığı iptali istisnası Response.End()catchable değildir, bu yüzden kodu çevreleyen try... finallytatmin olmaz.

Her zaman kaçınmam gerekip gerekmediğini merak ediyor Response.End().

Kullanmalıyım zaman kimse, önerebilir Response.End()zaman Response.Close()ve ne zaman HttpContext.Current.ApplicationInstance.CompleteRequest()?

ref: Rick Strahl'in blog girişi .


Aldığım girdiye dayanarak, cevabım, Evet, Response.Endzararlıdır , ancak bazı sınırlı durumlarda yararlıdır.

  • İstisnai koşullarda Response.End()derhal feshetmek için erişilemez bir atış olarak kullanın HttpResponse. Hata ayıklama sırasında da yararlı olabilir. Rutin yanıtları tamamlamaktan kaçınınResponse.End() .
  • Response.Close()istemciyle bağlantıyı hemen kapatmak için kullanın . Başına bu MSDN blog yayınında , bu yöntem , normal HTTP isteği işleme için tasarlanmamıştır. Bu yöntemi çağırmak için iyi bir nedeninizin olması pek olası değildir.
  • CompleteRequest()normal bir isteği sonlandırmak için kullanın . geçerli olay tamamlandıktan sonra CompleteRequestASP.NET ardışık düzeninin EndRequestolaya atlamasını sağlar HttpApplication. Eğer ararsanız CompleteRequest, daha sonra yanıta bir şey daha yazın, yazma istemciye gönderilir.

Düzenle - 13 Nisan 2011

Daha fazla netlik burada bulabilirsiniz:
- MSDN Blog yararlı yazı
- Jon Reid tarafından yararlı analiz


2
Bu cevaptan bu yana ne değiştiğine dair bir fikrim yok, ama Response.End ThreadAbortExceptiongayet iyi yakalıyorum .
Maslow

1
Unutmayın ki Response.Redirectve Server.Transferher ikisi de çağırır Response.Endve kaçınılmalıdır.
Owen Blacker

Yanıtlar:


66

Uygulamanızda bir istisna günlüğü çalıştırdıysanız ThreadAbortException, bu iyi huylu Response.End()çağrılardan gelen s ile sulanır . Bu Microsoft'un "Kes şunu!" Demenin yolu olduğunu düşünüyorum.

Sadece Response.End()istisnai bir durum olsaydı ve başka bir eylem mümkün değilse kullanardım . Belki de, bu istisnanın günlüğe kaydedilmesi aslında bir uyarı gösterebilir.


107

TL; DR

Başlangıçta sadece [Response.End] için yaptığınız tüm çağrıları [...] CompleteRequest () çağrıları ile değiştirmenizi tavsiye etmiştim, ancak geri gönderme işleminden ve html oluşturma işleminden kaçınmak isterseniz [.. .] de geçersiz kılar.

Jon Reid , "Nihai Analiz"


MSDN, Jon Reid ve Alain Renon'a göre:

ASP.NET Performansı - Özel Durum Yönetimi - Özel Durumları Önleyen Kod Yazma

Server.Transfer, Response.Redirect, Response.End yöntemlerinin tümü istisna oluşturur. Bu yöntemlerin her biri dahili olarak Response.End olarak adlandırılır. Response.End çağrısı da, ThreadAbortException özel durumuna neden olur .

ThreadAbortException Çözümü

HttpApplication.CompleteRequest (), iş parçacığının Page olay zincirini değil, Application olay zincirini HttpApplication olayı ardışık düzenindeki [-] olayların çoğunu atlamasına neden olan bir değişken ayarlar.

...

Sayfanın sonlanması gerekip gerekmediğini belirten bir sınıf düzeyinde değişken oluşturun ve ardından etkinliklerinizi işlemeden veya sayfanızı oluşturmadan önce değişkeni kontrol edin. [...] Sadece RaisePostBackEvent ve Render yöntemlerini geçersiz kılmanızı tavsiye ederim

Response.End ve Response.Close, performans önemli olduğunda normal istek işlemede kullanılmaz. Yanıt: Talep işlemeyi, ilişkili bir performans cezasıyla sonlandırmak için kullanışlı, yoğun bir yöntemdir. Response.Close, IIS / soket düzeyinde HTTP yanıtının derhal sonlandırılması içindir ve KeepAlive gibi şeylerle ilgili sorunlara neden olur.

ASP.NET isteğini sonlandırmak için önerilen yöntem HttpApplication.CompleteRequest'dir. ASP.NET oluşturmanın el ile atlanması gerektiğini unutmayın;


kod

Telif hakkı © 2001-2007, C6 Software, Inc anlatabildiğim kadarıyla.


Referans

HttpApplication.CompleteRequest

ASP.NET'in HTTP pipeline yürütme zincirindeki tüm olayları ve filtrelemeyi atlamasına ve doğrudan EndRequest olayını yürütmesine neden olur.

Response.End

Bu yöntem yalnızca ASP ile uyumluluk için sağlanır ; yani ASP.NET'ten önce gelen COM tabanlı Web programlama teknolojisiyle uyumluluk için. ASP.NET'ten önce geldi. [Vurgu eklenmiştir]

Response.Close

Bu yöntem, istemciye olan bağlantıyı aniden sonlandırır ve normal HTTP istek işlemesi için tasarlanmamıştır . [Vurgu eklenmiştir]


4
> HttpApplication.CompleteRequest, ASP.NET Sayfası ardışık düzenini (uygulama kanalında bir aşama olan) değil, IIS / ASP.NET uygulama ardışık düzenini atladığından ASP.NET oluşturmanın el ile atlanması gerektiğini unutmayın. Ve bunu nasıl başarıyorsunuz?
2018'de PilotBob

1
Jon Reid'in bir bayrağın nasıl ayarlanacağını ve istenildiğinde normal uygulamayı atlamak için Page RaisePostBackEvent ve Render yöntemlerini nasıl geçersiz kılacağını gösterdiği kodun bağlantısına bakın. (Bunu muhtemelen tüm uygulama sayfalarınızın devralması gereken bir temel sınıfta yaparsınız
user423430

4
Sadece yeniden ifade etmek gerekirse: HttpApplication.CompleteRequest, Response.End gibi yanıtı sonlandırmaz.
Glen Little

2
HttpApplication.CompleteRequest ayrıca kod akışını durdurmaz, bu nedenle sonraki satırlar çalışmaya devam eder. Bu, tarayıcının gördüklerini etkilemeyebilir, ancak bu satırlar başka bir işlem yaparsa, gerçekten kafa karıştırıcı olabilir.
Joshua Frank

3
Düşünemiyorum ama Web Formları tasarım tarafından kırıldı. Daha fazla performans kaybı, Response.End () öğesini çağırmak veya sayfanın her şeyi yüklemesine izin vermek ve ardından yanıtı bastırmak nedir? Response.End () 'in burada "daha fazla" zararlı olduğunu göremiyorum. Dahası, Microsoft `` ThreadAbortedException '' ı bu koddan da anlaşılacağı üzere normal bir olay olarak ele alır: referenceource.microsoft.com/#System.Web/UI/Page.cs,4875 Response.End () 'ye karşı olan bir şey başarısız olabilir bazen yanıtın görüntülenmesine neden olabilecek yanıtı iptal etmek.
Ghasan

99

Bu soru yanıtla ilgili tüm google aramalarının üst kısmında görünür. Son olarak, ASPX sayfasının tamamını oluşturmadan bir etkinliğe yanıt olarak CSV / XML / PDF vb. Göndermek isteyen diğer aramalar için bunu nasıl yaparım? . (oluşturma yöntemlerini geçersiz kılmak, böyle basit bir görev IMO'su için aşırı karmaşıktır)

// 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
Bunu yapmak için bir APSX sayfası kullanmamalısınız. Bu çok boşa giden bir çaba. Bir ASMX veya Web Hizmeti, ASPX sayfası dışında bir şey kullanmanız gerekir.
mattmanser

19
Bu en kolay uygulama ile cevap gibi görünüyor. Anahtar Response.SuppressContent = True.
Chris Weber

3
@mattmanser - Aynı kaynağın farklı gösterimleri için ayrı bir sayfaya sahip olmak her zaman kolay / en iyi / tavsiye edilemez. REST, vb. Hakkında düşünün. İstemci, başlık veya param yoluyla csv, xml istediklerini belirtirse, asp.net'in normal oluşturma olanakları aracılığıyla html desteği sağlarken, bu yöntem kesinlikle en iyisi olacaktır.
Chris Weber

1
Bu benim için işe yaramadı. Response.End () ile çalışan bir sayfam vardı, ancak Response.Close (), Response.Flush () her türlü kombinasyonunu kullanıyorum. HttpContext.Current.ApplicationInstance.CompleteRequest () ve diğer çeşitli şeyler, Yanıt'ta bir GzipStream filtresi olsaydı çalışmadı. Görünen şey, sayfamın dosyamla birlikte hâlâ çıktı almasıydı. Sonunda Render () işlevini (boş olması) geçersiz kıldım ve bu benim için çözdü.
Aerik

1
CompleteRequest, uygulama kanalının bölümlerini atlar, ancak yine de sayfa oluşturma işleminin geri kalanında çalışır, bunun yanıt gibi hemen durmaz. Son, daha zariftir. Bu sayfadaki diğer cevaplarda neden daha ayrıntılı açıklamalar var.
Jay Zelos

11

"Hala Response.Close ve CompleteRequest () arasındaki farkı bilmiyorum" sorusunda şunu söyleyebilirim:

CompleteRequest () yöntemini tercih edin, Response.Close () yöntemini kullanmayın.

Bu davanın iyi bir özeti için aşağıdaki makaleye bakın .

CompleteRequest () öğesini çağırdıktan sonra bile, yanıt çıktı akışına bazı metinlerin (ör. ASPX kodundan yeniden yönlendirilmiş) ekleneceğini unutmayın. Aşağıdaki makalede açıklandığı gibi Render ve RaisePostBackEvent yöntemlerini geçersiz kılarak bunu önleyebilirsiniz .

BTW: Response.nd () yönteminin kullanılmasını önlemeyi kabul ediyorum, özellikle de dosya indirme işlemini taklit etmek için http akışına veri yazarken. Günlük dosyamız ThreadAbortExceptions ile dolana kadar Response.End () yöntemini kullandık.


Açıkladığınız gibi Render'ı geçersiz kılmakla ilgileniyorum, ancak "sonraki makale" bağlantısı öldü. Belki girişinizi güncelleyebilirsiniz?
paqogomez

Geç cevap verdiğim için üzgünüm. Bu makalede ne olduğunu tam olarak hatırlamıyorum. Ancak, bunu webarchive.org'da
Jan Šotola

9

" Response.End zararlıdır " ifadesine katılmıyorum . Kesinlikle zararlı değil. Yanıt. Ne diyorsa onu yapar; sayfanın yürütülmesini sonlandırır. Nasıl uygulandığını görmek için reflektör kullanılması sadece öğretici olarak görülmelidir.


Benim 2cent Öneri
KAÇININ kullanarak Response.End()kontrol akışı.
DO kullanımı Response.End()istek yürütme durdurma ve (genellikle) * kod bu noktada geçmiş yürütmek farkında olmak gerekirse.


* Response.End()ve ThreadAbortException s.

Response.End() geçerli uygulamasının bir parçası olarak bir ThreadAbortException oluşturur (OP tarafından belirtildiği gibi).

ThreadAbortException yakalanabilecek özel bir istisnadır, ancak catch bloğunun sonunda otomatik olarak tekrar yükseltilecektir.

, ThreadAbortExceptions ile ilgilenmek zorundadır kod yazmak SO için Mehrdad cevabı @ görmek için nasıl çalıştığını görmek için nasıl nihayet engellemek bir bir ThreadAbortException algılayabilir diye başvuran nerede RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup Yöntem ve Kısıtlı Yürütme Bölgeler


Rick Strahl makale söz öğreticidir ve emin sıra yorumları okumak için yapmak. Strahl'ın konusunun özel olduğunu unutmayın. Verileri istemciye (bir görüntüye) almak ve daha sonra görüntünün sunumunu yavaşlatmayan isabet izleme veritabanı güncellemesini işlemek istedi.


Bu yayının gördük stackoverflow.com/questions/16731745/... yerine Response.End () ait Response.SuppressContent kullanarak düşündüren = Doğru HttpContext.Current.ApplicationInstance.CompleteRequest ()
jazzBox

3

Program akışını kontrol etmek için Response.End () kullanmayı hiç düşünmedim.

Ancak Response.End (), örneğin bir kullanıcıya dosya sunarken faydalı olabilir.

Dosyayı yanıta yazdınız ve yanıtın dosyanıza zarar verebileceğinden başka bir şey eklenmesini istemiyorsunuz.


1
"Yanıt tamamlandı" diyen bir API ihtiyacını anlıyorum. Ancak Response.End () de bir iş parçacığı iptali yapar. Bu sorunun en önemli noktası. Bu iki şeyi birleştirmek ne zaman iyi bir fikirdir?
Cheeso

2

Daha önce zorla bitirmek için .NET ve Klasik ASP'de Response.End () kullandım. Örneğin, çok sayıda giriş denemesi olduğunda kullanıyorum. Veya kimliği doğrulanmamış bir girişten güvenli bir sayfaya erişildiğinde (kaba örnek):

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

Bir kullanıcıya dosya sunarken Yıkama kullanacağım, Son sorunlara neden olabilir.


Unutmayın, Flush () "bu son" değildir. Sadece "şimdiye kadar her şeyi yıkayın". "Bu son" istemenin nedeni, istemcinin tüm içeriğe sahip olduğunu bilmesine izin vermektir, sunucu gidip başka şeyler yapabilir - bir günlük dosyasını güncelleyin, bir veritabanı sayacını sorgulayın veya her neyse. Response.Flush'ı çağırır ve sonra bunlardan birini yaparsanız, istemci daha fazlasını beklemeye devam edebilir. Response.End () öğesini çağırırsanız, kontrol atlar ve DB sorgu vb.
Almaz

Alternatif olarak, boolun 'endResponse olduğu geçersiz kılınan Response.Redirect ("....", true) geçersiz kılmayı kullanabilirsiniz: Sayfanın geçerli yürütmesinin sona ermesi gerekip gerekmediğini gösterir "
Robert Paulson

Giriş kimlik bilgileriyle güvence altına alınması gereken sayfaları korumak için Form Kimlik Doğrulaması çerçevesini kullanmak her zaman daha iyidir.
Robert Paulson

3
Aslında, kendimi düzeltmek için, varsayılan olarak Response.Redirect ve Server.Transfer değerlerinin geçersiz kılınması ve 'false' iletilmemesi halinde Response.End'i çağırması gerektiğine inanıyorum. Kodunuzun yazılma şekli Response.Ve asla çağrılmaz ,
Robert Paulson

1
Response.end .net içinde klasik ASP'de olduğundan çok farklı çalışır. .Net'te oldukça kötü olabilen bir tehdit borusu istisnasına neden olur.
Andy

2

Ben sadece Response.End () test / hata ayıklama mekanizması olarak kullandım

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

Araştırma açısından yayınladığınız şeyden yola çıkarak, Yanıt gerektiriyorsa bunun kötü bir tasarım olacağını söyleyebilirim.


0

Klasik asp, bazı ajax çağrılarında 3 ila 10 saniye arasında bir TTFB (Time To First Byte) vardı, normal sayfalarda TTFB daha çok daha fazla SQL çağrıları ile.

Döndürülen ajax, sayfaya enjekte edilecek bir HTML segmentiydi.

TTFB, oluşturma süresinden birkaç saniye daha uzundu.

Bir yanıt eklersem. Render işleminden sonra TTFB büyük ölçüde azaldı.

Aynı etkiyi bir "</body> </html>" yayarak elde edebilirim, ancak bu muhtemelen json veya xml çıktısı verirken çalışmaz; here response.end gereklidir.


Bunun eski bir cevap olduğunu biliyorum, ama sonra tekrar klasik asp eski. Bunu yararlı buldum ;-)
Leif Neland
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.