Skip to content

Upgrade to .NET 10 and Orleans 10 with Roslyn 5.x pinning - #20

Merged
billsonnn merged 3 commits into
mainfrom
claude/turbo-dotnet-10-upgrade-5fdy5j
Aug 28, 2026
Merged

Upgrade to .NET 10 and Orleans 10 with Roslyn 5.x pinning#20
billsonnn merged 3 commits into
mainfrom
claude/turbo-dotnet-10-upgrade-5fdy5j

Conversation

@billsonnn

Copy link
Copy Markdown
Contributor

Summary

Upgrade the project from .NET 9 to .NET 10, Orleans 9.2.1 to 10.2.2, and Microsoft.Extensions packages to 10.0.11. Pin Roslyn (Microsoft.CodeAnalysis) to 5.0.0 to resolve transitive version conflicts between Orleans 10 (which requires 5.x) and EF Core 9 design-time packages (which still reference 4.8.0). EF Core remains on 9.x pending Pomelo MySQL provider support for EF Core 10.

Key Changes

  • Target framework: Updated all .csproj files from net9.0 to net10.0
  • SDK version: Bumped global.json from 9.0.310 to 10.0.400
  • Orleans: Upgraded from 9.2.1 to 10.2.2 across all packages
  • Microsoft.Extensions: Updated DependencyInjection, Hosting, Logging, and DependencyModel from 9.0.8 to 10.0.11
  • Microsoft.CodeAnalysis: Pinned Common, CSharp, CSharp.Workspaces, Workspaces.Common, and Workspaces.MSBuild to 5.0.0 with explanatory comments
  • NetAnalyzers: Updated from 9.0.0 to 10.0.400
  • EF Core: Patched from 9.0.8 to 9.0.19 (held on 9.x due to Pomelo 9.0.0 constraints)
  • Removed dependency: Removed unused System.Collections 4.3.0 package reference from Turbo.Main
  • Async cleanup: Removed .ConfigureAwait(false) calls throughout codebase (now unnecessary in .NET 10 with improved async context handling)
  • Documentation: Updated AGENTS.md, README.md, bootstrap scripts, and VS Code configuration to reflect .NET 10 baseline

Implementation Details

  • Central transitive pinning of Roslyn packages ensures a single resolved version across the dependency graph, preventing conflicts between Orleans 10's requirement for 5.x and EF Core 9's design-time tooling references
  • EF Core remains pinned to 9.x with documented rationale; upgrade to 10.x blocked until Pomelo ships an EF Core 10 provider
  • Async/await patterns simplified by removing explicit ConfigureAwait(false) calls, leveraging .NET 10's improved default context behavior

https://claude.ai/code/session_01H1WWL4hLiAvJr2jzxoGyaP

claude added 2 commits August 23, 2026 19:05
Retarget every project to net10.0 and pin the SDK to 10.0.400 (LTS) in
global.json.

Package updates:
- Microsoft.Extensions.* 9.0.8 -> 10.0.11
- Microsoft.Orleans.* 9.2.1 -> 10.2.2
- Microsoft.CodeAnalysis.NetAnalyzers 9.0.0 -> 10.0.400
- Microsoft.EntityFrameworkCore.* 9.0.8 -> 9.0.19 (latest 9.x patch)
- dotnet-ef tool 9.0.8 -> 9.0.19 to match the EF Core runtime

EF Core stays on 9.x because Pomelo.EntityFrameworkCore.MySql 9.0.0 pins
Microsoft.EntityFrameworkCore.Relational to [9.0.0, 9.0.999] and Pomelo has
no EF Core 10 release yet. The hold is documented in Directory.Packages.props
and AGENTS.md.

Orleans 10 requires Microsoft.CodeAnalysis 5.x while EF Core 9's design-time
packages still ask for 4.8.0, which fails restore under central transitive
pinning (NU1107). The Roslyn family is now pinned explicitly at 5.0.0.

Also dropped the explicit System.Collections 4.3.0 reference, which .NET 10
prunes automatically (NU1510), and refreshed the SDK version checks in the
bootstrap scripts, the net9.0 output paths in .vscode configs, and the stack
versions in AGENTS.md/README.md.

Verified with a clean `dotnet build Turbo.Main/Turbo.Main.csproj
-t:TurboCloudQualityGate -p:TurboAIPolicyPhase=1` on SDK 10.0.400:
0 errors, gate green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H1WWL4hLiAvJr2jzxoGyaP
ConfigureAwait(false) is an explicit opt-out of the current task scheduler.
In grain code that means the continuation resumes on TaskScheduler.Default
instead of the activation's scheduler, which drops the grain context and
voids the turn-based single-threaded execution guarantee for everything
after the await. Orleans has documented this as "never do this in grain
code" for years; Orleans 10 added ORLEANS0014 to detect it.

The two load-bearing cases were PlayerWalletGrain.TryDebitAsync, where the
escape happened on the first await and took the whole debit transaction
(state mutation, SaveChanges, Commit, and the outgoing presence call) off
the scheduler, and the two InventoryGrain grant paths, which did the same
around SaveChangesAsync and AddFurnitureAsync. The remaining sites were
trailing awaits with no code after them.

Removed rather than rewritten to ConfigureAwait(true): that is the default,
and .editorconfig already disables CA2007 for grain code, so these files
stay warning-free.

Only grain classes are touched. ConfigureAwait(false) in services, handlers
and providers is correct and left as-is.

Clean quality gate on SDK 10.0.400: 0 errors, ORLEANS0014 cleared, no new
CA2007.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H1WWL4hLiAvJr2jzxoGyaP
@nitrodevco nitrodevco deleted a comment from chatgpt-codex-connector Bot Aug 28, 2026
GrantCatalogOfferAsync and GrantLtdFurnitureAsync disposed their DbContext
through an explicit try/finally, which is exactly what `await using var`
compiles to. Switched both to the declaration form, matching how
PlayerWalletGrain already creates its context.

No behavioral change: disposal still happens on every exit path, including
exceptions. Pure de-indent of the former try bodies.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H1WWL4hLiAvJr2jzxoGyaP
@billsonnn
billsonnn merged commit e7d66b7 into main Aug 28, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants