LabHub

Blog

Modern .NET 2026 — .NET 9 / .NET 10 LTS / Aspire / Blazor United / MAUI / Avalonia 11 / FastEndpoints Deep Dive

한국어English日本語

Prologue — "Another enterprise that isn't Java"

May 2026. A senior engineer at a Korean fintech said, half joking: "Lots of people say they don't use .NET. They just don't know their card issuer's backend runs on it." It's a joke, but it carries about 50% truth.

Conference stages still belong to TypeScript, Go, and Rust. But payments, banking, manufacturing, government, and a meaningful slice of game backends run on .NET. And .NET itself has been busy reshaping since the .NET 5 unification in 2020, shipping a fresh major every November.

What happened between 2024 and 2026:

This post lays out a map of .NET in 2026 in one read. Which version do you pick. ASP.NET Core 10 vs FastEndpoints. Do you really need Aspire. MAUI vs Avalonia 11. EF Core vs Dapper. CQRS patterns after MediatR went commercial. The real limits of NativeAOT. And who should pick .NET in the first place.

One thing up front: .NET is not dead. Far from it — in Korean and Japanese enterprise / finance / government systems it is, quietly, more entrenched than ever. It's a tool with a different grain from JVM / Go / Node, and there are domains where that grain fits perfectly.


1. The 2026 .NET map — in one table

AreaDe facto standard in 2026Note
Runtime.NET 10 LTS (2025-11).NET 9 EOL imminent (2026-05)
LanguageC# 13 / C# 14F# 9, VB stable maintained
Web backendASP.NET Core 10 + Minimal APIs+ FastEndpoints / Carter
DataEF Core 9 / Dapper / MartenWide choice
MessagingMassTransit / NServiceBus / WolverineMediatR going paid changed things
CQRSWolverine / Brighter / hand-rolledMediatR 8.x is paid
Cloud orchestration.NET AspireBicep + OTel built in
Web UIBlazor UnitedServer + WASM + SSR
Mobile / desktop.NET MAUIiOS/Android/Mac/Win
Cross-platform desktopAvalonia 11Linux included
GameUnity (.NET 8 based), Stride, MonoGameUnity has its own runtime
DeploymentContainer + NativeAOTself-contained shrinking
PackagesNuGet 6 + Central Package Managementglobal.json standardized
AnalysisRoslyn analyzers + StyleCop + Sonarnullable enforcement

The headline summary:


2. .NET 10 LTS (2025-11) — The flagship release

.NET 10 went GA in November 2025 as Long Term Support, supported until November 2028. It follows .NET 6 (2021-11) and .NET 8 (2023-11) in the LTS line, with .NET 9 sitting between them as STS.

Key changes:

LTS doesn't just mean "longer patch window" — it means the ecosystem is most aligned. EF Core 10, ASP.NET Core 10, the Aspire stable channel, MassTransit, the MediatR forks — nearly every major library treats .NET 10 as a first-class target.

Upgrade guidance:


3. .NET 9 (2024-11) — STS in context

.NET 9 is STS, meaning 18 months of support, which lands in May 2026 — right around when this post is written. .NET 9 served as "the lab notebook for the next LTS, .NET 10".

Features that landed in .NET 9 and got polished in .NET 10:

Bottom line: teams on .NET 9 must move to .NET 10 by mid-2026. Going back to 8 (LTS) is pointless — .NET 8 itself ends in November 2026.

The LTS / STS rhythm is clear now:

Enterprises typically skip STS releases entirely. The canonical path is .NET 6 → 8 → 10.


4. C# 13 / C# 14 — params collections, field accessor

C# ships a new major every November alongside .NET. C# 13 (2024) and C# 14 (2025) landed with .NET 9 and .NET 10 respectively.

C# 13 highlights:

C# 14 highlights:

The field keyword in one shot:

// Old style — explicit backing field
private string _name = string.Empty;
public string Name
{
    get => _name;
    set => _name = value?.Trim() ?? throw new ArgumentNullException();
}

// C# 14 — field keyword
public string Name
{
    get;
    set => field = value?.Trim() ?? throw new ArgumentNullException();
} = string.Empty;

You don't hand-declare _name; the compiler generates it. The _camelCase backing-field naming debate goes away.


5. ASP.NET Core 10 — performance + DX

ASP.NET Core 10 shipped with .NET 10. As of May 2026, the canonical shape of a modern .NET web app:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenApi();
builder.Services.AddDbContext<AppDbContext>(opts =>
    opts.UseNpgsql(builder.Configuration.GetConnectionString("Default")));

var app = builder.Build();

app.MapOpenApi();              // /openapi/v1.json
app.MapScalarApiReference();   // Scalar UI integration

app.MapGet("/users/{id:guid}", async (Guid id, AppDbContext db) =>
{
    var user = await db.Users.FindAsync(id);
    return user is null ? Results.NotFound() : Results.Ok(user);
})
.WithName("GetUser")
.WithOpenApi();

app.MapPost("/users", async (CreateUserDto dto, AppDbContext db) =>
{
    var user = new User(dto.Name, dto.Email);
    db.Users.Add(user);
    await db.SaveChangesAsync();
    return Results.Created($"/users/{user.Id}", user);
});

app.Run();

What's different:

Performance numbers (TechEmpower-style microbench):

In 2026 ASP.NET Core remains one of the fastest mainstream web frameworks.


6. Aspire (Nov 2024 GA) — Cloud-native orchestration

Aspire went GA in November 2024 — .NET's cloud-native orchestration + local dev environment + telemetry integration toolkit. The name is grand, but the essence is simple.

What Aspire solves:

The AppHost project:

var builder = DistributedApplication.CreateBuilder(args);

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

var redis = builder.AddRedis("cache");

var rabbitmq = builder.AddRabbitMQ("messaging");

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

builder.AddProject<Projects.WebFrontend>("web")
    .WithReference(apiService);

builder.Build().Run();

dotnet run on this code:

  1. Postgres / Redis / RabbitMQ containers spin up automatically.
  2. API service and Web Frontend start as .NET processes.
  3. Connection strings are injected as environment variables.
  4. OpenTelemetry data flows into the Aspire Dashboard.
  5. Distributed traces, logs, metrics — all on one screen.

Aspire Dashboard:

Cloud deploy:

Docker compose vs Aspire:

Criteriondocker-composeAspire
Definition languageYAMLC#
DebuggingAttach to containerDirect .NET process debugging
TelemetrySeparate installBuilt in
Cloud deploySeparate conversionBuilt-in generator
Non-.NET servicesWorks wellWorks well (Postgres, Redis, OS images, etc.)

For teams running .NET microservices, Aspire became the de facto default. In polyglot environments with many non-.NET services, docker-compose still feels natural.


7. Blazor United — Server + WASM + SSR + streaming

Eight years after the 2018 WebAssembly hype, in 2026 Blazor settled into a single model where one component can pick from several render modes. Microsoft's docs call this Blazor United.

Four render modes:

  1. Static SSR — Server renders once. Fastest, no interactivity.
  2. Streaming SSR — Streams async data results via chunked transfer.
  3. Server interactive — SignalR-based, event handling on the server.
  4. WebAssembly interactive — Client WASM, offline-capable.

A single page can mix modes per component.

@page "/dashboard"
@rendermode InteractiveAuto

<h1>Dashboard</h1>
<StaticSummary />
<InteractiveChart />

InteractiveAuto boots fast in Server mode (SignalR) on first visit, then flips to WASM after the WASM payload finishes downloading. A pattern that hides the first-interaction latency.

Blazor strengths:

Blazor weaknesses:

Who uses it: Internal tools, B2B admin, full-stack .NET teams' SPAs. Public marketing or SEO-critical pages stay on Static SSR.


8. .NET MAUI — Cross-platform native

.NET MAUI (Multi-platform App UI) succeeded Xamarin.Forms in 2022 and stabilized between 2024 and 2026. iOS / Android / macOS / Windows from a single C# codebase.

MAUI structure:

MAUI Hybrid + Blazor Hybrid:

A BlazorWebView inside MAUI lets you reuse Razor components as a native app. Blazor UI built for the web ends up nearly as-is in the mobile app.

<BlazorWebView HostPage="wwwroot/index.html">
    <BlazorWebView.RootComponents>
        <RootComponent Selector="#app" ComponentType="{x:Type local:Main}" />
    </BlazorWebView.RootComponents>
</BlazorWebView>

This pattern is attractive when a full-stack .NET team also needs a mobile app. Build/deploy is simpler than React Native, and integration with the .NET backend is more natural than Flutter.

MAUI weaknesses:

2026 recommendation: Internal mobile / Windows desktop. For public app-store consumer apps, compare with Flutter, SwiftUI/Compose, React Native first.


9. Avalonia 11 — A truly cross-platform UI

Avalonia is the community-maintained, .NET Foundation-operated open-source cross-platform UI framework. 11.0 shipped in November 2023, with 11.1 / 11.2 / 11.3 following through 2024-2025.

vs MAUI:

Criterion.NET MAUIAvalonia 11
GovernanceMicrosoftCommunity + commercial (AvaloniaUI company)
PlatformsiOS/Android/Mac/WiniOS/Android/Mac/Win/Linux/WebAssembly
RenderingNative controls per platformOwn renderer (Skia-based)
UI consistencyDiffers per platformIdentical on every platform
Design patternXAML + handlersXAML + own control tree
Hot reloadSupportedSupported
Desktop focusWeakStrong

When Avalonia shines:

Real-world examples:

Weaknesses:

2026 recommendation: WPF's natural successor. First pick for cross-platform desktop .NET apps that include Linux/Mac.


10. Entity Framework Core 9

EF Core 9 shipped with .NET 9 in November 2024, and EF Core 10 with .NET 10 in November 2025. As of May 2026 the de facto standard is EF Core 10.

Changes over the last 2-3 years:

Typical code:

public class AppDbContext : DbContext
{
    public DbSet<Order> Orders => Set<Order>();

    protected override void OnModelCreating(ModelBuilder mb)
    {
        mb.Entity<Order>(b =>
        {
            b.ToTable("orders");
            b.ComplexProperty(o => o.ShippingAddress);
            b.OwnsMany(o => o.Items);
            b.Property(o => o.Metadata)
                .HasColumnType("jsonb");
        });
    }
}

// Bulk delete - one SQL statement
await db.Orders
    .Where(o => o.Status == OrderStatus.Cancelled && o.CreatedAt < DateTime.UtcNow.AddYears(-1))
    .ExecuteDeleteAsync();

EF Core vs Dapper vs Marten:

ToolModelStrengthsWeaknesses
EF CoreORM / change trackingRich LINQ, migrations, relationshipsComplex queries hurt SQL readability
DapperMicro-ORMFast, SQL hand-writtenEverything manual
MartenPostgres + event sourcingDocument DB + event storePostgres only
LinqToDBSQL-shape LINQPerformance + LINQ expressivenessLearning curve

The 2026 default is EF Core + Dapper mixed. EF Core for CRUD and domain mutations, Dapper for heavy report / analytics queries.


11. MediatR / MassTransit / NServiceBus — CQRS and messaging

In late 2024 the .NET CQRS scene shook: MediatR moved to a commercial license from 8.x. The same author's AutoMapper introduced a paid edition around the same time. The decision sparked sharp community debate.

Current options:

ToolModelLicenseNote
MediatR 8+In-process mediatorCommercialStable. Costs money.
WolverineIn-process + messagingOSS (MIT)Jeremy D. Miller. CQRS + saga integrated.
BrighterCommand processorOSS (BSD)Messaging-integrated.
Hand-rolledDI + interfacen/aSmall projects do fine.

Wolverine example:

// Handler — discovered by method signature, no interface needed
public class CreateOrderHandler
{
    public async Task<OrderCreated> Handle(CreateOrder command, AppDbContext db)
    {
        var order = new Order(command.CustomerId, command.Items);
        db.Orders.Add(order);
        await db.SaveChangesAsync();
        return new OrderCreated(order.Id);
    }
}

// Call site
var result = await bus.InvokeAsync<OrderCreated>(new CreateOrder(...));

Method-signature discovery without interfaces is the Wolverine signature. MediatR's IRequestHandler boilerplate evaporates.

Messaging (out-of-process):

ToolTransportsLicenseStrengths
MassTransitRabbitMQ, Azure Service Bus, Kafka, etc.OSS (Apache) + some ProMost widely used
NServiceBusVariousCommercialEnterprise. Strong saga story.
WolverineRabbitMQ, Kafka, Azure Service BusOSS (MIT)CQRS + messaging integrated
RebusRabbitMQ, Azure Service Bus, etc.OSSLightweight

MassTransit saga pattern:

public class OrderSaga : MassTransitStateMachine<OrderState>
{
    public State Submitted { get; private set; }
    public State Paid { get; private set; }
    public State Shipped { get; private set; }

    public Event<OrderSubmitted> OnSubmitted { get; private set; }
    public Event<PaymentReceived> OnPaid { get; private set; }

    public OrderSaga()
    {
        InstanceState(x => x.CurrentState);

        Initially(
            When(OnSubmitted)
                .Then(c => c.Saga.OrderId = c.Message.OrderId)
                .TransitionTo(Submitted));

        During(Submitted,
            When(OnPaid)
                .TransitionTo(Paid));
    }
}

2026 recommendations:


12. FastEndpoints / Carter / Minimal APIs

ASP.NET Core 10 routing has three flavors now.

1. Minimal APIs (default):

app.MapGet("/orders/{id:guid}", async (Guid id, AppDbContext db) =>
{
    var order = await db.Orders.FindAsync(id);
    return order is null ? Results.NotFound() : Results.Ok(order);
});

Pros: lightweight, fast startup. Cons: Program.cs balloons in a large API.

2. Controllers (classic):

[ApiController]
[Route("orders")]
public class OrdersController : ControllerBase
{
    [HttpGet("{id:guid}")]
    public async Task<IActionResult> Get(Guid id) { ... }
}

Pros: familiar, class-level organization. Cons: lots of boilerplate.

3. FastEndpoints / Carter (structured minimal):

FastEndpoints forces the "endpoint per class" pattern.

public class GetOrderEndpoint : Endpoint<GetOrderRequest, OrderResponse>
{
    public AppDbContext Db { get; set; } = null!;

    public override void Configure()
    {
        Get("/orders/{id:guid}");
        AllowAnonymous();
    }

    public override async Task HandleAsync(GetOrderRequest req, CancellationToken ct)
    {
        var order = await Db.Orders.FindAsync([req.Id], ct);
        if (order is null) { await SendNotFoundAsync(ct); return; }
        await SendAsync(new OrderResponse(order), cancellation: ct);
    }
}

Carter is the spiritual successor to Nancy with module-level routing.

public class OrdersModule : ICarterModule
{
    public void AddRoutes(IEndpointRouteBuilder app)
    {
        app.MapGet("/orders/{id:guid}", async (Guid id, AppDbContext db) =>
        {
            var order = await db.Orders.FindAsync(id);
            return order is null ? Results.NotFound() : Results.Ok(order);
        });
    }
}

Comparison:

CriterionMinimal APIControllersFastEndpointsCarter
BoilerplateVery lowHighLowVery low
OrganizationWeakStrongStrong (per-class)Medium (per-module)
PerformanceFastestSlightly slowerFastest (on Minimal)Fastest (on Minimal)
OpenAPIAutoAutoAuto + richAuto
Learning curveLowLowMediumLow
Large-API friendlyWeakStrongStrongMedium

Recommendation: Below 50 endpoints, Minimal API. Above that, FastEndpoints or Controllers. Carter if you want lightweight module splits.


13. NativeAOT — Small single-file executables

NativeAOT went GA in .NET 7 and matured through .NET 9 and 10. The core idea: ahead-of-time compile to a single native executable instead of relying on the JIT.

Strengths:

Limitations:

AOT-friendly libraries:

AOT-unfriendly:

Example — AOT minimal API:

<PropertyGroup>
    <PublishAot>true</PublishAot>
    <InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
dotnet publish -c Release -r linux-x64
# Single native executable -> bin/Release/net10.0/linux-x64/publish/MyApi
# Size: typically 15-25 MB

When to use:

When not to use:


14. Roslyn analyzers / NuGet / dotnet CLI

Roslyn analyzers:

.NET analyzers catch quality / security / performance issues at compile time. The 2026 default set:

.editorconfig controls the rules:

[*.cs]
dotnet_diagnostic.CA1822.severity = warning   # mark members as static
dotnet_diagnostic.IDE0005.severity = error    # unused using
dotnet_analyzer_diagnostic.category-Style.severity = suggestion

Nullable enforcement:

<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>

These two lines mark the biggest gap between a modern .NET project and a legacy one. Null safety is enforced by the compiler.

NuGet 6 + Central Package Management:

A single Directory.Packages.props governs every package version in the solution:

<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
  </PropertyGroup>
  <ItemGroup>
    <PackageVersion Include="MediatR" Version="8.4.0" />
    <PackageVersion Include="EntityFrameworkCore.Sqlite" Version="10.0.0" />
    <PackageVersion Include="Serilog.AspNetCore" Version="8.0.3" />
  </ItemGroup>
</Project>

Each csproj only writes <PackageReference Include="MediatR" /> without a version. Version conflicts dissolve.

dotnet CLI unified:

# The 2026 baseline workflow
dotnet new aspire-starter -n MyApp        # Create an Aspire solution
dotnet add package Serilog.AspNetCore     # Add a package (CPM writes to Directory.Packages.props)
dotnet ef migrations add InitialCreate    # EF Core migration
dotnet aspire run                         # Run the Aspire app
dotnet test --collect:"XPlat Code Coverage" # Tests + coverage
dotnet format                             # Auto-format
dotnet workload install android ios       # MAUI workloads
dotnet run app.cs                         # Single-file run (.NET 10)

global.json:

Place it at the repo root to pin the SDK version per solution.

{
  "sdk": {
    "version": "10.0.100",
    "rollForward": "latestFeature"
  }
}

That one file removes a whole class of subtle bugs caused by teammates running different SDKs.


15. Korea / Japan — Toss, Nintendo, SoftBank

.NET seems invisible in Korean / Japanese tech press, but it is widely deployed in enterprise / finance / game backends.

Korea:

Japan:

Summary: in both Korea and Japan, .NET is a de facto standard option in enterprise / finance / telecom / government domains. Less visible on conference stages, but plenty present by revenue and system scale.


16. Who should pick .NET

Pick .NET when:

Avoid .NET when:

Decision tree (simplified):

Q1. Domain?
├── Enterprise / finance / government / insurance / Windows integration
│   └── .NET 10 + ASP.NET Core 10 + EF Core 10
├── Public consumer web / SEO-first
│   └── Consider Next.js / Remix / SvelteKit first
├── Game (Unity)
│   └── C# (.NET-compatible runtime)
└── Mobile app (consumer)
    └── Native or Flutter / RN first

Q2. Team language?
├── Strong C# -> .NET
├── Strong Java/Kotlin -> Spring / Quarkus
├── Strong TS/JS -> Node / Deno
└── Strong Python -> FastAPI / Django

Q3. Deployment?
├── Azure / on-prem Windows -> .NET feels natural
├── AWS / GCP / K8s -> .NET works, lean on OpenTelemetry and Aspire
└── Vercel / Cloudflare / Edge -> .NET is a poor fit

One-line recommendations (as of May 2026):

The most important meta-recommendation: there are domains where not picking .NET is the rational choice. But before you assume you're in one of them, it's worth measuring how far modern .NET has come for yourself. The .NET of 2026 is nearly a different tool from the .NET of 2018.


References

Comments

No comments yet.

Sign in to leave a comment