재우니 개발자 블로그

 

 

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <location path="." inheritInChildApplications="false">
    <system.webServer>
      <handlers>
        <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
      </handlers>
      <aspNetCore processPath="dotnet" arguments=".\GW.WebUI.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess" />
      <!-- IIS 헤더 크기 제한 증설 (쿠키 크기 초과 방지) -->
      <security>
        <requestFiltering>
          <!-- 최대 URL 길이: 64KB, 쿼리 스트링: 32KB -->
          <requestLimits maxUrl="65536" maxQueryString="32768">
            <!-- Cookie 헤더 최대 크기: 64KB -->
            <headerLimits>
              <add header="Cookie" sizeLimit="65536" />
            </headerLimits>
          </requestLimits>
        </requestFiltering>
      </security>
    </system.webServer>
  </location>
</configuration>
<!--ProjectGuid: 3DE55D15-CE32-4895-BD17-D74F07EBF2D0-->

 

 

 

한눈에 이해하실 수 있도록, 복잡한 텍스트 대신 직관적인 도식입니다.

현재 web.config 설정(hostingModel="inprocess")을 기준으로 한 요청 처리 흐름도입니다.

 

 

 

설명 1

🌐 외부 사용자 (웹 브라우저 / 클라이언트)
  │
  │ 1️⃣ HTTP 요청 (URL 주소, 파라미터, 쿠키 등)
  ▼
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ 🖥️ IIS 서버 프로세스 ( w3wp.exe )                                            ┃
┃   ※ 주의: 현재 설정에서는 dotnet.exe가 따로 뜨지 않고 이 안에서 다 해결됩니다!   ┃
┃                                                                            ┃
┃  [ 🛡️ 2️⃣ 보안 검문소 (Request Filtering) ]                                  ┃
┃    ├─ URL 길이 64KB 이하인가? (통과)                                         ┃
┃    ├─ 쿼리 스트링 32KB 이하인가? (통과)                                      ┃
┃    └─ 쿠키(Cookie) 크기 64KB 이하인가? (통과)                                ┃
┃         │                                                                  ┃
┃         ▼ (검문 무사 통과!)                                                  ┃
┃                                                                            ┃
┃  [ 🔌 3️⃣ 전담 매니저 (AspNetCoreModuleV2) ]                                 ┃
┃         │ 요청을 받아서 내부의 .NET 환경으로 토스!                           ┃
┃         │                                                                  ┃
┃         ▼                                                                  ┃
┃  ┌──────────────────────────────────────────────────────────────────────┐  ┃
┃  │ 📦 4️⃣ .NET 런타임 (In-Process)                                       │  ┃
┃  │   - w3wp.exe 뱃속(메모리)에 직접 올라가 있는 상태입니다.                   │  ┃
┃  │                                                                      │  ┃
┃  │   🚀 GW.WebUI.dll (우리가 만든 앱)                                     │  ┃
┃  │     - 여기서 C# 코드가 실행되고, DB(MSSQL 등)를 조회하고 HTML을 만듭니다. │  ┃
┃  └──────────────────────────────────────────────────────────────────────┘  ┃
┃         │                                                                  ┃
┃         ▼ (응답 데이터 생성 완료)                                            ┃
┃  [ 🔌 전담 매니저 (AspNetCoreModuleV2) ]                                     ┃
┗━━━━━━━━━│━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
          │ 5️⃣ HTTP 응답 (최종 완성된 웹 페이지나 데이터)
          ▼
🌐 외부 사용자 브라우저 화면에 출력! 🎉

 

 

 

💡 핵심 포인트 (그림 해설)

  • 큰 네모 박스 하나(w3wp.exe) 안에서 모든 게 끝납니다. In-Process 호스팅의 가장 큰 특징입니다.
  • 우리가 만든 GW.WebUI.dll 파일은 별도의 독립된 프로그램으로 도는 게 아니라, IIS(w3wp.exe) 안에 세들어 살면서 요청을 처리합니다.
  • 따라서 이 웹사이트가 아무리 트래픽을 많이 받아도 작업 관리자에는 w3wp.exe의 CPU/메모리만 올라갈 뿐, .NET Host(dotnet.exe) 프로세스는 생기지 않습니다.

 


 

설명 2

 

 

이제 전체 구조를 한눈에 볼 수 있는 구조도도 보여드릴게요.위 두 가지를 같이 쓰시면 좋습니다.

 

스텝 위젯 (첫 번째)은 각 단계를 클릭하면서 설명과 web.config 코드를 함께 볼 수 있어서 발표나 스터디용으로 적합하고,

구조도 (두 번째)는 전체 흐름을 한눈에 볼 수 있어서 화이트보드 설명 대용으로 쓰기 좋습니다.

 

이 web.config에서 특히 강조할 핵심 포인트 세 가지를 요약하면 이렇습니다.

 

첫째, hostingModel="inprocess" 덕분에 작업 관리자에 dotnet.exe(.NET Host)가 별도로 뜨지 않습니다. 모든 것이 w3wp.exe 안에서 돌아갑니다.

 

둘째, path="*" verb="*"는 .html, .css 같은 정적 파일 요청도 전부 ASP.NET Core로 넘긴다는 의미입니다. (정적 파일 미들웨어가 먼저 처리하도록 UseStaticFiles()가 등록되어 있어야 합니다.)

 

셋째, requestFiltering의 Cookie 64KB 제한은 JWT나 인증 쿠키가 기본 IIS 제한(4KB)을 넘을 때 추가하는 설정입니다. 이게 없으면 로그인은 되는데 두 번째 요청부터 400 에러가 납니다.

 

 


 

전담 매니저 `AspNetCoreModuleV2` 꼭 필요한가?

 

 "그냥 넘겨주는 것뿐인데 왜 중요해?" — 사실 이게 핵심을 찌르는 질문이에요.


왜 예전엔 없었나?

**클래식 ASP.NET (.NET Framework 시절)**은 IIS와 완전히 결합되어 있었습니다.

IIS ──────────────── w3wp.exe
         System.Web (IIS 전용 API)
         ASP.NET 코드가 IIS 내부에서 직접 실행

System.Web이라는 라이브러리 자체가 IIS에 종속적으로 설계되어 있어서, IIS 파이프라인과 ASP.NET이 한 몸이었어요. 별도의 브릿지가 필요 없었습니다.


ASP.NET Core가 이걸 일부러 끊었다

ASP.NET Core를 설계할 때 Microsoft가 내린 결정:

"IIS 없이도, Linux에서도, Docker에서도 돌아가게 만들자"

그래서 System.Web을 완전히 버리고 Kestrel이라는 자체 웹서버를 만들었습니다. 덕분에 ASP.NET Core는 IIS를 전혀 모르는 상태가 되었어요.

 

ASP.NET Core 앱  =  그냥 콘솔 프로그램
dotnet run 하면  =  Kestrel이 직접 포트를 열고 서비스

 

 

그런데 기존에 IIS 인프라를 쓰던 기업들은 ASP.NET Core를 IIS 위에서 돌리고 싶었습니다. 이 간극을 메우기 위해 ANCM이 태어난 겁니다.

 


"그냥 넘겨주는 것뿐"이 아닌 이유

 

 

ANCM이 실제로 하는 일은 꽤 많습니다.

 

 

역할 설명

프로세스 생명주기 관리 앱이 크래시나면 자동 재시작, 앱 실행/종료 담당
CLR 로딩 (In-Process) w3wp 안에 .NET 런타임 자체를 주입
환경 변수 전달 ASPNETCORE_ENVIRONMENT 등 설정값 주입
stdout 로그 리디렉션 stdoutLogEnabled 설정이 여기서 처리됨
포트 동적 할당 (Out-of-Process) 랜덤 포트를 Kestrel에 할당하고 프록시

특히 프로세스 재시작이 중요합니다. ANCM이 없으면 앱이 뻗었을 때 아무도 다시 살려주지 않아요.


한 줄 요약

ANCM은 "IIS를 모르는 ASP.NET Core"와 "ASP.NET Core를 모르는 IIS"를 이어주기 위해 만들어진 브릿지입니다. 예전엔 System.Web이 그 역할을 대신했고, ASP.NET Core가 플랫폼 독립성을 얻는 대신 이 브릿지가 필요해진 거예요.