次の方法で共有


方法 : 非同期 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 ハンドラ クラスを作成するには

  1. 操作する Web サイトにまだ App_Code ディレクトリがない場合は、サイトのルートの下に App_Code ディレクトリを作成します。

  2. 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 でハンドラを登録するには

  1. Web サイトにまだ Web.config ファイルがない場合は、サイトのルートの下に Web.config ファイルを作成します。

  2. Web.config ファイルに次の強調表示されたマークアップを追加します。

    <configuration>
      <system.web>
        <httpHandlers>      <add verb="*" path="*.SampleAsync"         type="HelloWorldAsyncHandler"/>    </httpHandlers>
      </system.web>
    </configuration>
    

    この構成要素により、HelloWorldAsyncHandler ハンドラは末尾が .SampleAsync である要求に対するハンドラとして登録されます。

  3. 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 でハンドラを登録するには

  1. Web サイトにまだ Web.config ファイルがない場合は、サイトのルートの下に Web.config ファイルを作成します。

  2. Web.config ファイルに次の強調表示されたコードを追加します。

    ms227433.alert_note(ja-jp,VS.90).gifメモ :

    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 ファイル名拡張子がマップされます。

    ms227433.alert_note(ja-jp,VS.90).gifメモ :

    カスタム ファイル名拡張子を登録するので、handlers セクションと httpHandlers セクションの両方にハンドラを登録します。クラシック モードでは、下位互換性を確保するために、ハンドラは modules 属性を使用して ISAPI モジュールとして指定されます。ASP.NET ISAPI dll のパスは、scriptProcessor 属性を使用して指定されます。name 属性は handlers セクションでは必須です。

統合モードで実行されている IIS 7.0 でハンドラを登録するには

  1. Web サイトにまだ Web.config ファイルがない場合は、サイトのルートの下に Web.config ファイルを作成します。

  2. Web.config ファイルに次の強調表示されたコードを追加します。

    <configuration>
      <system.webServer>
        <handlers>      <add verb="*" path="*.SampleAsync"        name="HelloWorldAsyncHandler"        type="HelloWorldAsyncHandler"/>    </handlers>
      </system.webServer>
    </configuration>
    

    構成要素により、カスタム ハンドラがクラス名で登録され、.SampleAsync ファイル名拡張子がマップされます。

    ms227433.alert_note(ja-jp,VS.90).gifメモ :

    登録は、httpHandlers セクションではなく handlers セクションで行われます。name 属性は必須です。

カスタム HTTP ハンドラのテスト

カスタム HTTP ハンドラを作成して登録すると、それをテストできます。

カスタム HTTP ハンドラをテストするには

  • アプリケーションを参照し、末尾が .SampleAsync である URL をブラウザに入力します。

    HelloWorldAsyncHandler クラスで定義されたテキストが表示されます。

参照

処理手順

チュートリアル : 同期 HTTP ハンドラの作成

概念

IIS 5.0 および 6.0 における ASP.NET アプリケーションのライフ サイクルの概要

その他の技術情報

HTTP ハンドラの概要