Response.Redirect neden System.Threading.ThreadAbortException özelliğine neden oluyor?


230

Formumu yeni bir sayfaya yönlendirmek için Response.Redirect (...) kullandığımda hatayı alıyorum:

Mscorlib.dll dosyasında 'System.Threading.ThreadAbortException' türünün ilk şans istisnası oluştu mscorlib.dll dosyasında
'System.Threading.ThreadAbortException' türü istisnası oluştu, ancak kullanıcı kodunda işlenmedi

Bunun benim anlayışım, hatanın web sunucusunun, yanıt.redirect'in çağrıldığı sayfanın geri kalanını iptal etmesinden kaynaklanıyor olmasıdır.

Response.RedirectEndResponse denilen ikinci bir parametre ekleyebileceğimi biliyorum . EndResponse öğesini True olarak ayarlarsam hala hatayı alıyorum, ancak False olarak ayarlarsam almıyorum. Bu, web sunucusunun yönlendirdiğim sayfanın geri kalanını çalıştırdığı anlamına geldiğinden eminim. Hangi az söylemek verimsiz gibi görünüyor. Bunu yapmanın daha iyi bir yolu var mı? Başka bir şey Response.Redirectveya alamayacağım yerlerde eski sayfayı yüklemeyi durdurmaya zorlamak için bir yolu var ThreadAbortExceptionmı?

Yanıtlar:


332

Doğru desen, endResponse = false ile Yönlendirme aşırı yükünü çağırmak ve denetimi döndürdüğünüzde IIS kanalına doğrudan EndRequest aşamasına ilerlemesi gerektiğini bildirmek için bir çağrı yapmaktır:

Response.Redirect(url, false);
Context.ApplicationInstance.CompleteRequest();

Thomas Marquardt'ın bu blog yazısı , bir Application_Error işleyicisinin içindeki özel yönlendirme durumunun nasıl ele alınacağı da dahil olmak üzere ek ayrıntılar sağlar.


6
Sonra kodu yürütür Context.ApplicationInstance.CompleteRequest();. Neden? returnOlay işleyicisinden şartlı olarak almam gerekecek mi?
IsmailS

4
@Ismail: Redirect'in eski sürümü, sonraki kodların yürütülmesini önlemek için bir ThreadAbortException oluşturur. Daha yeni, tercih edilen sürüm atmaz, ancak işleyicide ek kod varsa, kontrolü erken iade etmek sizin sorumluluğunuzdadır.
Joel Fillmore

12
Bence The old version of Redirectyorumunuzda kullandığınız cümle yerine "ikinci aşırı yük" demek daha doğru , MS'in uygulamayı değiştirdiği gibi değil, sadece başka bir aşırı yük.
BornToCode

2
Bunun ideal bir kalıp olduğunu düşünmüyorum. Sayfadan yanıtı sonlandırmamasını ve yürütmeye devam etmemesini ve ardından isteği programlı olarak tamamlamasını istiyorsunuz. Peki ya aspx sayfa ve olay işleyicileri oluşturma hakkında? yanıt anlamına gelmezse, "completeRequest ()" öğesine basmadan önce aspx sayfasının oluşturulmasını tamamlayacaktır. Şimdi sayfamda bir sunucu tarafı özelliği kullanıyorsam, geçerli oturum açmayı belirlemek için bir oturum değişkeni söylüyorum, bu sürenin dolması durumunda yeniden yönlendirmeden önce boş bir istisna atacaktır. Bunu düzeltmenin tek yolu, sonResponse'yi tekrar doğru yapmaktır.
Abs

1
Bu yanıtı oylayacaktı, ancak bu sayfa kodu yürütülmeye devam etti. Bu benim durumum için ideal değil. "ThreadAbortException" işlemek veya yoksaymak için çok daha temiz
DaniDev

159

Orada hiçbir basit ve zarif bir çözüm RedirectASP.Net WebForms sorunun. Kirli çözelti ile Sıkıcı çözelti arasında seçim yapabilirsiniz

Kirli : Response.Redirect(url)tarayıcıya bir yönlendirme gönderir ve ardından ThreadAbortedExceptiongeçerli iş parçacığını sonlandırmak için a atar . Bu nedenle, Redirect () - çağrısının ötesinde hiçbir kod yürütülmez. Dezavantajları: Kötü bir uygulamadır ve bu gibi iplikleri öldürmek için performans sonuçları vardır. Ayrıca, ThreadAbortedExceptionsistisna günlüğünde görünecektir.

Sıkıcı : Önerilen yol aramaktırResponse.Redirect(url, false) ve sonra Context.ApplicationInstance.CompleteRequest()Ancak kod yürütme devam eder ve sayfa yaşam döngüsünde kalan olay işleyicileri yine de yürütülür. (Örneğin, yönlendirmeyi Page_Load içinde gerçekleştirirseniz, yalnızca işleyicinin geri kalanı yürütülmez, Page_PreRender vb. De çağrılır - işlenen sayfa tarayıcıya gönderilmez. ör. sayfada bir bayrak ayarlama ve ardından herhangi bir işlem yapmadan önce sonraki olay işleyicilerin bu bayrağı kontrol etmesine izin verin.

(Belgelerin CompleteRequest" ASP.NET'in HTTP boru hattı yürütme zincirindeki tüm olayları ve filtrelemeyi atlamasına neden olduğunu" belirtmektedir . geçerli sayfa yaşam döngüsünde.)

Daha derin sorun, WebForms'un bir soyutlama eksikliğidir. Bir olay işleyicisindeyseniz, çıktı almak için zaten bir sayfa oluşturma sürecindesiniz. Farklı bir sayfa oluşturmak için kısmen oluşturulmuş bir sayfayı sonlandırdığınız için bir olay işleyicisinde yeniden yönlendirme çirkindir. MVC bu sorunla karşılaşmaz, çünkü kontrol akışı görüntüleme görünümlerinden ayrıdır, bu yüzden RedirectActionbir görünüm oluşturmadan kontrolöre bir geri döndürerek temiz bir yönlendirme yapabilirsiniz .


7
Ben şimdiye kadar duydum webforms en iyi açıklaması "yalan sos" olduğuna inanıyorum.
mcfea

9
Bu cevaptaki ayrıntı miktarını seviyorum. Kabul edilen cevaptan daha iyi
Jess

Kirli seçeneğini kullanırsanız, Visual Studio'da ThreadAbortException üzerinde sonu kapatabilirsiniz. DEBUG> İstisnalar ... . CLR> System.Threading> System.Threading.ThreadAbortException öğesinin işaretini genişletin .
Jess

Tanrıya şükür düzgün cevabı olan biri var ve bu en yüksek oyu alan cevap olmalı.
Abs

1
Benim durumumda bu istisna her seferinde gelmiyor, aralarında sadece birkaç kez oluyor. Araçlar Canlı uygulamanın aynı düğmesine tıklanırsa ve çalışıyorsa ancak diğer makineden aynı bağlantı ve aynı düğmeye tıklandığında System.Threading.ThreadAbortException veriyor. Neden her zaman olmuyor fikri?
Sagar Shirke

33

Geç kaldım biliyorum ama benim eğer sadece hiç bu hatayı yaşadım Response.Redirectbir olduğunu Try...Catchbloğu.

Bir Try.Catch bloğuna asla bir Response.Redirect koymayın. Kötü uygulama

Düzenle

@ Kiquenet'in yorumuna yanıt olarak, Response.Redirect'i Try ... Catch bloğuna koymak için alternatif olarak ne yapardım.

Metodu / fonksiyonu iki adıma böldüm.

Try ... Catch bloğunun içindeki birinci adım, istenen eylemleri gerçekleştirir ve eylemlerin başarılı veya başarısız olduğunu belirtmek için bir "sonuç" değeri ayarlar.

Try ... Catch bloğunun dışındaki ikinci adım, "sonuç" değerinin ne olduğuna bağlı olarak yönlendirme yapar (veya yapmaz).

Bu kod mükemmel olmaktan uzaktır ve test etmediğim için muhtemelen kopyalanmamalıdır

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.
    }
}

@Kiquenet, ne yapacağımı gösteren bir örnek için güncellenmiş cevabımı inceleyin. Söylememenin en iyi yolu, ama bence geçerli bir alternatif.
Ortund

Ben bir deneyin kodumu tamamlayana kadar sorunu yoktu, yakalamak ... Başka kod çağrıları .NET bu davranışa neden merak ediyorum
ilginç-adı-burada

8

Response.Redirect() geçerli isteği iptal etmek için bir istisna atar.

Bu KB makalesi , ( Request.End()ve Server.Transfer()yöntemleri için de ) bu davranışı açıklar .

İçin Response.Redirect()aşırı yüklenmeye vardır:

Response.Redirect(String url, bool endResponse)

Eğer geçerseniz endResponse = false , daha sonra özel durum değildir (ancak çalışma zamanı Mevcut isteği işlemeye devam edeceğiz).

Eğer endResponse = true (veya başka aşırı yük kullanılırsa), istisna atılır ve mevcut talebi derhal iptal edilecektir.


7

İşte sorundaki resmi hat (En son bulamadım, ancak .net'in sonraki sürümleri için durumun değiştiğini düşünmüyorum)


5
@svick Bağlantı çürümesine bakılmaksızın, yalnızca bağlantı yanıtları gerçekten harika yanıtlar değildir. meta.stackexchange.com/q/8231 I think that links are fantastic, but they should never be the only piece of information in your answer.
Ryan Gates

7

İşte böyle Response.Redirect(url, true) çalışır. ThreadAbortExceptionİpliği iptal etmek için atar . Sadece bu istisnayı görmezden gelin. (Gördüğünüz bazı küresel hata işleyici / kaydedici olduğunu sanıyorum?)

İlginç ilgili tartışma Response.End()Zararlı kabul edilen? .


4
Bir iş parçacığını iptal etmek, erken yanıt sonu ile başa çıkmak için gerçekten ağır bir yol gibi görünüyor. Çerçevenin yerini almak için yeni bir tane döndürmek yerine ipliği yeniden kullanmayı tercih etmeyeceğini garip buluyorum.
harcama

3

Ayrıca başka bir çözüm denedim, ancak bazı kod yeniden yönlendirmeden sonra yürütüldü.

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

Bu nedenle, yönlendirmeden sonra kod yürütülmesini önlemeniz gerekiyorsa

try
{
   //other code
   Response.Redirect("")
  // code not to be executed
}
catch(ThreadAbortException){}//do there id nothing here
catch(Exception ex)
{
  //Logging
}

1
sadece Jorge cevabını takip et. Bu, İş parçacığı iptali istisnasının günlüğünü ectually kaldıracaktır.
Maxim Lavrov

Birisi neden bir İstisna aldığını sorduğunda, ona sadece try..catch ile oynamasını söylemek bir cevap değildir. Kabul edilen cevaba bakınız. Ben "geç cevap" incelerken cevabınıza yorum yaptım
manuell

Bu, Response.Redirect'in 2. argümanı için false koymakla aynı etkiye sahiptir, ancak "false", ThreadAbortException özel durumunu yakalamaktan daha hoş bir çözümdür. Bunu bu şekilde yapmak için iyi bir neden olduğunu görmüyorum.
NickG

2

ben bile, sadece iş parçacığı üzerindeki iptal iptal yapıyor, ancak bunu önlemek için çalıştı, ama yerine "CompleteRequest" ile bırakın ve devam - benim kod yine de yönlendirmeler sonra dönüş komutları vardır. Böylece bu yapılabilir

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

1

Yaptığım başka bir istisna dışında bu istisnayı yakalamak. Umarım bu birine yardım eder.

 catch (ThreadAbortException ex1)
 {
    writeToLog(ex1.Message);
 }
 catch(Exception ex)
 {
     writeToLog(ex.Message);
 }

2
Daha iyi önlemek ThreadAbortException istisna dışında av ve hiçbir şey ?
Kiquenet

-1

Ben de bu problemi yaşadım.

Kullanmayı deneyin Server.Transfer yerineResponse.Redirect

Benim için çalıştı.


2
Server.Transfer yine de ThreadAbortException: support.microsoft.com/kb/312629 atar , bu yüzden önerilen bir çözüm değildir.
Joel Beckham

9
Server.Transfer kullanıcıya bir yönlendirme göndermez. Tamamen farklı bir amacı var!
Marcel

1
Server.transfer ve responce.redirect farklı
mzonerz
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.