Обработка исключений ThreadAbortException в asp.net при выполнении метода Response.End()

Во время выполнения Response.End(); метод в asp.net кидает ThreadAbortException который я обработал в блоке catch, после завершения внутреннего блока catch я хочу выполнить некоторый дополнительный код, но он непосредственно переходит к внешнему блоку catch. Это происходит из-за того, что ответ закончился, и.net framework не выполняет никакого дополнительного кода?

protected void btn_click(object sender, EventArgs e)
{

    try
    {
        string fileToDownload = MapPath(@"~\Sample.txt");
        string fileToRead = MapPath(@"~\FileNotExist.txt");

        try
        {
            //Section 1
            try
            { 
                // try to read the file which does not exist to raise the exception
                StreamReader ss = new StreamReader(fileToRead);
            }
            catch (IOException IoEx)
            {
                // Just for sample exception
            }

            // Section 2 code block still execute because exception handled by upper try catch block 
            //Section 2

            Response.Clear();
            Response.ClearHeaders();
            Response.AddHeader("Content-Disposition", "attachment;filename=SampleTemplate.txt");
            Response.ContentType = "text";
            Response.WriteFile(fileToDownload);
            Response.Flush();
            Response.End();

        }
        catch (System.Threading.ThreadAbortException abrtEx)
        {
          // do not treat this exception as Exception
        }

        //Section 3 Code block not executing even after exception handeled by ThreadAbortException 
        //Section 3
         string test = "Do futher process after sample downloaded";


    }
    catch (Exception ex) // Outer Catch Block
    {
        throw ex;
    }


}

3 ответа

Решение

Вместо

Response.End()

использование

HttpContext.Current.ApplicationInstance.CompleteRequest()

Как это

protected void btn_click(object sender, EventArgs e)
{
    try
    {
        string fileToDownload = MapPath(@"~\Sample.txt");
        string fileToRead = MapPath(@"~\FileNotExist.txt");

        try
        {
            //Section 1
            try
            { 
                // try to read the file which does not exist to raise the exception
                StreamReader ss = new StreamReader(fileToRead);
            }
            catch (IOException IoEx)
            {
                // Just for sample exception
            }

            // Section 2 code block still execute because exception handled by upper try catch block 
            //Section 2

            Response.Clear();
            Response.ClearHeaders();
            Response.AddHeader("Content-Length", fileToDownload.Length.ToString()); 
            Response.AddHeader("Content-Disposition","attachment;filename=SampleTemplate.txt");
            Response.ContentType = "text";
            Response.WriteFile(fileToDownload);
            Response.Flush();
            HttpContext.Current.ApplicationInstance.CompleteRequest();

        }
        catch (System.Threading.ThreadAbortException abrtEx)
        {

        }

        //Section 3 Code block not executing even after exception handeled by ThreadAbortException 
        //Section 3
         string test = "Do futher process after sample downloaded";


    }
    catch (Exception ex) // Outer Catch Block
    {
        throw ex;
    }
}

Согласно PRB: ThreadAbortException возникает, если вы используете Response.End, Response.Redirect или Server.Transfer:

Если вы используете метод Response.End, Response.Redirect или Server.Transfer, возникает исключение ThreadAbortException. Вы можете использовать оператор try-catch, чтобы перехватить это исключение.

Метод Response.End завершает выполнение страницы и переносит выполнение в событие Application_EndRequest в конвейере событий приложения. Строка кода, следующая за Response.End, не выполняется.

Эта проблема возникает в методах Response.Redirect и Server.Transfer, поскольку оба метода вызывают Response.End внутри.

Чтобы обойти эту проблему

используйте один из следующих методов:

Для Response.End вызовите метод HttpContext.Current.ApplicationInstance.CompleteRequest вместо Response.End, чтобы пропустить выполнение кода для события Application_EndRequest.

Для Response.Redirect используйте перегрузку Response.Redirect(String url, bool endResponse), которая передает значение false для параметра endResponse, чтобы подавить внутренний вызов Response.End. Например: Response.Redirect ("nextpage.aspx", false); Если вы используете этот обходной путь, выполняется код, следующий за Response.Redirect.

Для Server.Transfer используйте вместо этого метод Server.Execute.

Такое поведение является особенностью.

Это потому, что вы не вызываете Thread.ResetAbort в блоке catch. Без этого CLR не будет продолжать выполнять этот метод. Итак, ваш код должен быть:

try
{
   ...
}
catch (System.Threading.ThreadAbortException abrtEx)
{
   Thread.ResetAbort();
}

Но это не очень хорошая практика. Вы можете прочитать, почему это вредно здесь - Response.End() считается вредным?

Вы можете завершить свою логику, а затем после нее вызвать Response.End(), а не в середине метода

Другие вопросы по тегам