λͺ©μ
.NET 9 Blazorμ μΆκ°, λ³κ²½λ κΈ°λ₯ νꡬ
λͺ©ν
- Static SSR λ° νμ΄λΈλ¦¬λ λμμ± νμΈ
- κ°λ¨ν λΈλ‘κ·Έ μλΉμ€ λ§λ€κΈ°
.NET 9 Blazorμ μΆκ°, λ³κ²½λ κΈ°λ₯ νꡬ
@BigSquare λμ΄ μμ μ Static SSRμ κΈ°λ³Έ λμμ±μ νμΈνμ ¨μ΅λλ€.
Static SSRλ μλ² λλ ν΄λΌμ΄μΈνΈμμ μ΄μ Blazor νμ΄μ§ μ²λΌ μνΈ μμ©νλ κ²κ³Όλ λ€λ₯΄κ² β μ¬κΈ°μ μνΈμμ©μ΄λ μν
κ° μ μ§λκ³ ν΄λ¦ λ±μ μν΄ μν
κ° λ³κ²½λλ©° κ·Έ μνλ₯Ό λ΄κ³ μλ μΈμ€ν΄μ€κ° κ³μ μ μ§λλ κ²μ μλ―Έν©λλ€ β Static SSRμ μλ²μμ νμ΄μ§λ₯Ό λ λλ§ νκ³ λ ν μΈμ€ν΄μ€λ νκΈ°λλ λ°©μ μ
λλ€.
λ€λ§ Blazorμμ μ 곡νλ Static SSRμ κ²½μ° μ 체 νμ΄μ§κ° 리νλ μ λμ΄ μ¬μ©μ±μ΄ μ νλκΈ° λλ¬Έμ Blazorμμλ ν₯μλ μμ μ²λ¦¬λ₯Ό ν΅ν΄ μ΄λ₯Ό 보μν©λλ€.
.NET MAUI μν¬λ‘λλ₯Ό μ€μΉν ν
dotnet workload install maui
λ€μμ λͺ λ Ήμ μ΄μ©ν΄μ Blazor μΉμ± MAUI ν νλ¦ΏμΌλ‘ νλ‘μ νΈλ₯Ό μμν μ μμ΅λλ€.
dotnet new maui-blazor-web
μ΄ ν νλ¦ΏμΌλ‘ μ±μ μ€ννλ©΄ Blazorλ‘ MAUI νκ²½μμ μ ν리μΌμ΄μ μ κ°λ°ν μ μμΌλ©° Server λλ WebAssembly λ°©μμΌλ‘ λμνλ κ²μ΄ μλλΌ μΈλ² λ© λ WebViewμμ λ λλ§ νλ λ°©μμΌλ‘ λμνκ² λ©λλ€.
9.0 μμ μκ°λ μ΄ μ루μ ν νλ¦Ώμ μΉμ±κ³Ό ν¬λ‘μ€ νλ«νΌ λ°μ€ν¬ν μ±μ UIλ₯Ό Blazor νλλ‘ μμ±ν μ μλ λ°©λ²μ μλ €μ£Όλ κ² κ°μ΅λλ€.
8.0 κΉμ§λ§ ν΄λ, μμ κ°μ ꡬμ±μ νκΈ° μν΄μλ μλμ²λΌ ꡬμ±μ νμ΄μΌ νμ΅λλ€.
μμ κ°μ΄ ꡬμ±ν μ΄μ λ Blazor hybrid/Hosting κ³Ό Blazor Webassemblyμ μΈν°λ ν°λΈ λͺ¨λκ° κΈ°λ³Έμ μΌλ‘ κ°κΈ° λλ¬Έμ λλ€.
μ€μ λ‘ ν΄λ³΄μλ©΄, μλ² μΈ‘ μΈν°λ ν°λΈμ ν΄λΌμ΄μΈνΈ μΈ‘ μΈν°λ ν°λΈλ₯Ό λͺ¨λ λ§μ‘±νλ λ μ΄μ μμλ₯Ό RCLμ μμ±νλ κ²μ μ¬μ€ κ½€ μ΄λ ΅λ€λ μ μ μκ² λ©λλ€.
9.0 ν νλ¦Ώμ μλ² μΈ‘ λ λλ§μ΄ λ μ λ°μ μμ΄ λ³΄μ΄λλ°, μλλ λ€λ₯ΌκΉ λ λ λͺ¨λ μ²λ¦¬μ κ΄ν μ£Όμ μ¬νμ΄ λ¬Έμμ λ§μ΄ λμ€λ€μ.
ν리뷰 λ±μ§ λΌκ³ λμ€λ©΄, μ΄λ»κ² ꡬμ±νλμ§ μ΄ν΄ λ΄μΌκ² μ΅λλ€.
νμ΄λΈλ¦¬λμμ λ λ λͺ¨λ μ μ©μ΄ μμ§μ μ μλ§ μ§μνλ€λ λ΄μ©μ νμΈνμλλ° μ΄λ€ λΆλΆμ΄ RCLμμ μΈν°λ ν°λΈ ꡬνμ μ΄λ ΅κ² νλμ§ κΆκΈν©λλ€.
μ κ° μ΄ν΄ν λ°λ‘λ Blazor νμ΄λΈλ¦¬λ λ°©μμ Server / WebAssembly λ°©μμ΄ μλλΌ WebViewλ₯Ό μ§μ μ¬μ©ν΄μ λ λλ§νλ κ²μΌλ‘ μκ³ μλλ°μ μ΄λ WebAssemblyλ³΄λ€ Serverμ μΈν°λ ν°λΈ λμμ κ°κΉκ² μ§λ§ μ΄μ¨λ Server λͺ¨λλ μλλλ€.
κ΄λ ¨ν΄μ μ‘°κΈ λ μ€λͺ λΆν λ립λλ€.
RCLμ μλ μμλ€μ κΈ°λ³Έμ μΌλ‘ μΈν°λ ν°λΈ λͺ¨λλ₯Ό μ§μ νμ§ μμ΅λλ€. (κ·Έλ κ² κΆκ³ λκ³ μμ΅λλ€)
λ¬Έμ λ μμκ° Routable Component(νμ΄μ§)μ΄κ³ , λΈλ μ΄μ μΉμ±μμ κ°μ Έλ€ μ°λ κ²½μ°μ λλ€.
μΉμ±μμ λ λλ§ λͺ¨λλ₯Ό μ§μ νμ§ μμΌλ©΄, Static SSR μ΄ λλλ°, μ΄ κ²½μ°, μμμ μΈν°λ ν°λΈ μ½λκ° λμνμ§ μμ΅λλ€. (form νκ·Έλ§ λμν©λλ€)
μΈν°λ ν°λΈ μ½λκ° λμνκΈ° μν΄μλ, μΉμ±μ μΈν°λ ν°λΈ λͺ¨λλ₯Ό μ μμΌλ‘ νλλ₯Ό μ§μ ν΄μΌ ν©λλ€. μ΄ μ§μ μ λ°λΌμ, μλ² μΈ‘ νλ‘μ νΈλ ν΄λΌμ΄μΈνΈ μΈ‘ νλ‘μ νΈ μ€ νλλ§ μ¬μ©ν μ μμ΅λλ€.
λ¬Έμμ 보λ, μ¬κΈ°μ λν΄ MAUIμμ λ λ λͺ¨λ κ΄λ ¨ μλ¬λ μλ€μ.
The app automatically adopts global interactivity, which is important because MAUI apps always run interactively and throw errors on Razor component pages that explicitly specify a render mode. For more information, see BlazorWebView needs a way to enable overriding ResolveComponentForRenderMode (
dotnet/aspnetcore
#51235).
μ΄λ¬ν κ³ λ―Όμ μμ λ €λ©΄, RCL μλ μΈν°λ ν°λΈ λͺ¨λλ₯Ό κ°λ³ν μ μλ non-routable μμλ§ μ μν΄μΌ νλλ°, μ΄ κ²½μ°, λͺ¨λ μ€ν νλ‘μ νΈμ λμΌν νμ΄μ§ μμλ€μ μ€λ³΅μ μΌλ‘ λ£μ΄ μ€μΌ νλ λΆνΈμ΄ λ°μν©λλ€.
μΉλ·°μ λΈλΌμ°μ λ κ°μ μ€ν 컨ν
μ€νΈλΌ ν μ μμ΅λλ€.
μ¦, λΈλ μ΄μ κ° ν΄λΌμ΄μΈνΈ μΈ‘μμ μ€νλ¨μ μλ―Έν©λλ€.
μ λκΈμ μ μν 8.0 μ루μ ꡬ쑰λ, μμ μλ² μΈ‘ 컨ν μ€νΈλ₯Ό λ°°μ νμ¬, ν΄λΌμ΄μΈνΈ μΈ‘ νλλ‘ μ€ν 컨ν μ€νΈλ₯Ό λ¨μνν κ²μ λλ€. (μ΄ λλ¬Έμ, μλ² μΈ‘ λΈλ μ΄μ λ₯Ό κ°μ νλ Blazor Wep appμ μ¬μ©νμ§ μκ² λ©λλ€.)
μ΄λ¬ν κ°μ μ΄ μμΌλ©΄, RCLμ λͺ¨λ μμλ νλμ μ€ν 컨ν μ€νΈλ§ κ°μ νμ¬ ν΅μΌμ μΌλ‘ μμ±ν μ μκ³ , λͺ¨λ ν΄λΌμ΄μΈνΈ μΈ‘ νλ‘μ νΈμμ μ¬μ©ν μκ² λλ κ²μ΄μ£ .
μ΄λ¬ν ν΅μΌμ±μΌλ‘ μΈν΄, RCL νλ‘μ νΈλ νμ΄μ§λ λ¬Όλ‘ , App.razor κΉμ§ 보μ ν μ μκ² λ©λλ€. RCL μ΄ App μ λͺ¨λ λ‘μ§κ³Ό μμ°μ κ°κ² λλ κ²μ΄μ£ .
μ΄λ MAUI λ XAMARIN μμ 곡μ νλ‘μ νΈμ App ν΄λμ€λ₯Ό λλ κ²κ³Ό κ°μ λ°©μμΌλ‘, νλμ UI μ½λλ₯Ό (νλ‘ νΈ)μΉμ±, λ°μ€νΈ ν μ±, λͺ¨λ°μΌ μ±μμ (μ½λ μμ μμ΄) μ¬μ©νλ ꡬ쑰μ λλ€.
λ λ λͺ¨λκ° interactive
μ΄λ©΄μ prerender
κ° true
(κΈ°λ³Έ μ€μ ) μΌ κ²½μ° νμ΄μ§λ μ¬μ©μμκ² λΉ λ₯΄κ² 보μ΄κΈ° μν΄ μνΈμμ© μ μ μ μΌλ‘ λ¨Όμ λ λλ§μ ν μ΄ν μνΈμμ©μ΄ κ°λ₯ν νμ΄μ§λ‘ λ€μ λ λλ§μ ν΄μ μ΄ λ λ² ν΄λΉ νμ΄μ§ (λλ μ»΄ν¬λνΈ)μ μΈμ€ν΄μ€κ° μμ±λ©λλ€.
μ΄μ λ°λΌ νλ©΄μ 보μ¬μ§λ κ°μ΄ μ μ§ λμ§ μλλ° μ΄λ₯Ό νμΈνλ κ°λ¨ν λ°©λ²μ λ€μμ μ½λλ‘ νμΈν μ μμ΅λλ€.
@page "/counter"
@rendermode InteractiveAuto
@*@rendermode InteractiveWebAssembly*@
@* @rendermode InteractiveServer *@
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<p>@RendererInfo.Name</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
int currentCount = Random.Shared.Next(0, 100);
void IncrementCount()
{
currentCount++;
}
}
@rendermode
κ°InteractiveServer
μΌ κ²½μ° λΉ λ₯΄κ² νλ©΄μ΄ μ νλκΈ° λλ¬ΈμAuto
λWebAssembly
μ΄μ΄μΌ μ ν λλ κ²μ νμΈν μ μμ΅λλ€.
μ΅μ΄μλ μλμ²λΌ StaticμΌλ‘ λ λλ§μ΄ λμκ³ μ΄κΈ° μΉ΄μ΄νΈ κ°μ΄ 82
μλλ°
νμ΄μ§κ° λͺ¨λ μ€λΉκ° λλ©΄ WebAssembly
μΌλ‘ λ λλ§ λκ³ μ΄κΈ° κ°μ΄ 91
λ‘ λ°λ κ²μ νμΈν μ μμ΅λλ€.
미리 λ λλ§λ μνλ₯Ό κ³μ μ μ§νλ €λ©΄ PersistentComponentState μλΉμ€λ₯Ό μλμ κ°μ΄ μ΄μ©ν μ μμ΅λλ€.
@page "/counter"
@implements IDisposable
@rendermode InteractiveAuto
@*@rendermode InteractiveWebAssembly*@
@* @rendermode InteractiveServer *@
@inject PersistentComponentState ApplicationState
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<p>@RendererInfo.Name</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount;
private PersistingComponentStateSubscription persistingComponentStateSubscription;
protected override void OnInitialized()
{
persistingComponentStateSubscription = ApplicationState.RegisterOnPersisting(PersistCount);
if (!ApplicationState.TryTakeFromJson<int>(nameof(currentCount), out var restoredCount))
{
currentCount = Random.Shared.Next(100);
}
else
{
currentCount = restoredCount;
}
}
private Task PersistCount()
{
ApplicationState.PersistAsJson(nameof(currentCount), currentCount);
return Task.CompletedTask;
}
private void IncrementCount()
{
currentCount++;
}
void IDisposable.Dispose() => persistingComponentStateSubscription.Dispose();
}
| 미리 λ λλ§
| μνΈμμ© μ μ© ν
PersistentComponentStateμ κ΄λ ¨λ λ·λ·λ°λΈ κΈμ @BigSquare λμ λΈλ μ΄μ 8.0 μ ν μ₯μ μμ μ°Ύμ μ μμ΅λλ€.
PersistentComponentState
μλΉμ€λ μ΄λ»κ² 미리 λ λλ§λ μμ μμμ μνλ₯Ό 보쑴ν μ μμκΉμ? 미리 λ λλ§λ htmlμ μ΄ν΄λ³΄λ©΄ λ€μμ μ£Όμμ΄ λμ λλλ€.
...
<!--Blazor-Server-Component-State:CfDJ8K93lMGTYKpAgncimEFm28D7H3mLLAO3PvR2WrIlslhYg7Vd82+05p2l...
<!--Blazor-WebAssembly-Component-State:eyJfX1Jlc291cmNlQ29sbGVjdGlvblVybCI6Iklp...
μ΄ μ€ Blazor-WebAssembly-Component-State
λ₯Ό base64 볡νΈν νλ©΄,
{...,"currentCount":"NDk="}
μ¦, ApplicationState.PersistAsJson(nameof(currentCount), currentCount);
μ μν΄μ JSONμΌλ‘ μ μ₯λ currentCount
κ°μ΄λΌλ κ²μ νμΈν μ μμ΅λλ€.
Blazor-Server-Component-State
μ κ²½μ° base64 λμ½λ©μ νλλΌλ μνΈν λμ΄ μλλ° μ΄λ μλ²μμ 볡νΈν ν΄μ μ¬μ©ν΄μΌ ν μνμ΄λ―λ‘ ν΄λΌμ΄μΈνΈμμ λ³μ‘°ν μ μλλ‘ λμ΄ μλκ²μΌλ‘ 보μ
λλ€.
κΈ°μ‘΄ app.UseStaticFiles()
μμ app.MapStaticAssets()
μΌλ‘ μ μ μλ£μ μ κ·Όνλ λ°©μμ΄ λ¬λΌμ‘μ΅λλ€. λ€λ§ UseStaticAssets()
λ μ»΄νμΌ λ° κ²μ μμ μμ μ μ μμμ μ΅μ ν νλ―λ‘ λ°νμ μ λ±λ‘λλ μ μ μλ£μ μ κ·ΌνκΈ° μν΄μλ UseStaticFiles()
λ₯Ό μ¬μ ν μ¬μ©ν΄μΌ νλ€κ³ ν©λλ€.
κ·Έλ λ€λ©΄ μ μ μμ°μ μ μ νμΌκ³Ό μ΄λ€ μ°¨μ΄κ° μμκΉμ? μμμ μμΆνκ³ λ μ λλ‘ μΊμ±λ μ μλλ‘ νλ μΌλ ¨μ μ²λ¦¬κ° λ©λλ€.