HAVIT Knowledge Base

Vývoj webových aplikací, .NET, SQL, návrh
Welcome to HAVIT Knowledge Base Sign in | Join | Help
-
Home Články Forums Obrázky Soubory

ASP.NET

Vývoj webových aplikací ASP.NET

Pozor na Response.Redirect(), Response.End() a obsluhu výjimek

Jak myslíte, že dopadne následující příklad po kliknutí na tlačítko? (Stránka obsahuje jen label MyLabel a button MyButton)

public partial class _Default : System.Web.UI.Page
{
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        MyLabel.Text = (string)Session["OK"];
    }

    void MyButton_Click(object sender, EventArgs e)
    {
        try
        {
            Session["OK"] = "ok";
            Response.Redirect("~/");
        }
        catch
        {
            Session["OK"] = "exception";
        }
    }
}

Mnohé z Vás asi překvapím, když řeknu, že do Session["OK"] se uloží "exception" a ten se v dalším requestu i zobrazí.

Response.Redirect(), resp. metoda Response.End(), kterou Redirect sám volá, totiž funguje tak, že vyvolá ve webové aplikaci interní výjimku (Thread.CurrentThread.Abort()), která je samotnou webovou aplikací zpracovávána tak, aby bylo dosaženo kýženého efektu, tj. aby se vykonávání kódu zastavilo v daném místě a další kód se nevykonal.

Potíž však nastane v okamžiku, kdy sami obalíme volání Response.Redirect() či Response.End() zachytáváním výjimek a nespecifikujeme dostatečně typ výjimek, které chceme zachytávat. Pokud necháme chytat výjimky všechny, uvedeme jako typ Exception, pak se dočkáme nežádoucího efektu, kdy nám volání Response.Redirect()/End() způsobí vykonání obsluhy výjimky, blok catch. Zachycení oné speciální interní výjimky je totiž v call-stacku poměrně vysoko a náš catch blok se dostane na řadu dříve (Zajímavé nicméně je, že přestože náš catch block výjimku obslouží, další kód za Redirect()/End() se přesto nevykoná. Interní výjimka je totiž použita pouze jako nosič informace, ale Thread.Abort() proběhne v nativním kódu úspěšně).

Východiskem je tedy obsluhovat pouze specifické typy výjimek, tak, jak to ostatně obecné guidelines doporučují pro všechny situace.

Published 6. března 2008 12:08 by Robert Haken

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

 

F. said:

Response.Redirect() je ale pretazena, druhy parameter potom hovori, ci sa ma volat hned Response.End() alebo najpr ukoncit spracovanie aktualnej stranky.

března 6, 2008 14:05
 

Robert Haken said:

Jo, nicméně nechat doběhnout kód stránky následující po Response.Redirect() zpravidla není vůbec žádoucí a sám si neuvědomuji, že bych někdy ten End() nechtěl.

března 6, 2008 15:10
 

Radek Petřík said:

Není pravda, že se po obsloužení výjimky další kód za Response.End() nevykoná. Response.End() vyvolá ThreadAbortException, která má speciální chování - na konci catch bloku je automaticky vyvolána znovu. Takže po Response.End() jsou tím pádem vykonány všechny finally bloky a catch bloky, které akceptují tuto výjimku. Před ukončením vlákna je tedy proveden jen ten kód, u kterého je to nezbytně nutné. Můžete si všimout, že je po Response.End() vykonána virtuální metoda Page.OnUnload(), která je volána z finally bloku Page.ProcessRequest() (což je další důkaz, že se nějaký kód po obsloužení výjimky vykoná).

ThreadAbortException se takto chová i ve WinForms aplikacích.

listopadu 18, 2010 20:21

What do you think?

(required) 
(optional)
(required) 
Enter the code you see below

Submit