Обработка исключений 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;
}
}
Если вы используете метод 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(), а не в середине метода