.NET 9 Blazor: Blazor United를 활용한 풀스택 개발 가이드 2026
.NET 9 Blazor United는 정적 SSR, Server, WebAssembly 렌더링 모드를 하나의 풀스택 프레임워크로 통합합니다. 렌더링 모드 활용법, 스트리밍 렌더링, 생성자 주입, 프로덕션 패턴을 실습 중심으로 다루는 튜토리얼입니다.

.NET 9의 Blazor United는 정적 서버 사이드 렌더링(SSR), 인터랙티브 Server, WebAssembly라는 세 가지 렌더링 전략을 하나의 풀스택 프레임워크로 통합한 기술입니다. .NET 8에서 처음 도입되고 .NET 9에서 더욱 정교해진 이 통합 모델 덕분에, 코드를 작성하기 전에 Blazor 호스팅 모델을 선택해야 하는 부담이 사라졌습니다.
Blazor United를 사용하면 동일한 애플리케이션 내에서 정적 SSR, Server 인터랙티비티, WebAssembly 인터랙티비티를 혼합하여 사용할 수 있습니다. 각 컴포넌트가 독립적으로 렌더링 모드를 선언하므로, 페이지별로 성능과 인터랙티비티를 세밀하게 제어할 수 있습니다.
.NET 9 Blazor 웹 앱 설정하기
.NET 9의 blazorweb 템플릿은 세 가지 렌더링 모드를 모두 지원하는 프로젝트를 자동으로 생성합니다. 설정에는 .NET 9 SDK(9.0.100 이상)가 필요하며, 하나의 명령으로 서버 프로젝트와 클라이언트(WASM) 프로젝트가 함께 생성됩니다.
# Create a new Blazor Web App with all render modes enabled
dotnet new blazorweb -n FullStackApp --interactivity Auto --all-interactive false
cd FullStackApp
dotnet run--interactivity Auto 플래그를 사용하면 Server와 WebAssembly 렌더링 모드가 모두 활성화됩니다. --all-interactive false를 설정하면 기본 렌더링 모드가 정적 SSR로 유지되어, 전역이 아닌 컴포넌트 단위로 인터랙티비티를 선택하는 구조가 됩니다.
.NET 9의 Blazor 렌더링 모드 이해하기
Blazor 웹 앱의 모든 컴포넌트는 실행 위치, 인터랙티비티 지원 여부, 서버와의 통신 방식을 결정하는 렌더링 모드를 갖습니다. .NET 9에서는 네 가지 렌더링 모드를 제공합니다.
| 렌더링 모드 | 호스팅 | 인터랙티비티 | 적합한 용도 | |---|---|---|---| | 정적 SSR | 서버 | 없음 | 마케팅 페이지, 문서, SEO 콘텐츠 | | Interactive Server | SignalR 기반 서버 | 완전 지원 | 대시보드, CRUD, 폼 | | Interactive WebAssembly | WASM 기반 브라우저 | 완전 지원 | 오프라인, 클라이언트 측 고부하 로직 | | Interactive Auto | 서버 → WASM | 완전 지원 | 빠른 로딩과 독립성의 조화 |
렌더링 모드는 @rendermode 지시문 속성을 사용하여 컴포넌트 수준에서 설정됩니다. 이러한 컴포넌트 단위의 세분화 덕분에 하나의 페이지 내에서 정적 섹션과 인터랙티브 섹션을 혼합할 수 있습니다.
@page "/dashboard"
@rendermode InteractiveServer
<PageTitle>Dashboard</PageTitle>
<h1>Real-Time Metrics</h1>
<!-- This component renders interactively via SignalR -->
<MetricsChart />
<!-- Static content below renders as plain HTML -->
<footer>Updated every 5 seconds</footer>.NET 9에서 추가된 ComponentBase.RendererInfo API를 사용하면 컴포넌트가 런타임에 현재 렌더링 모드를 감지할 수 있으며, 실행 컨텍스트에 따른 조건부 로직을 구현할 수 있습니다.
@if (RendererInfo.IsInteractive)
{
<button @onclick="HandleClick">Interactive Action</button>
}
else
{
<a href="/fallback">Static Fallback Link</a>
}
@code {
private void HandleClick()
{
// Runs only in interactive modes (Server or WASM)
}
}비동기 작업이 많은 페이지를 위한 스트리밍 렌더링
비동기적으로 데이터를 가져오는 정적 SSR 페이지는 모든 작업이 완료될 때까지 응답을 차단할 수 있습니다. 스트리밍 렌더링은 플레이스홀더 HTML을 즉시 전송한 후, 데이터가 도착하면 최종 콘텐츠를 푸시하여 이 문제를 해결합니다. .NET 9에서는 [StreamRendering] 속성에 true 매개변수가 더 이상 필요하지 않으며, 기본적으로 활성화됩니다.
@page "/products"
@attribute [StreamRendering]
<PageTitle>Product Catalog</PageTitle>
@if (products is null)
{
<p>Loading products...</p>
}
else
{
<div class="product-grid">
@foreach (var product in products)
{
<ProductCard Item="@product" />
}
</div>
}
@code {
private List<Product>? products;
// Data loads asynchronously; streaming pushes updates to the browser
protected override async Task OnInitializedAsync()
{
products = await ProductService.GetAllAsync();
}
}스트리밍 렌더링은 HTTP/1.1 청크 전송 인코딩에 의존하며, 모든 최신 브라우저에서 지원됩니다. 플레이스홀더 콘텐츠가 즉시 렌더링되고, 전체 페이지 새로고침 없이 최종 마크업으로 교체됩니다.
Blazor 컴포넌트의 생성자 주입
.NET 9에서는 기존의 @inject 지시문과 [Inject] 속성을 보완하는 Blazor 컴포넌트용 생성자 주입이 도입되었습니다. C# 12의 기본 생성자와 결합하면 서비스 의존성이 컴포넌트의 타입 시그니처에 포함됩니다.
@page "/orders"
@rendermode InteractiveServer
<h2>Order History</h2>
@if (orders is not null)
{
<table>
<thead>
<tr><th>Order ID</th><th>Date</th><th>Total</th></tr>
</thead>
<tbody>
@foreach (var order in orders)
{
<tr>
<td>@order.Id</td>
<td>@order.PlacedAt.ToShortDateString()</td>
<td>@order.Total.ToString("C")</td>
</tr>
}
</tbody>
</table>
}
@code {
// Constructor injection via primary constructor
[Inject] public required IOrderService OrderService { get; set; }
[Inject] public required NavigationManager Nav { get; set; }
private List<Order>? orders;
protected override async Task OnInitializedAsync()
{
orders = await OrderService.GetRecentOrdersAsync();
}
}생성자 주입을 통해 의존성이 명시적으로 드러나며, 단위 테스트가 간소화됩니다. Program.cs에 등록된 서비스는 자동으로 해석되며, builder.Services.AddKeyedScoped<T>()로 추가된 키 기반 서비스도 포함됩니다.
.NET 면접 준비가 되셨나요?
인터랙티브 시뮬레이터, flashcards, 기술 테스트로 연습하세요.
Interactive Auto 모드 — 양쪽의 장점을 모두 취하다
Auto 렌더링 모드는 가장 빠른 체감 로딩 속도를 제공합니다. 첫 방문 시 컴포넌트는 SignalR을 통해 서버에서 실행되면서, 백그라운드에서 WebAssembly 런타임이 다운로드됩니다. 이후 방문부터는 실행이 완전히 브라우저로 이동합니다.
@page "/chat"
@rendermode InteractiveAuto
<h2>Live Chat</h2>
<div class="chat-messages">
@foreach (var msg in messages)
{
<div class="message">@msg.Author: @msg.Text</div>
}
</div>
<input @bind="newMessage" @onkeydown="HandleKey" placeholder="Type a message..." />
@code {
[Inject] public required IChatService ChatService { get; set; }
private List<ChatMessage> messages = new();
private string newMessage = string.Empty;
protected override async Task OnInitializedAsync()
{
messages = await ChatService.GetRecentMessagesAsync();
}
private async Task HandleKey(KeyboardEventArgs e)
{
if (e.Key == "Enter" && !string.IsNullOrWhiteSpace(newMessage))
{
await ChatService.SendAsync(newMessage);
newMessage = string.Empty;
}
}
}Auto 모드에서는 컴포넌트의 의존성과 로직이 서버와 WASM 두 컨텍스트 모두에서 동작해야 합니다. 서비스는 인터페이스로 추상화하고, 서버와 클라이언트의 DI 컨테이너에 모두 등록해야 합니다.
.NET 9의 재연결 및 복원력 개선
.NET 9에서는 Blazor Server의 재연결 로직이 지수 백오프 전략으로 전면 재작성되었습니다. 고정 간격으로 재시도하는 대신, 프레임워크가 빠른 재시도로 시작하여 점차 지연 시간을 늘립니다. 이를 통해 장애 시 서버 부하를 줄이면서도 일시적인 연결 끊김에서 빠르게 복구할 수 있습니다.
주요 개선 사항:
- 탭으로 다시 돌아오면 즉시 재연결을 시도합니다
- 서버가 이미 서킷을 해제한 경우, 페이지가 자동으로 새로고침됩니다
- 기본 UI에 "서버에 재연결 중..."과 진행 표시기가 표시됩니다
- 재시도 간격은
Blazor.start()를 통해 구성할 수 있습니다
Blazor.start({
circuit: {
reconnectionOptions: {
retryIntervalMilliseconds: (retryNumber) => {
// Exponential backoff: 200ms, 400ms, 800ms, max 30s
return Math.min(200 * Math.pow(2, retryNumber), 30000);
},
maxRetries: 15
}
}
});정적 SSR과 선택적 인터랙티비티
2026년 대부분의 Blazor 웹 앱에 권장되는 아키텍처는 정적 SSR을 기본값으로 사용하고, 필요한 곳에만 인터랙티비티를 추가하는 방식입니다. [ExcludeFromInteractiveRouting] 속성(.NET 9 신규 기능)은 정적으로 유지해야 하는 페이지를 표시하는 데 사용되며, HTTP 쿠키나 요청/응답 주기에 의존하는 페이지에 유용합니다.
@page "/privacy"
@attribute [ExcludeFromInteractiveRouting]
<PageTitle>Privacy Policy</PageTitle>
<!-- This page always renders as static HTML -->
<!-- Even if global interactivity is enabled -->
<article>
<h1>Privacy Policy</h1>
<p>Last updated: April 2026</p>
<!-- Content -->
</article>이 패턴은 MapStaticAssets와 잘 어울립니다. MapStaticAssets는 .NET 9의 새로운 미들웨어로, 빌드 시점에 정적 파일을 압축하고 핑거프린팅 처리하여 기존의 UseStaticFiles 방식을 최적화된 전달 방식으로 대체합니다.
.NET 9 AOT 컴파일을 통한 성능 향상
.NET 9 AOT(Ahead-of-Time) 컴파일은 .NET 8 대비 WebAssembly 페이로드 크기를 최대 40% 줄입니다. Google Lighthouse 벤치마크 기준으로 Blazor WASM 시작 속도가 25% 빨라졌습니다. 이러한 성능 개선은 AOT를 활성화하여 퍼블리시하면 자동으로 적용됩니다.
# Publish with AOT for production
dotnet publish -c Release -p:RunAOTCompilation=true인터랙티브 Server 컴포넌트에서 WebSocket 압축도 기본적으로 활성화됩니다. 압축 관련 공격 벡터를 완화하기 위해 콘텐츠 보안 정책(frame-ancestors: 'self')이 자동으로 적용됩니다.
연습을 시작하세요!
면접 시뮬레이터와 기술 테스트로 지식을 테스트하세요.
결론
- .NET 9의 Blazor United는 정적 SSR, Server, WebAssembly를 단일 프로젝트에 통합하여 호스팅 모델 선택의 부담을 없앱니다
@rendermode로 컴포넌트별 렌더링 모드를 설정하여 각 페이지를 독립적으로 최적화할 수 있습니다 — SEO에는 정적, 대시보드에는 Server, 하이브리드 시나리오에는 Auto를 적용합니다[StreamRendering]을 활용한 스트리밍 렌더링으로 비동기 작업이 많은 페이지의 로딩 지연을 해소할 수 있습니다- .NET 9의 신규 기능인 생성자 주입은 컴포넌트의 의존성을 명시적이고 테스트 가능하게 만듭니다
- Auto 렌더링 모드는 Server를 통한 빠른 첫 렌더링을 제공한 후, 재방문 시 WASM으로 전환하여 완전한 클라이언트 독립성을 실현합니다
- 지수 백오프 재연결로 연결 끊김이 줄어들고 수동 페이지 새로고침이 불필요해집니다
- AOT 컴파일로 WASM 페이로드 크기가 40% 감소하고 시작 시간이 25% 단축됩니다
- 모든 Blazor 웹 앱은 정적 SSR을 기본값으로 시작한 후, UX가 요구하는 곳에 인터랙티비티를 추가하는 것이 권장됩니다
연습을 시작하세요!
면접 시뮬레이터와 기술 테스트로 지식을 테스트하세요.
태그
공유
관련 기사

Entity Framework Core: 2026년 성능 최적화와 모범 사례
EF Core 10의 성능 최적화를 다룹니다. AsNoTracking, 컴파일된 쿼리, 배치 작업, 분할 쿼리, LeftJoin 연산자 등 .NET 10 프로덕션 애플리케이션을 위한 실용적인 C# 코드 예제를 제공합니다.

.NET을 활용한 Clean Architecture 실전 가이드
C#과 .NET으로 Clean Architecture를 마스터합니다. SOLID 원칙, 계층 분리, 유지보수가 쉬운 애플리케이션을 위한 구현 패턴을 학습합니다.

C# 및 .NET 면접 질문: 2026년 완벽 가이드
가장 자주 출제되는 C# 및 .NET 면접 질문 17선입니다. LINQ, async/await, 의존성 주입, Entity Framework, ASP.NET Core 등 상세한 답변과 코드 예제를 다룹니다.