Share via


방법: 비동기 HTTP 처리기 만들기

업데이트: 2007년 11월

이 연습에서는 비동기 HTTP 처리기를 만드는 방법을 설명합니다. 비동기 HTTP 처리기를 사용하면 처리기가 계속 처리하는 동안 외부 프로세스(예: 원격 서버에 대한 메서드 호출)를 시작할 수 있습니다. 처리기는 외부 프로세스의 완료를 기다리지 않고 계속 처리할 수 있습니다.

비동기 HTTP 처리기를 처리하는 동안 ASP.NET에서는 일반적으로 외부 프로세스에 사용될 스레드를 처리기가 외부 프로세스에서 콜백을 받을 때까지 스레드 풀에 다시 넣습니다. 이렇게 하면 제한된 개수의 스레드만 동시에 실행되므로 스레드 차단을 방지하고 성능을 향상시킬 수 있습니다. 외부 프로세스에 의존하는 동기 HTTP 처리기를 여러 사용자가 요청하는 경우, 많은 스레드가 차단되어 외부 프로세스가 끝날 때까지 기다리기 때문에 운영 체제의 스레드가 빨리 부족해질 수 있습니다.

이 연습의 예제에서는 ASP.NET 응용 프로그램에서 파일 이름 확장명이 .SampleAsync인 파일에 대해 요청을 처리하는 비동기 HTTP 처리기를 보여 줍니다. 예제에서는 처리기의 코드를 보여 준 다음 ASP.NET에서 .SampleAsync 확장명을 처리기에 매핑하는 방법을 보여 줍니다. 또한 IIS에서 .SampleAsync 확장명을 ASP.NET에 매핑하여 IIS가 .SampleAsync로 끝나는 요청을 ASP.NET에 전달하는 방법을 보여 줍니다.

ASP.NET 런타임에서 IIS 6.0과 상호 작용하는 방법에 대한 자세한 내용은 IIS 5.0 및 6.0의 ASP.NET 응용 프로그램 수명 주기 개요를 참조하십시오. IIS 7.0과의 ASP.NET 통합에 대한 자세한 내용은 IIS 7.0의 ASP.NET 응용 프로그램 수명 주기 개요를 참조하십시오.

이 연습에서 수행할 작업은 다음과 같습니다.

  • HTTP 처리기 클래스의 코드를 만드는 방법. 이 클래스에서는 ProcessRequest 메서드와 IsReusable 속성을 구현해야 합니다.

  • Web.config 파일에서 처리기를 등록하고 .SampleAsync 파일 이름 확장명을 매핑하는 방법

  • IIS에서 .sample 파일 이름 확장명을 ASP.NET에 매핑하는 방법

사전 요구 사항

이 연습을 완료하려면 다음과 같은 요건을 갖추어야 합니다.

  • Visual Studio 또는 Visual Web Developer

  • IIS를 사용하여 실행할 수 있는 ASP.NET 웹 사이트

  • IIS 6.0 또는 IIS 7.0

비동기 HTTP 처리기 클래스 만들기

먼저 비동기 처리기를 구현하는 클래스를 만듭니다.

HelloWorldAsyncHandler HTTP 처리기 클래스를 만들려면

  1. 작업 중인 웹 사이트에 아직 App_Code 폴더가 없으면 사이트의 루트에 만듭니다.

  2. App_Code 디렉터리에서 HelloWorldAsyncHandler라는 클래스를 만들고 클래스 파일에 다음 코드를 추가합니다.

    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 메서드에서 ThreadPool 개체에 StartAsyncTask 대리자를 추가합니다. 스레드를 사용할 수 있게 되면 StartAsyncTask 메서드가 호출됩니다. 이 메서드는 다른 문자열을 Response 속성에 작성합니다. 그런 다음 AsyncCallback 대리자를 호출함으로써 작업이 완료됩니다.

IIS 6.0에서 사용자 지정 HTTP 처리기 등록

사용자 지정 HTTP 처리기 클래스를 만든 후에는 응용 프로그램의 Web.config 파일에 등록해야 합니다. 이렇게 하면 URL이 .SampleAsync로 끝나는 리소스에 대해 요청할 때 ASP.NET에서 처리기를 찾을 수 있습니다.

IIS 6.0과 IIS 7.0 중 어떤 것으로 작업하는지에 따라 처리기 등록 절차가 달라집니다. 이 단원에서는 IIS 6.0에서 처리기를 등록하는 방법을 설명합니다. 다음 단원에서는 IIS 7.0에서 처리기를 등록하는 방법을 설명합니다.

IIS 6.0에서 처리기를 등록하려면

  1. 웹 사이트에 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.config 파일이 없는 경우 사이트의 루트에 해당 파일을 만듭니다.

  2. 아래에 강조 표시된 요소를 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에서 처리기를 등록하려면

  1. 웹 사이트에 Web.config 파일이 없는 경우 사이트의 루트에 해당 파일을 만듭니다.

  2. 아래에 강조 표시된 요소를 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 클래스에 정의된 텍스트가 표시됩니다.

참고 항목

작업

연습: 동기 HTTP 처리기 만들기

개념

IIS 5.0 및 6.0의 ASP.NET 응용 프로그램 수명 주기 개요

기타 리소스

HTTP 처리기 소개