WebForms Core vs Modern Web Concepts: 아키텍처 유사점과 차이점
Source: Dev.to
Source: …
소개
대부분의 최신 프론트‑엔드 프레임워크에서는 클라이언트가 주요 의사결정자 역할을 합니다. UI를 구축하고, 상태를 관리하며, 데이터를 가져오고, 변화에 반응합니다. 서버는 보통 API 제공자로 축소됩니다. **WebForms Core (WFC)**는 이 모델을 의도적으로 뒤집습니다. WFC에서는 서버가 오케스트레이터 역할을 하여 명시적인 UI 및 동작 지시를 내리고, WebFormsJS가 클라이언트에서 해당 지시를 자동으로 실행합니다.
이 글은 단순한 기능 체크리스트를 제공하는 것이 아닙니다. 대신 WebForms Core가 현대 웹 개념과 어떻게 일치하거나, 차별화되며, 의도적으로 반대되는지를 아키텍처 수준에서 설명합니다.
전통적인 WebForms 아키텍처에서는 모든 클라이언트‑사이드 이벤트가 서버에 전체 페이지 요청을 보내야 했습니다. 이 방식은 대역폭 소모를 크게 늘리고 응답 속도를 저하시켰습니다. WebForms Core는 명령 기반 통신(Command‑Based Communication) 아키텍처를 도입함으로써 이 영역에 근본적인 혁신을 가져옵니다.
WebForms Core 프로젝트는 두 개의 주요 파트로 구성됩니다:
| 파트 | 설명 |
|---|---|
| View | HTML 파일 또는 Razor 페이지 |
| Controller | 이벤트 관리를 담당하는 서버‑사이드 클래스 |
View (Index.cshtml 또는 index.html)
@page
@controller TextBoxController
Change TextBox Color
서버‑사이드 Controller (TextBoxController.cs)
using CodeBehind;
public partial class TextBoxController : CodeBehindController
{
public void PageLoad(HttpContext context)
{
// Check if keyup parameter exists in QueryString
if (context.Request.Query.ContainsKey("keyup"))
{
TextBox_keyUp();
return;
}
// Set up events in initial page load
WebForms form = new WebForms();
form.SetGetEvent("TextBox1", HtmlEvent.OnKeyUp, "?keyup");
Write(form.ExportToHtmlComment());
}
private void TextBox_keyUp()
{
WebForms form = new WebForms();
// Get the value entered by the user
string colorValue = Fetch.GetValue("TextBox1");
// Set the background color of TextBox1
form.SetBackgroundColor("TextBox1", colorValue);
// Set cache for one year (31536000 seconds)
form.SetCache(31536000);
// Send response (this is NOT an HTML comment, it's INI text)
Write(form.Response());
// Ignore View and Layout
IgnoreAll();
}
}
1단계 – 초기 페이지 요청
- 사용자가 페이지 URL로 이동합니다.
- 서버가 컨트롤러를 호출하고
PageLoad를 실행합니다. - 쿼리 문자열에
keyup매개변수가 없기 때문에 조건 블록이 건너뛰어지고 이벤트‑설정 코드가 실행됩니다:
WebForms form = new WebForms();
form.SetGetEvent("TextBox1", HtmlEvent.OnKeyUp, "?keyup");
Write(form.ExportToHtmlComment());
ExportToHtmlComment는 페이지에 삽입되는 HTML 주석을 생성합니다 (이 예시에서는 주석 자체가 비어 있습니다).- 브라우저에 전송되는 전체 응답은 다음과 같습니다:
Change TextBox Color
web-forms.js 스크립트가 주석을 읽고 #TextBox1에 keyup 리스너를 연결합니다.
2단계 – 사용자 상호작용 (KeyUp 이벤트)
사용자가 텍스트 상자에 (예: “red”) 입력하면 web-forms.js가 주석에 정의된 URL로 Ajax 요청을 보냅니다:
GET /page?keyup&TextBox1=red HTTP/1.1
3단계 – 서버에서의 요청 처리
컨트롤러가 다시 호출됩니다. 이번에는 쿼리 문자열에 keyup가 포함되어 있으므로 다음 메서드가 실행됩니다:
private void TextBox_keyUp()
{
WebForms form = new WebForms();
// Get the value "red" from the TextBox1 parameter
string colorValue = Fetch.GetValue("TextBox1");
// Set TextBox1 background color to red
form.SetBackgroundColor("TextBox1", colorValue);
// Set cache for one year (31536000 seconds)
form.SetCache(31536000);
// Send response (INI pattern without HTML comment wrapper)
Write(form.Response());
// Ignore View and Layout
IgnoreAll();
}
Response()는 일반 텍스트(INI 형식) 출력을 생성하며, HTML 주석으로 감싸지 않습니다:
[web-forms]
bcTextBox1=@$vTextBox1
cd=31536000
스크립트는 이 원시 텍스트를 받아 바로 파싱합니다.
4단계 – 브라우저에서 명령 수신 및 실행
web-forms.js는 응답을 해석합니다:
| Command | Meaning |
|---|---|
bcTextBox1=@$vTextBox1 | ID가 TextBox1인 요소의 배경색을 사용자가 제공한 값(red)으로 설정합니다. |
cd=31536000 | 페이지를 브라우저에 31 536 000초(1년) 동안 캐시합니다. |
명령을 실행한 후:
- 텍스트 박스 배경이 red로 즉시 변경되며 전체 페이지 새로 고침이 필요하지 않습니다.
- 페이지가 1년 동안 캐시됩니다.
5단계 – 이후 페이지 요청
사용자가 페이지를 다시 방문하면:
- 브라우저는 local cache에서 페이지를 로드합니다(
cd=31536000지시문 덕분). - 서버로 요청이 전송되지 않습니다.
[web-forms]주석은keyup이벤트를 등록하는데, 캐시된 HTML에 여전히 존재하므로 모든 클라이언트‑사이드 이벤트가 정상적으로 작동합니다.
통신 흐름 요약
| 단계 | 클라이언트 동작 | 서버 동작 | 응답 유형 |
|---|---|---|---|
| 1️⃣ 초기 로드 | 페이지 요청 | PageLoad → 이벤트를 등록 | HTML 주석 (<!-- … -->) |
| 2️⃣ 이벤트 (키업) | Ajax GET with ?keyup 및 필드 값 | TextBox_keyUp → 명령을 생성 | 일반 INI 텍스트 ([web-forms]…) |
| 3️⃣ 브라우저 | INI를 파싱하고 UI 변경을 적용하며 캐시를 설정 | — | — |
| 4️⃣ 이후 로드 | 캐시에서 제공 | — | — |
통신 세부 사항
초기 요청
HTML 주석 <!-- … --> – HTML에 삽입되어 이벤트를 등록합니다.
후속 응답
| 유형 | 설명 |
|---|---|
Plain Text (INI) [web‑forms] … | UI 명령과 캐시 지시문을 포함합니다. |
| Raw response body | 클라이언트가 실행하여 변경을 적용하고 캐시를 설정합니다. |
핵심 구분: 초기 이벤트 등록만 HTML 주석으로 전송됩니다. 클라이언트와 서버 간의 모든 런타임 상호작용은 플레인 텍스트 응답을 사용하여 대역폭과 파싱 오버헤드를 최소화합니다.
장점
- 최소한의 대역폭 소비
- 서버 부하의 현저한 감소
- 원활하고 빠른 사용자 경험
- 지능형 캐싱 전략 – 첫 번째 사용자 상호작용 이후, 동적 콘텐츠가 올바르게 작동하고 이후 방문은 즉시 로딩의 혜택을 받습니다. 개발자는 캐시 기간을 완전히 제어할 수 있습니다.
- 구현의 단순성 – 무거운 SPA 프레임워크, 복잡한 상태 관리, 별도의 RESTful API가 필요 없습니다.
- MVC 아키텍처와의 호환성 – 예제를 한 단계로 만들 수 있으며, 댓글은 한 번만 전송되어 이벤트를 기록하고 실행 명령을 전달합니다.
예제 (C#)
using CodeBehind;
public partial class TextBoxController : CodeBehindController
{
public void PageLoad(HttpContext context)
{
WebForms form = new WebForms();
form.SetCommentEvent("TextBox1", HtmlEvent.OnKeyUp, "keyup");
form.StartIndex("keyup");
form.SetBackgroundColor("TextBox1", Fetch.GetValue("TextBox1"));
Write(form.ExportToHtmlComment());
}
}
WebForms Core는 유연합니다: 필요에 따라 클라이언트 중심 또는 서버 중심 아키텍처를 채택할 수 있습니다. 이 유연성이 가장 큰 강점입니다.
Source: …
아키텍처 개요
실시간 통신
- Server‑Sent Events (SSE) – UI 지시를 점진적으로 전달하기 위해 HTTP 연결을 유지합니다.
- WebSocket 지원 (구현은 서버에서 제공해야 함).
Note: SSE와 WebSocket이 지원되지만, 기본 인프라는 서버에서 구현해야 합니다.
렌더링
- SSR (Server‑Side Rendering) 기본 제공 – 빠른 최초 페인트, SEO 친화적. 이후 업데이트는 전체 페이지 새로 고침이 아닌, 서버가 발행한 대상 명령을 통해 수행됩니다.
- Client‑Side Rendering도 가능하지만, 전통적인 SPA 방식은 아닙니다; 렌더링 결정은 여전히 서버 주도입니다.
- Hydration 없음 – 초기 요청은 HTML +
WebFormsJS를 전달합니다. 이후 상호작용은 HTML 조각이나 동작‑제어 지시만 반환하여 클라이언트의 CPU, JS 복잡도 및 메모리 사용을 줄입니다.
정적 사이트 생성
WFC는 결정론적인 HTML을 생성할 수 있기 때문에 정적 사이트 워크플로와 잘 통합됩니다: 페이지를 미리 렌더링하고, 연결이 가능할 때 서버‑주도 인터랙션으로 강화할 수 있습니다.
SPA‑유사 경험
- 전체 페이지 새로 고침 없이 부분 업데이트만 수행합니다.
- 탐색, 라우팅 및 업데이트는 서버에 의해 조정되며(클라이언트가 소유한 SPA가 아님)
클라이언트‑사이드 라우팅
내부 라우트를 대상으로 하는 앵커 태그는 자동으로 가로채어 페이지 새로 고침을 방지하고, 탐색을 서버‑주도 지시 파이프라인에 위임합니다.
아키텍처 입장
- Headless 아키텍처(렌더링이 콘텐츠/로직과 분리된 형태)는 거부됩니다. 서버가 데이터 와 프레젠테이션/동작을 모두 제공하여 제어를 중앙집중화하고 프런트‑엔드 복잡성을 감소시킵니다.
- Islands Architecture와 유사점: 페이지의 모든 부분이 동일하게 인터랙티브하지는 않습니다. 그러나 WFC의 인터랙티브는 서버‑관리 UI 영역이며, 고립된 JavaScript 섬이 아닙니다. WFC에서 서버 프레임워크를 교체하는 것이 전통적인 섬 기반 시스템에서 프런트‑엔드 프레임워크를 마이그레이션하는 것보다 종종 더 쉽습니다.
상태 관리
- 상태는 자동으로 서버에서 관리됩니다.
- 개발자는
AddState와 같은 메커니즘을 사용해 일시적인 클라이언트 상태를 저장할 수 있지만, 전체 수명 주기는 여전히 서버가 주관합니다.
바인딩 모델
- 명령형, 지시 기반 바인딩 – 데이터는 현대 프레임워크에서 사용하는 선언형/반응형 바인딩과 달리, 서버 명령을 통해 HTML 요소에 명시적으로 주입됩니다.
URL 및 데이터 매핑
- 대부분 자동화되어 초기 웹 원칙과 일치합니다.
- 고급 라우팅 시나리오는 Service‑based 확장을 통해 구현할 수 있습니다.
WebForms Core (WFC) 개요
- 서버‑주도 UI 오케스트레이션 – 상호작용은 이벤트‑드리븐이며 서버에서 트리거되어, 필요한 명령만 포함된 지연‑로드 응답을 반환합니다.
성능 및 압축
- Gzip 압축은 서버‑측과 클라이언트‑측 모두에 적용될 수 있습니다.
- 압축된 명령 형식은 기존 JSON‑기반 API에 비해 페이로드 크기를 더욱 줄여줍니다.
- WebForms Core에서는 파일과 폼 데이터 모두를 Gzip 압축으로 전송할 수 있습니다.
WebFormsJS가 보낸 Gzip을 서버가 압축 해제하는 것이 서버의 책임입니다.
DOM 처리
- WFC는 Virtual DOM이나 diff 알고리즘을 구현하지 않습니다.
- 일시적인 DOM 접근 방식을 사용합니다:
- 대상 요소를 복제합니다.
- 여러 변경을 적용합니다.
- 한 번의 작업으로 커밋합니다.
- 이를 통해 깜박임을 방지하고 인지된 성능을 향상시킵니다.
Progressive Web App (PWA) 지원
- WFC는 Service Worker와 Web App Manifest를 통해 PWA 기능을 완전하게 지원합니다.
- 오프라인 동작, 설치 가능성, 캐시 전략 등을 핵심 아키텍처를 변경하지 않고 관리할 수 있습니다.
컴포넌트 모델
- WFC는 진정한 Web Components(커스텀 엘리먼트, Shadow DOM)를 구현하지 않습니다.
- 재사용 가능한 컴포넌트는 다음을 통해 시뮬레이션할 수 있습니다:
- 서버‑측 템플릿
- HTML 조각
- 확장 메서드
WebAssembly 통합
- 필요에 따라 클라이언트에서 WebAssembly 모듈을 호출할 수 있어, 전체 프로그래밍 모델을 바꾸지 않고도 고성능 작업을 수행할 수 있습니다.
브라우저 API 접근
- 카메라, Bluetooth, 파일 시스템 등 브라우저 API에 대한 직접 접근은 WFC 코어에 포함되어 있지 않습니다.
- 필요 시 맞춤 JavaScript 모듈을 통해 활성화할 수 있습니다.
무상태 & 확장 가능한 아키텍처
- WebForms Core는 완전 무상태이며 서버리스 아키텍처와 호환됩니다.
- 로드 밸런서 뒤나 수평 확장이 가능한 환경에서도 원활히 동작합니다.
테스트 전략
- 테스트는 주로 서버‑중심입니다.
- 클라이언트‑측 로직이 최소이고 프로토콜이 안정적이므로 단위 테스트가 더 간단하고 결정적입니다.
- 통신 계약은 프레임워크 자체가 유지하므로 클라이언트‑측 테스트 복잡성이 감소합니다.
CLI & 개발 통합
- WFC는 독립 실행형 CLI를 제공하지 않습니다.
- 기존 백‑엔드 프로젝트에 직접 통합됩니다.
- 개발에는 서버‑측
WebForms클래스와 HTML<script>태그에WebFormsJS를 포함하는 것만 필요합니다.
아키텍처 철학
- WebForms Core는 현대적이지만 현대 프론트‑엔드 프레임워크를 모방하려 하지 않습니다.
- 서버‑주도 UI 오케스트레이션과 최소한의, 순응적인 클라이언트를 지향하는 다른 아키텍처 철학을 나타냅니다.
- 많은 현대 웹 개념을 지원하지만 근본적으로 다른 방식으로 구현되며, 일부는 의도적으로 배제됩니다.
포지셔닝 & 사용 사례 적합성
- JAMstack, Headless, Reactive SPA와 같은 기존 카테고리에 WFC가 들어가는지를 묻기보다, 서버‑명령 모델이 프로젝트 목표와 일치하는가가 더 중요한 질문입니다.
- 다음을 추구하는 팀에게:
- 프론트‑엔드 복잡성 감소
- 중앙 집중식 제어
- 예측 가능한 동작
- WebForms Core는 뚜렷하고 일관된 대안을 제공합니다.