LabHub

블로그

모던 .NET 2026 완벽 가이드 - .NET 9 · C# 13 · F# 9 · ASP.NET Core · Blazor United · MAUI · Aspire · EF Core 9 심층 분석

한국어English日本語

프롤로그 — 2026년, .NET은 더 이상 "윈도우의 자바"가 아니다

2010년대까지 .NET을 보는 시선은 단순했다. "윈도우 서버에 IIS 깔고 C# 짜는 마이크로소프트 스택." 자바의 라이센스 비용을 못 내는 곳이 갈 곳이 아니라, 윈도우 쇼핑몰을 운영하는 곳이 가는 곳이었다.

2026년에는 그 그림이 완전히 다르다.

그리고 .NET 9가 2024년 11월에 STS(Standard Term Support, 18개월)로 나왔고, .NET 10이 2025년 11월에 LTS(Long Term Support, 36개월)로 나왔다. 2026년 5월 현재, 새 프로젝트는 거의 다 .NET 10에 자리잡았고, .NET 9는 마이그레이션 중인 프로젝트의 중간 단계다.

이 글은 2026년의 .NET 스택을 처음부터 끝까지 정리한다. 런타임·언어·웹·UI·데이터·분산·게임·테스트까지 — 그리고 "어디서 어떤 라이브러리를 쓸지" 결정하는 매트릭스까지.


1장 · .NET 런타임 — STS와 LTS의 사이클

.NET은 2년 주기로 LTS를 낸다. 짝수년이 LTS, 홀수년이 STS다.

2026년 5월에 .NET 9의 지원이 끝났다. 새 프로젝트는 .NET 10으로 시작하는 게 정답이다. .NET 8 LTS는 11월까지 살아남는다.

# 현재 SDK 확인
dotnet --list-sdks

# .NET 10 설치 (macOS Homebrew)
brew install --cask dotnet-sdk

# global.json로 특정 버전 고정
cat > global.json <<EOF
{
  "sdk": {
    "version": "10.0.100",
    "rollForward": "latestFeature"
  }
}
EOF

# 새 프로젝트
dotnet new console -n HelloWorld
cd HelloWorld
dotnet run

런타임의 핵심 키워드는 셋이다.

기억할 한 줄: ".NET 10이 2028년까지 살아남는 LTS, .NET 9는 2026년 5월에 끝나는 STS."


2장 · C# 13 — params 컬렉션, lock 객체, partial 멤버

.NET 9와 함께 나온 C# 13이 일상 코드를 바꿨다. 가장 큰 셋:

params 컬렉션params 매개변수가 더 이상 배열만 받지 않는다. IEnumerable, Span, ReadOnlySpan, 어떤 컬렉션 타입이든 받는다.

// C# 12까지는 params object[] only
void Log(params object[] args) { }

// C# 13 — params ReadOnlySpan<object>
void Log(params ReadOnlySpan<object> args)
{
    foreach (var arg in args)
        Console.WriteLine(arg);
}

// 호출 시 배열 할당 없음. Span은 스택 할당.
Log("hello", 42, DateTime.Now);

lock 객체lock 키워드가 새 System.Threading.Lock 타입을 받는다. 기존 lock(obj)보다 약 30% 빠르고, 컴파일러가 잘못된 사용을 잡아준다.

using System.Threading;

public class Counter
{
    private readonly Lock _lock = new();
    private int _count;

    public void Increment()
    {
        lock (_lock)
        {
            _count++;
        }
    }
}

partial 속성과 인덱서 — 메서드만 됐던 partial이 속성·인덱서까지 확장. 소스 제너레이터가 더 강력해졌다.

public partial class ViewModel
{
    public partial string Name { get; set; }
}

// 다른 파일에서 소스 제너레이터가 구현 제공
public partial class ViewModel
{
    private string _name = "";
    public partial string Name
    {
        get => _name;
        set { _name = value; OnPropertyChanged(); }
    }
}

escape 시퀀스\e가 ESC(0x1B) 문자로 추가. ANSI 컬러 코드를 짤 때 더 깔끔.

Console.WriteLine("\e[31mRed text\e[0m");

C# 14는 .NET 10과 함께 나왔다. 새 키워드 field(자동 속성의 백킹 필드 참조), partial 생성자, 확장 멤버(extension everything)가 큰 셋이다.


3장 · F# 9 / F# 10 — 함수형·AI 친화·실용주의

F#은 마이크로소프트의 ML 계열 함수형 언어다. .NET 위에서 OCaml과 비슷한 문법으로 짠다.

2026년의 F#은 두 가지 이유로 다시 주목받는다.

F# 9의 핵심: 컴퓨테이션 표현식 개선, nullness 분석, 진단 메시지 정돈. F# 10은 .NET 10과 함께 나왔다.

가장 작은 F# 예제 — Fibonacci.

let rec fib n =
    match n with
    | 0 | 1 -> n
    | _ -> fib (n - 1) + fib (n - 2)

[0..10]
|> List.map fib
|> List.iter (printfn "%d")

레코드와 판별 공용체(discriminated union)는 F#의 정수다.

type Shape =
    | Circle of radius: float
    | Rectangle of width: float * height: float
    | Triangle of a: float * b: float * c: float

let area shape =
    match shape with
    | Circle r -> System.Math.PI * r * r
    | Rectangle (w, h) -> w * h
    | Triangle (a, b, c) ->
        let s = (a + b + c) / 2.0
        sqrt (s * (s - a) * (s - b) * (s - c))

printfn "%f" (area (Circle 5.0))

F#은 dotnet fsi로 REPL이 된다. Jupyter에서도 .NET Interactive 커널로 돈다.


4장 · VB.NET — 유지보수 모드, 아직 죽지 않았다

Visual Basic .NET은 마이크로소프트의 공식 발표대로 "유지보수 모드"다. 새 언어 기능은 들어가지 않지만, .NET 런타임 위에서 계속 돈다.

2026년 새 프로젝트를 VB.NET으로 시작할 이유는 거의 없다. 하지만 20년 된 ASP.NET Web Forms 시스템이 VB.NET이라면, 마이그레이션 비용은 그대로 남아 있다.


5장 · ASP.NET Core 10 — Minimal API, Native AOT

ASP.NET Core는 .NET 위의 웹 프레임워크다. .NET 6 이후로 표준이 된 두 가지 패턴:

가장 작은 Minimal API.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello, World!");
app.MapGet("/hello/{name}", (string name) => $"Hello, {name}!");
app.MapPost("/items", (Item item) => Results.Created($"/items/{item.Id}", item));

app.Run();

record Item(int Id, string Name);

ASP.NET Core 10의 Native AOT 지원이 큰 변화다. 콜드 스타트가 100ms 아래, 메모리는 절반, 단일 바이너리가 10MB.

dotnet publish -c Release -p:PublishAot=true
# bin/Release/net10.0/<rid>/publish/MyApi (단일 바이너리)

AOT의 제약은 분명하다. 리플렉션·동적 코드·Expression.Compile()이 안 된다. 대신 소스 제너레이터로 컴파일 타임에 코드를 만든다. System.Text.Json도 소스 제너레이터 기반으로 쓴다.

[JsonSerializable(typeof(User))]
public partial class AppJsonContext : JsonSerializerContext { }

// AOT 친화 직렬화
var json = JsonSerializer.Serialize(user, AppJsonContext.Default.User);

6장 · Blazor United — 서버 · WASM · SSR을 한 번에

Blazor는 C#으로 SPA를 짜는 프레임워크다. 2026년의 핵심 모드는 셋, 그리고 그걸 섞는 "United" 패턴.

.NET 8부터 이 셋을 한 프로젝트에서 페이지 단위로 섞을 수 있다.

@page "/counter"
@rendermode InteractiveServer

<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;
    private void IncrementCount() => currentCount++;
}

@rendermodeInteractiveServer, InteractiveWebAssembly, InteractiveAuto로 바꾸면 같은 컴포넌트가 다른 환경에서 돈다. InteractiveAuto는 처음엔 Server로 시작했다가 WASM 번들이 로드되면 자동으로 클라이언트로 전환.

핵심 포인트:


7장 · .NET MAUI 9 — iOS · Android · macOS · Windows 한 번에

MAUI(Multi-platform App UI)는 Xamarin.Forms의 후속작이다. 2026년 5월 기준 Xamarin.Forms는 공식 EOL(2024년 5월), 새 모바일 프로젝트는 다 MAUI다.

dotnet new maui -n MyApp
cd MyApp

# iOS
dotnet build -t:Run -f net10.0-ios
# Android
dotnet build -t:Run -f net10.0-android
# macOS
dotnet build -t:Run -f net10.0-maccatalyst
# Windows
dotnet build -t:Run -f net10.0-windows10.0.19041.0

가장 작은 XAML 페이지.

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyApp.MainPage">
    <VerticalStackLayout Padding="20" Spacing="10">
        <Label Text="Hello, MAUI!" FontSize="32" />
        <Button Text="Click me" Clicked="OnClicked" />
        <Label x:Name="CounterLabel" Text="0" />
    </VerticalStackLayout>
</ContentPage>
public partial class MainPage : ContentPage
{
    int count = 0;
    public MainPage() { InitializeComponent(); }
    void OnClicked(object sender, EventArgs e)
    {
        count++;
        CounterLabel.Text = count.ToString();
    }
}

MAUI 9의 핵심:

약점은 솔직히 인정해야 한다. iOS·Android 둘 다 1급 시민이지만, React Native·Flutter만큼의 커뮤니티 생태계는 아니다. 한국·일본 기업 내부 앱·기존 Xamarin 마이그레이션이 주 시장이다.


8장 · Avalonia 11 · Uno Platform 5 — 커뮤니티 대안

마이크로소프트가 만들지 않은 .NET UI 프레임워크 두 개도 2026년에 강력하다.

Avalonia 11 — Linux·macOS·Windows·iOS·Android·WebAssembly에서 도는 XAML 기반 UI. JetBrains Rider가 Avalonia로 일부 UI를 만든다.

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        x:Class="HelloAvalonia.MainWindow"
        Title="HelloAvalonia">
  <StackPanel Margin="20">
    <TextBlock Text="Hello from Avalonia!" FontSize="24" />
    <Button Content="Click me" Click="OnClick" />
  </StackPanel>
</Window>

Uno Platform 5 — WinUI 3 XAML을 모든 플랫폼에서 재사용. WebAssembly·Skia 렌더링까지 지원. 윈도우 중심 개발자가 한 번 짜서 여러 OS로 옮기고 싶을 때 선택.

이 둘과 MAUI의 차이:


9장 · .NET Aspire 9 — 분산 앱 오케스트레이션

Aspire는 .NET 8과 함께 나온 분산 앱 프레임워크다. "여러 서비스를 한 솔루션으로 묶고, 한 명령으로 띄우고, 한 대시보드에서 본다"가 핵심.

// AppHost/Program.cs
var builder = DistributedApplication.CreateBuilder(args);

var redis = builder.AddRedis("cache");
var postgres = builder.AddPostgres("db").AddDatabase("appdb");

var api = builder.AddProject<Projects.MyApi>("api")
    .WithReference(redis)
    .WithReference(postgres);

builder.AddProject<Projects.MyWeb>("web")
    .WithReference(api);

builder.Build().Run();
dotnet run --project AppHost
# 브라우저에서 https://localhost:17000 — Aspire Dashboard

Aspire Dashboard에서 보는 것:

Aspire 9의 새 기능: 통합 모듈 강화(Azure ServiceBus·Postgres·MongoDB·Kafka), GitHub Codespaces 지원, 배포용 매니페스트(Helm/Bicep) 자동 생성.

기억할 한 줄: "docker-compose가 컨테이너의 docker-compose라면, Aspire는 .NET 서비스의 docker-compose."


10장 · Entity Framework Core 9 — JSON · 컴파일 모델

EF Core는 .NET 진영의 표준 ORM이다. 9.0의 큰 변화:

public class Blog
{
    public int Id { get; set; }
    public string Name { get; set; } = "";
    public BlogMetadata Metadata { get; set; } = new();
}

public class BlogMetadata
{
    public string Author { get; set; } = "";
    public List<string> Tags { get; set; } = new();
}

public class BloggingContext : DbContext
{
    public DbSet<Blog> Blogs => Set<Blog>();

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>().OwnsOne(b => b.Metadata, b => b.ToJson());
    }
}

// LINQ로 JSON 안 필드 쿼리
var blogs = await db.Blogs
    .Where(b => b.Metadata.Tags.Contains("dotnet"))
    .ToListAsync();

마이그레이션은 dotnet ef migrations add / dotnet ef database update로 관리한다.

dotnet tool install --global dotnet-ef
dotnet ef migrations add InitialCreate
dotnet ef database update

11장 · Dapper 3 · Marten — 가벼운 대안

EF Core가 풀 ORM이라면, Dapper는 마이크로 ORM이다. SQL을 직접 짜고 결과만 객체로 매핑.

using Dapper;
using Npgsql;

await using var conn = new NpgsqlConnection(connStr);
var users = await conn.QueryAsync<User>(
    "SELECT id, name FROM users WHERE active = @active",
    new { active = true });

foreach (var u in users)
    Console.WriteLine($"{u.Id}: {u.Name}");

쓸 때: 핫 패스 쿼리, 복잡한 SQL, EF의 추상화가 거추장스러울 때.

Marten — Postgres를 도큐먼트 DB + 이벤트 스토어로 쓴다. CQRS·이벤트 소싱에 강하다.

var store = DocumentStore.For(opts =>
{
    opts.Connection(connStr);
    opts.Events.AddEventType(typeof(OrderPlaced));
});

await using var session = store.LightweightSession();
session.Events.Append(orderId, new OrderPlaced(orderId, items));
await session.SaveChangesAsync();

쓸 때: 이미 Postgres가 있는 환경, 이벤트 소싱이 필요한 도메인.


12장 · MediatR 13 — CQRS 패턴

MediatR은 in-process 메디에이터 패턴 라이브러리다. 핸들러·노티피케이션·파이프라인 동작을 깔끔하게 분리.

public record GetUserById(int Id) : IRequest<User>;

public class GetUserByIdHandler : IRequestHandler<GetUserById, User>
{
    private readonly AppDbContext _db;
    public GetUserByIdHandler(AppDbContext db) { _db = db; }

    public async Task<User> Handle(GetUserById req, CancellationToken ct)
    {
        return await _db.Users.FindAsync(new object[] { req.Id }, ct)
            ?? throw new KeyNotFoundException();
    }
}

// 컨트롤러
public class UsersController(IMediator mediator) : ControllerBase
{
    [HttpGet("{id}")]
    public Task<User> Get(int id) => mediator.Send(new GetUserById(id));
}

2024년 말, 저자(Jimmy Bogard)가 MediatR을 상용화하겠다고 발표하면서 커뮤니티 일부가 포크를 만들었다(예: Brighter, Mediator.SourceGenerator). 그래서 2026년 새 프로젝트에서는 MediatR을 쓸지, 소스 제너레이터 기반 대안을 쓸지 결정해야 한다.


13장 · Orleans 9 — 가상 액터, 그레인 기반 분산

Orleans는 마이크로소프트 리서치가 만든 분산 액터 프레임워크다. 가상 액터(virtual actor) 모델이 핵심: 그레인(grain)은 ID로 식별되고, 위치는 런타임이 관리한다.

public interface IUserGrain : IGrainWithIntegerKey
{
    Task<string> GetNameAsync();
    Task SetNameAsync(string name);
}

public class UserGrain : Grain, IUserGrain
{
    private string _name = "";
    public Task<string> GetNameAsync() => Task.FromResult(_name);
    public Task SetNameAsync(string name) { _name = name; return Task.CompletedTask; }
}

// 클라이언트
var user = client.GetGrain<IUserGrain>(123);
await user.SetNameAsync("Alice");
var name = await user.GetNameAsync();

쓸 때: 게임 백엔드(Halo·Forza·Gears of War가 Orleans), IoT, 채팅, 실시간 멀티유저.

대안: Akka.NET 1.5 — Akka의 .NET 포트, 명시적 액터 모델, 페르시스턴스·클러스터링 지원.


14장 · SignalR · gRPC — 실시간 통신

SignalR — 양방향 실시간 통신. WebSocket·Server-Sent Events·롱폴링을 자동으로 협상.

public class ChatHub : Hub
{
    public async Task SendMessage(string user, string message)
    {
        await Clients.All.SendAsync("ReceiveMessage", user, message);
    }
}

// Program.cs
builder.Services.AddSignalR();
app.MapHub<ChatHub>("/chathub");

클라이언트는 JS·.NET·Java·Python 다 된다.

gRPC for .NET — protobuf 기반 RPC. 마이크로서비스 간 통신·다국어 환경에 강하다.

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply);
}

message HelloRequest { string name = 1; }
message HelloReply { string message = 1; }
public class GreeterService : Greeter.GreeterBase
{
    public override Task<HelloReply> SayHello(HelloRequest req, ServerCallContext ctx)
    {
        return Task.FromResult(new HelloReply { Message = $"Hello {req.Name}" });
    }
}

쓸 때: 마이크로서비스 내부 통신, 다국어 클라이언트, 스트리밍 RPC.


15장 · 로깅 · 관측성 — Serilog 4, OpenTelemetry

기본 옵션은 Microsoft.Extensions.Logging이다. 카테고리·필터·스코프가 기본 제공.

public class OrderService(ILogger<OrderService> logger)
{
    public void Process(Order order)
    {
        logger.LogInformation("Processing order {OrderId} for {Amount}",
            order.Id, order.Amount);
    }
}

구조화 로깅·파일·Elasticsearch 싱크가 필요하면 Serilog 4.

Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Information()
    .WriteTo.Console()
    .WriteTo.File("logs/app-.txt", rollingInterval: RollingInterval.Day)
    .WriteTo.Seq("http://localhost:5341")
    .CreateLogger();

Log.Information("User {UserId} logged in from {IP}", userId, ip);

OpenTelemetry — 트레이스·메트릭·로그의 벤더 중립 표준. .NET에서 1급 지원.

builder.Services.AddOpenTelemetry()
    .WithTracing(t => t
        .AddAspNetCoreInstrumentation()
        .AddHttpClientInstrumentation()
        .AddOtlpExporter())
    .WithMetrics(m => m
        .AddAspNetCoreInstrumentation()
        .AddRuntimeInstrumentation()
        .AddOtlpExporter());

Aspire Dashboard는 OpenTelemetry를 받아서 시각화한다. Jaeger·Grafana·Datadog도 같은 프로토콜.


16장 · 테스트 — xUnit 3, NUnit 4, MSTest 3

세 개의 메이저 테스트 프레임워크, 그리고 그 위의 mocking 라이브러리들.

xUnit 3 — 가장 인기 있는 선택. 2025년에 v3가 나왔다. 비동기 friendly, 깔끔한 어트리뷰트.

public class CalculatorTests
{
    [Fact]
    public void Add_TwoNumbers_ReturnsSum()
    {
        var sut = new Calculator();
        Assert.Equal(5, sut.Add(2, 3));
    }

    [Theory]
    [InlineData(1, 1, 2)]
    [InlineData(2, 3, 5)]
    [InlineData(-1, 1, 0)]
    public void Add_Various_ReturnsExpected(int a, int b, int expected)
    {
        var sut = new Calculator();
        Assert.Equal(expected, sut.Add(a, b));
    }
}

NUnit 4 — 자바의 JUnit 스타일. 어트리뷰트가 더 풍부.

MSTest 3 — 마이크로소프트 공식, Visual Studio와 통합 강력.

mocking 라이브러리:

// NSubstitute
var repo = Substitute.For<IUserRepository>();
repo.FindById(1).Returns(new User(1, "Alice"));

var sut = new UserService(repo);
var user = sut.GetUser(1);

repo.Received(1).FindById(1);

BenchmarkDotNet 0.14 — 성능 마이크로벤치마크의 표준.

[MemoryDiagnoser]
public class StringBenchmarks
{
    [Benchmark]
    public string ConcatStrings()
    {
        var s = "";
        for (var i = 0; i < 100; i++) s += i;
        return s;
    }

    [Benchmark]
    public string StringBuilder()
    {
        var sb = new StringBuilder();
        for (var i = 0; i < 100; i++) sb.Append(i);
        return sb.ToString();
    }
}

BenchmarkRunner.Run<StringBenchmarks>();

17장 · 개발 경험 — dotnet watch, Hot Reload, Polyglot Notebooks

dotnet watch는 파일 변경을 감지하고 자동으로 재빌드·재시작한다.

dotnet watch run
# Program.cs 수정 → 자동 재시작
# Razor 페이지 수정 → 핫 리로드 (재시작 없이 변경 반영)

ASP.NET Core·Blazor·MAUI 모두 핫 리로드를 지원한다. C# 메서드 본문 변경·XAML·CSS·Razor 마크업은 재시작 없이 반영, 시그니처 변경은 재시작 필요.

Polyglot Notebooks — Jupyter 스타일의 .NET 노트북. C#·F#·PowerShell·SQL을 한 노트북에서 섞는다.

dotnet tool install -g Microsoft.dotnet-interactive
dotnet interactive jupyter install

VS Code 확장(Polyglot Notebooks)으로 .ipynb.dib 파일을 연다. 데이터 탐색·문서·교재에 강하다.

// .NET 노트북 셀
#r "nuget: System.Text.Json"

using System.Text.Json;

var json = """{"name": "Alice", "age": 30}""";
var doc = JsonDocument.Parse(json);
display(doc.RootElement);

18장 · 빌드 시스템 — dotnet CLI, MSBuild, NUKE, FAKE, Cake

기본 빌드 시스템은 dotnet CLI + MSBuild다. 대부분의 프로젝트는 이걸로 충분.

dotnet new sln -n MySolution
dotnet new classlib -n MyLibrary
dotnet sln add MyLibrary
dotnet build
dotnet test
dotnet pack
dotnet nuget push -s nuget.org -k <api-key>

CI/CD 파이프라인이 복잡해지면 다음 셋 중 하나:

NUKE 예제 — _build/Build.cs.

class Build : NukeBuild
{
    public static int Main() => Execute<Build>(x => x.Compile);

    Target Clean => _ => _
        .Executes(() => Directory.Delete("bin", true));

    Target Compile => _ => _
        .DependsOn(Clean)
        .Executes(() => DotNetTasks.DotNetBuild(s => s
            .SetConfiguration("Release")));

    Target Test => _ => _
        .DependsOn(Compile)
        .Executes(() => DotNetTasks.DotNetTest(s => s
            .SetConfiguration("Release")
            .EnableNoBuild()));
}
./build.sh test
# 또는
nuke test

19장 · NuGet 6.12 — 패키지 관리

NuGet은 .NET의 npm·pip·Maven에 해당한다.

# 패키지 추가
dotnet add package Serilog --version 4.0.0

# 업데이트
dotnet add package Serilog

# 제거
dotnet remove package Serilog

# 복원
dotnet restore

Directory.Packages.props로 중앙 집중식 버전 관리:

<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
  </PropertyGroup>
  <ItemGroup>
    <PackageVersion Include="Serilog" Version="4.0.0" />
    <PackageVersion Include="Dapper" Version="3.0.0" />
  </ItemGroup>
</Project>

각 프로젝트는 버전 없이 PackageReference만 적는다. 큰 솔루션에서 버전 드리프트를 막는다.

global.json은 SDK 버전, Directory.Packages.props는 패키지 버전. 둘 다 모노레포에서 표준.


20장 · 게임 개발 — Unity 6, Godot, Stride

Unity 6 (2024년 말 출시, 2026년에 안정) — 게임 엔진 시장의 점유율 1위. C# 13까지 지원. URP(Universal Render Pipeline)·HDRP(High Definition)·DOTS(Data-Oriented Tech Stack)가 핵심.

using UnityEngine;

public class PlayerController : MonoBehaviour
{
    [SerializeField] float speed = 5f;
    Rigidbody rb;

    void Start() { rb = GetComponent<Rigidbody>(); }

    void Update()
    {
        var h = Input.GetAxis("Horizontal");
        var v = Input.GetAxis("Vertical");
        rb.linearVelocity = new Vector3(h, 0, v) * speed;
    }
}

2023년 가격 정책 사태 이후 Unity는 정책을 되돌렸지만, 신뢰는 한 번 깨졌다. 2026년에도 메이저 인디·모바일은 Unity가 압도적이지만, 새 프로젝트에서 Godot·Unreal로 가는 흐름도 있다.

Godot 4 (C#) — 오픈소스 게임 엔진. GDScript가 주력이지만 C# 바인딩도 안정. 모바일·인디에서 인기 상승.

Stride 4 — 순수 .NET 게임 엔진. C#로 모든 걸 짠다. 작은 커뮤니티지만 .NET 개발자에게 친숙한 워크플로우.


21장 · 데스크톱 레거시 — WPF · WinForms

WPF(Windows Presentation Foundation)와 WinForms는 2026년에도 "레거시"가 아니다. 둘 다 .NET 10 기준으로 활발히 업데이트되고, 윈도우 엔터프라이즈 데스크톱의 표준이다.

// WinForms
public partial class MainForm : Form
{
    public MainForm()
    {
        InitializeComponent();
        var btn = new Button { Text = "Click me", Location = new Point(20, 20) };
        btn.Click += (s, e) => MessageBox.Show("Hello!");
        Controls.Add(btn);
    }
}

WPF는 XAML·MVVM·강력한 데이터 바인딩. 한국·일본의 엔터프라이즈 인하우스 도구의 상당수가 WPF.

WinUI 3 — 윈도우 11 시대의 새 UI 프레임워크. Windows App SDK로 패키징. MAUI Windows도 내부적으로 WinUI 3을 쓴다.

선택 매트릭스:


22장 · 클라우드 배포 — Azure · AWS · GCP

.NET은 어떤 클라우드에서도 1급 시민이다.

Azure App Service — 가장 자연스러운 선택. .NET 새 버전이 가장 먼저 풀린다.

az webapp up --name myapp --runtime "DOTNETCORE:10.0"

AWS Lambda — .NET 10 런타임 지원. 콜드 스타트는 AOT로 100ms 아래.

public class Function
{
    public async Task<APIGatewayHttpApiV2ProxyResponse> Handle(
        APIGatewayHttpApiV2ProxyRequest req, ILambdaContext ctx)
    {
        return new APIGatewayHttpApiV2ProxyResponse
        {
            StatusCode = 200,
            Body = $"Hello from {req.RequestContext.Http.Path}"
        };
    }
}

배포는 dotnet lambda deploy-function 또는 SAM·CDK.

Google Cloud Run — 컨테이너 기반. Dockerfile 하나로 끝.

FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
WORKDIR /app
EXPOSE 8080

FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
COPY . /src
WORKDIR /src
RUN dotnet publish -c Release -o /app/publish

FROM base AS final
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "MyApi.dll"]

Aspire가 이 셋의 매니페스트를 자동 생성한다. dotnet run --project AppHost --publisher manifest 한 번이면 K8s YAML·Bicep·Cloud Run 매니페스트가 나온다.


23장 · Roslyn 분석기 · 소스 제너레이터

Roslyn은 C#·VB.NET의 컴파일러다. 코드를 트리로 보고, 트리를 변환하는 API를 제공한다.

분석기(Analyzer) — 빌드 타임에 코드를 검사하고 경고·에러를 낸다. StyleCop.Analyzers, Microsoft.CodeAnalysis.NetAnalyzers가 대표적.

dotnet add package Microsoft.CodeAnalysis.NetAnalyzers

빌드 시 자동으로 수백 개의 규칙이 적용된다. dotnet_diagnostic.CA1822.severity = error 같은 .editorconfig로 세부 조정.

소스 제너레이터(Source Generator) — 컴파일 타임에 코드를 생성한다. AOT 친화, 리플렉션 대체.

대표 사례:

public partial class EmailValidator
{
    [GeneratedRegex(@"^[^@]+@[^@]+\.[^@]+$")]
    private static partial Regex EmailRegex();

    public bool IsValid(string s) => EmailRegex().IsMatch(s);
}

빌드 시 컴파일러가 EmailRegex() 본문을 생성. 런타임 정규식 컴파일 비용이 없다.


24장 · 한국·일본 .NET 커뮤니티

한국

일본

영어권 자료:


에필로그 — 2026년의 .NET 선택 매트릭스

10년 전 ".NET = 윈도우 + IIS + Visual Studio"가 답이었다면, 2026년에는 답이 갈래로 갈라진다.

선택의 기준 세 줄.

런타임의 핵심.

기억할 한 줄: ".NET은 더 이상 윈도우의 자바가 아니다. 2026년의 .NET은 크로스 플랫폼·AOT·클라우드 1급 시민의 풀스택 런타임이다."

도구는 매년 바뀌지만 핵심은 그대로다. 타입·강력한 라이브러리·풀스택 통합 — 그게 30년 전 Visual Studio가 약속한 것이고, 2026년의 .NET이 여전히 지키는 것이다.


References

— 끝 —

댓글

아직 댓글이 없습니다.

로그인하면 댓글을 쓸 수 있습니다