Migrating from .NET Framework to .NET 5
This section provides information on how to migrate your projects from .NET Framework to .NET 5.
Switching to .NET 5 is caused by its ability to meet the cross-platform needs and create high-performance and scalable systems.
Migration Guide#
The project file (.csproj) can be divided into 5 parts:
- General properties for any configuration (release/debug, float/double)
- Configuration-related properties
- Links to libraries, including the UNIGINE ones
- List of the project .cs files
- PostBuildEvent, which copied the compiled file to the bin folder and transformed into the file of the project_name_x64[d].exe type
In .NET 5, parts 2, 3, and 5 become united, and PostBuildEvent now runs the utility that generates the component properties.
Therefore, manual migration of the project file contains the following steps:
- Moving the .csproj file to the project root folder.
- Migrating common properties.
- Migrating configuration-related properties.
- Configuring links to libraries.
- Adding PostBuildEvent for the automatic property file generation for all components.
1. Moving .csproj File to Project Root Folder#
.NET 5 / .NET Core implies that the project file is located in the root folder. That simplifies the work with the project in such environments as Visual Studio Code.
Therefore, you also need to change paths to folders and files: ..\bin should be changed to bin, AppSystemLogic.cs to source\AppSystemLogic.cs, etc.
2. Migrating Common Properties#
Compared to .NET Framework, .NET 5 project files became much simpler, and some elements are singled out to individual files (such as the project run settings, for example).
-
Remove all arguments of the <Project> tag.
Previously:
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
Now:
<Project>
-
Change WinExe to Exe to allow cross-platform running:
<OutputType>Exe</OutputType>
-
Delete the <TargetFrameworkVersion> and/or <TargetFrameworkProfile> tags, if any, and write the following instead:
<TargetFramework>net5.0</TargetFramework>
- The tags <ProjectGuid> and <AppDesignerFolder> can be deleted.
-
Delete these lines:
<Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> <Platform Condition="'$(Platform)' == ''">x64</Platform>
And use the following (if you have a float-based project, delete Debug-Double;Release-Double):
<Configurations>Debug;Release;Debug-Double;Release-Double</Configurations> <Platforms>x64</Platforms> <PlatformTarget>x64</PlatformTarget>
-
Add the following element to disable the automatic search of .cs files in the project. All necessary files are added by the Editor automatically or manually via the IDE. Disabling the automatic search significantly speeds up the build process:
<EnableDefaultItems>false</EnableDefaultItems>>
This will make the process of building the application significantly faster compared to the automatic search of all .cs files in your project.
Migrate <Import>. Previously there was only one import element in the project file:
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
Now there are two elements of this type. One of them is added at the very top of the project file, and the other — at the very bottom:
<Import Sdk="Microsoft.NET.Sdk" Project="Sdk.props"/> <Import Sdk="Microsoft.NET.Sdk" Project="Sdk.targets"/>
3. Migrating Configuration-Related Properties#
-
Previously, there was only <PropertyGroup> for each configuration. Now there is also <ItemGroup> to indicate which engine library is used for the specified configuration. (Platform) is not used in the Condition anymore.
Previously:
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
Now:
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
-
Remove <AssemblyName> from the common properties section and add to each configuration with its specific postfix: _x64, _x64d, _double_x64, _double_x64d. For example:
<AssemblyName>main_csharp_x64d</AssemblyName>
-
In <DebugType>, change the type from "pdbonly" and "full" to "portable", to allow the debug version run on Linux. It also makes sense to move it to the common properties section:
<DebugType>portable</DebugType>
- Delete the <PlatformTarget> element from the configuration-related properties, because we have already used it in the common properties.
- The <StartArguments> element is not used in .csproj files anymore. In the project root folder, create the folder named Properties, and create the file named launchSettings.json inside it. Use the commandLineArgs element to pass the command line arguments to the built application.
The launchSettings.json file has the following arrangement:
If you use Visual Studio Code as an IDE: in the project root folder, create the folder named .vscode, and create the file named launch.json inside it. In this case arguments are passed using the args key.{ "profiles": { "Project": { "commandName": "Project", "commandLineArgs": "-data_path ./data -console_command "world_load \"csharp_app\"", } } }
The launch.json file has the following arrangement:
{ "version": "0.2.0", "configurations": [ { "name": "Run Debug", "type": "coreclr", "request": "launch", "preLaunchTask": "build debug", "program": "${workspaceFolder}/bin/main_csharp_x64d.dll", "args": [ "-data_path", "./data" ], "cwd": "${workspaceFolder}", "console": "internalConsole", "stopAtEntry": false, } ] }
-
Add <ItemGroup> immediately below each configuration. The arrangement is as follows:
Use the corresponding postfix for each configuration.
<ItemGroup Condition="'$(Configuration)'=='Debug'"> <Reference Include="UnigineSharp_x64d"> <SpecificVersion>false</SpecificVersion> <HintPath>bin\UnigineSharp_x64d.dll</HintPath> </Reference> </ItemGroup>
4. Configuring Links to Libraries#
- System libraries: in .NET 5, you don't need to use links to system libraries anymore, therefore <Reference Include="System"/> can be deleted.
- UNIGINE libraries: we have already added them during the previous step, therefore, they can be deleted.
- External libraries: if any external libraries have been added, keep them as is.
5. Adding PostBuildEvent#
- Add the <SkipPostBuild> item with the false value. This is a part of optimization. The Editor and Build Tool will change this value to true, if you need to build the project, but there haven't been any changes in the source code components.
Add <SkipPostBuild> in the Common properties as well.
<SkipPostBuild>false</SkipPostBuild>
- Add the <DOTNET_HOST_PATH> item for the cross-platform purposes. In this case the project is always built using the dotnet tool on any platform.
Add <DOTNET_HOST_PATH> in the Common properties as well.
<DOTNET_HOST_PATH Condition="'$(DOTNET_HOST_PATH)' == ''">dotnet</DOTNET_HOST_PATH>
- In the bottom of the .csproj file, above the import of Sdk.targets, replace the old <PostBuildEvent> item to the <Target> item of the following arrangement:
If your project has a float precision, remove all _double and -Double postfixes. This target will run the tool that generates property files for all components used in the project.
<Target Name="PostBuild" AfterTargets="PostBuildEvent"> <Exec Command=""$(DOTNET_HOST_PATH)" "$(OutputPath)cspropgen_double_x64d.dll" -p "$(OutputPath)$(AssemblyName).dll" -data_path ../data/" Condition="'$(Configuration)'=='Debug-Double' And $(SkipPostBuild)=='false'"/> <Exec Command=""$(DOTNET_HOST_PATH)" "$(OutputPath)cspropgen_double_x64.dll" -p "$(OutputPath)$(AssemblyName).dll" -data_path ../data/" Condition="'$(Configuration)'=='Release-Double' And $(SkipPostBuild)=='false'"/> </Target>
Project File Example#
Here is an example of the .NET Framework project file and the same project file ported to .NET 5:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
<Platform Condition="'$(Platform)' == ''">x64</Platform>
<ProjectGuid>{2BFF5419-1600-4B67-D91D-4D9A45D3CDDD}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>UnigineApp</RootNamespace>
<AssemblyName>csharp_app</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<PlatformTarget>x64</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\bin</OutputPath>
<DefineConstants>TRACE;DEBUG;UNIGINE_DOUBLE;</DefineConstants>
<WarningLevel>4</WarningLevel>
<StartArguments>-data_path ../ -engine_config "../data/csharp_app/unigine.cfg" -console_command "world_load \"csharp_app\""</StartArguments>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<PlatformTarget>x64</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\bin</OutputPath>
<DefineConstants>TRACE;UNIGINE_DOUBLE;</DefineConstants>
<WarningLevel>4</WarningLevel>
<StartArguments>-data_path ../ -engine_config "../data/csharp_app/unigine.cfg" -console_command "world_load \"csharp_app\""</StartArguments>
</PropertyGroup>
<ItemGroup>
<Reference Include="System"/>
<Reference Include="System.Core"/>
<Reference Include="UnigineSharp">
<SpecificVersion>false</SpecificVersion>
<HintPath Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../bin/UnigineSharp_double_x64d.dll</HintPath>
<HintPath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../bin/UnigineSharp_double_x64.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="AppEditorLogic.cs" />
<Compile Include="AppSystemLogic.cs" />
<Compile Include="AppWorldLogic.cs" />
<Compile Include="main.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>if $(ConfigurationName) == Debug (
copy "$(TargetPath)" "$(TargetDir)$(ProjectName)_$(PlatformName)d.exe"
) else (
copy "$(TargetPath)" "$(TargetDir)$(ProjectName)_$(PlatformName).exe"
)
</PostBuildEvent>
</PropertyGroup>
</Project>
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<BaseIntermediateOutputPath>junk\csharp_app\</BaseIntermediateOutputPath>
</PropertyGroup>
<Import Sdk="Microsoft.NET.Sdk" Project="Sdk.props"/>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
<GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
<GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
<RootNamespace>UnigineApp</RootNamespace>
<StartupObject>UnigineApp.UnigineApp</StartupObject>
<WarningLevel>4</WarningLevel>
<IntermediateOutputPath>junk\csharp_app\$(Configuration)\</IntermediateOutputPath>
<OutputPath>bin</OutputPath>
<ApplicationIcon>source\common\Unigine.ico</ApplicationIcon>
<EnableDefaultItems>false</EnableDefaultItems>
<SkipPostBuild>false</SkipPostBuild>
<Configurations>Debug;Release;Debug-Double;Release-Double</Configurations>
<Platforms>x64</Platforms>
<PlatformTarget>x64</PlatformTarget>
<DebugType>portable</DebugType>
<DOTNET_HOST_PATH Condition="'$(DOTNET_HOST_PATH)' == ''">dotnet</DOTNET_HOST_PATH>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<AssemblyName>csharp_app_x64d</AssemblyName>
<DebugSymbols>true</DebugSymbols>
<Optimize>false</Optimize>
<DefineConstants>TRACE;DEBUG;</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(Configuration)'=='Debug'">
<Reference Include="UnigineSharp_x64d">
<SpecificVersion>false</SpecificVersion>
<HintPath>bin\UnigineSharp_x64d.dll</HintPath>
</Reference>
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<AssemblyName>csharp_app_x64</AssemblyName>
<Optimize>true</Optimize>
<DefineConstants>TRACE;NDEBUG;</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(Configuration)'=='Release'">
<Reference Include="UnigineSharp_x64">
<SpecificVersion>false</SpecificVersion>
<HintPath>bin\UnigineSharp_x64.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup/>
<ItemGroup>
<Compile Include="source/csharp/apps/main/**/*.cs"/>
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command=""$(DOTNET_HOST_PATH)" "$(OutputPath)cspropgen_x64d.dll" -p "$(OutputPath)$(AssemblyName).dll" -data_path ../data/" Condition="'$(Configuration)'=='Debug' And $(SkipPostBuild)=='false'"/>
<Exec Command=""$(DOTNET_HOST_PATH)" "$(OutputPath)cspropgen_x64.dll" -p "$(OutputPath)$(AssemblyName).dll" -data_path ../data/" Condition="'$(Configuration)'=='Release' And $(SkipPostBuild)=='false'"/>
</Target>
<Import Sdk="Microsoft.NET.Sdk" Project="Sdk.targets"/>
</Project>