If you have ever stared at a stack trace from a failed async method and wondered which half of those frames belong to your code and which are compiler-generated state machine plumbing, .NET 11 Preview 2 has good news. Released on 10 March 2026, this preview lands several features that address long-standing friction points: async debugging is finally getting the runtime-level treatment it deserves, ASP.NET Core bakes in OpenTelemetry tracing without a third-party library, Kestrel stops choking on malformed traffic, and EF Core gains vector search support for AI workloads. Here is what matters and why.
Runtime Async: the state machine gets a demotion
For over a decade, every async method in C# has been lowered by the compiler into a state machine class. Local variables are hoisted to fields, the method body is split across MoveNext() calls, and the resulting stack traces look like they were written by a compiler — because they were. Debugging async code has always meant mentally filtering out generated infrastructure.
Runtime Async (sometimes called "async2") changes this by moving suspension and resumption into the runtime itself. Instead of the compiler generating a full state machine type, it emits simpler IL and lets CoreCLR handle the mechanics of pausing and resuming execution.
The practical benefits are immediate:
- Cleaner stack traces. Your actual method names appear on the call stack, not
MoveNext()wrappers. When an exception occurs threeawaitcalls deep, the stack trace reads like the code you wrote. - Lower overhead. Local variables stay on the stack unless they genuinely need to survive an
awaitboundary. In the old model, everything was hoisted to the heap via state machine fields regardless. - Better debugging. Breakpoints bind correctly inside runtime-async methods, and stepping through
awaitboundaries no longer jumps into compiler-generated infrastructure.
// NOTE
Runtime Async is enabled by default in Preview 2 for CoreCLR. However, the core runtime libraries themselves are not yet compiled with runtime-async support — that is expected in later previews.
You do not need to change your code. The same async/await keywords produce the new behaviour automatically. This is a runtime improvement, not a language change.
public class OrderProcessor(IOrderRepository repository, IPaymentGateway gateway)
{
public async Task<OrderResult> ProcessAsync(Order order)
{
var validated = await repository.ValidateAsync(order);
var payment = await gateway.ChargeAsync(validated.Total);
return await repository.CompleteAsync(order.Id, payment.TransactionId);
}
}
In .NET 10, a stack trace from CompleteAsync throwing would include frames like <ProcessAsync>d__0.MoveNext(). In .NET 11, you see OrderProcessor.ProcessAsync directly. A small change in output, a meaningful change in developer experience.
Native OpenTelemetry in ASP.NET Core
Until now, collecting OpenTelemetry traces from ASP.NET Core required the OpenTelemetry.Instrumentation.AspNetCore NuGet package. That library hooked into the framework's diagnostic events and populated the semantic convention attributes that observability backends expect.
Preview 2 eliminates that dependency. ASP.NET Core now natively populates OpenTelemetry semantic attributes on the HTTP server activity. Attributes like http.request.method, url.path, http.response.status_code, and server.address are added directly by the framework.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenTelemetry()
.WithTracing(tracing => tracing
.AddSource("Microsoft.AspNetCore")
.AddOtlpExporter());
var app = builder.Build();
app.MapGet("/orders/{id}", (int id) => Results.Ok(new { Id = id }));
app.Run();
That is all you need. No AddAspNetCoreInstrumentation() call, no extra package. Subscribe to the Microsoft.AspNetCore activity source and the framework does the rest.
// TIP
If you are migrating from the instrumentation library, remove the OpenTelemetry.Instrumentation.AspNetCore package and replace AddAspNetCoreInstrumentation() with AddSource("Microsoft.AspNetCore"). The semantic attributes are identical.
If you have a scenario where you explicitly do not want these attributes, you can suppress them:
AppContext.SetSwitch(
"Microsoft.AspNetCore.Hosting.SuppressActivityOpenTelemetryData", true);
This is a meaningful step towards making observability a first-class concern in the framework rather than a bolt-on.
Kestrel's resilient HTTP parser
Kestrel's HTTP/1.1 request parser has historically thrown BadHttpRequestException when it encountered malformed requests. In a clean environment, that is rarely a problem. In production, where port scanners, misconfigured clients, and outright malicious traffic are facts of life, throwing and catching exceptions for every garbage request burns CPU cycles.
Preview 2 replaces the exception-throwing code path with a result struct that indicates success, incomplete, or error states. Valid request processing is completely unaffected — the improvement targets the failure path exclusively.
The numbers are significant: benchmarks show 20 to 40 per cent throughput improvement in scenarios with high volumes of malformed requests. If your services are internet-facing and you have ever noticed CPU spikes correlating with port scans, this is the fix.
// WARNING
This change is transparent — you do not need to modify any code. However, if you have logging or monitoring that specifically watches for BadHttpRequestException counts to detect malicious traffic, verify that your detection still works as expected.
EF Core meets vector search
The AI wave has made vector similarity search a mainstream database operation. EF Core 10 introduced support for the SQL Server vector data type and VECTOR_DISTANCE() function. Preview 2 goes further with support for:
- DiskANN vector indexes for approximate nearest neighbour search on large datasets
VECTOR_SEARCH()for performing similarity queries against those indexes- Full-text catalogs and indexes for traditional text search
JSON_CONTAINS()for JSON containment checks
For AI workloads, this means you can build retrieval-augmented generation (RAG) pipelines entirely within EF Core and SQL Server 2025.
public class ProductRepository(ApplicationDbContext context)
{
public async Task<List<Product>> FindSimilarAsync(
float[] queryEmbedding, int count = 10)
{
return await context.Products
.OrderBy(p => EF.Functions.VectorDistance(
"cosine", p.Embedding, queryEmbedding))
.Take(count)
.ToListAsync();
}
}
For exact nearest neighbour on small datasets, VECTOR_DISTANCE() is sufficient. For larger datasets, DiskANN indexes provide approximate search with dramatically better performance — though you still need raw SQL to create DiskANN indexes, as EF Core migrations do not yet generate them.
// NOTE
Vector search requires SQL Server 2025 or Azure SQL Database. The vector data type is not available in earlier versions.
LINQ MaxBy and MinBy
A smaller but welcome addition: EF Core now translates MaxBy() and MinBy() LINQ operators to SQL.
// Find the most expensive product in each category
var results = await context.Products
.GroupBy(p => p.CategoryId)
.Select(g => g.MaxBy(p => p.Price))
.ToListAsync();
Previously, you had to write subqueries or use raw SQL for this pattern.
Blazor SSR gets TempData
Blazor Server-Side Rendering now supports TempData — the same concept that MVC and Razor Pages developers have relied on for years. TempData persists values for exactly one subsequent request, making it ideal for flash messages, POST-Redirect-GET confirmations, and one-time notifications.
The feature registers automatically when you call AddRazorComponents(). TempData appears as a cascading parameter, with values encrypted using ASP.NET Core Data Protection.
@code {
[CascadingParameter]
public ITempDataDictionary TempData { get; set; } = default!;
private async Task SubmitOrder()
{
await orderService.CreateAsync(model);
TempData["SuccessMessage"] = "Order created successfully.";
Navigation.NavigateTo("/orders");
}
}
On the target page, calling TempData.Get("SuccessMessage") retrieves and removes the value in one step — exactly the one-time read semantics you would expect.
// TIP
TempData in Blazor SSR uses cookie-based storage with Data Protection encryption. If you are running multiple server instances, ensure you have a shared Data Protection key ring configured.
The Web Worker template
A new project template lets you offload computation to a Web Worker, keeping the browser UI responsive. Create one with:
dotnet new webworker -n MyWorker
The template provides a WebWorkerClient class with a factory pattern for creating worker instances. Methods marked with [JSExport] run in the worker thread, communicating back to the main thread without blocking rendering.
This is particularly useful for Blazor WebAssembly applications that need to perform heavy calculations — parsing large datasets, running compression, or processing images — without freezing the UI.
Smaller SDK, sharper analysers
Two quality-of-life improvements round out the release:
Reduced installer size. SDK installers on Linux and macOS are up to 26 per cent smaller thanks to symbolic link deduplication of shared assemblies. SDK container images are up to 17 per cent smaller. If you are building CI pipelines or development containers, your image pulls just got faster.
Improved code analysers. The CA1873 analyser (prefer AsSpan over Substring) has been refined to produce fewer false positives and clearer diagnostic messages. Several other analyser bugs in CA1515, CA1034, and CA1859 have been fixed.
Common pitfalls
Assuming Runtime Async changes your code. It does not. This is a runtime optimisation that improves diagnostics and performance. Your existing async/await code works identically — you just get better stack traces and slightly less allocation overhead.
Removing the OpenTelemetry instrumentation package prematurely. The native tracing covers HTTP server spans. If you rely on the instrumentation library for additional features like request/response body logging or custom enrichment callbacks, check that those are available natively before removing the package.
Using VECTOR_DISTANCE() on large datasets without DiskANN. Exact nearest neighbour scales linearly with dataset size. For anything beyond a few thousand rows, create a DiskANN index and use VECTOR_SEARCH() instead.
Forgetting Data Protection configuration with Blazor TempData. TempData is encrypted. In a load-balanced environment without a shared key ring, a value set on one server cannot be read on another. Configure a persistent key storage provider before deploying.
Expecting EF Core migrations to create DiskANN indexes. They will not — at least not yet. Create these indexes using raw SQL in your migration's Up() method or as a separate deployment step.
Summary
- Runtime Async moves async state machine management into the runtime, producing cleaner stack traces, better debugging, and reduced allocation overhead — with zero code changes required.
- Native OpenTelemetry in ASP.NET Core eliminates the need for
OpenTelemetry.Instrumentation.AspNetCore, making observability configuration simpler. - Kestrel's non-throwing HTTP parser improves throughput by 20-40% under malformed traffic, a significant win for internet-facing services.
- EF Core vector search with DiskANN support brings AI workloads like RAG into the ORM, alongside new
MaxBy/MinByLINQ translation andJSON_CONTAINS(). - Blazor SSR TempData finally brings flash-message patterns to Blazor server-side rendering.
- The Web Worker template enables background computation in browser-based .NET applications.
.NET 11 Preview 2 is available now. If you are tracking the preview cycle, this is a good one to take for a spin — Runtime Async alone makes the debugging experience noticeably better.