Soru Response.Redirect neden System.Threading.ThreadAbortException neden olur?


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

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

Bunu anlamış olmak, hataya, web sunucusunun, answer.redirect'in çağrıldığı sayfanın geri kalanını iptal etmesinden kaynaklanmasıdır.

Biliyorum ikinci bir parametre ekleyebilirim Response.Redirect buna endResponse denir. EndResponse'yi True olarak ayarlıyorum, hala hatayı alıyorum ama eğer bunu False olarak ayarlarsam, o zaman yapmam. Eminim ki bu, web sunucusunun yönlendirdiğim sayfanın geri kalanını çalıştırdığı anlamına geliyor. En azını söyleyecek kadar verimsiz gibi görünüyor. Bunu yapmanın daha iyi bir yolu var mı? Başka bir şey Response.Redirect ya da eski sayfanın, ThreadAbortException?


212
2018-05-05 22:02


Menşei




Cevaplar:


Doğru desen, endResponse = false ile Redirect aşırı yüklenmesini çağırmak ve IIS boru hattına denetime geri döndükten sonra doğrudan EndRequest aşamasına ilerlemesi gerektiğini bildiren bir çağrı yapmaktır:

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

Bu blog yazısı Thomas Marquardt, bir Application_Error işleyicisindeki özel yönlendirme durumunun nasıl ele alınacağı dahil olmak üzere ek ayrıntılar sağlar.


305
2018-05-05 22:28



Sonra kod yürütür Context.ApplicationInstance.CompleteRequest();. Niye ya? Zorunda mıyım return olay işleyicisinden koşullu olarak mı? - IsmailS
@Ismail: Redirect'in eski sürümü herhangi bir sonraki kodun yürütülmesini önlemek için bir ThreadAbortException atar. Daha yeni, tercih edilen sürüm atmaz, ancak işleyicide ek kodunuz varsa, kontrolün erkenden iade edilmesinden siz sorumlusunuz. - Joel Fillmore
Bence "ikinci aşırı yük" demek yerine daha doğru The old version of Redirect Yorumunuzda kullandığınız ifade, MS'nin uygulamayı değiştirdiği gibi değil, sadece başka bir aşırı yüklenme. - BornToCode
Bunun ideal bir model olduğunu düşünmüyorum. Sayfanın yanıtı sonlandırmamasını ve yürütme işlemine devam etmemesini ve ardından programlı olarak isteği tamamlamasını istemiyorsunuz. Ancak aspx sayfasının ve etkinlik işleyicilerinin oluşturulmasına ne dersiniz? yanıt aracını sonlandırmadan, "completeRequest ()" düğmesine basmadan önce aspx sayfasını oluşturmayı bitirecektir. Şimdi sayfamda bir sunucu tarafı özelliğini kullanıyorum, geçerli oturum açma belirlemek için bir oturum değişkeni demek, eğer süresinin bitmesi durumunda bile yeniden yönlendirmeden önce boş bir istisna atar. Ve bunu düzeltmenin tek yolu, endResponse'yi gerçeğe dönüştürmektir. - Abs
@Abs İfadenizin "yanıtın bitmemesi anlamına gelmediğine inanıyorum, isabetten önce aspx sayfasını oluşturmayı bitirecek" completeRequest () '"doğru değil. MSDN'ye göre (msdn.microsoft.com/en-us/library/ms178472.aspx#Anchor_0) sayfa, sayfa yüklendikten ve diğer kontrol olaylarından sonra işlenecektir. - Hawkeye


Var yok hayır basit ve zarif bir çözüm Redirect ASP.Net WebForms'ta sorun. Arasında seçim yapabilirsiniz Kirli çözüm ve Sıkıcı çözüm

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

Sıkıcı: Tavsiye edilen yol aramaktır Response.Redirect(url, false) ve sonra Context.ApplicationInstance.CompleteRequest() Ancak, kod yürütme devam edecek ve sayfa iş döngüsündeki olay işleyicilerinin kalanı yine de yürütülecektir. (Örneğin, Page_Load içinde yönlendirmeyi gerçekleştirirseniz, yalnızca işleyicinin geri kalanı çalıştırılacak, Page_PreRender vb. Yine de çağrılacak - işlenen sayfa tarayıcıya gönderilmeyecektir. Örneğin, sayfada bir bayrağın ayarlanması ve ardından herhangi bir işlem yapmadan önce sonraki olay işleyicilerinin bu bayrağı kontrol etmesine izin verin.

(Belgelere CompleteRequest bunu belirtir "ASP.NET'in tüm olayları atlamasına ve HTTP boru hattı yürütme zincirinde filtrelemesine neden olur". Bu kolayca yanlış anlaşılabilir. Daha fazla HTTP süzgeçlerini ve modüllerini atlatır, ancak şu andaki diğer olayları atlamaz. sayfa yaşam döngüsü.)

Daha derin sorun, WebForms'un bir soyutlama seviyesinden yoksun olmasıdır. Bir olay işleyicisinde bulunduğunuzda, çıktı almak için bir sayfa oluşturma sürecindesiniz. Bir olay işleyicide yönlendirme çok çirkindir çünkü farklı bir sayfa oluşturmak için kısmen oluşturulmuş bir sayfayı sonlandırıyorsunuz. Kontrol akışı görüntüleme görünümlerinden ayrı olduğu için MVC'nin bu sorunu yoktur, bu yüzden yalnızca bir geri dönüş yaparak temiz bir yönlendirme yapabilirsiniz. RedirectActionkontrolörde, bir görünüm oluşturmadan.


142
2017-10-18 15:09



Bleurg ... bu, web formlarının çirkin olmasının nedenlerinden biri ... - mortb
Duyduğum en iyi web formlarının "yalancı sos" olduğunu düşünüyorum. - mcfea
Bu cevabın detayını çok seviyorum. Kabul edilen cevaptan daha iyi - Jess
Kullanırsanız kirli seçeneği, Visual Studio'da ThreadAbortException üzerinde mola devre dışı bırakabilirsiniz. DEBUG> İstisnalar .... genişletmek CLR> System.Threading> System.Threading.ThreadAbortException öğesinin işaretini kaldırın.. - Jess
Benim durumumda bu istisna her seferinde değil, sadece birkaç kez arasında gerçekleşiyor. Anlamı Aynı uygulamada Live (Canlı) düğmesine tıklarsanız ve çalışıyorsa, aynı bağlantı ve aynı buton diğer makineden tıklandığında System.Threading.ThreadAbortException değerini veriyor. Her zaman neden olmasın bir fikrin var mı ?? - Sagar Shirke


Biliyorum geç kaldım, ama sadece bu hatayı yaşadım Response.Redirect içinde Try...Catch blok.

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

Düzenle

@ Kiquenet'in yorumuna cevaben, Response.Redirect'i Try ... Catch bloğuna koymanın bir alternatifi olarak yapacağım şey.

Yöntemi / işlevi iki aşamaya ayırırdım.

Deneyin içinde bir adım ... Yakalama bloğu istenen eylemleri gerçekleştirir ve eylemlerin başarısını veya başarısızlığını göstermek için bir "sonuç" değeri ayarlar.

Try dışında iki adım ... Catch bloğu, "sonuç" değerinin ne olduğuna bağlı olarak yönlendirmeyi (veya yapmaz) yapar.

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

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

28
2018-06-28 06:51



Hangisi iyi desen ve uygulama ? - Kiquenet
@Kiquenet, ne yapacağımı gösteren bir örnek için güncellenmiş cevabımı gör. En iyi rotasını söylemek için değil, ama bence uygun bir alternatif. - Ortund
Kodumu bir denemeye kadar yakalamadan sorun çıkmadı, yakalamam ... Diğer kod çağrılarının bu davranışı .NET'e neden olduğunu merak ediyorum - GibralterTop


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

Bu KB makalesi Bu davranışı açıklar Request.End() ve Server.Transfer() yöntemler).

İçin Response.Redirect() aşırı yüklenme var:

Response.Redirect(String url, bool endResponse)

Eğer geçersen endResponse = yanlışsonra istisna atılmaz (ancak çalışma zamanı, geçerli isteği işlemeye devam edecektir).

Eğer endResponse = true (veya diğer aşırı yük kullanılırsa), istisna atılır ve mevcut istek hemen sonlandırılır.


8
2018-05-05 22:11





Response.Redirect (url, true) nasıl çalışır. İş parçacığını iptal etmek için ThreadAbortException'ı atar. Sadece bu istisnayı görmezden gel. (Bunu gördüğünüz bazı global hata işleyici / kaydedici olduğunu farz ediyorum?)

İlginç bir tartışma Response.End () zararlı mıdır?


7
2018-05-05 22:09



Bir iş parçacığının iptal edilmesi, yanıtın erken sonuyla başa çıkmak için gerçekten ağır bir yol gibi görünüyor. Çerçevenin yerini almak için yeni bir iplik üretmek yerine ipliği tekrar kullanmayı tercih etmemesi garip geliyor. - spender


Burada resmi hat problem üzerine (en sonunu bulamadım, fakat durumun daha geç sürümler için değiştiğini düşünmüyorum)


6
2018-05-05 22:08



@svick Link rot'tan bağımsız olarak, sadece cevaplar gerçekten mükemmel cevaplar 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


Yaptığım şey, bu istisnayı, başka bir olası istisna ile birlikte yakalamaktır. Umarım bu birisine yardım eder.

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

1
2018-02-28 17:00



Daha iyi kaçının ThreadAbortException  istisna göre yakala ve hiçbir şey yap ? - Kiquenet


Ayrıca başka bir çözüm denedim, ancak yönlendirme sonrasında çalıştırılan kodlardan bazıları.

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

Yani yönlendirme sonra kod yürütme önlemek gerekiyorsa

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

1
2018-01-17 15:23



Jorge yanıtını takip et. Bu, iş parçacığı iptal özel durumunun günlüğe kaydedilmesini genellikle kaldıracaktır. - Maxim Lavrov
Birisi neden bir istisna aldığını sorduğunda, sadece onu denemekle oynamayı söylüyorum .. yakalama bir cevap değildir. Kabul edilen cevaba bakınız. Cevabınızı "geç cevap" ı incelerken açıkladım. - manuell
Bu Response.Redirect'in 2. argümanı için false koyma ile aynı etkiye sahiptir, ancak "false" ThreadAbortException'ı yakalamaktan daha güzel bir çözümdür. Bunu bu şekilde yapmak için iyi bir neden olduğunu görmüyorum. - NickG


Bunu önlemek için bile denedim, sadece iş parçacığı üzerinde el ile iptal, ancak ben "CompleteRequest" ile bırakın ve devam ediyorum - benim kodları yönlendirmeler sonra yine de dönüş komutları vardır. Yani 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
2017-09-03 19:52