この記事は、HTTPHandler で Server.Transfer メソッドを使用して、ASP.NET Web アプリケーションのあるページから別のページにコントロールを転送したときにエラーがスローされる可能性があるという問題を解決するのに役立ちます。
元の製品バージョン: ASP.NET
元の KB 番号: 817266
現象
HTTPHandlerで Server.Transfer メソッドを使用して、ASP.NET Web アプリケーション内のあるページから別のページにコントロールを転送すると、次のエラー メッセージが表示されることがあります。
System.Threading.ThreadAbortException: スレッドを中止しようとしました。 at
System.Threading.Thread.AbortInternal() 場所 System.Threading.Thread.Abort() 場所
System.Threading.Thread.Abort(Object stateInfo) 場所 System.Web.HttpResponse.End() 場所
System.Web.HttpServerUtility.Transfer(String path, Boolean preserveForm)
原因
Server.Transfer を呼び出すと、ASP.NET は内部で Server.Execute メソッドを呼び出してコントロールを転送し、Response.End メソッドを呼び出して現在のページの処理を終了します。
Response.End はページの実行を終了し、Thread.Abort メソッドを呼び出します。
Thread.Abort メソッドを使用すると、ThreadAbortException エラー メッセージが表示されます。
回避策
この問題を回避するには、HTTPHandler の ProcessRequest メソッドで Server.Transfer の代わりに Server.Execute を使用します。 変更された ProcessRequest メソッドは次のとおりです。
C# コード サンプル
public void ProcessRequest(HttpContext context) { try { context.Server.Execute("WebForm1.aspx"); } catch(System.Exception e) { context.Response.Write(e.StackTrace); context.Response.Write(e.ToString()); } }Visual Basic サンプル コード
Public Sub ProcessRequest(ByVal context As HttpContext) _ Implements IHttpHandler.ProcessRequest Try context.Server.Execute("WebForm1.aspx") Catch e As Exception context.Response.Write(e.StackTrace) End Try End Sub
状態
この動作は仕様によるものです。
動作を再現する手順
Microsoft Visual Studio で、Visual Basic または C# を使用して、Web フォーム アプリケーション プロジェクト ASP.NET 新しいプロジェクトを作成します。 既定では、WebForm1.aspx が作成されます。 プロジェクトに「ServerTransferTest」という名前を付けます。
[WebForm1.aspx] を右クリックし、[HTML ソースの表示] を選択します。
既存のコードを次のサンプル コードに置き換えます。
<%@ Page %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" > <HTML> <HEAD> <title>WebForm1</title> </HEAD> <body MS_POSITIONING="GridLayout"> <form id="Form1" method="post" runat="server"> <asp:HyperLink id="HyperLink1" style="Z-INDEX: 101; LEFT: 324px; POSITION: absolute; TOP: 181px" runat="server" NavigateUrl="http://localhost/ServerTransferTest/test.ashx"> http://localhost/ServerTransferTest/test.ashx</asp:HyperLink> <asp:Label id="Label1" style="Z-INDEX: 102; LEFT: 292px; POSITION: absolute; TOP: 149px" runat="server">On Clicking this URL should not throw any exception</asp:Label> </form> </body> </HTML>WebForm1.aspxのデザイン ビューをダブルクリックし、分離コード ページの終了コードを次のサンプル コードに置き換えます。
C# コード サンプル
using System; using System.Web; using System.Web.UI.WebControls; namespace ServerTransferTest { /// <summary> /// Summary description for WebForm1. /// </summary> public class WebForm1 : System.Web.UI.Page { protected System.Web.UI.WebControls.Label Label1; protected System.Web.UI.WebControls.HyperLink HyperLink1; private void Page_Load(object sender, System.EventArgs e) { } #region Web Form Designer generated code override protected void OnInit(EventArgs e) { // CODEGEN: ASP.NET Web Form Designer requires this call. InitializeComponent(); base.OnInit(e); } /// <summary> /// Required method for Designer support - do not modify /// the contents of this method by using the code editor. /// </summary> private void InitializeComponent() { this.Load += new System.EventHandler(this.Page_Load); } #endregion } }Visual Basic サンプル コード
Public Class WebForm1 Inherits System.Web.UI.Page Protected WithEvents Label1 As System.Web.UI.WebControls.Label Protected WithEvents HyperLink1 As System.Web.UI.WebControls.HyperLink 'Web Form Designer requires this call. <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent() End Sub Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init 'CODEGEN: Web Form Designer requires this method call. 'Do not modify it by using the code editor. InitializeComponent() End Sub Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'Put user code to initialize the page here End Sub End Class
[ファイル] メニューで、[新しいアイテムの追加] を選択します。
[新しいアイテムの追加] で、[ クラス] を選択します。 Nameテキスト ボックスの [新しい項目追加クラス
HelloWorldHandlerの名前を変更し、Open を選択します。HelloWorldHandlerクラス ファイルの既存のコードを次のサンプル コードに置き換えます。C# コード サンプル
using System.Web; namespace ServerTransferTest { public class HelloWorldHandler : IHttpHandler { public void ProcessRequest(HttpContext context) { try { context.Server.Transfer("WebForm1.aspx", true ); } catch(System.Exception e) { context.Response.Write(e.StackTrace); context.Response.Write(e.ToString()); } } public bool IsReusable { // To enable pooling, return true here. // This keeps the handler in memory. get { return false; } } } }Visual Basic サンプル コード
Imports System Imports System.Web Public Class HelloWorldHandler Implements IHttpHandler Public Sub ProcessRequest(ByVal context As HttpContext) _ Implements IHttpHandler.ProcessRequest Try ' context.Server.Transfer("WebForm1.aspx", True) context.Server.Execute("WebForm1.aspx") Catch e As Exception context.Response.Write(e.StackTrace) End Try End Sub ' Override the IsReusable property. Public ReadOnly Property IsReusable() As Boolean _ Implements IHttpHandler.IsReusable Get Return True End Get End Property End Class
手順 5 と 6 を繰り返して、別のクラス ファイルを追加します。 クラス ファイルの名前を
HelloWorldHandlerFactoryに変更します。HelloWorldHandlerFactoryクラス ファイルの既存のコードを次のサンプル コードに置き換えます。C# コード サンプル
using System.Web; namespace ServerTransferTest { public class HelloWorldHandlerFactory : IHttpHandlerFactory { public IHttpHandler GetHandler( HttpContext context, System.String requestType, System.String url, System.String pathTranslated) { HttpResponse Response = context.Response; Response.Write("<html>"); Response.Write("<body>"); Response.Write("<h1> Hello from HelloWorldHandlerFactory.GetHandler </h1>"); Response.Write("</body>"); Response.Write("</html>"); return new HelloWorldHandler(); } public void ReleaseHandler( IHttpHandler handler ) { } } }Visual Basic サンプル コード
Imports System Imports System.Web Public Class HelloWorldHandlerFactory Implements IHttpHandlerFactory Public Overridable Function GetHandler(ByVal context As HttpContext, _ ByVal requestType As String, ByVal url As String, ByVal pathTranslated As String) _ As IHttpHandler _ Implements IHttpHandlerFactory.GetHandler Dim Response As HttpResponse = context.Response Response.Write("<html>") Response.Write("<body>") Response.Write("<h1> Hello from HelloWorldHandlerFactory.GetHandler </h1>") Response.Write("</body>") Response.Write("</html>") Return New HelloWorldHandler() End Function Public Overridable Sub ReleaseHandler(ByVal handler As IHttpHandler) _ Implements IHttpHandlerFactory.ReleaseHandler End Sub End Class
web.config ファイルを開き、次のように
<system.web>セクションに<httpHandlers>セクションを追加します。<configuration> <system.web> <httpHandlers> <add verb="*" path="*.ashx" type="ServerTransferTest.HelloWorldHandlerFactory,ServerTransferTest" /> </httpHandlers> ..... </system.web> </configuration>Debug メニューの Start を選択し、WebForm1.aspxで次のハイパーリンクを選択します。
http://localhost/ServerTransferTest/test.ashx