Last updated .

DNX - what is it?

A google search for DNX reveals that it's something about digital nomads - it-savvy people living and working out of 3rd world countries. But it's also the acronym for the next major development on the .Net platform. It is short for ".NET Execution Environment". Somewhat ironically, Microsoft is working hard to relieve itself of .Net and make it open source and cross platform. DNX is both an SDK and a runtime environment that comes with everything needed to build and run .NET applications. Not only on Windows, but also on Linux and Mac.

Why?

A survey of the available info suggests there are essentially these three motivations behind DNX:

With these motivations, Microsoft created a light-weight and cross-platform version of the .NET framework, called .NET Core. It includes a subset of class libraries from the full .NET framework. It has a corresponding runtime called CoreCLR. .NET core lacks some well-known libraries such as System.Drawing, System.Windows and other libraries that are coupled to the Windows platform. This poses some practical challenges in developing solutions based on .Net Core.

DNX - the .Net eXecution environment - contains everything required to bootstrap and run a .Net app. It includes the compilation system, SDK tools and the native CLR host, with NuGet packages being used to get assemblies referenced by the solution.

Anatomy of a Visual Studio 2015 DNX project

DNX is installed with Visual Studio 2015. At the time of writing, the latest version is v1.0.0-rc1-15540. With RC1 installed, I can make a DNX project with Visual Studio. There are three project templates to choose from - all grouped under the Web Category. This is probably due to the fact that the development of a new DNX-based version of ASP.Net has been the driving force. Still, it is a bit surprising to see a Console type of application in that category. Let's create one of those and see what comes out of it:

New Console Application (Package) project
New Console Application (Package) project

The project composition as shown in solution explorer sure looks outlandish. That structure is an almost direct reflection of the file structure on disc. One thing to notice is the lack of a project file in the traditional sense. Instead, the project.json file functions as a container for project settings, weighing in at just 677 bytes! Compiling the solution brings another new experience: There is no visible output! There is no bin directory, no Obj directory, no exe file.

What does that project file contain?

project.json
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
{ "version": "1.0.0-*", "description": "DNXConsole02 Console Application", "authors": [ "Niels" ], "tags": [ "" ], "projectUrl": "", "licenseUrl": "", "compilationOptions": { "emitEntryPoint": true }, "dependencies": { }, "commands": { "DNXConsole02": "DNXConsole02" }, "frameworks": { "dnx451": { }, "dnxcore50": { "dependencies": { "Microsoft.CSharp": "4.0.1-beta-23516", "System.Collections": "4.0.11-beta-23516", "System.Console": "4.0.0-beta-23516", "System.Linq": "4.0.1-beta-23516", "System.Threading": "4.0.11-beta-23516" } } } }
The project in solution explorer
The project in solution explorer

Let's try writing some code:

program.cs
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
using System; namespace DNXConsole02 { public class Program { public static void Main(string[] args) { Console.WriteLine("Hello DNX!"); Console.ReadLine(); } } }

As you'd expect this code compiles just fine and I can run it from within Visual Studio as usual. But there is no output to be found on disc. I found a Publish command, available from a context menu when the project node is right-clicked in solution explorer. Clicking on that I create a MyProfile profile and get this:

2 DNX targets and 2 processor architectures gives 4 options
2 DNX targets and 2 processor architectures gives 4 options
The application is published to a subfolder of the solution
The application is published to a subfolder of the solution

I selected the default target DNX and clicked Publish. After a little while, a slew of files and folders have been added to the solution directory and a few files have been added to the project for the newly created "publish profile":

Folder structure under solution ("DNXConsole02")
approot folder contents
Solution explorer view

The contents of the [Solution folder]\artifacts\bin\DNXConsole02\Release\PublishOutput\approot folder (see above) looks promising. There is a cmd file named DNXConsole02.cmd. Running that gives me an instance of the console app I just wrote:

And what does that command file contain, then? This:

DNXConsole02.cmd
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
@echo off SET DNX_FOLDER=dnx-clr-win-x86.1.0.0-rc1-update1 SET "LOCAL_DNX=%~dp0runtimes\%DNX_FOLDER%\bin\dnx.exe" IF EXIST %LOCAL_DNX% ( SET "DNX_PATH=%LOCAL_DNX%" ) for %%a in (%DNX_HOME%) do ( IF EXIST %%a\runtimes\%DNX_FOLDER%\bin\dnx.exe ( SET "HOME_DNX=%%a\runtimes\%DNX_FOLDER%\bin\dnx.exe" goto :continue ) ) :continue IF "%HOME_DNX%" NEQ "" ( SET "DNX_PATH=%HOME_DNX%" ) IF "%DNX_PATH%" == "" ( SET "DNX_PATH=dnx.exe" ) @"%DNX_PATH%" --project "%~dp0src\DNXConsole02" --configuration Release DNXConsole02 %*

In this script, if I read it correctly, every line except the last one is about establishing a path to a dnx.exe executable. It is then executed with project and configuration parameters. As it turns out, the path to dnx.exe is resolved as C:\Projects\DNXConsole02\artifacts\bin\DNXConsole02\Release\PublishOutput\approot\runtimes\dnx-clr-win-x86.1.0.0-rc1-update1\bin\dnx.exe and the project argument is set to C:\Projects\DNXConsole02\artifacts\bin\DNXConsole02\Release\PublishOutput\approot\src\DNXConsole02. (The solution folder in this case is C:\Projects\DNXConsole02).

That project folder contains, among other things, a copy of the source code for my project: a Program.cs file and a Properties\AssemblyInfo.cs file. There is also a copy of the project.json file and a project.lock.json file. The latter file is not identical to the file of the same name in the Visual Studio project, though. The one in the Visual Studio projects is 78 kb in size, while this one is only 507 bytes.

'Project' folder

The conclusion to draw from all this can only be that the "Publish" operation does not produce any binary output by itself. Instead, the source code is copied to a publish folder together with dependencies and the dnx.exe file. When that .cmd file is executed, it spawns dnx.exe, which in turn causes a compilation of the source code, ending in the console app being run. Well, actually, there is no DNXConsole02.exe being run (that file doesn't even exist). Instead, there is a running instance of dnx.exe, which goes away when I close the command window. In other words, my console program is being hosted by dnx.exe. All dependencies needed in the compilation of the program are found in the runtimes\dnx-clr-win-x86.1.0.0-rc1-update1\bin subfolder.

The Visual Studio experience

Targeting DNX 4.5.1 and DNX Core 5.0, you can quickly meet some stumbling blocks writing code. It's one thing that Windows-specific .Net libraries such as System.Windows are a no-go, but that is not all. Since the sample I just made is a console app, it is natural to investigate what I can do now in that environment. Not as much as I used to, it seems! Attempting to use the Console.Beep method, I get this in the editor:

Beeping is prohibited
Console members

In the intellisense, that method has a yellow warning icon on it, and the pop-up tip tells me that member is not available on Core 5.0. If I complete the statement, my project won't compile. The tip told me that I can use the navigation bar to switch context. The navigation bar is the name for the dropdowns at the top of the code editor window. In the leftmost one I can pick one of the options DNX 4.5.1 or DNX Core 5.0. But I don't see the point; it doesn't make a difference in the code editor and it's not compiling under either setting. Leave out the call to Beep, that's what I can do. It turns out about half of the members of the Console class are marked as not cross-platform. Luckily, I can still use ReadLine and WriteLine!

It would be instructive to see which assemblies are actually loaded in the process when the console app is run from Visual Studio. There are some settings on the project property page that provide a clue: Under the Debug tab, you can see that when a Debug build is launched by pressing F5, it will run under .Net Framework x86:

Debugging under 1.0.0-rc1-update1, .Net Framework, x86

The Modules window lists the loaded assemblies. Notice that some are taken from the GAC. These are the assemblies that would go into a 'normal' console app. Others are fetched from my Users directory; these are the DNX assemblies. DNX.exe is the host process.

Modules loaded under 1.0.0-rc1-update1, .Net Framework, x86

Let's see what it looks like when running under 1.0.0-rc1-update1, .Net Core, x64:

Debugging under 1.0.0-rc1-update1, .Net Core, x64

Again, the Modules window lists the loaded assemblies. The set of assemblies is completely different now, but the Microsoft.DNX.* assemblies are loaded in both cases.

Modules loaded under 1.0.0-rc1-update1, .Net Core, x64

Managing the execution environment

DNX comes with a set of tools to manage it all on the client machine. The management central is the DNVM utility (.Net Version Manager), which is really just a PowerShell script. DNX is installed to a C:\Users\[Username]\.dnx folder and dnvm.cmd is found a bin subfolder. That path is in the PATH environment variable, so dnvm can be started from any directory. Starting it with no arguments causes it to list available commands:

DNVM

As you might gather from the command names, dnvm is used to manage the dnx local installation. With DNVM, you can specify which version of the .NET Execution Environment to use at the process, user, or machine level. Another tool is dnx. It is used for compiling and running source code. To experiment with that I started Notepad and added a Program.cs file and a project.json file to a new C:\Temp\DNX Sandbox folder:

Program.cs
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
using System; namespace DNX_Testing { public class MyClass { public static void Main(string[] args) { Console.WriteLine("I am dynamically compiled!"); Console.ReadLine(); } } } project.json
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
{ "version": "1.0.0-*", "description": "My DNX Console Application", "authors": [ "Anonymous" ], "tags": [ "" ], "projectUrl": "", "licenseUrl": "", "compilationOptions": { "emitEntryPoint": true }, "dependencies": { }, "commands": { "DNXTest": "DNXTest" }, "frameworks": { "dnx451": { }, "dnxcore50": { "dependencies": { "Microsoft.CSharp": "4.0.1-beta-23516", "System.Collections": "4.0.11-beta-23516", "System.Console": "4.0.0-beta-23516", "System.Linq": "4.0.1-beta-23516", "System.Threading": "4.0.11-beta-23516" } } } }

Opening a command prompt in that C:\Temp\DNX Sandbox directory, I attempted to run my code using dnx run. But it doesn't just work. First, do a dnvm use [runtimeVersion] command to indicate which runtime to use, then dnu restore to refresh dependencies. I have emphasized the commands with orange boxes in the screenshot below:

Compiling source code and running it using dnvm, dnu and dnx
Compiling source code and running it using dnvm, dnu and dnx

DNU is another command-line tool used to manage library packages in an application, or to package and publish our an application. Packages need to be downloaded every time you edit dependencies in project.json. As shown above, use the dnu restore command after editing this section of the file. When using Visual Studio, this is all handled behind the scenes.

2016 by Niels Hede Pedersen Linked in