|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +title: Upgrading SeedFolder to .NET 10 LTS - Maintaining Multi-Target Framework Support |
| 4 | +description: How to upgrade a .NET Global Tool to support .NET 10 while maintaining backward compatibility with .NET 8 and 9 |
| 5 | +summary: A walkthrough of upgrading SeedFolder to support .NET 10 (LTS) while maintaining full backward compatibility with .NET 8 and 9. Covers multi-targeting, dependency management, CI/CD updates, and testing strategies for .NET global tools. |
| 6 | +cover_image: /images/seedfolder-dotnet10-upgrade.svg |
| 7 | +tags: |
| 8 | +- dotnet-global-tools |
| 9 | +- dotnet |
| 10 | +- csharp |
| 11 | +- dotnet10 |
| 12 | +- multi-targeting |
| 13 | +- nuget |
| 14 | +- ci-cd |
| 15 | + |
| 16 | +--- |
| 17 | +**Overview** ☀ |
| 18 | + |
| 19 | +With .NET 10 now released as the latest Long-Term Support (LTS) version, it was time to update [SeedFolder](https://github.com/solrevdev/seedfolder) to support the newest framework while maintaining compatibility with .NET 8 and 9. This post walks through the process of adding .NET 10 support to a global tool, managing dependencies, updating CI/CD pipelines, and ensuring a smooth upgrade path for users. |
| 20 | + |
| 21 | +**Why .NET 10?** 🎯 |
| 22 | + |
| 23 | +.NET 10 is the latest LTS release, providing long-term support until November 2028. By adding .NET 10 support alongside existing .NET 8 and 9 targets, SeedFolder users get: |
| 24 | + |
| 25 | +- **Latest LTS**: Long-term support until November 2028 |
| 26 | +- **Performance improvements**: Built-in performance enhancements from .NET 10 |
| 27 | +- **Forward compatibility**: Automatic use of the highest installed SDK |
| 28 | +- **Backward compatibility**: Continued support for .NET 8 (LTS) and .NET 9 (STS) |
| 29 | + |
| 30 | +The beauty of multi-targeting is that users with any of these SDK versions can install and run the tool. When multiple SDKs are installed, the .NET CLI automatically selects the highest compatible version. |
| 31 | + |
| 32 | +**The Upgrade Process** 🚀 |
| 33 | + |
| 34 | +The upgrade was surprisingly straightforward, thanks to .NET's excellent multi-targeting support. Here's the step-by-step process I followed: |
| 35 | + |
| 36 | +**1. Research and Planning** 📚 |
| 37 | + |
| 38 | +Before making any changes, I researched the .NET 10 requirements: |
| 39 | + |
| 40 | +- **Target Framework Moniker (TFM)**: `net10.0` |
| 41 | +- **SDK Version**: `10.0.100` or later |
| 42 | +- **Breaking Changes**: Reviewed Microsoft docs for any breaking changes (none affecting SeedFolder) |
| 43 | + |
| 44 | +I also reviewed the git history to understand how previous SDK upgrades were handled: |
| 45 | + |
| 46 | +```bash |
| 47 | +git log --all --grep=".NET" --oneline | head -20 |
| 48 | +``` |
| 49 | + |
| 50 | +This showed that the last major upgrade ([PR #259c452](https://github.com/solrevdev/seedfolder/commit/259c45284d67cb8ab6b1ff2f65d9fe2c5bfa8223)) added .NET 8 and 9 support, following a similar pattern I could replicate. |
| 51 | + |
| 52 | +**2. Update Project File** 🔧 |
| 53 | + |
| 54 | +The key change was adding `net10.0` to the `TargetFrameworks` property in the `.csproj` file: |
| 55 | + |
| 56 | +```diff |
| 57 | +<Project Sdk="Microsoft.NET.Sdk"> |
| 58 | + <PropertyGroup> |
| 59 | + <OutputType>Exe</OutputType> |
| 60 | +- <TargetFrameworks>net8.0;net9.0</TargetFrameworks> |
| 61 | ++ <TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks> |
| 62 | + <LangVersion>latest</LangVersion> |
| 63 | + <ImplicitUsings>enable</ImplicitUsings> |
| 64 | + <PackAsTool>true</PackAsTool> |
| 65 | + <ToolCommandName>seedfolder</ToolCommandName> |
| 66 | + <PackageOutputPath>./nupkg</PackageOutputPath> |
| 67 | + <NoDefaultExcludes>true</NoDefaultExcludes> |
| 68 | +- <Version>1.3.3</Version> |
| 69 | ++ <Version>1.4.0</Version> |
| 70 | + <!-- ... other properties ... --> |
| 71 | + </PropertyGroup> |
| 72 | +</Project> |
| 73 | +``` |
| 74 | + |
| 75 | +**Important considerations:** |
| 76 | +- Use semicolon-separated list for multiple targets |
| 77 | +- Bump the version number for NuGet release (1.3.3 → 1.4.0) |
| 78 | +- Maintain existing targets for backward compatibility |
| 79 | + |
| 80 | +**3. Update CI/CD Pipeline** ⚙️ |
| 81 | + |
| 82 | +The GitHub Actions workflow needed to install the .NET 10 SDK alongside existing versions: |
| 83 | + |
| 84 | +```diff |
| 85 | +- name: setup .net core sdk |
| 86 | + uses: actions/setup-dotnet@v4 |
| 87 | + with: |
| 88 | + dotnet-version: | |
| 89 | + 8.0.x |
| 90 | + 9.0.x |
| 91 | ++ 10.0.x |
| 92 | +``` |
| 93 | + |
| 94 | +This ensures the CI pipeline can build all three target frameworks. |
| 95 | + |
| 96 | +**4. Dependency Management** 📦 |
| 97 | + |
| 98 | +I ran `dotnet outdated` to check for package updates: |
| 99 | + |
| 100 | +```bash |
| 101 | +dotnet tool install -g dotnet-outdated-tool |
| 102 | +dotnet outdated |
| 103 | +``` |
| 104 | + |
| 105 | +This revealed that Figgle (the ASCII art library) had a newer version (0.6.5). However, upon investigation, version 0.6.x introduced breaking changes by splitting fonts into a separate package. Since the upgrade goal was .NET 10 support, not dependency updates, I kept Figgle at 0.5.1 to avoid unnecessary complexity. |
| 106 | + |
| 107 | +**5. Build and Test** ✅ |
| 108 | + |
| 109 | +Building for multiple frameworks is straightforward with multi-targeting: |
| 110 | + |
| 111 | +```bash |
| 112 | +dotnet build solrevdev.seedfolder.sln --configuration Release |
| 113 | +``` |
| 114 | + |
| 115 | +Output showed successful builds for all three targets: |
| 116 | + |
| 117 | +``` |
| 118 | +solrevdev.seedfolder -> src/bin/Release/net8.0/solrevdev.seedfolder.dll |
| 119 | +solrevdev.seedfolder -> src/bin/Release/net9.0/solrevdev.seedfolder.dll |
| 120 | +solrevdev.seedfolder -> src/bin/Release/net10.0/solrevdev.seedfolder.dll |
| 121 | +``` |
| 122 | + |
| 123 | +**Testing the Tool Locally** 🧪 |
| 124 | + |
| 125 | +Before publishing, I packaged and tested the tool locally: |
| 126 | + |
| 127 | +```bash |
| 128 | +# Package the tool |
| 129 | +dotnet pack -c Release -o /tmp/seedfolder-test |
| 130 | + |
| 131 | +# Install from local package |
| 132 | +dotnet tool uninstall -g solrevdev.seedfolder |
| 133 | +dotnet tool install -g --add-source /tmp/seedfolder-test solrevdev.seedfolder |
| 134 | + |
| 135 | +# Verify installation |
| 136 | +seedfolder --version |
| 137 | +# Output: seedfolder version 1.4.0 |
| 138 | +``` |
| 139 | + |
| 140 | +Then I tested various commands in `/tmp` to ensure functionality: |
| 141 | + |
| 142 | +```bash |
| 143 | +# Test dry-run mode |
| 144 | +seedfolder --dry-run -t node test-node-app |
| 145 | + |
| 146 | +# Create Python project |
| 147 | +seedfolder -t python test-python-app |
| 148 | + |
| 149 | +# Create .NET project |
| 150 | +seedfolder --template dotnet test-dotnet-app |
| 151 | + |
| 152 | +# Verify help and template listing |
| 153 | +seedfolder --help |
| 154 | +seedfolder --list-templates |
| 155 | +``` |
| 156 | + |
| 157 | +All tests passed successfully! 🎉 |
| 158 | + |
| 159 | +**6. Update Documentation** 📝 |
| 160 | + |
| 161 | +Documentation updates included: |
| 162 | + |
| 163 | +**README.md** - Updated requirements section: |
| 164 | +```diff |
| 165 | +## Requirements |
| 166 | + |
| 167 | +- This tool requires **.NET 8.0 or .NET 9.0 SDK** to be installed |
| 168 | ++ This tool requires **.NET 8.0, .NET 9.0, or .NET 10.0 SDK** to be installed |
| 169 | + |
| 170 | +- **Runtime**: .NET 8.0 or later |
| 171 | +``` |
| 172 | + |
| 173 | +**CLAUDE.md** - Updated framework information: |
| 174 | +```diff |
| 175 | +## Multi-Target Framework Support |
| 176 | +- The project targets .NET 8.0 (LTS) and 9.0 (STS) |
| 177 | ++ The project targets .NET 8.0 (LTS), 9.0 (STS), and 10.0 (LTS) |
| 178 | ++ .NET 10 is the latest LTS release providing long-term support until November 2028. |
| 179 | +``` |
| 180 | + |
| 181 | +**Multi-Targeting Best Practices** 💡 |
| 182 | + |
| 183 | +From this experience, here are some best practices for multi-targeting .NET global tools: |
| 184 | + |
| 185 | +**1. Use Multi-Targeting, Not Multiple Projects** |
| 186 | +```xml |
| 187 | +<!-- Good: Single project, multiple targets --> |
| 188 | +<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks> |
| 189 | + |
| 190 | +<!-- Bad: Multiple projects for different versions --> |
| 191 | +``` |
| 192 | + |
| 193 | +**2. Maintain LTS Versions** |
| 194 | + |
| 195 | +Keep the previous LTS version (net8.0) alongside the new one. This gives users flexibility and ensures broad compatibility. |
| 196 | + |
| 197 | +**3. Test All Targets** |
| 198 | + |
| 199 | +The NuGet package includes all target frameworks: |
| 200 | + |
| 201 | +``` |
| 202 | +tools/net8.0/any/solrevdev.seedfolder.dll |
| 203 | +tools/net9.0/any/solrevdev.seedfolder.dll |
| 204 | +tools/net10.0/any/solrevdev.seedfolder.dll |
| 205 | +``` |
| 206 | + |
| 207 | +Verify each target builds correctly and the tool runs on all supported SDKs. |
| 208 | + |
| 209 | +**4. Handle Dependencies Carefully** |
| 210 | + |
| 211 | +When upgrading, check if dependencies support all your target frameworks. If a dependency doesn't support your newest target, you have options: |
| 212 | + |
| 213 | +- Keep the dependency at a compatible version |
| 214 | +- Use conditional package references for different targets |
| 215 | +- Find an alternative package |
| 216 | + |
| 217 | +**5. Update CI/CD First** |
| 218 | + |
| 219 | +Install all SDK versions in your CI pipeline before merging. This catches incompatibilities early: |
| 220 | + |
| 221 | +```yaml |
| 222 | +- name: setup .net core sdk |
| 223 | + uses: actions/setup-dotnet@v4 |
| 224 | + with: |
| 225 | + dotnet-version: | |
| 226 | + 8.0.x |
| 227 | + 9.0.x |
| 228 | + 10.0.x |
| 229 | +``` |
| 230 | +
|
| 231 | +**The Results** 📊 |
| 232 | +
|
| 233 | +After merging [PR #17](https://github.com/solrevdev/seedfolder/pull/17), the CI/CD pipeline automatically: |
| 234 | +
|
| 235 | +1. Built all three target frameworks |
| 236 | +2. Ran integration tests |
| 237 | +3. Packaged the NuGet package |
| 238 | +4. Published version 1.4.0 to NuGet |
| 239 | +
|
| 240 | +Users can now install the updated version: |
| 241 | +
|
| 242 | +```bash |
| 243 | +dotnet tool update --global solrevdev.seedfolder |
| 244 | +seedfolder --version |
| 245 | +# Output: seedfolder version 1.4.0 |
| 246 | +``` |
| 247 | + |
| 248 | +The tool automatically uses the highest installed SDK when run, so users with .NET 10 get the latest performance improvements while users on .NET 8 or 9 continue to work seamlessly. |
| 249 | + |
| 250 | +**Framework Support Timeline** 📅 |
| 251 | + |
| 252 | +Current support timeline for SeedFolder: |
| 253 | + |
| 254 | +| Framework | Type | Support Until | Status | |
| 255 | +|-----------|------|---------------|--------| |
| 256 | +| .NET 8.0 | LTS | November 2026 | ✅ Supported | |
| 257 | +| .NET 9.0 | STS | 18 months | ✅ Supported | |
| 258 | +| .NET 10.0 | LTS | November 2028 | ✅ Supported | |
| 259 | + |
| 260 | +**Lessons Learned** 🎓 |
| 261 | + |
| 262 | +1. **Multi-targeting is powerful**: Adding .NET 10 support while maintaining .NET 8 and 9 compatibility was trivial thanks to proper multi-targeting setup. |
| 263 | + |
| 264 | +2. **Dependency management matters**: Always check dependencies when upgrading. Sometimes staying on older (but stable) dependency versions is the right choice. |
| 265 | + |
| 266 | +3. **Testing is essential**: Local testing before publishing caught issues that automated tests might miss. |
| 267 | + |
| 268 | +4. **Documentation updates are important**: Users need to know what versions are supported and what's changed. |
| 269 | + |
| 270 | +5. **CI/CD automation pays off**: Once configured properly, the entire build-test-publish pipeline runs automatically on merge. |
| 271 | + |
| 272 | +**What's Next?** 🔮 |
| 273 | + |
| 274 | +With .NET 10 support in place, SeedFolder is well-positioned for the future. The next areas of focus include: |
| 275 | + |
| 276 | +- Template marketplace functionality ([Issue #15](https://github.com/solrevdev/seedfolder/issues/15)) |
| 277 | +- Additional project templates based on community feedback |
| 278 | +- Enhanced template customization options |
| 279 | + |
| 280 | +The full source code and history of this upgrade are available on [GitHub](https://github.com/solrevdev/seedfolder/pull/17). |
| 281 | + |
| 282 | +**Installation** 📦 |
| 283 | + |
| 284 | +Try the latest version with .NET 10 support: |
| 285 | + |
| 286 | +```bash |
| 287 | +# Install or update to the latest version |
| 288 | +dotnet tool update --global solrevdev.seedfolder |
| 289 | + |
| 290 | +# Create a new project with your favorite template |
| 291 | +seedfolder --template python my-new-project |
| 292 | + |
| 293 | +# Or use interactive mode |
| 294 | +seedfolder |
| 295 | +``` |
| 296 | + |
| 297 | +Success! 🎉 |
0 commit comments