다음을 통해 공유


연습: 네이티브 코드를 사용하여 Request-Level HTTP 모듈 만들기

이 연습에서는 C++를 사용하여 IIS 7에서 새 요청 처리 아키텍처를 구현하는 샘플 요청 수준 HTTP 모듈을 만드는 방법을 보여 줍니다. 이 새로운 아키텍처는 이전 버전의 ASP.NET HTTP 모듈 및 ISAPI 필터 또는 확장을 통해 IIS 애플리케이션을 작성할 때 네이티브 코드 프로그래밍의 기능을 확장합니다. 새 요청 처리 아키텍처를 사용하여 HTTP 모듈을 디자인하는 방법에 대한 자세한 내용은 Native-Code HTTP 모듈 디자인을 참조하세요.

이 연습에서는 HTTP 모듈에 대한 C++ 프로젝트를 만들고 "헬로 월드" 프로젝트에 필요한 코드를 추가한 다음 모듈을 컴파일하고 테스트합니다.

사전 요구 사항

예제의 단계를 완료하려면 다음 소프트웨어가 필요합니다.

  • IIS 7.

  • Visual Studio 2005.

  • Windows SDK(소프트웨어 개발 키트).

    참고 연습 단계가 동일하지 않을 수 있지만 Visual Studio .NET 2003 이하를 사용할 수 있습니다.

모듈 만들기

연습의 이 부분에서는 HTTP 모듈에 대한 빈 C++ DLL 프로젝트를 만듭니다.

새 C++ DLL 프로젝트를 만들려면

  1. Visual Studio 2005를 엽니다.

  2. 전역 옵션에 SDK 포함 파일에 대한 모든 올바른 경로가 있는지 확인합니다.

    1. 도구 메뉴에서 옵션을 클릭합니다.

    2. 트리 뷰에서 프로젝트 및 솔루션 노드를 확장한 다음 VC++ 디렉터리를 클릭합니다.

    3. 디렉터리 표시 드롭다운 상자에서 파일 포함을 선택합니다.

    4. Windows SDK 포함 파일을 설치한 경로가 나열되어 있는지 확인합니다. 경로가 나열되지 않으면 새 줄 아이콘을 클릭한 다음 SDK 포함 파일을 설치한 경로를 추가합니다. 기본 설치 디렉터리가 $(VCInstallDir)PlatformSDK\bin입니다.

    5. 확인을 클릭합니다.

  3. 새 C++ 프로젝트를 만듭니다.

    1. 파일 메뉴에서 새로 만들기를 가리킨 다음 프로젝트를 클릭합니다.

      새 프로젝트 대화 상자가 열립니다.

    2. 프로젝트 형식 창에서 Visual C++ 노드를 확장한 다음 Win32를 클릭합니다.

    3. 템플릿 창에서 Win32 프로젝트를 선택합니다.

    4. 이름 상자에 HelloWorld를 입력합니다.

    5. 위치 상자에 샘플의 경로를 입력합니다.

    6. 확인을 클릭합니다.

      Win32 애플리케이션 마법사가 열립니다.

    7. 애플리케이션 설정을 클릭합니다.

    8. 애플리케이션 유형에서 DLL을 클릭합니다.

    9. 추가 옵션에서 빈 프로젝트를 클릭합니다.

    10. Finish를 클릭합니다.

코드 및 소스 파일 추가

다음 단계는 프로젝트에 필요한 C++ 및 모듈 정의 파일을 추가하는 것입니다.

프로젝트에 원본 파일을 추가하려면

  1. RegisterModule 함수를 내보내는 모듈 정의 파일을 만듭니다.

    1. 솔루션 탐색기 원본 파일을 마우스 오른쪽 단추로 클릭하고 추가를 가리킨 다음 새 항목을 클릭합니다.

      새 항목 추가 대화 상자가 열립니다.

    2. 범주 창에서 Visual C++ 노드를 확장한 다음 코드를 클릭합니다.

    3. 템플릿 창에서 모듈 정의 파일 템플릿을 선택합니다.

    4. 이름 상자에 HelloWorld를 입력하고 위치 상자에 파일의 기본 경로를 그대로 둡니다.

    5. 추가를 클릭합니다.

    6. RegisterModule를 사용하여 줄을 EXPORTS 추가합니다. 파일은 아래 코드와 같아야 합니다.

      LIBRARY"HelloWorld"  
      EXPORTS  
          RegisterModule  
      

      참고

      모듈 정의 파일을 만드는 대신 /EXPORT:RegisterModule 스위치를 사용하여 RegisterModule 함수를 내보낼 수 있습니다.

  2. C++ 파일을 만듭니다.

    1. 솔루션 탐색기 원본 파일을 마우스 오른쪽 단추로 클릭하고 추가를 가리킨 다음 새 항목을 클릭합니다.

      새 항목 추가 대화 상자가 열립니다.

    2. 범주 창에서 Visual C++ 노드를 확장한 다음 코드를 클릭합니다.

    3. 템플릿 창에서 C++ 파일 템플릿을 선택합니다.

    4. 이름 상자에 HelloWorld를 입력하고 위치 상자에 파일의 기본 경로를 그대로 둡니다.

    5. 추가를 클릭합니다.

    6. 다음 코드를 추가합니다.

      #define _WINSOCKAPI_
      #include <windows.h>
      #include <sal.h>
      #include <httpserv.h>
      
      // Create the module class.
      class CHelloWorld : public CHttpModule
      {
      public:
          REQUEST_NOTIFICATION_STATUS
          OnBeginRequest(
              IN IHttpContext * pHttpContext,
              IN IHttpEventProvider * pProvider
          )
          {
              UNREFERENCED_PARAMETER( pProvider );
      
              // Create an HRESULT to receive return values from methods.
              HRESULT hr;
              
              // Retrieve a pointer to the response.
              IHttpResponse * pHttpResponse = pHttpContext->GetResponse();
      
              // Test for an error.
              if (pHttpResponse != NULL)
              {
                  // Clear the existing response.
                  pHttpResponse->Clear();
                  // Set the MIME type to plain text.
                  pHttpResponse->SetHeader(
                      HttpHeaderContentType,"text/plain",
                      (USHORT)strlen("text/plain"),TRUE);
      
                  // Create a string with the response.
                  PCSTR pszBuffer = "Hello World!";
                  // Create a data chunk.
                  HTTP_DATA_CHUNK dataChunk;
                  // Set the chunk to a chunk in memory.
                  dataChunk.DataChunkType = HttpDataChunkFromMemory;
                  // Buffer for bytes written of data chunk.
                  DWORD cbSent;
                  
                  // Set the chunk to the buffer.
                  dataChunk.FromMemory.pBuffer =
                      (PVOID) pszBuffer;
                  // Set the chunk size to the buffer size.
                  dataChunk.FromMemory.BufferLength =
                      (USHORT) strlen(pszBuffer);
                  // Insert the data chunk into the response.
                  hr = pHttpResponse->WriteEntityChunks(
                      &dataChunk,1,FALSE,TRUE,&cbSent);
      
                  // Test for an error.
                  if (FAILED(hr))
                  {
                      // Set the HTTP status.
                      pHttpResponse->SetStatus(500,"Server Error",0,hr);
                  }
      
                  // End additional processing.
                  return RQ_NOTIFICATION_FINISH_REQUEST;
              }
      
              // Return processing to the pipeline.
              return RQ_NOTIFICATION_CONTINUE;
          }
      };
      
      // Create the module's class factory.
      class CHelloWorldFactory : public IHttpModuleFactory
      {
      public:
          HRESULT
          GetHttpModule(
              OUT CHttpModule ** ppModule, 
              IN IModuleAllocator * pAllocator
          )
          {
              UNREFERENCED_PARAMETER( pAllocator );
      
              // Create a new instance.
              CHelloWorld * pModule = new CHelloWorld;
      
              // Test for an error.
              if (!pModule)
              {
                  // Return an error if the factory cannot create the instance.
                  return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
              }
              else
              {
                  // Return a pointer to the module.
                  *ppModule = pModule;
                  pModule = NULL;
                  // Return a success status.
                  return S_OK;
              }            
          }
      
          void
          Terminate()
          {
              // Remove the class from memory.
              delete this;
          }
      };
      
      // Create the module's exported registration function.
      HRESULT
      __stdcall
      RegisterModule(
          DWORD dwServerVersion,
          IHttpModuleRegistrationInfo * pModuleInfo,
          IHttpServer * pGlobalInfo
      )
      {
          UNREFERENCED_PARAMETER( dwServerVersion );
          UNREFERENCED_PARAMETER( pGlobalInfo );
      
          // Set the request notifications and exit.
          return pModuleInfo->SetRequestNotifications(
              new CHelloWorldFactory,
              RQ_BEGIN_REQUEST,
              0
          );
      }
      

모듈 컴파일 및 테스트

프로젝트를 컴파일하고 테스트하려면

  1. HTTP 모듈을 컴파일합니다.

    1. 빌드 메뉴에서 솔루션 빌드를 클릭합니다.

    2. Visual Studio에서 오류 또는 경고를 반환하지 않았는지 확인합니다.

    3. %windir%\system32\inetsrv\config\applicationHost.config 파일의 섹션에 globalModules HelloWorld.dll 모듈(전체 경로 포함)을 추가합니다.

  2. 인터넷 Explorer 사용하여 웹 사이트로 이동합니다. 요청 수가 표시된 "요청 시작 샘플"이 표시됩니다.

참고

후속 빌드에서 프로젝트를 연결하기 전에 IIS를 중지해야 합니다.

설정 문제 해결

모듈이 컴파일되지 않거나 예상대로 작동하지 않는 경우 검사 수 있는 몇 가지 영역은 다음과 같습니다.

  • 내보낸 함수에 대해 지정 __stdcall 했거나 호출 규칙을 사용하여 컴파일을 __stdcall (/Gz) 구성했는지 확인합니다.

  • IIS가 HelloWorld.dll 로드되었는지 확인합니다.

    1. IIS 관리자의 연결 창에서 기본 웹 사이트를 클릭합니다.

    2. 작업 영역(가운데 창)에서 기능 보기를 선택합니다.

    3. 그룹화 기준 상자에서 범주를 선택합니다.

    4. 서버 구성 요소 범주에서 모듈을 두 번 클릭합니다.

    5. HelloWorld 모듈이 나열되어 있는지 확인합니다.

  • 정의 파일에 올바른 RegisterModule 내보내기를 추가했는지 확인합니다.

  • 프로젝트 설정에 정의 파일을 추가해야 합니다. 프로젝트 설정에 파일을 추가하려면 다음 단계를 완료합니다.

    1. 프로젝트 메뉴에서 속성을 클릭합니다.

    2. 트리 뷰에서 구성 속성 노드를 확장하고 링커 노드를 확장한 다음 입력을 클릭합니다.

    3. 모듈 정의 파일 설정의 경우 정의 파일이 나열되어 있는지 확인합니다.

참고 항목

Native-Code HTTP 모듈 만들기
Native-Code HTTP 모듈 디자인