方法 : 非同期 HTTP ハンドラを作成する
更新 : 2007 年 11 月
このチュートリアルでは、非同期 HTTP ハンドラを作成する方法について説明します。非同期 HTTP ハンドラを使用すると、リモート サーバーに対するメソッド呼び出しなどの外部プロセスを開始した際に処理を続行できます。ハンドラは、外部プロセスが終了するのを待たずに処理を続行できます。
非同期 HTTP ハンドラの処理中、ハンドラが外部プロセスからコールバックを受け取るまで、ASP.NET は、通常であれば外部プロセスが使用するスレッドをスレッド プール内に戻します。これにより、一度に実行できるスレッドの数が制限されるため、スレッドのブロックが防止され、パフォーマンスが向上します。外部プロセスに依存する同期 HTTP ハンドラを多くのユーザーが要求した場合には、多くのスレッドがブロックされて外部プロセスを待つため、オペレーティング システムですぐにスレッドが不足する可能性があります。
このチュートリアルの例では、ASP.NET アプリケーション内で、ファイル名拡張子が .SampleAsync のファイルの要求を処理する非同期 HTTP ハンドラについて説明します。また、ハンドラに実装するコードの例を示し、次に .SampleAsync 拡張子を ASP.NET 内のハンドラにマップする方法を紹介します。さらに、末尾が .SampleAsync である要求を IIS が ASP.NET に転送するように、.SampleAsync 拡張子を IIS 上の ASP.NET にマップする方法を紹介します。
ASP.NET ランタイムが IIS 6.0 と対話する方法の詳細については、「IIS 5.0 および 6.0 における ASP.NET アプリケーションのライフ サイクルの概要」を参照してください。ASP.NET と IIS 7.0 との統合の詳細については、「IIS 7.0 における ASP.NET アプリケーションのライフ サイクルの概要」を参照してください。
このチュートリアルでは、以下のタスクを行います。
HTTP ハンドラ クラスのコードを作成する。このクラスにより ProcessRequest メソッドと IsReusable プロパティが実装される必要があります。
Web.config ファイルにハンドラを登録し、.SampleAsync ファイル名拡張子をマップする。
.sample ファイル名拡張子を IIS の ASP.NET にマップする
前提条件
このチュートリアルを実行するための要件は次のとおりです。
Visual Studio または Visual Web Developer。
IIS を使用して実行できる ASP.NET Web サイト。
IIS 6.0 または IIS 7.0。
非同期 HTTP ハンドラ クラスの作成
まず、非同期ハンドラを実装するクラスを作成します。
HelloWorldAsyncHandler HTTP ハンドラ クラスを作成するには
操作する Web サイトにまだ App_Code ディレクトリがない場合は、サイトのルートの下に App_Code ディレクトリを作成します。
HelloWorldAsyncHandler という名前のクラスを App_Code ディレクトリに作成し、次のコードをクラス ファイルに追加します。
Imports Microsoft.VisualBasic Imports System.Web Imports System.Threading Public Class HelloWorldAsyncHandler Implements IHttpAsyncHandler Public ReadOnly Property IsReusable() As Boolean Implements System.Web.IHttpHandler.IsReusable Get Return False End Get End Property Public Function BeginProcessRequest( _ ByVal context As System.Web.HttpContext, _ ByVal cb As System.AsyncCallback, _ ByVal extraData As Object) _ As System.IAsyncResult _ Implements System.Web.IHttpAsyncHandler.BeginProcessRequest context.Response.Write("<p>Begin IsThreadPoolThread is " _ & Thread.CurrentThread.IsThreadPoolThread & "</p>" & vbCrLf) Dim asynch As New AsynchOperation(cb, context, extraData) asynch.StartAsyncWork() Return asynch End Function Public Sub EndProcessRequest(ByVal result As _ System.IAsyncResult) _ Implements System.Web.IHttpAsyncHandler.EndProcessRequest End Sub Public Sub ProcessRequest(ByVal context _ As System.Web.HttpContext) _ Implements System.Web.IHttpHandler.ProcessRequest Throw New InvalidOperationException() End Sub End Class Class AsynchOperation Implements IAsyncResult Private _completed As Boolean Private _state As [Object] Private _callback As AsyncCallback Private _context As HttpContext ReadOnly Property IsCompleted() As Boolean _ Implements IAsyncResult.IsCompleted Get Return _completed End Get End Property ReadOnly Property AsyncWaitHandle() As WaitHandle _ Implements IAsyncResult.AsyncWaitHandle Get Return Nothing End Get End Property ReadOnly Property AsyncState() As [Object] _ Implements IAsyncResult.AsyncState Get Return _state End Get End Property ReadOnly Property CompletedSynchronously() As Boolean _ Implements IAsyncResult.CompletedSynchronously Get Return False End Get End Property Public Sub New(ByVal callback As AsyncCallback, _ ByVal context As HttpContext, _ ByVal state As [Object]) _callback = callback _context = context _state = state _completed = False End Sub Public Sub StartAsyncWork() ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf StartAsyncTask), Nothing) End Sub Private Sub StartAsyncTask(ByVal workItemState As [Object]) _context.Response.Write("<p>Completion IsThreadPoolThread is " & Thread.CurrentThread.IsThreadPoolThread & "</p>" & vbCrLf) _context.Response.Write("Hello World from Async Handler!") _completed = True _callback(Me) End Sub 'StartAsyncTask End Class 'AsynchOperation
using System; using System.Web; using System.Threading; class HelloWorldAsyncHandler : IHttpAsyncHandler { public bool IsReusable { get { return false; } } public HelloWorldAsyncHandler() { } public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) { context.Response.Write("<p>Begin IsThreadPoolThread is " + Thread.CurrentThread.IsThreadPoolThread + "</p>\r\n"); AsynchOperation asynch = new AsynchOperation(cb, context, extraData); asynch.StartAsyncWork(); return asynch; } public void EndProcessRequest(IAsyncResult result) { } public void ProcessRequest(HttpContext context) { throw new InvalidOperationException(); } } class AsynchOperation : IAsyncResult { private bool _completed; private Object _state; private AsyncCallback _callback; private HttpContext _context; bool IAsyncResult.IsCompleted { get { return _completed; } } WaitHandle IAsyncResult.AsyncWaitHandle { get { return null; } } Object IAsyncResult.AsyncState { get { return _state; } } bool IAsyncResult.CompletedSynchronously { get { return false; } } public AsynchOperation(AsyncCallback callback, HttpContext context, Object state) { _callback = callback; _context = context; _state = state; _completed = false; } public void StartAsyncWork() { ThreadPool.QueueUserWorkItem(new WaitCallback(StartAsyncTask), null); } private void StartAsyncTask(Object workItemState) { _context.Response.Write("<p>Completion IsThreadPoolThread is " + Thread.CurrentThread.IsThreadPoolThread + "</p>\r\n"); _context.Response.Write("Hello World from Async Handler!"); _completed = true; _callback(this); } }
このコードは、BeginProcessRequest メソッドを実装します。このメソッドは、文字列を現在の HttpContext オブジェクトの Response プロパティに書き込み、AsyncOperation クラスの新しいインスタンスを作成し、StartAsyncWork メソッドを呼び出します。次に、StartAsyncWork メソッドが StartAsyncTask デリゲートを ThreadPool オブジェクトに追加します。スレッドが使用できるようになると、StartAsyncTask メソッドが呼び出され、別の文字列が Response プロパティに書き込まれます。そして、タスクは AsyncCallback デリゲートを起動して終了します。
IIS 6.0 でのカスタム HTTP ハンドラの登録
カスタム HTTP ハンドラ クラスを作成した後、アプリケーションの Web.config ファイルに登録する必要があります。登録により、ASP.NET は URL の末尾が .SampleAsync であるリソースへの要求が行われたときにハンドラを探すことができるようになります。
IIS 6.0 または IIS 7.0 のどちらを使用しているかによって、ハンドラを登録する方法は異なります。このセクションでは、IIS 6.0 でハンドラを登録する方法について説明します。次のセクションでは、IIS 7.0 でハンドラを登録する方法について説明します。
IIS 6.0 でハンドラを登録するには
Web サイトにまだ Web.config ファイルがない場合は、サイトのルートの下に Web.config ファイルを作成します。
Web.config ファイルに次の強調表示されたマークアップを追加します。
<configuration> <system.web> <httpHandlers> <add verb="*" path="*.SampleAsync" type="HelloWorldAsyncHandler"/> </httpHandlers> </system.web> </configuration>
この構成要素により、HelloWorldAsyncHandler ハンドラは末尾が .SampleAsync である要求に対するハンドラとして登録されます。
IIS マネージャを使用して、.SampleAsync ファイル名拡張子のアプリケーション拡張子の割り当てを登録します。詳細については、「方法 : IIS で HTTP ハンドラ拡張子を構成する」を参照してください。
IIS 7.0 でのカスタム HTTP ハンドラの登録
IIS 7.0 では、クラシック モードまたは統合モードでアプリケーションを実行できます。クラシック モードでは、要求は IIS 6.0 の場合とほぼ同じ方法で処理されます。統合モードでは、IIS 7.0 は ASP.NET と要求、モジュール、およびその他の機能を共有できるようにするパイプラインを使用して要求を管理します。
IIS 7.0 でのハンドラの登録には、Web.config ファイルまたは IIS マネージャへのハンドラの登録が必要です。管理は IIS 7.0 に一元化されているため、アプリケーションの Web.config ファイルを変更すると、アプリケーションの IIS マネージャ インターフェイスに反映されます。その逆もまた同様です。次の手順では、ハンドラは Web.config ファイルに登録されます。
IIS 7.0 向けにハンドラを登録する方法は、クラシック モードおよび統合モードのどちらで実行されているかにより異なります。使用している IIS モードでの手順に従います。
クラシック モードで実行されている IIS 7.0 でハンドラを登録するには
Web サイトにまだ Web.config ファイルがない場合は、サイトのルートの下に Web.config ファイルを作成します。
Web.config ファイルに次の強調表示されたコードを追加します。
メモ : aspnet_isapi.dll ファイルを正しいパスに置き換えます。.dll ファイルは、.NET Framework がインストールされているフォルダにあります。既定では、これは C:\WINDOWS\Microsoft.NET\Framework\version です。
<configuration> <system.web> <httpHandlers> <add verb="*" path="*.SampleAsync" type="HelloWorldAsyncHandler"/> </httpHandlers> </system.web> <system.webServer> <handlers> <add verb="*" path="*.SampleAsync" name="HelloWorldAsyncHandler" type="HelloWorldAsyncHandler" modules="IsapiModule"/> scriptProcessor="%path%\aspnet_isapi.dll" </handlers> </system.webServer> </configuration>
構成要素により、カスタム ハンドラがクラス名で登録され、.SampleAsync ファイル名拡張子がマップされます。
メモ : カスタム ファイル名拡張子を登録するので、handlers セクションと httpHandlers セクションの両方にハンドラを登録します。クラシック モードでは、下位互換性を確保するために、ハンドラは modules 属性を使用して ISAPI モジュールとして指定されます。ASP.NET ISAPI dll のパスは、scriptProcessor 属性を使用して指定されます。name 属性は handlers セクションでは必須です。
統合モードで実行されている IIS 7.0 でハンドラを登録するには
Web サイトにまだ Web.config ファイルがない場合は、サイトのルートの下に Web.config ファイルを作成します。
Web.config ファイルに次の強調表示されたコードを追加します。
<configuration> <system.webServer> <handlers> <add verb="*" path="*.SampleAsync" name="HelloWorldAsyncHandler" type="HelloWorldAsyncHandler"/> </handlers> </system.webServer> </configuration>
構成要素により、カスタム ハンドラがクラス名で登録され、.SampleAsync ファイル名拡張子がマップされます。
メモ : 登録は、httpHandlers セクションではなく handlers セクションで行われます。name 属性は必須です。
カスタム HTTP ハンドラのテスト
カスタム HTTP ハンドラを作成して登録すると、それをテストできます。
カスタム HTTP ハンドラをテストするには
アプリケーションを参照し、末尾が .SampleAsync である URL をブラウザに入力します。
HelloWorldAsyncHandler クラスで定義されたテキストが表示されます。
参照
処理手順
概念
IIS 5.0 および 6.0 における ASP.NET アプリケーションのライフ サイクルの概要