So, you’ve read up about .NET Core, and you’ve even installed the things that you need to have installed.

Now, we’re going to make a “Hello, World” application.

Hello, World in .NET Core

So the first thing you’ll want to do is fire up a terminal or command prompt.

I’m an old school guy, so you’ll have to forgive me for wanting to do this from the Terminal. Don’t worry, I’ll guide you through it.

Next you’ll want to create a directory called “HelloWorld”:

mkdir helloworld
cd helloWorld
view raw bash.sh hosted with ❤ by GitHub

Those commands should create a directory called “HelloWorld” on your file system and change into it. Now, we need to create a .NET Core project:

dotnet new
view raw bash.sh hosted with ❤ by GitHub

You should get a message back that is similar to the following:

Created new C# project in /Your/Directory/Here.
view raw bash.sh hosted with ❤ by GitHub

Where “/Your/Directory/Here” is the full path to where you just ran the command.
Creating a new .NET Core project will place two files in that directory.

It’s why we changed directory before we ran that command.

If you look in that directory, you’ll see two files:

  • Program.cs
  • project.json

Let’s take a look at these files

Program.cs

This is the actual source code of your new application. Here’s the contents of the Program.cs that was created when I created a new .NET Core project.

I’m creating a “Hello, World” project as I’m authoring this post.

using System;
namespace ConsoleApplication
{
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}
view raw program.cs hosted with ❤ by GitHub

As you can see, this is a perfectly created C# program that already does what we want it to.

If you’ve never seen C# syntax before, then take a look over here: https://docs.microsoft.com/en-us/dotnet/articles/csharp/index

Let’s take a look at the project.json

Project.json

{
"version": "1.0.0-*",
"buildOptions": {
"debugType": "portable",
"emitEntryPoint": true
},
"dependencies": {},
"frameworks": {
"netcoreapp1.0": {
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.0"
}
},
"imports": "dnxcore50"
}
}
}
view raw project.json hosted with ❤ by GitHub

If you’re familiar with GULP, GRUNT or any of the other similar Javascript task running systems, then this syntax should look familiar to you.

The dependencies Section

It seems silly to have to say it, but this is where you list your external dependencies. Lets say that you rely on Netwonsoft.Json to serialise and deserialise binary data to JSON, in that case you’ll list it in the dependencies section.

It’s pretty simple to do, heres the dependencies section of a project.json where I’ve referenced Newtonsoft.Json:

"dependencies": {
"Newtonsoft.Json" : "9.0.1"
}
view raw project.json hosted with ❤ by GitHub

To find the package names and version numbers, you’ll have to search on NuGet for them. There’s a way to do this from Visual Studio Code, but I’ll cover this in a later post.

However, just listing a dependency isn’t enough to go get it.

Those who have done .NET development on Windows will know that NuGet (which is where all of these packages live) is fantastic, and is a little similar to NPM but for .NET packages.

As with NPM, just listing a dependency isn’t enough. You have to tell .NET Core to actually go and download the dependency before you can build your project. So let’s go and do that.

Getting Dependencies

Once you’ve created a project, you’ll need to tell .NET Core to go grab the dependent libraries. To do this, from your terminal, issue this command:

dotnet restore
view raw bash.sh hosted with ❤ by GitHub

You should get a message back that is similar to the following:

log : Lock file has not changed. Skipping lock file write. Path: /Your/Diretory/Here/project.lock.json
log : /Your/Diretory/Here/project.json
log : Restore completed in 1208ms.
view raw bash.sh hosted with ❤ by GitHub

If .NET Core finds your project.json file, it will go out to NuGet and start downloading the packages that you need in order to build your application.

More information on the project.json file can be found here: https://docs.microsoft.com/en-us/dotnet/articles/core/tools/project-json

In the default project.json, .NET Core will find read this section and begin grabbing the libraries that it needs in order the build the project:

"frameworks": {
"netcoreapp1.0": {
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.0"
}
},
"imports": "dnxcore50"
}
}
view raw project.json hosted with ❤ by GitHub

Since we have no dependencies, .NET Core will not download any. But it will detect a framework, specifically “Microsoft.NETCore.App” version 1.0.0 and it will go download everything it needs for that.

The package files will be downloaded and stored to a hidden directory in your user’s home called .nuget/packages.

For more information on how this works, see the dotnet restore documentation here: https://docs.microsoft.com/en-us/dotnet/articles/core/tools/dotnet-restore

Once these are downloaded, a project.json.lock file will be created, and you can build your application.

When you build this project the future, .NET Core will look in the NuGet packages directory before attempting to download any packages or building your source code.

The project.json.lock file contains a list of all of the dependencies for your dependencies.

For example, in the default project.json we tell .NET Core that we require the “Microsoft.NETCore.App” framework. But this framework has dependencies of its own, so the project.json.lock file reflects the map of which packages are required for this framework.

You can see this by opening your project.json.lock file in a text editor, and you’ll see something like this:

project.json.lock
A project.json.lock file, based on the default project.json of an empty .NET Core console application

I’m using Visual Studio Code here, but you can use whatever text editor you like. And this file is massive, like 65+ thousand lines long.

When we come to it, we won’t be checking this file into source control because it will be in a state of flux, will be massive for real world applications, and can be generated each time that it’s needed. But source control is for another time.

Building

So you’ve created a .NET Core project and pulled the dependencies. Now what? Let’s build it. This step is the easiest, but the most fraught with danger.

This step will check whether you have the required packages downloaded, if not then it will go download them.

If all the packages are downloaded, then it will run through the build options of the project.json. Here’s our project.json’s build options:

"buildOptions": {
"debugType": "portable",
"emitEntryPoint": true
},
view raw project.json hosted with ❤ by GitHub

This tells the .NET Core compiler to build a portable executable, in debug mode. The “emitEntryPoint” flag tells the compiler whether you want to make a console application (if this is set to true) or a class library (more on this in another post).

Here’s the relevant line from CompilerOptions.cs from the DNX project:

var outputKind = compilerOptions.EmitEntryPoint.GetValueOrDefault() ?
OutputKind.ConsoleApplication : OutputKind.DynamicallyLinkedLibrary;

DNX (also known as Roslyn) is the .NET Core compiler, and you can read through this file at the GitHub page for it, here: https://github.com/aspnet/dnx/blob/dev/src/Microsoft.Dnx.Compilation.CSharp.Common/CompilerOptionsExtensions.cs#L70-L71

The next thing that the .NET Core compiler does is actually compile your C# source code. If there are any syntax or build errors, or any warnings, these will be displayed in your terminal.

Since we haven’t changed the code at all, there shouldn’t be any problems. So let’s build the code. To do this, issue the following command in the terminal:

dotnet build
view raw bash.sh hosted with ❤ by GitHub

This command tells .NET Core’s compiler to go and build you source code.

You should get a message back that is similar to the following:

Project HelloWorld (.NETCoreApp,Version=v1.0) will be compiled because expected outputs are missing
Compiling HelloWorld for .NETCoreApp,Version=v1.0
Compilation succeeded.
0 Warning(s)
0 Error(s)
Time elapsed 00:00:01.7556973
view raw bash.sh hosted with ❤ by GitHub

This tells us that our project (“HelloWorld” is used because that’s the directory name, but we can change this in the project.json if we want to) was compiled using .NETCoreApp version 1.0.0.

It also tells us that there were no errors or warnings, and that it took just under two seconds to build.

Let’s run the application, since it built successfully.

Running

We’re still doing all of this in the terminal, so let’s issue the following command to actually run out application:

dotnet run
view raw bash.sh hosted with ❤ by GitHub

If you issue this command before building your project, then .NET Core will go ahead and build it for you.

Because it’s nice like that.

You should get a message back that is similar to the following:

Project HelloWorld (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.
Hello World!
view raw bash.sh hosted with ❤ by GitHub

This tells us a bunch of stuff, primarily that .NET Core has detected that the project has already been built, so it wont build it again.

DNX (also known as Roslyn) will do some checking for you, each time that you run this command. If it detects changes in your source code, then it will re-build your project for you without even having to ask you.

It also provides us with the output of the compiled application:

Hello World!
view raw bash.sh hosted with ❤ by GitHub

Which, if you take a look back at our Program.cs, is exactly what we want the application to do:

using System;
namespace ConsoleApplication
{
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}
view raw program.cs hosted with ❤ by GitHub

So there you have it, your first .NET Core application.

Binaries

I’ll go into this in a deep dive post another time, but a quick word about the binaries.

If you look in the home directory of your source code, you’ll see a “bin” directory. This is where Roslyn places any compiled binary files.

Here’s a screenshot of what your bin directory might look like after compiling the “Hello, World” project:

bin Directory Screenshot
A screenshot of the bin directory after compiling a .NET Core project

In the screenshot, I’ve compiled a different project but it will be very similar for the “Hello, World” – only, the file names will be different. 

As was referenced in our project.json, we built in debug mode. This means that the compiled binary has some debug symbols which will allow use to attach a debugger when we run it, if we choose to.

This means that we can add breakpoints and step through the code, if we use something like Visual Studio or Visual Studio Code.

Also, our compiled binary is a .dll file.

Note: The following paragraph is correct at the time of writing (6th October 2016).

Native cross compilation has been disabled in .NET Core from RC2 onwards. This was announced on the official .NET Core Slack channel in mid 2016, and may be re-enabled in a later release of .NET Core.

When you run the project, all .dll files that were built in the build stage are loaded by the .NET Core runtime. They are then parsed into .NET Core’s Common Language Runtime and run on your machine.

I’ll go into this in more detail in a future post. But that’s the basics.

Conclusion

If you’ve followed the above steps, then you’ve created your first .NET Core project, restored all of the necessary packages and built a console application.

This cross platform, open source development stuff is pretty easy isn’t it?

Related Posts

A .NET developer specialising in ASP.NET MVC websites and services, with a background in WinForms and Games Development.

When not programming using .NET, he is either learning about .NET Core (and usually building something cross platform with it), speaking Japanese to anyone who’ll listen, learning about languages, writing for his non-dev blog, or writing for a blog about video games (which he runs with his brother)