As I wrote yesterday, I finally have the entire .NET Core runtime and tools installed on my Linux work laptop, including:
(I’m going to refer to ASP.NET 5 as ASP.NET Core from now on, as per the naming announcement.)
Last night I started testing various ASP.NET Core projects — which have, up to now, been running on the Mono runtime — on CoreCLR/CoreFx instead. So far they’ve all worked, although admittedly I am leaving the ones I am expecting problems with until last, especially those that use the more edge-casey parts of the Azure Storage SDK. 🙂
When I’ve got access to my big ol’ desktop box, I’m going to run some load tests against the various services running in both CoreCLR and Mono Docker containers, and I’ll publish the results of that experiment here.
But over the course of the last couple of days I’ve dug around in the various repositories of the dotnet organisation on GitHub, and what I’m seeing there is very exciting. And I’m not just talking about running on Linux.
The new CLI
dotnet CLI is very different from the
dnvm commands I’ve been using for the last year or so. Those are shell scripts (or Bash functions); if you
cat `which dnx` you can see the script, which runs a .NET DLL using Mono.
cat `which dotnet` you’ll get a screen full of gibberish, because
dotnet is a native executable.
I don’t know exactly what’s going on in there at present. Poking around in that
dotnet-nightly folder shows a lot of native executables that all seem to be the same size, which is odd, and maybe they’re just loaders for the .NET assemblies around them, but this is still pretty cool.
Curiosity about what made this possible led me to the CoreRT repository, which describes CoreRT as
a .NET Core runtime optimized for AOT (ahead of time compilation) scenarios, with the accompanying .NET Native compiler toolchain.
The what-now toolchain?
Hiding in the Documentation folder I found the intro-to-corert.md file, which explains what’s going on.
The developers of this project (which I think includes contributors both inside and outside Microsoft) are building a set of tools that will take MSIL byte-code (produced by compiling C# code using Roslyn), and ahead-of-time compile that to native x86/64 machine code.
The initial default implementation uses RyuJIT, the new 64-bit CLR JIT compiler (released last summer), to produce the machine code, but the toolchain can also use other compilers, including their own reference IL-to-C++ compiler (which is amazingly short) and LLILC, which is currently a JIT compiler for CoreCLR that uses LLVM, but which is intended to support AOT compilation in the future.
JIT compilers, as a rule, are optimised to do their job as quickly as possible, rather than to produce the best machine code possible.
An Ahead-Of-Time (AOT) compiler converts all the MSIL bytecode to native machine code up-front, for a specific target CPU and operating system, so you can distribute the application or library without the need for a separate runtime.
Because AOT compilers don’t have the same micro-time constraints as JIT compilers, in many cases they can produce more efficient, highly-optimised machine code.
CoreRT itself appears to be a modified version of the CoreCLR and libraries, with things organised in different ways and dependencies cleaned up. I’m speculating that this is — at least in part — to enable more efficient dead code elimination so that the native binaries are as small as possible.
This all means that C# is about to enter Go territory – a cross-platform, natively-compiled, garbage-collected programming language. Except, of course, that C# has modern language features like generics, async/await, etc.
Native ASP.NET Core
On that same page, under Roadmap, it says:
To start, we are targeting native executables (AKA "console apps"). Over time, we’ll extend that to include ASP.NET 5 apps…
So beyond even the current "XCOPY deployment" model for ASP.NET Core web applications, where you simply dump a directory tree onto a server, we can expect a "COPY deployment" model, where you just dump a single executable file. As the same page says, this could lead to Dockerfiles that look like this:
FROM debian:jessie EXPOSE 5000 ADD mycompiledapp.exe / # The .exe is just there to make a point :) ENTRYPOINT /mycompiledapp
It’s not clear whether this toolchain will be able to statically-link non-.NET libraries (e.g. libuv or libcurl) into the native binaries, or whether they’ll need to be installed alongside as dynamically-linked
.so files. Either way, this is going to make for very small Docker images, and containers that start up very quickly, but that train of thought quickly leads to wondering about unikernels… Will .NET Native be able to support those?
The preliminary answer, at least, would seem to be "Yes. Yes it will."
Obviously these projects are in the early stages, and it never does to get too excited too far in advance lest things are brutally murdered further down the roadmap, but all in all, I’d say it’s a good time to be a C# developer.
Hat tip: I was inspired to jump down this particular rabbit hole by Tugberk Ugurlu’s recent blog post about this stuff.