Visual Studio 2017 and NuGet
Visual Studio 2017 is out and its been amost a month since its release. Some time ago I was working on a Electron and Kestrel Series when I was reading about Visual Studio and net core. The articles talked about the tooling and how project.json is going away and csproj is going to be coming back as the net core project file. I was pessimistic because csproj has been pretty awful to work with in the past. In the end though the new csproj format is pretty nice. This article is nice introduction to the changes in csproj and how they relate to the project.json file.
So I put my series on hold until I could dive in to the new tools. Visual Studio 2017 launched and I started to use it. At first I was really hopeful everything seemed to be much faster and smoother then I remembered in past visual studios. Over time though I found many bugs and crashes that were uncharacteristic of my past experiences in Visual Studio 2017. Overall I think that VS 2017 was pushed out way to early. I think if they had waited till Build to release, it would of been better overall.
That said there are still some really compelling features that are must haves and make going to VS 2017 worth the bugs and issues. These are my overall favorite features
- Targeting multiple frameworks from a single project
- Include all files by default
- Better NuGet integration (when it works)
- Better Installation process
- Ability to edit csproj without unloading project
- Memory/CPU Diagnostic tools continue to get better
Lets breakdown a couple of those item and talk about the new csproj format. The new csproj format exists alongside the old format making VS 2017 able to load both formats at once. The new format while regulated to only the netcore templates can be used to build any .Net Framework including .Net 4.0 . The best parts of this new format is the clean and unclutter feel of the format. Here is a sample from one of my projects.
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>netcoreapp1.1</TargetFramework> <PackageTargetFallback>portable-net45+win8</PackageTargetFallback> <OutputType>Exe</OutputType> <RuntimeIdentifier>win10-x64</RuntimeIdentifier> </PropertyGroup> <ItemGroup> <Folder Include="wwwroot\" /> </ItemGroup> <ItemGroup> <PackageReference Include="LiteDB" Version="3.1.0" /> <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore" Version="1.1.1" /> <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.2" /> <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="1.1.1" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="1.1.1" /> <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="1.1.1" /> <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.Design" Version="1.1.1" /> <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.1" /> <PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" Version="1.1.0" /> <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="1.1.0" /> </ItemGroup> <ItemGroup> <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="1.0.0" /> </ItemGroup> </Project>
Thats it comparing it to another csproj from the old format you can see it lacks much of the clutter. There is only one property group not 15 and each file does not have to be manually included. On top of that you can do new and interesting things like targeting multiple frameworks. Changing TargetFramework to TargetFrameworks like such:
This allows you to target multiple frameworks and while in visual studio you can easily switch between the different frameworks to get the intellisense applicable to that framework. VS 2017 also has it built into the intellisense telling you when something is not supported in one of the frameworks you are targeting. This whole experience is amazing. For me I have constantly been working to make my software and libraries support as many different .Net Frameworks as possible. Until recently I was stuck on .Net 4.0 while some at my company worked on .Net 4.5.2, Xamarin, and Net Core. When I created libraries I had to figure out how to support all those frameworks which basically came down to multiple csproj files and linking files between projects. It was an utter mess and this new way is a million times better.
Of course this all fall apart when we get to NuGet support for this. NuGet packages have always supported targeting multiple frameworks but for VS 2017 it takes a big step back in my opinion. I found many issues and wierd design choices that I will go over in another article but lets just say that NuGet in the new csproj format doesn’t work that great. In theory it should work but in execution it falls on its face.
When installing a nuget package that only targets some of the frameworks and not all it does this:
<ItemGroup Condition="'$(TargetFramework)' == 'net45'"> <PackageReference Include="NuGet.Core"> <Version>2.14.0</Version> </PackageReference> </ItemGroup> <ItemGroup Condition="'$(TargetFramework)' == 'net461'"> <PackageReference Include="NuGet.Core"> <Version>2.14.0</Version> </PackageReference> </ItemGroup>
This basically says that it will target net461 and net45 but not netstandard1.4 for the nuget package ‘NuGet.Core’. If you try to do the following though to clean it up it will crash Visual Studio outright.
<ItemGroup Condition="'$(TargetFramework)' == 'net45' || '$(TargetFramework)' == 'net461'"> <PackageReference Include="NuGet.Core"> <Version>2.14.0</Version> </PackageReference> </ItemGroup>
I am not sure if this is supported but Visual Studio probably shouldn’t be crashing on something as simple as this. Also why is NuGet using the long form of PackageReference when the short form could also be used easily:
<PackageReference Include="NuGet.Core" Version="2.14.0" Condition="'$(TargetFramework)' == 'net461'" /> <PackageReference Include="NuGet.Core" Version="2.14.0" Condition="'$(TargetFramework)' == 'net45'" />
This looks much cleaner than the above version. Most likely nuget is expecting there will be more NuGet packages that fall into one or the other groups either net45 or net461 and is setting up the groups in anticipation. I feel as though thats up to the user though, if they want that kind of organization. Also I have on multiple occasions seen the NuGet targeting fail where it thinks a .Net 4.5 library can’t be used on net461 (it can!) and other strange occurences. Overall it really sours the targeting multipe frameworks feature.
Overall Visual Studio 2017 is great step forward into the Net Standard, Net Core world. I just wish that Visual Studio software had longer lives my company only purchase vs 2015 last year and I am already begging them to purchase the next version. It really grinds my gears that I have to purchase another visual studio to get these features and C# 7 when these could easily be released as an update to 2015. Then again we all have to make money some way.