Response.Redirect(...)を使用してフォームを新しいページにリダイレクトすると、エラーが発生します。
タイプ 'System.Threading.ThreadAbortException'の最初のチャンス例外がmscorlib.dllで発生しました
mscorlib.dllでタイプ 'System.Threading.ThreadAbortException'の例外が発生しましたが、ユーザーコードでは処理されませんでした
私の理解では、このエラーは、ウェブサーバーがresponse.redirectが呼び出されたページの残りを中止することによって引き起こされているということです。
EndResponseと呼ばれるResponse.Redirect
に2番目のパラメーターを追加できることを知っています。 endResponseをTrueに設定してもエラーは発生しますが、Falseに設定するとエラーは発生しません。確かに、それはウェブサーバーがリダイレクト先のページの残りを実行していることを意味します。控えめに言っても非効率的であると思われるでしょう。これを行うためのより良い方法はありますか? Response.Redirect
以外の何か、またはThreadAbortException
を取得しない場所で古いページの読み込みを強制的に停止する方法はありますか?
正しいパターンは、endResponse = falseでリダイレクトオーバーロードを呼び出し、IISパイプラインに呼び出しを行って、制御を戻したらEndRequestステージに直接進む必要があることです。
Response.Redirect(url, false);
Context.ApplicationInstance.CompleteRequest();
このブログ投稿 Thomas Marquardtから、Application_Errorハンドラー内でリダイレクトする特殊なケースを処理する方法など、追加の詳細が提供されています。
ASP.Net WebFormsのRedirect
問題に対するnoシンプルでエレガントなソリューションがあります。 DirtyソリューションとTediousソリューションから選択できます
Dirty:Response.Redirect(url)
はブラウザーにリダイレクトを送信し、ThreadAbortedException
をスローして現在のスレッドを終了します。したがって、Redirect()呼び出しを過ぎてコードは実行されません。欠点:悪い習慣であり、このようなスレッドを強制終了することはパフォーマンスに影響します。また、ThreadAbortedExceptions
は例外ログに表示されます。
Tedious:推奨される方法は、Response.Redirect(url, false)
を呼び出してからContext.ApplicationInstance.CompleteRequest()
を呼び出すことです。ただし、コードの実行は続行され、ページライフサイクルの残りのイベントハンドラーは引き続き実行されます。 (たとえば、Page_Loadでリダイレクトを実行すると、ハンドラーの残りが実行されるだけでなく、Page_PreRenderなども呼び出されます。レンダリングされたページはブラウザーに送信されません。追加の処理を回避するには、たとえば、ページにフラグを設定し、処理を行う前に後続のイベントハンドラーにこのフラグをチェックさせます。
(CompleteRequest
のドキュメントには、「ASP.NETが実行のHTTPパイプラインチェーンですべてのイベントとフィルタリングをバイパスすることを示しています」。 HTTPフィルターとモジュールをさらにバイパスしますが、現在のpageライフサイクルでさらにイベントをバイパスしません。
より深い問題は、WebFormsに抽象化のレベルが欠けていることです。イベントハンドラーを使用しているときは、出力するページを作成中です。別のページを生成するために部分的に生成されたページを終了しているため、イベントハンドラーでのリダイレクトは見苦しくなります。制御フローはビューのレンダリングとは別個であるため、MVCにはこの問題はありません。したがって、ビューを生成せずに、コントローラーでRedirectAction
を返すだけでクリーンリダイレクトを実行できます。
遅れていることはわかっていますが、Response.Redirect
がTry...Catch
ブロックにある場合にのみ、このエラーが発生しました。
Response.RedirectをTry ... Catchブロックに配置しないでください。それは悪い習慣です
@Kiquenetのコメントに応答して、Response.RedirectをTry ... Catchブロックに配置する代わりに私が行うことは次のとおりです。
メソッド/関数を2つのステップに分割します。
Try ... Catchブロック内のステップ1は、要求されたアクションを実行し、アクションの成功または失敗を示す「結果」値を設定します。
Try ... Catchブロックの外側のステップ2は、「結果」値が何であるかに応じてリダイレクトを行います(または行いません)。
このコードは完全とはほど遠いものであり、テストしていないのでおそらくコピーすべきではありません
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.
}
}
Response.Redirect()
は、現在の要求を中止するために例外をスローします。
この KB記事 は、この動作について説明しています(Request.End()
およびServer.Transfer()
メソッドについても)。
Response.Redirect()
にはオーバーロードが存在します:
Response.Redirect(String url, bool endResponse)
endResponse = falseを渡すと、例外はスローされません(ただし、ランタイムは現在のリクエストの処理を続行します)。
endResponse = trueの場合(または他のオーバーロードが使用されている場合)、例外がスローされ、現在のリクエストはすぐに終了します。
これは、Response.Redirect(url、true)の仕組みです。 ThreadAbortExceptionをスローして、スレッドを中止します。その例外を無視してください。 (私はそれがあなたがそれを見るいくつかのグローバルエラーハンドラ/ロガーだと思いますか?)
関連する興味深い議論 Response.End()は有害と考えられますか?
問題に関する 公式行 です(最新版は見つかりませんでしたが、.netの以降のバージョンでは状況が変わったとは思いません)
私はスレッドを手動で中止する場合にのみ、これを回避しようとしましたが、「CompleteRequest」でそれを残して続行します-私のコードにはリダイレクト後にリターンコマンドがあります。これができる
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();
}
また、他の解決策も試しましたが、リダイレクト後に実行されるコードの一部があります。
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();
}
リダイレクト後のコード実行を防ぐ必要がある場合
try
{
//other code
Response.Redirect("")
// code not to be executed
}
catch(ThreadAbortException){}//do there id nothing here
catch(Exception ex)
{
//Logging
}
私がしていることは、この例外を別の可能な例外と一緒にキャッチすることです。これが誰かを助けることを願っています。
catch (ThreadAbortException ex1)
{
writeToLog(ex1.Message);
}
catch(Exception ex)
{
writeToLog(ex.Message);
}
私もその問題を抱えていました。 Response.Redirect Workedの代わりにServer.Transferを使用してみてください