WARNING: This post is full of internal technical stuff. I think it's interesting and useful. You may not.
I had an interesting Error/Warning happen when showing some folks .NET Core recently and I thought I'd deconstruct it here for you, Dear Reader, because it's somewhat multi-layered and it'll likely help you. It's not just about Core, but also NuGet, Versioning, Package Management in general, version pinning, "Tools" in .NET Core, as well as how .NET Runtimes work and version. That's a lot! All that from this little warning. Let's see what's up.
First, let's say you have .NET Core installed. You likely got it from http://dot.net and you have either 1.0.0 or the 1.0.1 update.
Then say you have a website, or any app at all. I made one with "dotnet new -t web" in an empty folder.
I added "dotnet watch" as a tool in the project.json like this. NOTE the "1.0.0-*" there.
"tools": {
"Microsoft.DotNet.Watcher.Tools": "1.0.0-*"
}
dotnet watch is nice because it watches the source code underneath it while running your app. If you change your code files, dotnet-watch will notice, and exit out, then launch "dotnet run" (or whatever, even test, etc) and your app will pick up the changes. It's a nice developer convenience.
I tested this out on last weekend and it worked great. I went to show some folks on Monday that same week and got this error when I typed "dotnet watch."
C:\Users\scott\Desktop\foofoo>dotnet watch
The specified framework 'Microsoft.NETCore.App', version '1.1.0-preview1-001100-00' was not found.
- Check application dependencies and target a framework version installed at:
C:\Program Files\dotnet\shared\Microsoft.NETCore.App
- The following versions are installed:
1.0.0
1.0.1
- Alternatively, install the framework version '1.1.0-preview1-001100-00'.
Let's really look at this. It says "the specified framework...1.1.0" was not found. That's weird, I'm not using that one. I check my project.json and I see:
"Microsoft.NETCore.App": {
"version": "1.0.1",
"type": "platform"
},
So who wants 1.1.0? I typed "dotnet watch." Can I "dotnet run?"
C:\Users\scott\Desktop\foofoo>dotnet run
Project foofoo (.NETCoreApp,Version=v1.0) will be compiled because expected outputs are missing
Compiling foofoo for .NETCoreApp,Version=v1.0
Hosting environment: Production
Content root path: C:\Users\scott\Desktop\foofoo
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.
Hey, my app runs fine. But if I "dotnet watch" I get an error.
Remember that dotnet watch and other "tools" like it are not dependencies per se, but helpful sidecar apps. Tools can watch, squish css and js, precompile views, and do general administrivia that isn't appropriate at runtime.
It seems it's dotnet watch that wants something I don't have.
Now, I could go install the framework 1.1.0 that it's asking for, and the error would disappear, but would I know why? That would mean dotnet watch would use .NET Core 1.1.0 but my app (dotnet run) would use 1.0.1. That's likely fine, but is it intentional? Is it deterministic and what I wanted?
I'll open my generated project.lock.json. That's the calculated tree of what we ended up with after dotnet restore. It's a big calculated file but I can easily search it. I see two things. The internal details aren't interesting but version strings are.
First, I search for "dotnet.watcher" and I see this:
"projectFileToolGroups": {
".NETCoreApp,Version=v1.0": [
"Microsoft.AspNetCore.Razor.Tools >= 1.0.0-preview2-final",
"Microsoft.AspNetCore.Server.IISIntegration.Tools >= 1.0.0-preview2-final",
"Microsoft.DotNet.Watcher.Tools >= 1.0.0-*",
"Microsoft.EntityFrameworkCore.Tools >= 1.0.0-preview2-final",
"Microsoft.Extensions.SecretManager.Tools >= 1.0.0-preview2-final",
"Microsoft.VisualStudio.Web.CodeGeneration.Tools >= 1.0.0-preview2-final"
]
Ah, that's a reminder that I asked for 1.0.0-*. I asked for STAR for dotnet-watch but everything else was very clear. They were specific versions. I said "I don't care about the stuff after 1.0.0 for watch, gimme whatever's good."
It seems that a new version of dotnet-watch and other tools came out between the weekend and my demo.
Search more in project.lock.json and I can see what all it asked for...I can see my dotnet-watch's dependency tree.
"tools": {
".NETCoreApp,Version=v1.0": {
"Microsoft.DotNet.Watcher.Tools/1.0.0-preview3-final": {
"type": "package",
"dependencies": {
"Microsoft.DotNet.Cli.Utils": "1.0.0-preview2-003121",
"Microsoft.Extensions.CommandLineUtils": "1.1.0-preview1-final",
"Microsoft.Extensions.Logging": "1.1.0-preview1-final",
"Microsoft.Extensions.Logging.Console": "1.1.0-preview1-final",
"Microsoft.NETCore.App": "1.1.0-preview1-001100-00"
},
Hey now. I said "1.0.0-*" and I ended up with "1.0.0-preview3-final"
Looks like dotnet-watch is trying to bring in a whole new .NET Core. It wants 1.1.0. This new dotnet-watch is part of the wave of new preview stuff from 1.1.0.
But I want to stay on the released and supported "LTS" (long term support) stuff, not the new fancy builds.
I shouldn't have used 1.0.0-* as it was ambiguous. That might be great for my local versions or when I intend to chase the latest but not in this case.
I updated my version in my project.json to this and did a restore.
"Microsoft.DotNet.Watcher.Tools": "1.0.0-preview2-final",
Now I can reliably run dotnet restore and get what I want, and both dotnet watch and dotnet run use the same underlying runtime.
Sponsor: Big thanks to Telerik! They recently launched their UI toolset for ASP.NET Core so feel free to check it out or learn more about ASP.NET Core development in their recent whitepaper.
© 2016 Scott Hanselman. All rights reserved.