left-icon

.NET Core Succinctly®
by Giancarlo Lelli

Previous
Chapter

of
A
A
A

CHAPTER 3

Playing with .NET Core

Playing with .NET Core


Installing .NET Core on Windows

Before we start to play with .NET Core, we must install it. The easiest way to do it is to visit https://www.microsoft.com/net/core and download the official MSI installer.

Installing .NET Core - Step 1

Figure 3: Installing .NET Core - Step 1

The installation process is straightforward, and once finished, we should be able to fire up PowerShell, type dotnet --info, and get the following output:

Successful .NET Core installation

Figure 4: Successful .NET Core installation


The .NET Core CLI (Command line interface)

The CLI comes with a series of common commands:

Common options (passed before the command)

Table 1: CLI's common options

Command Syntax

Description

-v | --verbose

Enable verbose output

--version

Display .NET CLI Version Info

Common commands

Table 2: CLI's common commands

Command Syntax

Description

new

Initialize a basic .NET project

restore

Restore dependencies specified in the .NET project

build

Build a .NET project

publish

Publish a .NET project for deployment (including the runtime)

run

Compile and immediately execute a .NET project

test

Run unit tests using the test runner specified in the project

pack

Create a NuGet package

Tip: This website automatically detects the version of your OS and selects the right setup option for you.

Creating a project with the .NET Core CLI

As we saw in the previous paragraph, thanks to the CLI, creating a new .NET Core application seems quite easy. In fact, it is easy. In order to try this out and start playing a bit with .NET Core, let’s open up PowerShell or the command prompt and navigate to a folder of your choice. In my case, I simply created a folder named dotnetcore in my User folder.

Once you feel like you are ready to go, type the following command: dotnet new. You should receive an output similar to the following.

Successful project creation through the CLI

Figure 5: Successful project creation through the CLI

If this is the first time you run the dotnet new command, the CLI will populate your local package folder so that the operation of restoring NuGet packages is faster. The CLI also warns you that since the tooling is still in preview, a lot of telemetry is collected. If you’re not comfortable with that, you can turn telemetry off. You can find more information about telemetry at https://aka.ms/dotnet-cli-telemetry.

This simple command created three files inside the current directory. If you happen to be playing with ASP.NET Core 1.0, you might be familiar with the one named project.json. If not, don’t worry—we will now explain the purpose of each one.


The list of files created by the new command

Figure 6: The list of files created by the new command

Project.json

The Project.json file is used in every project that uses NuGet 3.0, and it serves as a configuration file for both NuGet and Visual Studio. Inside it, we can specify our dependencies, reference frameworks, custom commands, and compile options. Starting from Visual Studio 2015, several project types are utilizing this technology, such as:

  • Universal Windows Platform managed apps (UWP)
  • Portable class libraries (PCL)
  • ASP.NET Core applications

Further information about this file can be found in the official NuGet documentation or in the ASP.NET Core 1.0 documentation (available on GitHub). The following is the content of the Project.json file generated by the .NET CLI:

{

  "version""1.0.0-*",

  "buildOptions": {

    "debugType""portable",

    "emitEntryPoint"true

  },

  "dependencies": {},

  "frameworks": {

    "netcoreapp1.0": {

      "dependencies": {

        "Microsoft.NETCore.App": {

          "type""platform",

          "version""1.0.1"

        }

      },

      "imports""dnxcore50"

    }

  }

}

As you can see, we are building our console application against the .NET Core Framework (identified by the TFM netcoreapp1.0), and we only have one dependency, Microsoft.NETCore.App. The full schema of the Project.json file can be found here.

Note: At the time of writing, the .NET team made an announcement about some changes to he project.json concepts. You can read more about it here.

Program.cs

This is easiest file to understand; it’s a basic C# file with a “Hello World” code snippet in it.

using System;

 

namespace ConsoleApplication

{

    public class Program

    {

        public static void Main(string[] args)

        {

            Console.WriteLine("Hello World!");

        }

    }

}

Transitioning from DNVM to the .NET CLI

Before starting to play with the CLI and compiling and running our .NET Core console application, we must first ensure that our environment is configured correctly. In order to do that, we must check to see if the DNVM (acronym of .NET Version Manager) is installed, and that we have the latest (in our case, the unstable) version of the runtime installed and set as active.

As its name implies, DNVM provides the functionality needed to configure your .NET runtime. We can use DNVM to specify which version of the DNX (.NET Execution Environment) to use at the process, user, or machine level.

The .NET Execution Environment (DNX) is a software development kit (SDK) and runtime environment that has everything you need to build and run .NET applications for Windows, Mac, and Linux. It provides a host processes, CLR hosting logic, and managed entry-point discovery. DNX was built for running cross-platform ASP.NET Web applications, but it can run other types of .NET applications, too, such as cross-platform console apps.

Checking where the DNVM utility is installed

When the .NET Team released the RC1 version of .NET Core and ASP.NET Core, they also announced DNX tooling. However, with RC2 they transitioned to the newly introduced .NET Core CLI. They had their reasons, one being that the set of features of this toolset was made redundant by the CLI.

Scott Hanselman wrote an amazing blog post when the transition was happening. Reading it may help you understand this complex decision better.

For those who are completely new the existence of this set of tools (DNX, DNVM, and DNU), perhaps only because you’ve just started working with .NET Core, all you need to know is that DNX was a runtime and a toolset used to build .NET Core and ASP.NET Core applications. It was divided into three main pieces:

  • DNVM (Dotnet Version Manager): Used to download and manage the runtimes in your machine
  • DNX (Dotnet Execution Runtime): The runtime that executes your code
  • DNU (Dotnet Developer Utility): Used to package and publish your app and managing dependencies

Now that .NET Core is an RTM version, the tools, which are still in preview, that we have available are the CLI interface and Visual Studio or Visual Studio Code. The .NET CLI comes in two flavors: It can be installer-specific for the development platform you are using, or it can be an install script, useful for scenarios such as a continuous integration server.

One of the differences between the two toolsets is that now, in order for you to target a specific version of the framework, you need to add a package of a certain version, whereas with the DNX toolset, that came free with the runtime selection features of DNVM.

Commands not available in the CLI that were available in DNX

With the change in the toolset, some commands were remapped, and some were removed. Basically, all the commands now start with dotnet instead of dnx or dnu. If you already learned where a specific command was, you now have to simply replace that with dotnet. Table 3 contains a full list of the commands that were removed in the CLI.

Table 3: Commands not implemented in the CLI

DNX Command

CLI Command

Description

Dnx [cmd-name]

N/A

In DNX, run a command as defined in project.json.

Dnu install

N/A

In DNX, install a package as a dependency.

Dnu wrap

N/A

In DNX, wrap project.json in csproj.

Dnu commands

N/A

In DNX, manage the globally installed commands.

More about the transition

The .NET team had a valid reason for deciding not to support those commands in the CLI. However, since this transition is not always painless, there are some workarounds in case you still need to leverage those mechanisms in the latest version of the tooling.

The Global Commands are no longer supported because they were essentially a console application packaged as a NuGet package that was then invoked by DNX. The CLI is unfamiliar with this concept. However, you can still use the dotnet <command> syntax to achieve the same result.

With the CLI, the install command isn’t needed. In order to install a dependency, you need to edit the project.json file and run dotnet restore. Finally, in order for you to run your code, you can use the dotnet run command from the same directory where you previously did dotnet new or you can specify the path to your compiled assembly to the dotnet command, such as dotnet assembly/debug/compiled.dll

The transition from the DNX toolset to the CLI also had an impact on the way a project is structured. For this reason, the team set up a nice how-to that demonstrates migrating a DNX project to a CLI project. You can read more about it at https://docs.microsoft.com/en-us/dotnet/articles/core/migrating-from-dnx#migrating-your-dnx-project-to-net-core-cli.

Compile and run a project with the .NET CLI interface

In order to compile and then run our basic console application, we must first restore the dependencies that we have previously described. In order to do that, we simply need to type in the command dotnet restore, and the .NET CLI should start restoring our packages. I suggest you to use the -v flag enable Verbose logging.

The output of the dotnet restore command

Figure 7: The output of the dotnet restore command

Once the restore process is complete, you should have a new file named project.lock.json in the root of your project. You don’t need to know all the internals of this file; however, we’ll talk more about this file shortly.

The folder structure after the dnu restore command

Figure 8: The folder structure after the dnu restore command

Now we are ready to compile our program using the build option of the CLI.

Output of a successful compilation

Figure 9: Output of a successful compilation

If we want to run our application, we simply have to type dotnet run, and if we did everything correctly, the output you get should be like the following:

A Hello World message from .NET Core

Figure 10: A Hello World message from .NET Core

Of course, in a realistic example we would have edited the Program.cs file with some more advanced code (maybe an HTTP request), but this is a good starting point. In the course of the book, we will build a more advanced console application that will leverage all the further knowledge we will gain about the .NET CLI interface.

The project.lock.json file, AKA the lock file

The project.lock.json file is what now can be considered a solution-level packages folder. It basically tells us what set of packages should be used at compile time by our application. It's a way to scope the list of packages in %userprofile%.dnx\packages so that projects run considering only the packages relevant to the project. The second purpose of the lock file is to store the list of files and relevant content for compilation and runtime so that the runtime only has to read a single file instead of many .nuspec files. In an ASP.NET Core workload on Azure, this cuts the startup time in half. The following code is a portion of our application lock file.

{

  "locked"false,

  "version": 2,

  "targets": {

    ".NETCoreApp,Version=v1.0": { /* many packages */}

  },

  "libraries": { /* many libraries */ },

  "projectFileDependencyGroups": {

    "": [],

    ".NETCoreApp,Version=v1.0": [

      "Microsoft.NETCore.App >= 1.0.1"

    ]

  },

  "tools": {},

  "projectFileToolGroups": {}

}

As always, the structure is defined using a JSON schema. Let’s analyze each node. At the top of the file is a “locked” property.  The “locked” property is a Boolean, and therefore supporting two schools of thought. However, we need to understand the “target” node before we can see the effect the locked property has.

The target node holds the list of all the packages that the app is using. One thing to notice is how it differs from the list inside the “unlocked” project.json file. Under each package node we have a list of all its dependencies and the path to the reference assembly and the runtime assembly.

Another difference from project.json is that here we can’t use wildcards and be vague about versioning. This small but important distinction is made to support two different schools of thoughts about checking in dependencies into source control. The first is to lock the dependencies, setting the locked property to true to avoid any broken compilation due to API changes. The second school of thought is to leave the lock file unlocked, with the locked property set to false, so that the restore process can pick the latest version of the dependency (having as an upper limit the ones defined in the project.json file). If you find yourself in the position of deciding between them, just know that if you use the default Visual Studio .gitignore file on GitHub today, project.lock.json is specified to not be committed to source control.

Side note on reference assemblies

Quoting Jared Parsons, Developer on the C# Compiler: “A reference assembly is a slimmed down version of an implementation assembly that contains the API surface but no real code. A program can reference these assemblies at compile time, but cannot run against them. Instead, at deploy time, programs are paired with the original implementation assembly. Breaking up assemblies into reference and implementation pairs is a useful tool for creating targeted API surfaces.” You can read more about Jared’s adventure in his blog.

Advanced settings for the .NET Core CLI commands

You might have noticed that in the previous paragraph, during the package restore step, we specified a -v parameter to enable more verbose logging. This should be enough to raise a series of more than justified questions: Are there any more options like that? And if there are, what commands are available? What do they do? How do I use them?

Luckily for you, discovering these options is quite easy; you just need to append the -h flag after the option name. Here’s an example:

PS F:\dotnetcore> dotnet <command> -h

The following tables show all the available flags for each command. When a command is omitted, it simply means that it does not have any flags available.

Command options for: dotnet restore

Option

Description

--force-english-output

Forces the application to run using an invariant, English-based culture

-s <source>

Specifies a NuGet package source to use during the restore

--packages <pkgDir>

Directory to install packages in

--disable-parallel

Disables restoring multiple projects in parallel

-f <feed>

A list of package sources to use as a fallback

--configfile <file>

The NuGet configuration file to use

--no-cache

Do not cache packages and HTTP requests

--infer-runtimes

Temporary option to allow NuGet to infer RIDs for legacy repositories

-v <verbosity>

The verbosity of logging to use. Allowed values: Debug, Verbose, Information, Warning, Error

--ignore-failed-sources

Only warning of failed sources if there are packages meeting version requirements


Command options for: dotnet build

Option

Description

-o <OUTPUT_DIR>

Directory in which to place outputs

-b <OUTPUT_DIR>

Directory in which to place temporary outputs

-f <FRAMEWORK>

Compile a specific framework

-r <RUNTIME_IDENTIFICATION>

Target runtime to publish for

-c <CONFIGURATION>

Configuration under which to build

--version-suffix

Defines what * should be replaced with in version field in project.json

--build-profile

Set this flag to print the incremental safety checks that prevent incremental compilation

--no-incremental

Set this flag to turn off incremental build

--no-dependencies

Set this flag to ignore project-to-project references and only build the root project

Command options for: dotnet publish

Option

Description

-f <FRAMEWORK>

Target framework to compile for

-r <RUNTIME_IDENTIFIER>

Target runtime to publish for

-b <OUTPUT_DIR>

Directory in which to place temporary outputs

-o <OUTPUT_PATH>

Path in which to publish the app

-c <CONFIGURATION>

Configuration under which to build

--native-subdirectory

Temporary mechanism to include subdirectories from native assets of dependency packages in output

--version-suffix <VERSION_SUFFIX>

Defines what * should be replaced with in version field in project.json

--no-build

Do not build projects before publishing

Command options for: dotnet run

Option

Description

-f <arg>

Compile a specific framework

-c <arg>

Configuration under which to build

-p <arg>

The path to the project to run (defaults to the current directory). Can be a path to a project.json or a project directory

<args>

Arguments to pass to the executable or script

Command options for: dotnet pack

Option

Description

-b <OUTPUT_DIR>

Directory in which to place temporary build outputs

-o <OUTPUT_DIR>

Directory in which to place outputs

-c <CONFIGURATION>

Configuration under which to build

--version-suffix <VERSION_SUFFIX>

Defines what * should be replaced with in “version” field in project.json

--no-build

Do not build project before packing

-s | --serviceable

Set the serviceable flag in the package

Command options for: dotnet test

Option

Description

--parentProcessId

Used by IDEs to specify their process ID. Test will exit if the parent process does.

--port

Used by IDEs to specify a port number to listen for a connection

-c  <CONFIGURATION>

Configuration under which to build

-o <OUTPUT_DIR>

Directory in which to find the binaries to be run

-b <OUTPUT_DIR>

Directory in which to find temporary outputs

-f  <FRAMEWORK>

Look for test binaries for a specific framework

-r  <RUNTIME_IDENTIFIER>

 Look for test binaries for a for the specified runtime

--no-build

Do not build project before testing

Compile a native version of our console application

Now that we have seen the wealth of options we have in our commands, let’s try one out. We will now build our console application, specifying the -n flag on the compile command. This will prompt the .NET CLI to run the compilation through the .NET Native toolchain. The .exe that pops out is bigger, but it is only a single file.

Tip: This option is no longer available in RC2. However, if you download any version of .NET Core prior to RC2, you should be able to follow along. You can find more information about this on GitHub.

In order to compile successfully with the --native flag, we must run the compilation from the VS2015 x64 Native Command Tools Command Prompt.

The VS2015 x64 Native Command Line

Figure 11: The VS2015 x64 Native Command Line

If you hit Enter, you should get this output (ignore the warning):

The console output of the native compilation

Figure 12: The console output of the native compilation

And of course, if we look into the output folder F:\dotnetcore\bin\Debug\dnxcore50\native, we should have only one file, our executable (notice how the size is slightly higher because of the native compilation).

Our native executable

Figure 13: Our native executable


Scroll To Top
Disclaimer
DISCLAIMER: Web reader is currently in beta. Please report any issues through our support system. PDF and Kindle format files are also available for download.

Previous

Next



You are one step away from downloading ebooks from the Succinctly® series premier collection!
A confirmation has been sent to your email address. Please check and confirm your email subscription to complete the download.