The joys of .NET Core

I wanted to check out this whole .NET Core business, so I downloaded it and started hacking. Oh, and I’m using Linux, so it’s all command line. Recipe for success, right? Let’s dive in!

So, I did the obvious thing, added the dotnet-core apt repository to my system and ran a quick apt-get install dotnet-dev-1.0.1. Then it’s off to a new directory to make a project.

First thing I did, since I read an article or two:

$ dotnet new
Template Instantiation Commands for .NET Core CLI.

Usage: dotnet new [arguments] [options]

  template  The template to instantiate.

And then it’s got a list of options and templates. It also implies that some of the templates might not be shown.

Okay, well, I’m going to make a library, a test library, and a command line program, so I’ll probably want a solution too.

$ dotnet new sln
$ dotnet new classlib --name MyLibrary
$ dotnet new xunit --name MyLibrary.Test
$ dotnet new console --name MyConsoleApp
$ dotnet run
Couldn't find a project to run. Ensure a project exists in  /home/dhasenan/Projects/Testing/core/foo.
Or pass the path to the project using --project

Well, there are three projects, so maybe that’s the problem. Trying again:

$ dotnet run --project MyConsoleApp
Run a NuGet package restore.

Well, actually, it gave me about 1.5 screens of red text. But I’ll try that.

$ nuget package restore
Unknown command: 'package'
$ nuget restore
$ dotnet run --project MyConsoleApp
Run a NuGet package restore.

Fuck you. I just ran that. But I had read a couple articles, so I had some inkling that dotnet had its own nuget command built in:

$ dotnet nuget restore
Specify --help for a list of available options and commands.
error: Unrecognized command or argument 'restore'

Some more hunting reveals the existence of another command:

$ dotnet restore
warning : Unable to find a project to restore!
$ dotnet run --package MyConsoleApp
Run a NuGet package restore.


Turns out, creating a project doesn’t add it to the solution. And dotnet restore looks for projects from a solution file. Because the dotnet core CLI team hates us, I guess. I started hunting down the sln file format (with no success) and then found out about dotnet sln.

$ dotnet sln add MyConsoleApp
Project `MyConsoleApp` does not exist.
$ dotnet sln add MyConsoleApp/MyConsoleApp.csproj
Project `MyConsoleApp/MyConsoleApp.csproj` added to the solution.

Consistency is too much to ask for, apparently — I have to refer to the path to the project file here, but everywhere else so far, I can use the package name.

$ dotnet restore
  Restoring packages for foo/MyConsoleApp/MyConsoleApp.csproj...
  Generating MSBuild file foo/MyConsoleApp/obj/MyConsoleApp.csproj.nuget.g.props.
  Generating MSBuild file foo/MyConsoleApp/obj/MyConsoleApp.csproj.nuget.g.targets.
  Writing lock file to disk. Path: foo/MyConsoleApp/obj/project.assets.json
  Restore completed in 355.34 ms for foo/MyConsoleApp/MyConsoleApp.csproj.
  NuGet Config files used:
  Feeds used:
$ dotnet run
Couldn't find a project to run.

It can find projects to restore by looking at the solution, but it can’t find projects to run from the same file. Let’s try again, using small words that it might have a chance of understanding.

$ dotnet run --project MyConsoleApp
[five-second hang]
The project file could not be loaded. Access to the path 'foo/MyConsoleApp' is denied.

The path exists. I just created it with this very tool! I can list it and cd into it and modify files in it and everything!

Another bit of consistency: dotnet sln uses backticks to enquote the path. This uses single quotes. I’m not even disappointed anymore.

Let me have another go:

$ dotnet run --project MyConsoleApp/MyConsoleApp.csproj
Hello World!
$ cd MyConsoleApp
$ dotnet run
Hello World!

I think the openssl command line tool is better, overall. I mean, it’s even more arcane, but it’s doing a lot of stuff, and it even has interactive prompts for a lot of things. Recipes for specific use cases are widely published. This is a narrower focus, and it’s less predictable. The error messages lie to you left and right.

And it still takes over a second to run a hello world program. How do I fix that? There’s no .exe for me to point Mono at, even if Mono were compatible, which it isn’t. The only executable in /usr/share/dotnet that looks appropriate is corehost:

$ corehost MyConsoleApp/bin/Debug/netcoreapp1.1/MyConsoleApp.dll 
The specified framework 'Microsoft.NETCore.App', version '1.1.1' was not found.
  - Check application dependencies and target a framework version installed at:
  - Alternatively, install the framework version '1.1.1'.

Helpful. Telling it to use some other version that looks more installed doesn’t fix its problem — system-wide stuff seems to be using a different directory. Some more digging:

$ dotnet publish -c Release
$ corehost MyConsoleApp/bin/Debug/netcoreapp1.1/MyConsoleApp.dll
The specified framework 'Microsoft.NETCore.App', version '1.1.1' was not found.
$ dotnet publish -c Release -r ubuntu.16.04-x64
Assets file 'MyConsoleApp/obj/project.assets.json' doesn't have
a target for 'ubuntu.16.04-x64'. Restore the project.

I need to manually edit my project files to add a fixed list of supported targets. Do all my dependencies need the same platforms? What if .NET Core for WebAssembly comes out next week?

Best of all, this error message doesn’t tell me how to fix the problem! It doesn’t link to documentation that explains it.

Turns out you can run a DLL representing a console application with the dotnet utility itself — not that it’s documented:

$ dotnet publish -c Release
$ dotnet run MyConsoleApp/bin/Debug/netcoreapp1.1/MyConsoleApp.dll
Hello World!

The dotnet core team needs to fix this.

And yes, using the VS Code plugin fixes some of these issues, but not all of them. You can’t create projects or add them to solutions using VS Code, except as a text editor that lets you run shell commands. Which is no better than vim or emacs. It doesn’t fix the documentation to tell you how to run things.