diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 68b40a1e..432f52a0 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -30,6 +30,9 @@ /plugins/dotnet-upgrade/skills/dotnet-aot-compat/ @agocke @dotnet/appmodel /tests/dotnet-upgrade/dotnet-aot-compat/ @agocke @dotnet/appmodel +/plugins/dotnet-upgrade/skills/migrate-dotnet10-to-dotnet11/ @danmoseley @ViktorHofer +/tests/dotnet-upgrade/migrate-dotnet10-to-dotnet11/ @danmoseley @ViktorHofer + # dotnet-diag (perf investigations, debugging, incident analysis) /plugins/dotnet-diag/skills/analyzing-dotnet-performance/ @dotnet/dotnet-diag /tests/dotnet-diag/analyzing-dotnet-performance/ @dotnet/dotnet-diag diff --git a/plugins/dotnet-upgrade/skills/migrate-dotnet10-to-dotnet11/SKILL.md b/plugins/dotnet-upgrade/skills/migrate-dotnet10-to-dotnet11/SKILL.md new file mode 100644 index 00000000..ab8e406a --- /dev/null +++ b/plugins/dotnet-upgrade/skills/migrate-dotnet10-to-dotnet11/SKILL.md @@ -0,0 +1,202 @@ +--- +name: migrate-dotnet10-to-dotnet11 +description: > + Migrate a .NET 10 project or solution to .NET 11 and resolve all breaking changes. + This is a MIGRATION skill — use it when upgrading, migrating, or moving from + .NET 10 to .NET 11, NOT for writing new C# scripts or programs. + USE FOR: upgrading TargetFramework from net10.0 to net11.0, fixing build errors + and compilation errors after updating the .NET 11 SDK, resolving breaking changes + and behavioral changes introduced in .NET 11 / C# 15 / ASP.NET Core 11 / EF Core 11, + adapting to updated minimum hardware requirements (x86-64-v2, Arm64 LSE), + fixing C# 15 compiler breaking changes (Span collection expression safe-context, + ref readonly delegate/local function InAttribute, with() parsing, nameof(this.) + in attributes), resolving EF Core Cosmos DB sync I/O removal, and adapting to + core library behavioral changes (DeflateStream/GZipStream empty payloads, + MemoryStream capacity, TAR checksum validation, ZipArchive.CreateAsync). + DO NOT USE FOR: major framework migrations (e.g., .NET Framework to .NET 11), + upgrading from .NET 9 or earlier (address intermediate breaking changes first), + greenfield projects that start on .NET 11, writing new C# scripts or programs, + or purely cosmetic code modernization unrelated to the version upgrade. + LOADS REFERENCES: csharp-compiler, core-libraries, sdk-msbuild (always loaded), + efcore, cryptography, runtime-jit (loaded selectively based on project type). + NOTE: .NET 11 is in preview. This skill covers breaking changes through Preview 1. + Additional breaking changes are expected in later previews. +--- + +# .NET 10 → .NET 11 Migration + +Migrate a .NET 10 project or solution to .NET 11, systematically resolving all breaking changes. The outcome is a project targeting `net11.0` that builds cleanly, passes tests, and accounts for every behavioral, source-incompatible, and binary-incompatible change introduced in .NET 11. + +> **Note:** .NET 11 is currently in preview. This skill covers breaking changes documented through Preview 1. It will be updated as additional previews ship. + +## When to Use + +- Upgrading `TargetFramework` from `net10.0` to `net11.0` +- Resolving build errors or new warnings after updating the .NET 11 SDK +- Adapting to behavioral changes in .NET 11 runtime, ASP.NET Core 11, or EF Core 11 +- Updating CI/CD pipelines, Dockerfiles, or deployment scripts for .NET 11 +- Fixing C# 15 compiler breaking changes after SDK upgrade + +## When Not to Use + +- The project already targets `net11.0` and builds cleanly — migration is done +- Upgrading from .NET 9 or earlier — address the .NET 9→10 breaking changes first +- Migrating from .NET Framework — that is a separate, larger effort +- Greenfield projects that start on .NET 11 (no migration needed) + +## Inputs + +| Input | Required | Description | +|-------|----------|-------------| +| Project or solution path | Yes | The `.csproj`, `.sln`, or `.slnx` entry point to migrate | +| Build command | No | How to build (e.g., `dotnet build`, a repo build script). Auto-detect if not provided | +| Test command | No | How to run tests (e.g., `dotnet test`). Auto-detect if not provided | +| Project type hints | No | Whether the project uses ASP.NET Core, EF Core, Cosmos DB, etc. Auto-detect from PackageReferences and SDK attributes if not provided | + +## Workflow + +> **Answer directly from the loaded reference documents.** Do not search the filesystem or fetch web pages for breaking change information — the references contain the authoritative details. Focus on identifying which breaking changes apply and providing concrete fixes. +> +> **Commit strategy:** Commit at each logical boundary — after updating the TFM (Step 2), after resolving build errors (Step 3), after addressing behavioral changes (Step 4), and after updating infrastructure (Step 5). This keeps each commit focused and reviewable. + +### Step 1: Assess the project + +1. Identify how the project is built and tested. Look for build scripts, `.sln`/`.slnx` files, or individual `.csproj` files. +2. Run `dotnet --version` to confirm the .NET 11 SDK is installed. If it is not, stop and inform the user. +3. Determine which technology areas the project uses by examining: + - **SDK attribute**: `Microsoft.NET.Sdk.Web` → ASP.NET Core; `Microsoft.NET.Sdk.WindowsDesktop` with `` or `` → WPF/WinForms + - **PackageReferences**: `Microsoft.EntityFrameworkCore.*` → EF Core; `Microsoft.EntityFrameworkCore.Cosmos` → Cosmos DB provider + - **Dockerfile presence** → Container changes relevant + - **Cryptography API usage** → DSA on macOS affected + - **Compression API usage** → DeflateStream/GZipStream/ZipArchive changes relevant + - **TAR API usage** → Header checksum validation change relevant + - **`NamedPipeClientStream` usage with `SafePipeHandle`** → SYSLIB0063 constructor obsoletion relevant +4. Record which reference documents are relevant (see the reference loading table in Step 3). +5. Do a **clean build** (`dotnet build --no-incremental` or delete `bin`/`obj`) on the current `net10.0` target to establish a clean baseline. Record any pre-existing warnings. + +### Step 2: Update the Target Framework + +1. In each `.csproj` (or `Directory.Build.props` if centralized), change: + ```xml + net10.0 + ``` + to: + ```xml + net11.0 + ``` + For multi-targeted projects, add `net11.0` to `` or replace `net10.0`. + +2. Update all `Microsoft.Extensions.*`, `Microsoft.AspNetCore.*`, `Microsoft.EntityFrameworkCore.*`, and other Microsoft package references to their 11.0.x versions. If using Central Package Management (`Directory.Packages.props`), update versions there. + +3. Run `dotnet restore`. Fix any restore errors before continuing. + +4. Run `dotnet build`. Capture all errors and warnings — these will be addressed in Step 3. + +### Step 3: Fix source-breaking and compilation changes + +Load reference documents based on the project's technology areas: + +| Reference file | When to load | +|----------------|-------------| +| `references/csharp-compiler-dotnet10to11.md` | Always (C# 15 compiler breaking changes) | +| `references/core-libraries-dotnet10to11.md` | Always (applies to all .NET 11 projects) | +| `references/sdk-msbuild-dotnet10to11.md` | Always (SDK and build tooling changes) | +| `references/efcore-dotnet10to11.md` | Project uses Entity Framework Core (especially Cosmos DB provider) | +| `references/cryptography-dotnet10to11.md` | Project uses cryptography APIs or targets macOS | +| `references/runtime-jit-dotnet10to11.md` | Deploying to older hardware or embedded devices | + +Work through each build error systematically. Common patterns: + +1. **C# 15 Span collection expression safe-context** — Collection expressions of `Span`/`ReadOnlySpan` type now have `declaration-block` safe-context. Code assigning span collection expressions to variables in outer scopes will error. Use array type or move the expression to the correct scope. + +2. **`ref readonly` delegates/local functions need `InAttribute`** — If synthesizing delegates from `ref readonly`-returning methods or using `ref readonly` local functions, ensure `System.Runtime.InteropServices.InAttribute` is available. + +3. **`nameof(this.)` in attributes** — Remove `this.` qualifier; use `nameof(P)` instead of `nameof(this.P)`. + +4. **`with()` in collection expressions (C# 15)** — `with(...)` is now treated as constructor arguments, not a method call. Use `@with(...)` to call a method named `with`. + +5. **Dynamic `&&`/`||` with interface operand** — Interface types as left operand of `&&`/`||` with `dynamic` right operand now errors at compile time. Cast to concrete type or `dynamic`. + +6. **EF Core Cosmos sync I/O removal** — `ToList()`, `SaveChanges()`, etc. on Cosmos provider always throw. Convert to async equivalents. + +7. **SYSLIB0063: `NamedPipeClientStream` `isConnected` parameter obsoleted** — The constructor overload taking `bool isConnected` is obsoleted. Remove the `isConnected` argument and use the new 3-parameter constructor. Projects with `TreatWarningsAsErrors` will fail to build. + +### Step 4: Address behavioral changes + +These changes compile successfully but alter runtime behavior. Review each one and determine impact: + +1. **DeflateStream/GZipStream empty payload** — Now writes headers and footers even for empty payloads. If your code checks for zero-length output, update the check. + +2. **MemoryStream maximum capacity** — Maximum capacity updated and exception behavior changed. Review code that creates large MemoryStreams or relies on specific exception types. + +3. **TAR header checksum validation** — TAR-reading APIs now verify checksums. Corrupted or hand-crafted TAR files may now fail to read. + +4. **ZipArchive.CreateAsync eager loading** — `ZipArchive.CreateAsync` eagerly loads entries. May affect memory usage for large archives. + +5. **Environment.TickCount consistency** — Made consistent with Windows timeout behavior. Code relying on specific tick count behavior may need adjustment. + +6. **DSA removed from macOS** — DSA cryptographic operations throw on macOS. Use a different algorithm (RSA, ECDSA). + +7. **Japanese Calendar minimum date** — Minimum supported date corrected. Code using very early Japanese Calendar dates may be affected. + +8. **Minimum hardware requirements** — x86/x64 baseline moved to `x86-64-v2`; Windows Arm64 requires `LSE`. Verify deployment targets meet requirements. + +9. **Mono launch target for .NET Framework** — No longer set automatically. If using Mono for .NET Framework apps on Linux, specify explicitly. + +10. **`with()` switch-expression-arm parsing** — `(X.Y) when` now parsed as constant pattern + when clause instead of cast. + +### Step 5: Update infrastructure + +1. **Dockerfiles**: Update base images from 10.0 to 11.0: + ```dockerfile + # Before + FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build + FROM mcr.microsoft.com/dotnet/aspnet:10.0 + # After + FROM mcr.microsoft.com/dotnet/sdk:11.0 AS build + FROM mcr.microsoft.com/dotnet/aspnet:11.0 + ``` + +2. **CI/CD pipelines**: Update SDK version references. If using `global.json`, update the `sdk.version` in your existing file while preserving other keys (such as `rollForward` and test configuration): + ```diff + { + "sdk": { + - "version": "10.0.100", + - "rollForward": "latestFeature" + + "version": "11.0.100-preview.1", + + "rollForward": "latestFeature" + }, + "otherSettings": { + "...": "..." + } + } + ``` + +3. **Hardware deployment targets**: Verify all deployment targets meet the updated minimum hardware requirements (x86-64-v2 for x86/x64, LSE for Windows Arm64). + +### Step 6: Verify + +1. Run a full clean build: `dotnet build --no-incremental` +2. Run all tests: `dotnet test` +3. If the application is containerized, build and test the container image +4. Smoke-test the application, paying special attention to: + - Compression behavior with empty streams + - TAR file reading + - EF Core Cosmos DB operations (must be async) + - DSA usage on macOS + - Memory-intensive MemoryStream usage + - Span collection expression assignments +5. Review the diff and ensure no unintended behavioral changes were introduced + +## Reference Documents + +The `references/` folder contains detailed breaking change information organized by technology area. Load only the references relevant to the project being migrated: + +| Reference file | When to load | +|----------------|-------------| +| `references/csharp-compiler-dotnet10to11.md` | Always (C# 15 compiler breaking changes) | +| `references/core-libraries-dotnet10to11.md` | Always (applies to all .NET 11 projects) | +| `references/sdk-msbuild-dotnet10to11.md` | Always (SDK and build tooling changes) | +| `references/efcore-dotnet10to11.md` | Project uses Entity Framework Core (especially Cosmos DB provider) | +| `references/cryptography-dotnet10to11.md` | Project uses cryptography APIs or targets macOS | +| `references/runtime-jit-dotnet10to11.md` | Deploying to older hardware or embedded devices | diff --git a/plugins/dotnet-upgrade/skills/migrate-dotnet10-to-dotnet11/references/core-libraries-dotnet10to11.md b/plugins/dotnet-upgrade/skills/migrate-dotnet10-to-dotnet11/references/core-libraries-dotnet10to11.md new file mode 100644 index 00000000..d6cbf71d --- /dev/null +++ b/plugins/dotnet-upgrade/skills/migrate-dotnet10-to-dotnet11/references/core-libraries-dotnet10to11.md @@ -0,0 +1,81 @@ +# Core .NET Libraries Breaking Changes (.NET 11) + +These breaking changes affect all .NET 11 projects regardless of application type. Source: https://learn.microsoft.com/en-us/dotnet/core/compatibility/11 + +> **Note:** .NET 11 is in preview. Additional breaking changes are expected in later previews. + +## Obsoleted APIs + +### NamedPipeClientStream constructor with `isConnected` parameter obsoleted (SYSLIB0063) + +**Impact: High (for projects using `TreatWarningsAsErrors`).** The `NamedPipeClientStream` constructor overload that accepts a `bool isConnected` parameter has been obsoleted. The `isConnected` argument never had any effect — pipes created from an existing `SafePipeHandle` are always connected. A new constructor without the parameter has been added. + +```csharp +// .NET 10: compiles without warning +var pipe = new NamedPipeClientStream(PipeDirection.InOut, isAsync: true, isConnected: true, safePipeHandle); + +// .NET 11: SYSLIB0063 warning (error with TreatWarningsAsErrors) +// Fix: remove the isConnected parameter +var pipe = new NamedPipeClientStream(PipeDirection.InOut, isAsync: true, safePipeHandle); +``` + +**Fix:** Remove the `isConnected` argument and use the new 3-parameter constructor `NamedPipeClientStream(PipeDirection, bool isAsync, SafePipeHandle)`. + +Source: https://github.com/dotnet/runtime/pull/120328 + +## Behavioral Changes + +### DeflateStream and GZipStream write headers and footers for empty payloads + +**Impact: Medium.** `DeflateStream` and `GZipStream` now always write format headers and footers to the output stream, even when no data is written. Previously, these streams produced no output for empty payloads. + +This ensures the output is a valid compressed stream per the Deflate and GZip specifications, but code that checks for zero-length output will need updating. + +```csharp +// .NET 10: output stream is empty (0 bytes) +// .NET 11: output stream contains valid headers/footers +using var ms = new MemoryStream(); +using (var gz = new GZipStream(ms, CompressionMode.Compress, leaveOpen: true)) +{ + // write nothing +} +// ms.Length was 0 in .NET 10, now > 0 in .NET 11 +``` + +**Fix:** If your code checks for empty output to detect "no data was compressed," check the uncompressed byte count instead, or adjust the length check to account for headers/footers. + +Source: https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/11/deflatestream-gzipstream-empty-payload + +### MemoryStream maximum capacity updated and exception behavior changed + +**Impact: Medium.** The maximum capacity of `MemoryStream` has been updated and the exception behavior for exceeding capacity has changed. + +**Fix:** Review code that creates very large `MemoryStream` instances or catches specific exception types related to capacity limits. + +Source: https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/11/memorystream-max-capacity + +### TAR-reading APIs verify header checksums when reading + +**Impact: Medium.** TAR-reading APIs now verify header checksums during reading. Previously, invalid checksums were silently ignored. + +```csharp +// .NET 11: throws if TAR header checksum is invalid +using var reader = new TarReader(stream); +var entry = reader.GetNextEntry(); // may throw for corrupted files +``` + +**Fix:** Ensure TAR files have valid checksums. If processing hand-crafted or legacy TAR files, add error handling for checksum validation failures. + +Source: https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/11/tar-checksum-validation + +### ZipArchive.CreateAsync eagerly loads ZIP archive entries + +**Impact: Low.** `ZipArchive.CreateAsync` now eagerly loads ZIP archive entries instead of lazy loading. This may affect memory usage for very large archives. + +Source: https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/11/ziparchive-createasync-eager-load + +### Environment.TickCount made consistent with Windows timeout behavior + +**Impact: Low.** `Environment.TickCount` behavior has been made consistent with Windows timeout behavior. Code that relies on specific tick count wrapping or comparison patterns may need adjustment. + +Source: https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/11/environment-tickcount-windows-behavior diff --git a/plugins/dotnet-upgrade/skills/migrate-dotnet10-to-dotnet11/references/cryptography-dotnet10to11.md b/plugins/dotnet-upgrade/skills/migrate-dotnet10-to-dotnet11/references/cryptography-dotnet10to11.md new file mode 100644 index 00000000..9f88243c --- /dev/null +++ b/plugins/dotnet-upgrade/skills/migrate-dotnet10-to-dotnet11/references/cryptography-dotnet10to11.md @@ -0,0 +1,28 @@ +# Cryptography Breaking Changes (.NET 11) + +These breaking changes affect projects using cryptography APIs. Source: https://learn.microsoft.com/en-us/dotnet/core/compatibility/11 + +> **Note:** .NET 11 is in preview. Additional cryptography breaking changes are expected in later previews. + +## Behavioral Changes + +### DSA removed from macOS + +**Impact: Medium (macOS only).** DSA (Digital Signature Algorithm) has been removed from macOS. Code that uses DSA for signing or verification will throw on macOS. + +```csharp +// BREAKS on macOS in .NET 11 +using var dsa = DSA.Create(); +var signature = dsa.SignData(data, HashAlgorithmName.SHA256); + +// FIX: Use a different algorithm +using var ecdsa = ECDsa.Create(); +var signature = ecdsa.SignData(data, HashAlgorithmName.SHA256); +``` + +**Fix:** Migrate from DSA to a more modern algorithm: +- **ECDSA** — recommended replacement for digital signatures +- **RSA** — alternative if ECDSA is not suitable +- **Ed25519** — if available in your scenario + +This change only affects macOS. DSA continues to work on Windows and Linux (though it is generally considered a legacy algorithm). diff --git a/plugins/dotnet-upgrade/skills/migrate-dotnet10-to-dotnet11/references/csharp-compiler-dotnet10to11.md b/plugins/dotnet-upgrade/skills/migrate-dotnet10-to-dotnet11/references/csharp-compiler-dotnet10to11.md new file mode 100644 index 00000000..57bde25f --- /dev/null +++ b/plugins/dotnet-upgrade/skills/migrate-dotnet10-to-dotnet11/references/csharp-compiler-dotnet10to11.md @@ -0,0 +1,168 @@ +# C# 15 Compiler Breaking Changes (.NET 11) + +These breaking changes are introduced by the Roslyn compiler shipping with the .NET 11 SDK. They affect all projects targeting `net11.0` (which uses C# 15 by default). These are maintained separately from the runtime breaking changes at: https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/breaking-changes/compiler%20breaking%20changes%20-%20dotnet%2011 + +> **Note:** .NET 11 is in preview. Additional compiler breaking changes may be introduced in later previews. + +## Source-Incompatible Changes + +### Span/ReadOnlySpan collection expression safe-context changed to `declaration-block` + +**Impact: Medium.** The safe-context of a collection expression of `Span` or `ReadOnlySpan` type is now `declaration-block`, matching the specification. Previously the compiler incorrectly used `function-member`. + +This can cause new errors when assigning a span collection expression created in an inner scope to a variable in an outer scope: + +```csharp +// BREAKS — new error +scoped Span items1 = default; +foreach (var x in new[] { 1, 2 }) +{ + Span items = [x]; + if (x == 1) + items1 = items; // error: safe-context is declaration-block +} + +// FIX option 1: Use an array type +foreach (var x in new[] { 1, 2 }) +{ + int[] items = [x]; + if (x == 1) + items1 = items; // ok, using int[] conversion to Span +} + +// FIX option 2: Move collection expression to outer scope +Span items = [0]; +foreach (var x in new[] { 1, 2 }) +{ + items[0] = x; + if (x == 1) + items1 = items; // ok +} +``` + +See also: https://github.com/dotnet/csharplang/issues/9750 + +### `ref readonly` synthesized delegates require `InAttribute` + +**Impact: Low.** When the compiler synthesizes a delegate type for a `ref readonly`-returning method or lambda, it now properly emits metadata requiring `System.Runtime.InteropServices.InAttribute`. + +```csharp +class RefHelper +{ + private static int value = 42; + + public void M() + { + // May cause CS0518 if InAttribute is not available + var methodDelegate = this.MethodWithRefReadonlyReturn; + var lambdaDelegate = ref readonly int () => ref value; + } +} +``` + +**Fix:** Add a reference to an assembly defining `System.Runtime.InteropServices.InAttribute` (typically available via the default runtime references). + +### `ref readonly` local functions require `InAttribute` + +**Impact: Low.** Same as above but for `ref readonly`-returning local functions. + +```csharp +void Method() +{ + int x = 0; + ref readonly int local() => ref x; // CS0518 if InAttribute missing +} +``` + +**Fix:** Same as above — ensure `InAttribute` is available. + +### Dynamic `&&`/`||` with interface left operand disallowed + +**Impact: Low.** The compiler now reports a compile-time error when an interface type with `true`/`false` operators is used as the left operand of `&&` or `||` with a `dynamic` right operand. Previously this compiled but threw `RuntimeBinderException` at runtime. + +```csharp +interface I1 +{ + static bool operator true(I1 x) => false; + static bool operator false(I1 x) => false; +} + +class C1 : I1 +{ + public static C1 operator &(C1 x, C1 y) => x; + public static bool operator true(C1 x) => false; + public static bool operator false(C1 x) => false; +} + +void M() +{ + I1 x = new C1(); + dynamic y = new C1(); + _ = x && y; // error CS7083 +} +``` + +**Fix:** Cast the left operand to a concrete type or to `dynamic`: +```csharp +_ = (C1)x && y; // valid +_ = (dynamic)x && y; // valid +``` + +See also: https://github.com/dotnet/roslyn/issues/80954 + +### `nameof(this.)` in attributes disallowed + +**Impact: Low.** Using `this` or `base` inside `nameof` in an attribute is now properly disallowed per the language specification. This was unintentionally permitted since C# 12. + +```csharp +// Before (.NET 10) — compiled but was unintentionally permitted +class C +{ + string P; + [System.Obsolete(nameof(this.P))] + void M() { } +} +``` + +```csharp +// After (.NET 11) — remove 'this.' qualifier +class C +{ + string P; + [System.Obsolete(nameof(P))] + void M() { } +} +``` + +See also: https://github.com/dotnet/roslyn/issues/82251 + +### `with()` as collection expression element (C# 15) + +**Impact: Low.** When `LangVersion` is 15 or greater, `with(...)` as an element in a collection expression is treated as constructor/factory arguments (the new "collection expression arguments" feature), not as a call to a method named `with`. + +```csharp +object x, y, z = ...; +object[] items; + +items = [with(x, y), z]; // C# 14: call to with() method; C# 15: error +items = [@with(x, y), z]; // fix: escape to call method named 'with' +``` + +### Parsing of `with` in switch-expression-arm + +**Impact: Low.** In a switch expression, `(X.Y) when` is now parsed as a constant pattern `(X.Y)` followed by a `when` clause. Previously it was parsed as a cast expression casting `when` to `(X.Y)`. + +See also: https://github.com/dotnet/roslyn/issues/81837 + +## New Language Features (non-breaking but relevant) + +### Collection expression arguments + +C# 15 adds `with(...)` syntax as the first element of a collection expression, allowing constructor/factory arguments: + +```csharp +List names = [with(capacity: values.Count * 2), .. values]; +HashSet set = [with(StringComparer.OrdinalIgnoreCase), "Hello", "HELLO"]; +``` + +This is the feature that causes the `with()` method call breaking change above. diff --git a/plugins/dotnet-upgrade/skills/migrate-dotnet10-to-dotnet11/references/efcore-dotnet10to11.md b/plugins/dotnet-upgrade/skills/migrate-dotnet10-to-dotnet11/references/efcore-dotnet10to11.md new file mode 100644 index 00000000..4c417d2e --- /dev/null +++ b/plugins/dotnet-upgrade/skills/migrate-dotnet10-to-dotnet11/references/efcore-dotnet10to11.md @@ -0,0 +1,38 @@ +# Entity Framework Core Breaking Changes (.NET 11) + +These breaking changes affect projects using Entity Framework Core 11. Source: https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-11.0/breaking-changes + +> **Note:** .NET 11 is in preview. The changes below were introduced in **Preview 1**. Additional EF Core breaking changes are expected in later previews. + +## Medium-Impact Changes + +### Sync I/O via the Azure Cosmos DB provider has been fully removed (Preview 1) + +**Impact: Medium.** Synchronous I/O via the Azure Cosmos DB provider has been completely removed. In EF Core 10, sync I/O was unsupported by default but could be re-enabled with a special opt-in. In EF Core 11, calling any synchronous I/O API always throws — there is no opt-in to restore the old behavior. + +**Affected APIs:** +- `ToList()`, `First()`, `Single()`, `Count()`, and other synchronous LINQ operators +- `SaveChanges()` +- Any synchronous query execution against the Cosmos DB provider + +```csharp +// BREAKS in EF Core 11 — always throws +var items = context.Items.ToList(); +context.SaveChanges(); + +// FIX: Use async equivalents +var items = await context.Items.ToListAsync(); +await context.SaveChangesAsync(); +``` + +**Why:** Synchronous blocking on asynchronous methods ("sync-over-async") can lead to deadlocks and performance problems. Since the Azure Cosmos DB SDK only supports async methods, the EF Cosmos provider now requires async throughout. + +**Fix:** Convert all synchronous I/O calls to their async equivalents: +- `ToList()` → `await ToListAsync()` +- `First()` → `await FirstAsync()` +- `Single()` → `await SingleAsync()` +- `Count()` → `await CountAsync()` +- `SaveChanges()` → `await SaveChangesAsync()` +- `Any()` → `await AnyAsync()` + +Tracking issue: https://github.com/dotnet/efcore/issues/37059 diff --git a/plugins/dotnet-upgrade/skills/migrate-dotnet10-to-dotnet11/references/runtime-jit-dotnet10to11.md b/plugins/dotnet-upgrade/skills/migrate-dotnet10-to-dotnet11/references/runtime-jit-dotnet10to11.md new file mode 100644 index 00000000..5d1fc9b3 --- /dev/null +++ b/plugins/dotnet-upgrade/skills/migrate-dotnet10-to-dotnet11/references/runtime-jit-dotnet10to11.md @@ -0,0 +1,57 @@ +# Runtime and JIT Compiler Breaking Changes (.NET 11) + +These breaking changes affect the .NET runtime and JIT compiler. Source: https://learn.microsoft.com/en-us/dotnet/core/compatibility/11 + +> **Note:** .NET 11 is in preview. Additional runtime breaking changes are expected in later previews. + +## Behavioral Changes + +### Minimum hardware requirements updated + +**Impact: High for deployments on older hardware.** .NET 11 updates the minimum hardware requirements for both x86/x64 and Arm64 architectures. + +#### x86/x64 changes + +The baseline is updated from `x86-64-v1` to `x86-64-v2` on all operating systems. This means the minimum CPU must support: +- `CMOV`, `CX8`, `SSE`, `SSE2` (previously required) +- `CX16`, `POPCNT`, `SSE3`, `SSSE3`, `SSE4.1`, `SSE4.2` (newly required) + +This aligns with Windows 11 requirements and covers all Intel/AMD CPUs still in official support (older chips went out of support around 2013). + +The ReadyToRun (R2R) target is updated to `x86-64-v3` for Windows and Linux, adding `AVX`, `AVX2`, `BMI1`, `BMI2`, `F16C`, `FMA`, `LZCNT`, and `MOVBE`. Hardware that meets `x86-64-v2` but not `x86-64-v3` will experience additional JIT overhead at startup. + +| OS | Previous JIT/AOT min | New JIT/AOT min | Previous R2R target | New R2R target | +|----|---------------------|-----------------|--------------------|--------------------| +| Apple | x86-64-v1 | x86-64-v2 | x86-64-v2 | (No change) | +| Linux | x86-64-v1 | x86-64-v2 | x86-64-v2 | x86-64-v3 | +| Windows | x86-64-v1 | x86-64-v2 | x86-64-v2 | x86-64-v3 | + +#### Arm64 changes + +- **Apple**: No change to minimum hardware or R2R target. +- **Linux**: No change to minimum hardware (still supports Raspberry Pi). R2R target updated to include `LSE`. +- **Windows**: Baseline updated to require `LSE` (Load-Store Exclusive), required by Windows 11 and all Arm64 CPUs officially supported by Windows 10. R2R target updated to `armv8.2-a + RCPC`. + +| OS | Previous JIT/AOT min | New JIT/AOT min | Previous R2R target | New R2R target | +|----|---------------------|-----------------|--------------------|--------------------| +| Apple | Apple M1 | (No change) | Apple M1 | (No change) | +| Linux | armv8.0-a | (No change) | armv8.0-a | armv8.0-a + LSE | +| Windows | armv8.0-a | armv8.0-a + LSE | armv8.0-a | armv8.2-a + RCPC | + +#### Impact + +Starting with .NET 11, .NET fails to run on older hardware and prints: + +> The current CPU is missing one or more of the baseline instruction sets. + +For ReadyToRun-capable assemblies, there may be additional startup overhead on supported hardware that doesn't meet the R2R target. + +**Fix:** Verify all deployment targets meet the new minimum requirements. For x86/x64, any CPU from ~2013 or later should be fine. For Windows Arm64, ensure `LSE` support (all Windows 11 compatible Arm64 devices). + +Source: https://learn.microsoft.com/en-us/dotnet/core/compatibility/jit/11/minimum-hardware-requirements + +### Globalization: Japanese Calendar minimum supported date corrected + +**Impact: Low.** The minimum supported date for the Japanese Calendar has been corrected. Code using very early dates in the Japanese Calendar may be affected. + +Source: https://learn.microsoft.com/en-us/dotnet/core/compatibility/globalization/11/japanese-calendar-min-date diff --git a/plugins/dotnet-upgrade/skills/migrate-dotnet10-to-dotnet11/references/sdk-msbuild-dotnet10to11.md b/plugins/dotnet-upgrade/skills/migrate-dotnet10-to-dotnet11/references/sdk-msbuild-dotnet10to11.md new file mode 100644 index 00000000..16377e7a --- /dev/null +++ b/plugins/dotnet-upgrade/skills/migrate-dotnet10-to-dotnet11/references/sdk-msbuild-dotnet10to11.md @@ -0,0 +1,13 @@ +# SDK and MSBuild Breaking Changes (.NET 11) + +These changes affect the .NET SDK, CLI tooling, NuGet, and MSBuild behavior. Source: https://learn.microsoft.com/en-us/dotnet/core/compatibility/11 + +> **Note:** .NET 11 is in preview. Additional SDK/MSBuild breaking changes are expected in later previews. + +## Behavioral Changes + +### Mono launch target not set for .NET Framework apps + +**Impact: Low.** The mono launch target is no longer set automatically for .NET Framework apps. If you require Mono for execution on Linux, you need to specify it explicitly in the configuration. + +Source: https://learn.microsoft.com/en-us/dotnet/core/compatibility/sdk/11/mono-launch-target-removed diff --git a/tests/dotnet-upgrade/migrate-dotnet10-to-dotnet11/eval.yaml b/tests/dotnet-upgrade/migrate-dotnet10-to-dotnet11/eval.yaml new file mode 100644 index 00000000..e492711a --- /dev/null +++ b/tests/dotnet-upgrade/migrate-dotnet10-to-dotnet11/eval.yaml @@ -0,0 +1,229 @@ +scenarios: + # --- Scenario 1: Core libraries (DeflateStream, MemoryStream, TAR, ZipArchive) --- + - name: "Console app with compression and TAR operations" + prompt: | + Use the migrate-dotnet10-to-dotnet11 skill to help me migrate my .NET 10 console app to .NET 11. The app: + - Creates GZipStream to compress data, then checks if the output is empty (zero bytes) to detect "no data" scenarios + - Reads TAR archives that were hand-crafted by a legacy tool (some may have invalid checksums) + - Uses ZipArchive.CreateAsync for large ZIP files and relies on lazy loading behavior + - Uses MemoryStream with very large allocations close to the maximum capacity + What breaks when migrating to .NET 11? + assertions: + - type: "output_matches" + pattern: "(GZipStream|DeflateStream|header|footer|empty)" + - type: "output_matches" + pattern: "(TAR|checksum|verify|validation)" + - type: "output_matches" + pattern: "(ZipArchive|CreateAsync|eager)" + rubric: + - "Explains GZipStream/DeflateStream now writes headers and footers even for empty payloads; zero-length check needs updating" + - "Warns TAR-reading APIs now verify header checksums; corrupted or hand-crafted TAR files may fail" + - "Notes ZipArchive.CreateAsync now eagerly loads entries, potentially affecting memory usage" + - "Mentions MemoryStream maximum capacity update and changed exception behavior" + timeout: 180 + + # --- Scenario 2: C# 15 compiler breaking changes (Span safe-context, nameof, with()) --- + - name: "C# 15 compiler breaking changes — Span safe-context, nameof, with()" + prompt: | + Use the migrate-dotnet10-to-dotnet11 skill to help me. I'm migrating a .NET 10 library to .NET 11 / C# 15 and getting new compiler errors. Here's the code: + + ```csharp + // SpanHelper.cs + public static int[] ProcessItems(int[] source) + { + scoped Span results = default; + foreach (var x in source) + { + Span items = [x * 2]; + results = items; // worked in C# 14 + } + return results.ToArray(); + } + ``` + + ```csharp + // Metadata.cs + class MyService + { + string Endpoint; + [System.Obsolete(nameof(this.Endpoint))] + void LegacyConnect() { } + } + ``` + + ```csharp + // Pipeline.cs + object with(object a, object b) => (a, b); + object[] items = [with(x, y), z]; // worked in C# 14 + ``` + + What breaks in each case and how do I fix it? + assertions: + - type: "output_matches" + pattern: "(Span|safe.context|declaration.block|scope)" + - type: "output_matches" + pattern: "(nameof|this\\.|attribute)" + - type: "output_matches" + pattern: "(with|collection expression|@with|constructor)" + rubric: + - "Identifies the Span collection expression safe-context change to declaration-block; recommends using array type or moving expression to outer scope" + - "Identifies nameof(this.Endpoint) is now disallowed in attributes; recommends nameof(Endpoint)" + - "Explains with() in collection expressions is now treated as constructor arguments in C# 15; recommends @with() to call the method" + timeout: 180 + + # --- Scenario 3: EF Core Cosmos DB sync I/O removal --- + - name: "EF Core app with Cosmos DB provider using sync APIs" + prompt: | + Use the migrate-dotnet10-to-dotnet11 skill to help me. I'm migrating a .NET 10 web API to .NET 11. The app uses EF Core with the Azure Cosmos DB provider. + We have a repository pattern where some methods use synchronous LINQ: + + ```csharp + public class ProductRepository + { + private readonly CosmosDbContext _context; + + public List GetAll() + { + return _context.Products.ToList(); + } + + public Product GetById(int id) + { + return _context.Products.First(p => p.Id == id); + } + + public int GetCount() + { + return _context.Products.Count(); + } + + public void Save(Product product) + { + _context.Products.Add(product); + _context.SaveChanges(); + } + } + ``` + + In .NET 10 we had the sync-over-async opt-in configured. What breaks in .NET 11? + assertions: + - type: "output_matches" + pattern: "(sync|async|ToList|SaveChanges)" + - type: "output_matches" + pattern: "(Cosmos|always throws|no.*opt.in|removed)" + rubric: + - "Identifies that sync I/O via Cosmos DB provider is fully removed in EF Core 11 with no opt-in" + - "Recommends converting all sync methods to async: ToList→ToListAsync, First→FirstAsync, Count→CountAsync, SaveChanges→SaveChangesAsync" + - "Notes the methods must return Task and the callers must be updated to await" + timeout: 180 + + # --- Scenario 4: Minimum hardware requirements --- + - name: "Deployment to older hardware with minimum requirement changes" + prompt: | + Use the migrate-dotnet10-to-dotnet11 skill to help me. We're upgrading our .NET 10 microservices to .NET 11. We deploy to: + - x86-64 Linux containers on a mix of hardware, some dating back to 2012 + - Windows Arm64 devices (Surface Pro X with SQ1 chip) + - Raspberry Pi 4 running Linux for edge computing + After upgrading, one of our Linux x86 nodes fails with "The current CPU is missing + one or more of the baseline instruction sets." What's happening? + assertions: + - type: "output_matches" + pattern: "(x86.64.v2|baseline|minimum|hardware)" + - type: "output_matches" + pattern: "(SSE4|POPCNT|SSSE3)" + rubric: + - "Explains .NET 11 raised the x86/x64 minimum from x86-64-v1 to x86-64-v2, requiring SSE4.1, SSE4.2, POPCNT, etc." + - "Notes hardware from 2012 may lack x86-64-v2 support — need to upgrade or keep on .NET 10" + - "Confirms Raspberry Pi 4 (Arm64 Linux) is still supported — no change to Linux Arm64 minimum" + - "Notes Surface Pro X (SQ1) supports LSE so Windows Arm64 requirement is met" + timeout: 180 + + # --- Scenario 5: Cryptography — DSA on macOS --- + - name: "Cryptography app using DSA on macOS" + prompt: | + Use the migrate-dotnet10-to-dotnet11 skill to help me. We have a .NET 10 library that verifies legacy DSA signatures. It runs on Linux, Windows, + and macOS. After upgrading to .NET 11, the macOS builds fail at runtime when calling + DSA.Create(). What happened and how do we fix it? + assertions: + - type: "output_matches" + pattern: "(DSA|macOS|removed)" + - type: "output_matches" + pattern: "(ECDSA|RSA|alternative|replacement)" + rubric: + - "Explains DSA has been removed from macOS in .NET 11" + - "Notes DSA still works on Windows and Linux" + - "Recommends migrating to ECDSA or RSA" + timeout: 180 + + # --- Scenario 6: TFM update + global.json + Docker --- + - name: "Basic TFM update with Docker and global.json" + prompt: | + Use the migrate-dotnet10-to-dotnet11 skill to help me. I have a .NET 10 ASP.NET Core web app with: + - TargetFramework set to net10.0 in the csproj + - global.json pinning SDK to 10.0.100 + - A Dockerfile using mcr.microsoft.com/dotnet/aspnet:10.0 and sdk:10.0 + How do I update everything for .NET 11? + assertions: + - type: "output_matches" + pattern: "(net11\\.0|TargetFramework)" + - type: "output_matches" + pattern: "(global\\.json|11\\.0)" + - type: "output_matches" + pattern: "(Dockerfile|sdk:11\\.0|aspnet:11\\.0)" + rubric: + - "Updates TargetFramework from net10.0 to net11.0" + - "Updates global.json SDK version to 11.0.x" + - "Updates Dockerfile base images from 10.0 to 11.0" + - "Recommends updating Microsoft.* package references to 11.0.x versions" + timeout: 180 + + # --- Scenario 7: Dynamic operator with interface and ref readonly delegate --- + - name: "C# 15 dynamic operator and ref readonly delegate issues" + prompt: | + Use the migrate-dotnet10-to-dotnet11 skill to help me. After upgrading to .NET 11 / C# 15, I'm getting two new compiler errors: + + ```csharp + // DynamicOps.cs + interface IFilter + { + static bool operator true(IFilter x) => true; + static bool operator false(IFilter x) => false; + } + + class CompositeFilter : IFilter + { + public static CompositeFilter operator &(CompositeFilter x, CompositeFilter y) => x; + public static bool operator true(CompositeFilter x) => true; + public static bool operator false(CompositeFilter x) => false; + } + + void Apply(IFilter left, dynamic right) + { + var combined = left && right; // error! + } + ``` + + ```csharp + // RefHelper.cs + class RefHelper + { + private static int value = 42; + + public static void M() + { + var fn = ref readonly int () => ref value; // error CS0518 + } + } + ``` + + What's happening? + assertions: + - type: "output_matches" + pattern: "(interface|dynamic|CS7083|operator)" + - type: "output_matches" + pattern: "(ref readonly|InAttribute|CS0518)" + rubric: + - "Explains that interface types as left operand of && with dynamic right operand now produces CS7083 at compile time" + - "Recommends casting to concrete type or to dynamic" + - "Explains ref readonly delegate synthesis requires InAttribute; recommends ensuring proper assembly references" + timeout: 180