← Back to the blog .NET 11 Preview 5: C# gets unions, LINQ gets full joins, and the SDK gets more agent-friendly
dotnetcsharpaspnetcoreefcorelinqmcpdeveloper-tools

.NET 11 Preview 5: C# gets unions, LINQ gets full joins, and the SDK gets more agent-friendly

A practical breakdown of .NET 11 Preview 5: C# closed hierarchies and unions, LINQ FullJoin, JSON Lines, MCP server templates, Blazor SSR improvements, and EF Core 11 tooling.

Microsoft has released .NET 11 Preview 5, and this one is worth a closer look. It is not just a runtime-and-bug-fix drop. Preview 5 adds several signals about where the platform is heading: C# is moving toward stronger domain modeling, LINQ is filling long-standing data-shaping gaps, Blazor SSR keeps becoming more practical, and the SDK is leaning harder into file-based apps and agent workflows.

The official release notes list updates across the runtime, libraries, SDK, C#, ASP.NET Core, .NET MAUI, and EF Core. Here are the changes I think matter most for backend, cloud, and application developers.

C# 15: closed hierarchies and unions

The most interesting part of Preview 5 is in C#.

C# now has preview support for closed class hierarchies. A closed class can only be directly inherited from inside the same assembly, which allows the compiler to reason about all reachable direct subtypes and check switch-expression exhaustiveness.

public closed record class GateState;
public record class Closed : GateState;
public record class Open(float Percent) : GateState;

static string Describe(GateState state) => state switch
{
    Closed => "closed",
    Open(var percent) => $"{percent}% open"
};

This is useful for modeling finite states without leaving every consumer to guess whether a switch missed a case.

Preview 5 also introduces union declarations and union patterns. A union creates a value type that can contain one of a fixed set of case types.

public record class Dog(string Name);
public record class Cat(int Lives);

public union Pet(Dog, Cat);

static string Describe(Pet pet) => pet switch
{
    Dog(var name) => $"dog: {name}",
    Cat(var lives) => $"cat: {lives}"
};

For years, C# developers have used records, inheritance, OneOf-style libraries, or custom result types to approximate discriminated unions. This preview does not mean the design is final, but it is a big step toward first-class algebraic-style modeling in C#.

My read: if this matures well, it can improve how we model domain states, command results, validation outcomes, workflow transitions, and API responses.

Libraries: JSON Lines, FullJoin, X25519, and better comparers

System.Text.Json can now serialize IAsyncEnumerable<T> as JSON Lines by using JsonSerializer.SerializeAsyncEnumerable(..., topLevelValues: true).

That matters for logs, streaming exports, data pipelines, event feeds, and batch processing where each JSON value should be written as a separate line instead of wrapping everything in one large array.

LINQ also gets FullJoin for Enumerable, Queryable, and AsyncEnumerable.

var rows = catalog.FullJoin(
    sales,
    product => product.Sku,
    sale => sale.Sku,
    (product, sale) => new
    {
        Sku = product?.Sku ?? sale!.Sku,
        ProductName = product?.Name ?? "(not in catalog)",
        QuantitySold = sale?.Quantity ?? 0,
    });

This is one of those features that feels small until you need it. Full outer joins are common when reconciling two datasets: configured vs. discovered services, expected vs. observed inventory, old vs. new snapshots, or catalog vs. sales data.

Other useful library additions:

  • EqualityComparer<T>.Create(...) now supports key-selector creation, useful when equality should be based on one property for one collection without changing the type globally.
  • Random adds generic numeric APIs like NextInteger<T>() and NextBinaryFloat<T>().
  • StringBuilder.MoveChunks(...) can transfer internal chunks without copying, useful for parsers and generators.
  • Cryptography adds X25519DiffieHellman, the X25519 key-agreement curve used by modern protocols such as TLS 1.3, Signal, and Noise.

Runtime: async suspension, JIT, GC, and WebAssembly CoreCLR

Preview 5 includes runtime work that should mostly show up as “free” performance and reliability improvements.

The release notes highlight faster runtime-async suspension and resumption. Microsoft shows a suspension-heavy benchmark dropping from roughly 6357 ms to 457 ms. That is a large improvement for scenarios that stress async suspension.

The JIT also removes more redundant checks, especially in span/vectorized loops, and improves several codegen paths. GC trimming and compaction also get improvements, including a new DOTNET_GCTrimYoungestKeepPercent switch for controlling how much of the youngest generation is retained during trimming in low-memory modes.

For WebAssembly, Browser CoreCLR continues moving forward. Blazor WebAssembly can opt into CoreCLR with:

<PropertyGroup>
  <TargetFramework>net11.0</TargetFramework>
  <UseMonoRuntime>false</UseMonoRuntime>
</PropertyGroup>

This is still preview/opt-in territory, but it shows the direction: a more unified runtime story across workloads.

SDK: file-based apps grow up, and MCP lands in dotnet new

The SDK changes are very aligned with where developer tooling is going.

File-based apps can now reference other C# files:

#:ref lib.cs

Console.WriteLine(MyLib.Greeter.Greet("World"));

That makes file-based C# less of a toy and more useful for scripts, prototypes, small tools, demos, and agent-generated utilities.

CLI commands also handle file-based apps more consistently:

dotnet package add app.cs System.CommandLine
dotnet package list app.cs
dotnet nuget why app.cs System.CommandLine

The SDK can also check for vulnerable or end-of-life SDKs during build:

<PropertyGroup>
  <CheckSdkVulnerabilities>true</CheckSdkVulnerabilities>
</PropertyGroup>

New warnings include:

  • NETSDK1236 for SDKs with known vulnerabilities.
  • NETSDK1237 for SDKs that are end-of-life.

And yes: dotnet new now includes an MCP Server template.

dotnet new mcpserver --transport local

That is a strong signal. Microsoft is making agent/tool integration a first-class SDK path, not just an ecosystem add-on.

ASP.NET Core and Blazor: SSR keeps getting more useful

Blazor SSR forms now support client-side validation when using DataAnnotationsValidator, giving instant browser feedback without a server round trip.

Blazor also gets async form validation building blocks for scenarios like username availability checks, database lookups, or remote validation.

Validation localization is now supported across Blazor and Minimal APIs, including RESX-based localization and custom IStringLocalizerFactory strategies.

QuickGrid is more useful in static SSR scenarios too. Sorting and pagination can work without interactivity by using URL/query-string state instead of requiring a circuit or WebAssembly runtime.

That is important because it makes Blazor SSR more viable for fast, simple, shareable pages.

Other ASP.NET Core improvements include:

  • Blazor WebAssembly preserving server culture during prerendering/hydration.
  • [SupplyParameterFromSession] for session-backed component state.
  • A new Blazor WebAssembly Gateway development server.
  • Kestrel applying request header timeout protection to fragmented HTTP/2 and HTTP/3 trailer headers.
  • More accurate OpenAPI generation for enum parameters, array schema IDs, and multiple response content types.

EF Core 11: file-based apps, better warnings, and SQL Server 2022 by default

EF Core 11 Preview 5 extends dotnet ef to file-based apps:

dotnet ef migrations add InitialCreate --file .\App.cs

Scaffolding also supports --file and --startup-file, which makes EF fit better into the new single-file C# workflow.

There is also support for .config/dotnet-ef.json, so repeated EF commands can share default options without long command lines.

The new EF1004 analyzer warning is a good one: it warns when ToAsyncEnumerable() is used on an IQueryable<T> in a way that can execute synchronously. For EF queries, AsAsyncEnumerable() is the safer path.

SQL Server 2022 compatibility level 160 is now the default for the SQL Server provider. That unlocks newer SQL translations by default, but it is also something to review before upgrading if your database runs at an older compatibility level.

EF Core generated C# now uses file-scoped namespaces for migrations, snapshots, compiled models, and reverse-engineered code. Cleaner generated code is always welcome.

What I would watch before adopting it

This is still a preview. I would not put it into production blindly, especially with the C# language features. Closed hierarchies and unions are exciting, but the release notes explicitly show compiler support attributes and preview caveats. Treat the syntax and rules as moving pieces until later previews or RC builds.

For production codebases, the safer things to experiment with first are:

  • LINQ FullJoin in data reconciliation code.
  • JSON Lines serialization for streaming/export scenarios.
  • SDK vulnerability/EOL checks in CI.
  • Blazor SSR validation improvements in non-critical forms.
  • EF Core file-based tooling in prototypes or internal tools.

Bottom line

.NET 11 Preview 5 is more than a maintenance preview. It points to a platform that is becoming more expressive, more scriptable, and more agent-friendly.

The headline for me is C# moving toward first-class unions and closed hierarchies. The practical day-to-day wins are LINQ FullJoin, JSON Lines support, stronger SDK checks, better Blazor SSR, and EF tooling that works with file-based apps.

If you build backend systems, developer tools, cloud services, or Blazor apps, this preview is worth testing in a sandbox.

Sources

A COFFEE

Did any of this help?

I write all of this in my spare time, for fun. If something helped and you feel like it, buy me a coffee. No pressure — knowing it was useful is enough.

Buy me a coffee

Comments

Loading comments…