About a year ago my team inherited a somewhat neglected solution. VS 2010 solution with VS 2008 projects, a "Dependencies" folder containing reference assemblies such as NewtonSoft.Json.dll v.6.5 - the usual. The previous owner could not let us use their build system - so naturally we had to do something about that too.
A little googling led me to CsprojToVs2017 which also let's you upgrade to VS 2019. Only about 100 projects to the solution, so how long could it take? Just over a month on a separate branch - which sucks, because every little change on "develop" needs to be merged back, and when your csproj-file is changed, you are out of luck. You have to do a diff on develop to find the actual change made and translate that change to the new 2019 format and manually merge the change. Another sucky thing is how msbuild behaves when confronted with a mixed set of csproj-versions: Phantom cyclic project dependencies is one such thing, and it doesn't go away until you convert every single project in your dependency graph.
Lesson 1: Don't do a prolonged solution conversion, assign the whole team to the conversion and finish it in one sitting. Optionally make sure to merge back to develop frequently.
Which takes us to the next hard-earned lesson: If when using VS2019 format the default nuget restore will put an "assets.project.json" file in your /obj folder. VS2008-VS2015 do something entirely different, so everytime a project was upgraded, we needed everybody to clean/restore the affected project. But the build-system (in our case Jenkins) needs to be instructed to clean (naturally) but also that the restore as part of the build target is not sufficient. I inserted a separate msbuild /t:Restore in the build pipeline.
Also, as part of the build pipeline, we're building a WebApplication (NetFX) project. These are not upgradable, so of course building this requires us to nuget restore this project on its own.
Lesson 2: Nuget behavior changes, and solution with mixed projects need a little tender love and care. "ls obj -Recurse | rm -Force -Recurse" was heavily used
Msbuild has an option to specify an alternative /obj -folder: "/p:BaseIntermediateOutputPath=c:\foo" which is useful if you're building multiple projects in your pipeline and want to make sure that dependent assets aren't reused. Unfortunately this is not playing nice with
nuget restore / dotnet restore
The reason is that packages are restored to the /obj folder and not the BaseIntermediateOutputPath/obj - which means that your compilation will be missing the dependencies. The symptom will be a missing assets.json file reported by msbuild. There'll be many hints and hacks if you google it. Ultimately I had to abandon BaseIntermediateOutputPath all together.
Lesson 3: VS 2019 csproj and dotnet restore do not play nice with Msbuild - go for simplicity in your build pipeline.