.NET Project Upgrade Skill
When to Use This Skill
- •Upgrading project target frameworks (e.g.,
net6.0→net9.0) - •Updating .NET SDK versions across projects
- •Migrating multiple projects in a solution
- •Version pinning and controlled rollouts
- •Updating CI/CD pipelines for new .NET versions
- •Preparing hosting environments for new runtimes
Quick Start: Basic Upgrade Process
1. Identify Projects to Upgrade
List all project files that need upgrading:
find . -name "*.csproj" -o -name "*.vbproj" -o -name "*.fsproj"
2. Update Project Files (Minimum Required Change)
Open each project file (.csproj, .vbproj, or .fsproj) and update the <TargetFramework> property:
Before:
<PropertyGroup> <TargetFramework>net8.0</TargetFramework> </PropertyGroup>
After (upgrading to .NET 9):
<PropertyGroup> <TargetFramework>net9.0</TargetFramework> </PropertyGroup>
For multi-targeted projects, update <TargetFrameworks>:
<PropertyGroup> <TargetFrameworks>net8.0;net9.0</TargetFrameworks> </PropertyGroup>
3. Restore Workloads
If using specialized workloads (MAUI, ASP.NET, etc.):
dotnet workload restore
4. Build and Test
dotnet build dotnet test
The SDK will provide warnings and errors to guide further changes.
Advanced: Version Pinning Strategies
Pin SDK Version with global.json
Create or update global.json in your solution root to control which SDK version is used:
dotnet new globaljson --sdk-version 9.0.100 --roll-forward latestFeature
This ensures consistent builds across different machines and CI environments.
File structure after:
solution-root/ ├── global.json (pins SDK version) ├── src/ │ ├── Project1/ │ └── Project2/ └── tests/
Control Analyzer Behavior
Lock analyzer rules to a specific .NET version to prevent new warnings on upgrade:
<PropertyGroup> <AnalysisLevel>9.0</AnalysisLevel> </PropertyGroup>
This is useful when upgrading gradually—prevents new analyzer rules from breaking builds before you're ready to address them.
Manage Package Versions
Option A: Central Package Management (Recommended)
Create Directory.Packages.props in solution root:
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Microsoft.Extensions.AI" Version="9.10.1" />
<PackageVersion Include="Azure.Identity" Version="1.17.0" />
</ItemGroup>
</Project>
In project files, reference without version:
<ItemGroup> <PackageReference Include="Microsoft.Extensions.AI" /> <PackageReference Include="Azure.Identity" /> </ItemGroup>
Option B: Package Lock Files
Enable lock files to ensure reproducible restores:
<PropertyGroup> <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile> <RestoreLockedMode>true</RestoreLockedMode> </PropertyGroup>
Generate lock file:
dotnet restore
CI/CD Pipeline Updates
Update your CI/CD pipeline to use the new SDK version. For GitHub Actions:
Before:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0'
After:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0'
Multi-Project Upgrade Checklist
Copy this checklist and track progress:
Upgrade Progress: - [ ] Review breaking changes for target .NET version - [ ] Update all .csproj files to new target framework - [ ] Run dotnet workload restore if needed - [ ] Build entire solution: dotnet build - [ ] Run full test suite: dotnet test - [ ] Update global.json if using version pinning - [ ] Update CI/CD pipeline configuration - [ ] Test in CI/CD environment - [ ] Commit changes
Breaking Changes and Migration
Check for breaking changes specific to your target version:
Hosting Environment Updates
Docker
Update Dockerfile FROM statements:
# Old FROM mcr.microsoft.com/dotnet/aspnet:8.0 # New FROM mcr.microsoft.com/dotnet/aspnet:9.0
Azure App Service
Configuration changes are required through Azure Portal or IaC (e.g., Bicep, Terraform).
Linux Servers
Install new .NET runtime via package manager:
# Ubuntu/Debian sudo apt-get update sudo apt-get install -y dotnet-runtime-9.0
Troubleshooting
Validation Loop
- •Run
dotnet build - •If errors: review messages, fix issues, repeat step 1
- •Run
dotnet test - •If failures: fix tests, repeat step 3
- •Only proceed when both pass
Build Fails After Update
- •Check error messages—SDK provides guidance
- •Review breaking changes for your target version
- •Update NuGet packages that may have new version requirements
- •Run
dotnet cleanand rebuild
Tests Fail
- •Run tests individually to isolate issues
- •Check for API changes in updated packages
- •Review test framework compatibility (e.g., xUnit, NUnit versions)
CI/CD Pipeline Fails
- •Verify new SDK version is available in CI environment
- •Check
global.jsonis in repo root (CI should respect it) - •Update any hardcoded version references in pipeline
Key Resources
Examples by Scenario
Scenario 1: Simple Single-Project Upgrade
For a single .csproj project:
- •Update
<TargetFramework>net9.0</TargetFramework> - •Run
dotnet build - •Run
dotnet test - •Commit with message: "Upgrade to .NET 9"
Scenario 2: Multi-Project Solution with CI/CD
For solutions with multiple projects and GitHub Actions:
- •Update all
.csprojfiles in the solution - •Create/update
global.jsonin solution root - •Update
.github/workflows/*.ymlto use new version - •Run full test suite locally:
dotnet test - •Push and verify CI passes
- •Commit message: "Upgrade solution to .NET 9 (includes CI/CD updates)"
Scenario 3: Gradual Multi-Version Support
For libraries supporting multiple .NET versions:
- •Update
<TargetFrameworks>net8.0;net9.0</TargetFrameworks> - •Test on both versions:
dotnet test --framework net8.0 && dotnet test --framework net9.0 - •Document supported versions in README
- •Gradually drop old version support in future releases