Visual Studio 2017 introduced a new .csproj file format for C# project that is the key to move to .NET Standard but it is useful also for project with Full Framework, because is more human manageable.
The main drawback of this approach is that you end compatibility with older version of VS, if you open the .csproj with VS2015 you are not able to compile the project anymore. For this reason, switching to new format should be a decision that is well discussed in the team.
New project format is really human friendly, the only drawback is losing compatibility with older VS.
Luckily enough, when you have a solution with 68 project, you do not need to do all the work manually thanks to a nice tool found on GitHub, CsprojToVs2017. I’ve done manual conversion in the past, it is time consuming and frustrating, the above tools is not perfect but it does most of the work for you.
First of all I’ve run the tool to do a conversion of the entire solution without creating backup files (why should you take a backup when you can do all the test in a Git branch isolated from the rest of the code?).
csproj-to-2017 --no-backup .\mysln.sln
The tool output lots of information, warning and other suggestion, I simply stored in a file as reference but I immediately opened the solution to verify that it compiles successfully and the answer is no, but most of the work was already done for me.
Automated tool can do most of the work for you, but you will always do some manual work to finish and fine tune the conversion.
First of all the tool remove all the information of assembly from assemblyinfo.cs file, and in my situation it generates an error because I have AssemblyInformationalVersion in my assemblyinfo.cs, value of this attribute is “localCompile” and here what the tools generates.
Figure 1: Incorrectly Version generated by conversion tool
I still prefer all version information to be stored inside assemblyinfo.cs, so I removed all the version information from all .csproj file, added the attribute <GenerateAssemblyInfo>false</GenerateAssemblyInfo> to avoid automatic generation of assemblyinfo and finally reverted all the modification done to all assemblyinfo.cs to revert to previous content.
Then I start having a strange error:
Assets file …\obj\project.assets.json' not found. Run a NuGet package restore to generate this file
This error can be solved simply running a dotnet restore and in this particular situation it probably happens because in the sln file there are still a couple of web project that were not converted because web project still should use the old format. If we removed those two project from the solution everything compiles correctly, probably VS2017 got confused when a solution mixed the two types of project. The funny thing is that this error did not happened to every member of the team and happens only when we switched branch from a branch with the old format to the new format. This is usually not a big problem, when we switch branch we should only issue a git clean –xdf to clean every file not in source control, dotnet restore and we are ready to go. Now that we do not have active branches with the old format, this issue is gone away.
Then we start having some compilation errors because the new project formats includes automatically all .cs files inside project folders and during the years, some files were probably removed from the project , but they are still in the file system as you can see in following picture, where we have in the left the converted project to the right the original one.
As you can verify the file ConfigurationManagerProcessManagerConfiguration is present in file system but it is excluded from the project (right part of the picture) and it is incorrectly included by the new project format.
To solve this problem you should open side by side converted version of the project and original version and manually remove all cs files that are still in source code but are not referenced by the old project format, to avoid them to be incorrectly included after conversion.
One nice side effect of the conversion is that we found a bunch of files still in source control but not included in the solution
Then we have problem with Post Build Action, because we use Pre and Post build action to xcopy some files around but with the new format it seems not to work anymore. It turns out that in post build and pre build action some of the properties, as $(ConfigurationName) were not correctly populated, thus all the post and pre build actions generate error. The solution is really simple, convert them to a standard MsBuild Target as seen in the following snippet, where you can see the correct way to use xcopy and the original code that gets converted.
Conversion is really simple, original part is commented in the lower part of previous snippet, and it is composed by a series of xcopy command inside a PreBuildEvent. To made it work with the new csproj format the solution is adding a Target with a BeforeTarget=”PreBuildEvent” that will be run before the pre build event, then add a Exec task for each xcopy instruction. Remember also that the output folder is not bin/debug but you need to append the net461 (framework version).
The whole conversion took almost a couple of hours for a 68 project solution and thanks to the automatic conversion tool, most of the work was automated, we only need to tweak a little bit project files and solves some problems due to the fact that this is a 5 years old solution.
This conversion forces also you to review your build in VSTS or whatever build system you are using. I encountered a couple of modification to do to every build.
Once you switch to the new project version it is time to check the all automated builds.
- First of all I need to be sure that the version of NuGet used to restore dependencies should be set at minimum to 4.6. to be sure of the NuGet version used, you should use the couple of task NuGet Tool Installer plus Nuget, as I described in a previous post.
If you are using a wrong nuget version, probably the build solution will fail with an error like: Assets file ……\project.assets.json’ not found. Run a NuGet package restore to generate this file.
Another problem is due to switching between a branch that still uses old project format and branch that use the new format. It is imperative that obj folders are cleared because building again, or the build probably will fail. To accomplish this, I simply decide to clear everything before a get sources. (This was related to the issue I explained before.)
Symptoms of not clearing the obj folder are weird error like: Your project file doesn’t list ‘win’ as a “RuntimeIdentifier”. You should add ‘win’ to the “RuntimeIdentifiers” property in your project file and then re-run NuGet restore.
The overall process went smooth, and now we are ready to start the migration to dotnetcore.