Get Started With .NET Core on Docker

New .NET Core is the biggest change since the invention of .NET platform. It is fully open-source, componentised and is supported by Windows, Linux and Mac OSX. In this post I am going to give it a test ride by creating a containerized C# appliction with the latest .NET CORE CLI tool. I want to get a feel of how this experience is close to working with node.js or ruby.

Enviroment

Instead of installing .NET Core and CLI tool locally, I am going to use a .NET container as both the build and runtime environment. Offical .NET Docker images are hosted at https://hub.docker.com/r/microsoft/dotnet. Instructions on how to install Docker can be found from here: Mac , Windows, Linux.

##Application

I am building a solution to solve Poker hands problem. First, Lets get started by adding a project directory.

mkdir poker_hands
cd poker_hands

Then create a new project with the CLI tool

docker run --rm -v "$PWD":/src -w /src microsoft/dotnet:0.0.1-alpha dotnet new

The dotnet new command adds 3 new files into the working directory

NuGet.Config
Program.cs
project.json

NuGet.Config contains sources that NuGet packages can be loaded from. Program.cs contains application entry point which is a static Main method. Project.json is the project configuration file. Lets take a close look at it. (Note I have made changes to the generated one)

{
    "version": "1.0.0-*",
    "compilationOptions": {
        "emitEntryPoint": true
    },

    "dependencies": {
       "NETStandard.Library": "1.0.0-rc2-23811"
       "xunit": "2.1.0"
       "dotnet-test-xunit": "1.0.0-dev-128011-22"
    },

    "frameworks": {
        "netstandardapp1.5": {
          "imports": "dnxcore50"
       }
    }
}

emitEntryPoint is set to true, which tells .NET runtime to invoke Main method as entry point when the application runs. For class libraries, this setting is not needed.
In dependencies section, there is NETStandard.Library. This is a reference NuGet Package that references other packages such as System.Console, System.Collections. Unlike .NET framewokr, .NET Core is pay-to-play. To use Console, Collections, Linq and other features in code, corresponding packages must be installed as dependencies. The frameworks section lists all the Frameworks this application supports. Since I am targeting .NET Core only, just netstandardapp1.5 is included. The imports section maps old dnxcore50 to this new moniker. It is also possible to add “net46” to frameworks section. That will enable the application to support .NET framework 4.6. However, doing so will make this application lose its ability to run on a Linux runtime.

To make this application a self-contained docker image, we need a Dockfile

FROM microsoft/dotnet:0.0.1-alpha
RUN mkdir /src
WORKDIR /src
ADD . /src
CMD sh run.sh

run.sh is a helper script that calls restore and build before run

dotnet restore 
dotnet build
dotnet run

Run the application

docker build -t problem54 .
docker run -rm -v $(pwd):/src --rm  problem54 

If everything goes well, you are going to see “Hello World” printed out in the terminal. Not a very exciting application so far.

Unit testing

My first attempt was to use NUnit. However, NUnit console (and the underlying NUnit Engine) do not support running unit tests against .NET core yet. There is a work around according to this answer to my question on Stack Overflow. I gave it a try and it did work. Then I switched to XUnit which comes with a runner supports .NET Core. To use XUnit, add xunit and dotnet-test-xunit into dependencies section:

"dependencies": {
   "xunit": "2.1.0"
   "dotnet-test-xunit": "1.0.0-dev-128011-22",
   "NETStandard.Library": "1.5.0-rc2-23931"
}

and add this line to the project.json

"testRunner": "xunit"

Now add a test file and first test.

Poker_hands_tests.cs

using Xunit;
using Poker.models;

namespace Poker.tests
{
    public class Hand_tests {
        [Fact]
        public void Hight_card()
        {
            var result = Game.Judge("8C TS KC 9H 4S 7D 2S 5D 3S AC");
            Assert.True(result == 0);
        }
    }
 }

And update the run.sh to

dotnet restore 
dotnet build
dotnet test

Run tests:

docker run -rm -v $(pwd):/src --rm  problem54 

Following the green-red-refactory process, add tests and implementation until all scenarios are covered. Then we get a solution. The final code can be found here.

Summary

In this post I have shown how we can develop and run an application based on .NET Core in a Docker container. Although be in the very early stages, the .NET Command Line Interface tool seems to be as easy to use as NPM or bundler.