Share Code Between Legacy .NET Framework and Modern .NET Apps
- 3 minutes to read
Migrating a WinForms application from .NET Framework 4.7.2+ to .NET 8+ can be a complex and time-consuming process. Legacy dependencies, API changes, and platform differences require extensive testing before the .NET version is production-ready. To ensure business continuity, many teams choose to maintain both .NET Framework and .NET versions in parallel until the migration is fully tested.
This help topic outlines strategies to manage both versions while maximizing code reuse. To support both .NET Framework and .NET 8+, consider one of the following strategies:
- Multi-targeting in a single project
- Recommended for libraries and shared components.
- Two separate project files (.csproj) sharing a common .props file
- Useful for applications with different build settings or dependencies.
Tip
Analyze Dependencies
- Identify dependencies that are not compatible with .NET.
- Update Nu
Get packages to versions that support both .NET Framework and .NET 8+. - Replace deprecated APIs with cross-platform alternatives.
#Multi-Targeting in a Single Project
Use SDK projects and target multiple frameworks in a single .csproj file to maintain a unified codebase. This technique can be used for libraries and components that must work across both frameworks.
TargetFrameworks
specifies multiple targets.- Conditional package references include only necessary dependencies per target.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFrameworks>net8.0-windows;net472</TargetFrameworks>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DevExpress.Win" Version="25.1.3" />
</ItemGroup>
<ItemGroup Condition=“'$(TargetFramework)' == 'net472'”>
</ItemGroup>
</Project>
Note
Visual Studio supports design-time editing for only one target framework at a time in multi-targeted projects. It uses the first framework listed in the Target
property. The following setting forces Visual Studio to use the .NET (Core-based) Win
<TargetFrameworks>net8.0-windows;net472</TargetFrameworks>
To use the .NET Framework Designer instead, reverse the order:
<TargetFrameworks>net472;net8.0-windows</TargetFrameworks>
Use #if
directives to separate framework-specific implementations:
string GetEnvironmentInfo() {
#if NET472
return "Running on .NET Framework";
#elif NET8_0_OR_GREATER
return "Running on .NET 8+";
#else
return "Unknown Framework";
#endif
}
Pros | Cons |
---|---|
Maintains a single project structure. | Larger project files with multiple conditions. |
Easier code maintenance and refactoring. | Some dependencies may not support multi-targeting. |
Centralized build process. | Build tools must support SDK-style projects (VS 2019+). |
#Separate Projects with a Shared ‘.props’ File
For applications requiring different build configurations or dependencies, use two .csproj files that import a shared .props file:
- Shared properties are defined in DXApplication.Shared.props.
- Separate .csproj files allow you to use distinct dependencies and settings.
The application structure is usually as follows:
/DXApplication/
├── DXApplication.NET.csproj
├── DXApplication.FW.csproj
├── DXApplication.Shared.props
└── /Shared/ (actual code files)
<Project>
<ItemGroup>
<Compile Remove="obj*\**"/>
<None Remove="obj*\**"/>
<Content Remove="obj*\**"/>
<None Remove="DXApplication.Shared.props"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="DevExpress.Win" Version="25.1.3"/>
</ItemGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<Import Project="DXApplication.Shared.props" />
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<OutputType>WinExe</OutputType>
<UseWindowsForms>true</UseWindowsForms>
<BaseIntermediateOutputPath>obj.FW</BaseIntermediateOutputPath>
</PropertyGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="DXApplication.Shared.props" />
<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<OutputType>WinExe</OutputType>
<UseWindowsForms>true</UseWindowsForms>
<IntermediateOutputPath>obj.NET</IntermediateOutputPath>
</PropertyGroup>
</Project>
Pros | Cons |
---|---|
More control over framework-specific configurations. | Requires managing multiple project files. |
Clear separation of dependencies and build settings. | Possible code duplication. |
Easier debugging and targeted optimization per framework. | More complex build and deployment pipelines. |