5 minute read
<RunCommand> in the .csproj to resolve Visual Studio launch problems, but these can be managed with targeted fixes. It is practical to convert class libraries right away and only tackle web apps if you want SDK-style or plan to move off System.Web soon.- SDK-style .csproj files simplify your build system, cut clutter, and prepare .NET Framework codebases for future upgrades even when staying on net481.
- Some legacy web project features like the Web tab and built‑in publishing cannot be restored once converted to SDK‑style and must be replaced with manual configuration. see why — jump to the section that argues this
- For ASP.NET MVC/WebForms projects, using the community MSBuild.SDK.SystemWeb is the recommended way to adopt SDK-style while preserving familiar build and debugging behavior. see why — jump to the section that argues this
- Convert all eligible class libraries to SDK-style immediately, using Upgrade Assistant/try-convert or manual edits, then run CI tests to verify everything still builds and passes.
- For ASP.NET MVC/WebForms projects you choose to convert, use the community MSBuild.SDK.SystemWeb to preserve familiar build, F5 debugging, and publishing behavior.
- Only convert web apps to SDK-style if you either want SDK-style via MSBuild.SDK.SystemWeb or accept the added friction; otherwise, leave them in the old format for now.
I’ve been working with a customer who, like many, is stuck in the past. They were on Team Foundation Version Control (TFVC), and the backbone of their application is .NET 4.5. This creates real problems for modern engineering practices because many new tools just won’t work, so I am moving to Git, and as part of that looking to ensure that their setup is future ready. I also need to do something with all those peskie legacy DLLs that are scattered around the solution. One of the key upgrades I was looking at is moving to SDK-style projects. This is a big deal because it’s the future of .NET development, and it’s a lot easier to work with than the old project format.
The good news: you can move to SDK-style projects even if you’re targeting older .NET versions.
For the Azure DevOps Migration Tools, a contributor did the upgrade, and the capabilities are outstanding:
- Simpler project file format – no more messy MSBuild clutter
- Supports
Directory.Build.propsto consolidate configuration across the solution - Supports
Directory.Packages.propsto consolidate NuGet versions and avoid DLL hell - Builds with
dotnet build(your mileage may vary)
Additional reasons to move to SDK-style projects:
- Easier multi-targeting support
- Better integration with modern CI/CD pipelines
- Cleaner diffs in source control
- Consistent experience across .NET Core, .NET 5+, and .NET Framework
- Improved support for analyzers and code quality tools
- Faster restore and build times in many cases
The Azure DevOps Migration Tools combine class libraries and executables, with a mix of .NET 4.8.1, netstandard2.0, and net8.0 – they all have to interoperate smoothly.
SDK-style .csproj files simplify your build system, cut the clutter, and prepare you for future upgrades. Here’s the pragmatic reality: Microsoft does not officially support converting classic ASP.NET MVC/WebForms projects to SDK-style. Class libraries? Straightforward. Web apps? That takes discipline, skill, and a willingness to dive into the details. With the right approach, you can absolutely get this working and keep IIS Express debugging alive.
Let’s break it down with radical clarity.
Class Library Conversion – No-Brainer
Class libraries are the easy win. They have minimal impact on code but make it massively easier to organise and maintain.
Use .NET Upgrade Assistant or
try-convertAutomate the rewrite:try-convert -p YourProject.csproj --keep-current-tfms --no-backupThis keeps you on
net481but upgrades the project format.Manual option if you want full control:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net481</TargetFramework> </PropertyGroup> </Project>Switch from
packages.configto<PackageReference>Drop the legacy baggage.Test thoroughly. Rebuild, run tests, and make sure everything resolves. This is not the time to skip CI.
In my experience, the “right-click on project” → Upgrade option in Visual Studio also works well.
ASP.NET MVC/WebForms Conversion – Tread Carefully
This is where it gets tricky. There’s no official support for MVC/WebForms in SDK projects, and it’s like wrestling a bear to get it all working.
There are two practical approaches:
1. Use the Community MSBuild SDK (Recommended)
Convert with:
try-convert -p YourWebApp.csproj --keep-current-tfms --no-backup --force-web-conversionChange the SDK line:
<Project Sdk="MSBuild.SDK.SystemWeb/4.0.97">
Why this works:
- Adds the missing web build magic (
System.Web, Razor, content files) - Supports F5 debugging, publishing, transforms
- Keeps you close to classic Visual Studio behaviour
Keep an eye on MSBuild.SDK.SystemWeb on GitHub for updates.
2. Manual Tweaks Without External SDK
Set the output correctly:
<OutputType>Library</OutputType> <OutputPath>bin\</OutputPath> <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>Define the run command:
<RunCommand>$(MSBuildExtensionsPath64)\..\IIS Express\iisexpress.exe</RunCommand> <RunArguments>/path:"$(MSBuildProjectDirectory)" /port:YOUR_PORT</RunArguments>Check or add launchSettings.json, but note that Visual Studio often ignores it without the
RunCommandfix.
Recommendation: Don’t waste time fighting Visual Studio. Use SystemWeb SDK if you want a sustainable setup.
Debugging Survival Guide
Debugging can be a pain, and in complex apps, it’s still hit-or-miss. But here’s what typically works:
If you get the “RunCommand not set” error, add <RunCommand> and <RunArguments> in your .csproj. This tells Visual Studio how to launch IIS Express.
If you see the “Debugging Release build” warning, go to Project > Build and uncheck “Optimize code” in Debug. Also, confirm <Optimize>false</Optimize> is set in the .csproj and do a full clean and rebuild.
If you’re attaching to a running process, enable “Suppress JIT optimization on module load” in the Visual Studio debugging options. This will let you step through code without the headache of optimized binaries.
Finally, check that your PDB files are loaded. Open the Modules window during debugging and make sure the symbols are picked up from your output directory. Without them, breakpoints won’t bind, and you’re debugging blind.
Known Limitations
Some things just won’t come back. The “Web” tab in the project properties is gone, but you can configure everything you need using the .csproj and launchSettings.
Out-of-the-box publish won’t work because it expects a .NET 5+ project. You’ll need to script your own publish steps to get the bits into the right place.
If needed, you can leave web apps in the old format and just convert the class libraries. That’s a pragmatic call if you’re not planning to touch System.Web long-term.
Subscribe to Martin's engineering notes
Writing since 2006
Engineering Notes, Technical Tuesday. One click to leave.
Final Recommendations
Here’s where it all comes together. These are the pragmatic, no-nonsense calls you should make after working through the conversion process.
Convert class libraries: Yes, immediately.
Convert web apps:
- Use MSBuild.SDK.SystemWeb if you want SDK-style.
- Skip if you’re staying on .NET Framework and want zero friction.
The point of this work isn’t to show off modern .csproj files. It’s to make your engineering system simpler, more maintainable, and ready for what’s next.
Enjoyed this? One click, no account.
Questions this answers
How do I convert legacy .NET Framework class library projects to SDK-style csproj while staying on net481?
You can use tools like .NET Upgrade Assistant, try-convert, or the Visual Studio right‑click Upgrade option to rewrite the project file to SDK-style while keeping the target framework at net481, or you can manually replace the old project XML with an SDK-style definition targeting net481, switch from packages.config to PackageReference, then rebuild and test thoroughly.
Can I convert an ASP.NET MVC or WebForms application to SDK-style and still use IIS Express debugging?
Yes, you can convert ASP.NET MVC/WebForms apps to SDK-style even though it’s not officially supported, either by using the community MSBuild.SDK.SystemWeb (recommended), which adds the necessary System.Web and web build support and preserves F5/IIS Express debugging, or by manually tweaking the SDK-style project to set the correct output type and RunCommand so Visual Studio knows how to launch IIS Express.
How do I fix Visual Studio debugging issues after converting an ASP.NET project to SDK-style?
If you get a "RunCommand not set" error, define RunCommand and RunArguments in your csproj so Visual Studio can launch IIS Express; if you see a "Debugging Release build" warning, disable code optimization in the Debug configuration and ensure DebugType is set correctly, then clean and rebuild; also enable "Suppress JIT optimization on module load" when attaching to processes and confirm that PDB symbols are loaded in the Modules window.
Smart Classifications
Each classification [Concepts, Categories, & Tags] was assigned using AI-powered semantic analysis and scored across relevance, depth, and alignment. Final decisions? Still human. Always traceable. Hover to see how it applies.
