We’ve got a bunch of projects at work that are using the old style project file format. And since we’re already on Visual Studio 2017 and Rider, we were looking to new csproj format were the most interesting benefit would be it’s simplicity.

This is a how to guide on how to approach a such migration and description of few tricky moments and issues encountered.

Read the docs…

… or at least keep them at hand:


Using the Visual Studio Installer check that you have next components:

  • .NET Core cross-platform development workload
  • Targeting packs and SDKs for the version of the framework that you’re targeting

Upgrading the project

Simplest part. Replace the context of csproj with these lines:

<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">

Upgrading package references

Preparetive step, not strictly necessary. Go to Nuget settings of your IDE of choice and set “Default package management format” to “PackageReference”.

There’s an important difference while using new PackageReference compared to previous packages.config. New format includes only “top level” packages - ones that you reference directly in your code. As such don’t blindly add every package found in packages.config as a PackageReference. Instead:

  • Compile the project without any references
  • Follow compilation errors and edge them out one-by-one by adding missing packages

Cleanup & miscellaneous

  • Remove AssemblyInfo.cs. Check if it contains any useful attributes & set them in project properties or csproj directly
  • Remove packages.config
  • Remove packages folder in solution root

Dealing with embedded resources

If project contains any content/resource files, Include them explicitly in csproj:

    <Content Include="Mappings.csv">

Or, as embedded resources using wildcards:

    <EmbeddedResource Include=".\**\*.json" Exclude=".\bin\**\*.json;.\obj\**\*.json" />

Nuget integration

The new msbuild took over for some manipulations related to nuget packages. So this area will need to be reviewed. Some particular items:

  • nuspec files, if used, have to be referenced from csproj files explicitly
  • nuspec files can be avoided completely and properties defined directly in csproj
  • nuget pack will not work anymore. dotnet pack or the equivalent msbuild /t:pack have to be used to generate nuget packages.

Actually, the common package related pattern will be: msbuild /t:restore;build;pack.

Pitfalls & possible issues

  • New project will pick up all .cs files in the project file directories and sub-directories. Some leftovers might get in the project. Fix: review & remove unnecessary.
  • Warnings about binding redirects. Fix: open app.config and remove mentioned assemblies.
  • Compilation errors in AssemblyInfo.cs about duplicated definitions. Fix: remove AssemblyInfo.cs
  • Output folder now includes target framework moniker. Example: bin\Debug\net462. If any build or deployment scripts are relying on old path, then it has to be fixed.
  • Additional files that have to exist in output folder aren’t automatically included. Fix: any additional resource files have to be included explicitly in new csproj.
  • Directory.GetCurrentDirectory() returns a different thing than before. Affects Directory.Exists, Directory.CreateDirectory and probably any other API that are accepting relative paths. Apparently, new CLI tooling is setting default Working Directory (in both VS2017 and Rider) to location of the project file, contrary to output folder.
  • nuget pack will not work anymore. dotnet pack or the equivalent msbuild /t:pack have to be used to generate nuget packages.

Build server woes (TeamCity)

We’ve got TeamCity on the build duty. Few things were needed there to support building of new project format:

  • Update Nuget Tools to a version that supports the new msbuild tooling (4.x will do)
  • To get the new msbuild tools on agents most reasonable option will be to use Build Tools for Visual Studio 2017.
  • If you’re getting this error: error MSB4236: The SDK 'Microsoft.NET.Sdk' specified could not be found. then install .NET Core Build Tools payload. Event if the app isn’t targeting .NET Core, this payload is still needed to correctly handle PackageReference in csproj.
  • Build configuration was probably stamping the assembly with version. Previously common approach was to update AssemblyInfo.cs before passing it to msbuild. As we got rid of this file, we can achieve same results by passing Version parameter to msbuild.