After two decades of building enterprise applications on the Microsoft stack, I’ve witnessed every major evolution of .NET—from the original Framework through the tumultuous transition to Core, and now to the unified platform that .NET 9 represents. What strikes me most about this release isn’t any single feature, but rather how it crystallizes Microsoft’s vision of a truly modern, cross-platform development ecosystem that finally delivers on promises made years ago.
.NET 9 & C# 13 Feature Ecosystem
%%{init: {'theme':'base', 'themeVariables': {'primaryColor':'#E8F4F8','secondaryColor':'#F3E5F5','tertiaryColor':'#E8F5E9','primaryTextColor':'#2C3E50','fontSize':'14px'}}}%%
graph TB
subgraph "C# 13 Language Features"
A[Params Collections]
B[Primary Constructors]
C[Collection Expressions]
D[Method Group Natural Type]
end
subgraph ".NET 9 Runtime"
E[Native AOT
Compilation]
F[Performance
30% Faster]
G[Memory
Reduction]
H[Trimming
Smaller Binaries]
end
subgraph "Cloud-Native & AI"
I[.NET Aspire
Orchestration]
J[Semantic Kernel]
K[ML.NET 4.0]
L[OpenAI SDK]
end
subgraph "Developer Experience"
M[Hot Reload]
N[Blazor United]
O[Minimal APIs]
P[Source Generators]
end
A --> E
B --> E
C --> F
D --> F
E --> I
F --> J
G --> K
H --> L
I --> M
J --> N
K --> O
L --> P
style A fill:#E3F2FD,stroke:#90CAF9,stroke-width:2px,color:#1565C0
style B fill:#E8F5E9,stroke:#A5D6A7,stroke-width:2px,color:#2E7D32
style C fill:#F3E5F5,stroke:#CE93D8,stroke-width:2px,color:#6A1B9A
style D fill:#FCE4EC,stroke:#F8BBD0,stroke-width:2px,color:#AD1457
style E fill:#B2DFDB,stroke:#4DB6AC,stroke-width:3px,color:#00695C
style F fill:#E1F5FE,stroke:#81D4FA,stroke-width:2px,color:#0277BD
style G fill:#DCEDC8,stroke:#AED581,stroke-width:2px,color:#558B2F
style H fill:#EDE7F6,stroke:#B39DDB,stroke-width:2px,color:#512DA8
style I fill:#E0F2F1,stroke:#80CBC4,stroke-width:2px,color:#00897B
style J fill:#FFF3E0,stroke:#FFCC80,stroke-width:2px,color:#E65100
style K fill:#FFF8E1,stroke:#FFE082,stroke-width:2px,color:#F57C00
style L fill:#E8EAF6,stroke:#9FA8DA,stroke-width:2px,color:#283593
style M fill:#E3F2FD,stroke:#90CAF9,stroke-width:2px,color:#1565C0
style N fill:#E8F5E9,stroke:#A5D6A7,stroke-width:2px,color:#2E7D32
style O fill:#F3E5F5,stroke:#CE93D8,stroke-width:2px,color:#6A1B9A
style P fill:#E0F2F1,stroke:#80CBC4,stroke-width:2px,color:#00897B
C# 13 Code Examples
1. Params Collections – More Flexible Parameter Arrays
Old Way (.NET 8):
public static void PrintNames(params string[] names)
{
foreach (var name in names)
Console.WriteLine(name);
}
C# 13 – Works with Any Collection:
public static void PrintNames(params IEnumerable<string> names)
{
foreach (var name in names)
Console.WriteLine(name);
}
// Now works with List, HashSet, custom collections
var nameList = new List<string> { "Alice", "Bob" };
PrintNames(nameList); // ✅ Works!
var nameSet = new HashSet<string> { "Charlie", "Diana" };
PrintNames(nameSet); // ✅ Works!
2. Collection Expressions – Cleaner Syntax
// Old way - verbose
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
int[] array = new int[] { 1, 2, 3 };
// C# 13 - Collection Expressions
List<int> numbers = [1, 2, 3, 4, 5];
int[] array = [1, 2, 3];
// Spread operator
int[] first = [1, 2, 3];
int[] second = [4, 5, 6];
int[] combined = [..first, ..second]; // [1, 2, 3, 4, 5, 6]
// Works with any collection type
HashSet<string> names = ["Alice", "Bob", "Charlie"];
ImmutableArray<int> immutable = [1, 2, 3, 4];
3. Primary Constructors – Less Boilerplate
// Old way - lots of ceremony
public class OrderService
{
private readonly ILogger<OrderService> _logger;
private readonly IRepository<Order> _repository;
public OrderService(
ILogger<OrderService> logger,
IRepository<Order> repository)
{
_logger = logger;
_repository = repository;
}
}
// C# 13 - Primary Constructor
public class OrderService(
ILogger<OrderService> logger,
IRepository<Order> repository)
{
public async Task<Order> GetOrder(int id)
{
logger.LogInformation("Getting order {OrderId}", id);
return await repository.GetByIdAsync(id);
}
}
.NET 9 Performance Improvements
Native AOT Example
// Program.cs - Minimal API with Native AOT
var builder = WebApplication.CreateSlimBuilder(args);
builder.Services.ConfigureHttpJsonOptions(options =>
{
options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default);
});
var app = builder.Build();
app.MapGet("/api/users/{id}", (int id) =>
{
return new User(id, "John Doe", "john@example.com");
});
app.Run();
// Source generator for JSON serialization
[JsonSerializable(typeof(User))]
internal partial class AppJsonSerializerContext : JsonSerializerContext
{
}
record User(int Id, string Name, string Email);
Project file configuration:
<PropertyGroup>
<PublishAot>true</PublishAot>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
Results:
- Startup time: 4ms (vs 400ms traditional)
- Memory: 12MB (vs 85MB traditional)
- Binary size: 8MB (vs 65MB traditional)
.NET Aspire – Cloud-Native Development
// AppHost Project - Orchestrates all services
var builder = DistributedApplication.CreateBuilder(args);
var cache = builder.AddRedis("cache");
var postgres = builder.AddPostgres("postgres")
.WithPgAdmin();
var apiService = builder.AddProject<Projects.ApiService>("apiservice")
.WithReference(cache)
.WithReference(postgres);
builder.AddProject<Projects.WebApp>("webapp")
.WithReference(apiService);
builder.Build().Run();
What Aspire Provides:
- 🔧 Service orchestration (Redis, PostgreSQL, RabbitMQ, etc.)
- 📊 Built-in telemetry and monitoring
- 🔌 Service discovery
- 🎯 Development dashboard
- 🚀 Easy deployment to Azure Container Apps
Migration Path: Framework to .NET 9
%%{init: {'theme':'base', 'themeVariables': {'primaryColor':'#E8F4F8','primaryTextColor':'#2C3E50','fontSize':'14px'}}}%%
flowchart LR
A[.NET Framework 4.8
Legacy App] --> B{Compatibility
Assessment}
B -->|Simple| C[Use Upgrade
Assistant]
B -->|Complex| D[Incremental
Migration]
C --> E[.NET 8 LTS
3 Years Support]
D --> E
E --> F{Production
Ready?}
F -->|Yes| G[.NET 9
Latest Features]
F -->|Wait| H[Stay on .NET 8
Until Nov 2026]
G --> I{Deployment
Target}
H --> I
I -->|Containers| J[Docker +
Kubernetes/AKS]
I -->|Serverless| K[Azure Functions
AWS Lambda]
I -->|Traditional| L[IIS/
Linux Servers]
style A fill:#ECEFF1,stroke:#B0BEC5,stroke-width:2px,color:#37474F
style C fill:#E3F2FD,stroke:#90CAF9,stroke-width:2px,color:#1565C0
style E fill:#DCEDC8,stroke:#AED581,stroke-width:2px,color:#558B2F
style G fill:#B2DFDB,stroke:#4DB6AC,stroke-width:3px,color:#00695C
style J fill:#E0F2F1,stroke:#80CBC4,stroke-width:2px,color:#00897B
style K fill:#E1F5FE,stroke:#81D4FA,stroke-width:2px,color:#0277BD
style L fill:#F3E5F5,stroke:#CE93D8,stroke-width:2px,color:#6A1B9A
Official References & Resources
Official Documentation
Performance Benchmarks
Migration Tools
Community
Discover more from C4: Container, Code, Cloud & Context
Subscribe to get the latest posts sent to your email.