The .NET Core 2.0 Preview 1, version numbers and global.json

So as I'm sure most people reading this are aware, Microsoft announced ASP.NET Core and .NET Core 2.0 Preview 1 at Microsoft Build 2017 this week. I've been pretty busy with a variety of things, so I wasn't really planning on checking out most of the pieces for now. I've been keeping an eye on the community standups so I kind of knew what to expect. But after watching the video of Scott Hanselman and Dan Roth, and reading Steve Gordon's blog post, I couldn't resist!

If you haven't already, I really recommend you check out the various links above first - this post isn't really meant to serve as an introduction to ASP.NET Core, it focuses on installing the preview on your system while you continue to work on production ASP.NET Core 1.0/1.1 sites. In particular, it looks at the different version numbers associated with .NET Core.

Shortly after writing this, I realised Scott Hanselman had just written a very similar post, check it out!

Installing the .NET Core 2.0 Preview 1 SDK

The first step is obviously installing the .NET Core 2.0 Preview 1 SDK from https://www.microsoft.com/net/core/preview#windowscmd. This is pretty painless, no matrix of options, just a "Download now" button. And there's just one version number!

One interesting point is that .NET Core now also includes ASP.NET Core. That should mean smaller packages when deploying your applications, which is nice! I'll be exploring this at some point soon.

It's also worth noting that if you want to create ASP.NET Core 2.0 applications in Visual Studio, then you'll need to install the preview version of Visual Studio 2017. This should install side-by-side with the stable version, but I decided to just stick to the SDK for now while I'm just playing with it.

.NET Core version numbers

I pointed out just now that there's finally only one version number for the various .NET Core parts - 2.0 preview 1 - but that's not entirely true.

There are two different aspects to a .NET Core install: the version number of the SDK/Tools/CLI; and the version number of the .NET Core runtime (or .NET Core Shared Framework Host).

If you've just installed 2.0 preview 1, then when you run dotnet info you should see something like the following:

$ dotnet --info
.NET Command Line Tools (2.0.0-preview1-005977)

Product Information:  
 Version:            2.0.0-preview1-005977
 Commit SHA-1 hash:  414cab8a0b

Runtime Environment:  
 OS Name:     Windows
 OS Version:  10.0.14393
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\2.0.0-preview1-005977\

Microsoft .NET Core Shared Framework Host

  Version  : 2.0.0-preview1-002111-00
  Build    : 1ff021936263d492539399688f46fd3827169983

This gives you a whole bunch of different values, but there are two different versions listed here:

  • 2.0.0-preview1-005977 - the CLI version
  • 2.0.0-preview1-002111-00 - the runtime version

But these version numbers are slightly misleading. I also have version 1.0 of the .NET Core tools installed on the machine, as well as versions 1.1.1 and 1.0.4 of the .NET Core runtime.

Understanding multiple .NET Core runtime versions

One of the selling point of .NET Core is being able to install multiple versions of the .NET Core runtime side-by-side, without affecting one another. This is in contrast to the way .NET Framework works as a central install - you can't install version 4.5, 4.6 and 4.7 side-by-side withe the .NET Framework; 4.7 will replace the previous versions.

You can see which versions of the .NET Core runtime are installed by browsing to C:\Program Files\dotnet\shared\Microsoft.NETCore.App. As you can see, I have 3 versions available on my machine:

So the question is, how do you know which runtime will be used when you run an application?

Well, you specify it in your .NET .csproj file!

For example, in a .NET Core 1.1 project, you would set the <TargetFramework> (or <TargetFrameworks> if you're targeting more than one) to netcoreapp1.1:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp1.1</TargetFramework>
  </PropertyGroup>

</Project>

This will use the .NET Core version 1.1.1 that I have installed when it runs.

If you had set <TargetFramework> to netcoreapp1.0 then the version 1.0.4 that I have installed would be used.

Which brings us to the version 2.0 preview 1 .csproj:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.0</TargetFramework>
    <UserSecretsId>aspnet-v2test-32450BD7-D635-411A-A507-53B20874D210</UserSecretsId>
  </PropertyGroup>

  <ItemGroup>
    <Folder Include="wwwroot\" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0-preview1-final" />
  </ItemGroup>

</Project>  

As before, the csproj file specifies that the <TargetFramework> should be netcoreapp2.0, so the newest version of the 2.0 runtime on my machine will be used - 2.0.0-preview1-002111-00.

Understanding the SDK versions

Hopefully that clears up the .NET Core runtime versions, but there's still the issue of the SDK/CLI version. What is that used for?

If you navigate to C:\Program Files\dotnet\sdk, you can see the SDK versions installed on your system. I've got two versions installed on my machine: 1.0.0 and 2.0.0-preview1-005977.

It's a bit of an over-simplification, but you can think of the SDK/CLI as providing all of the "build" related commands, dotnet new, dotnet build, dotnet publish etc.

Generally speaking, any SDK version higher than the one used to create a project can be used to dotnet build and dotnet publish it. So you can use the 2.0 SDK to build projects created with the 1.0 SDK.

So in that case, you can just use the newer SDK all the time right? Well mostly. If you're still building project.json based projects then you need to ensure you use the RC2 SDK.

The current version of the SDK also becomes apparent when you call dotnet new - if you are using the 2.0 Preview 1 SDK, you will get a 2.0-based application, if you're using the 1.0 SDK you'll get a 1.1 based application!

The question is how do you control which version of the SDK is used?

Choosing an SDK version with global.json

The global.json file has a very simple schema, that simply defines which version of the SDK to use:

{
  "sdk": {
    "version": "1.0.0"
  }
}

Back in the day, the global.json was also used to define the source code folders for a "solution", but that functionality was removed with the 1.0.0 SDK.

When you run dotnet new or dotnet build, the dotnet host looks in the current folder,and all parent folders up to the drive's root for a global.json. If it can't find one, it will just use the newest version of the SDK - in my case 2.0.0-preview1-005977.

If a global.json exists (and the SDK version it references exists!) then that version will be used for all SDK commands, which is is basically all dotnet commands other than dotnet run.

Personally, I've put the above global.json in my Repos folder, so any existing projects will continue to use the 1.0.0 SDK, as will any new projects I create. I've then created a subfolder called netcore20 and added the following global.json. I can then use this folder whenever I'm playing with the ASP.NET Core 2.0 preview bits without risking any issues!

{
  "sdk": {
    "version": "2.0.0-preview1-005977"
  }
}

Summary

Versioning has been an issue throughout the recent history of .NET Core. Aligning all the versions going forward will definitely simplify things and hopefully cause less confusion, but it's still a good idea to try and understand the difference between runtime and SDK versions. I hope this post has helped clear some of that up!