Thursday, January 5, 2017

Doing a Self-Contained Deployment (SCD) of a .NET Core Application on Ubuntu

Before moving on I am assuming that you have the basic knowledge on .NET Core and application development targeting .NET Core.

In this post let’s see how we can do a Self-Contained Deployment (SCD) on a Ubuntu machine where there is no .NET Core SDK is installed.

So basically that’s the most important aspect of doing a SCD, we are no longer dependent on a machine wide framework. Framework is bundled with the our application (and third party dependencies if any) and it will get run on top of that. Where as in FDD (Framework-Dependent Deployment), we are deploying only the application (and third party dependencies if any). The application will get run on top of the framework which is installed on the machine.

(Some important thing to note here, in .NET Core Application Deployment documentation under SCD it says, "Creating an SCD does not, however, include the native dependencies of .NET Core itself on various platforms (for example, OpenSSL on macOS) so these need to be installed before running the application.". So there is a list of dependencies for Ubuntu and I have not installed any of those. I was confused about that. Thanks to fellow MVP @WilliamIvanski, I got some explanation from him. His explanation is as follows,

"-dev packages contain headers that allows one to recompile software that depend on these libraries. If you need to only run such software, the package without -dev may be installed. For example, libicu/libicu{somenumber} may be already installed. That's why your application runs fine. You'll need *-dev packages if you want to compile dotnet itself. ". Well that answered my question. When I checked for those packages, they were already installed upon OS installation.)

Here let’s start by creating a Console Application targeting .NET Core. I am using Visual Studio 2015 Update 3.

(You need to note that for this demo, I am using the latest stable versions of tools and frameworks as of today. There is a possibility that some of this will get changed in the future. For instance, I will be using project.json and it will get removed in Visual Studio 2017. But all we really need to do is understanding the concept.)
image
Console Application (.NET Core)
Having said that, I have created the project. This is what my default project.json looks like (this may be different from yours and it is based on the version of .NET Core tools that you have installed).
{
  "version": "1.0.0-*",
  "buildOptions": {
    "emitEntryPoint": true
  },
 
  "dependencies": {
    "Microsoft.NETCore.App": {
      "type": "platform",
      "version": "1.0.1"
    }
  },
 
  "frameworks": {
    "netcoreapp1.0": {
      "imports": "dnxcore50"
    }
  }
}
Here I am going to remove imports section and instead of targeting .NET Core 1.0, I am going to target .NET Core 1.1 as it’s the latest.
{
  "version": "1.0.0-*",
  "buildOptions": {
    "emitEntryPoint": true
  },
 
  "dependencies": {
    "Microsoft.NETCore.App": {
      "type": "platform",
      "version": "1.1.0"
    }
  },
 
  "frameworks": {
    "netcoreapp1.1": {
      
    }
  }
}
Now let’s do the changes which is required to make this application to be deployed as SCD.
{
  "version": "1.0.0-*",
  "buildOptions": {
    "emitEntryPoint": true
  },
 
  "runtimes": {
    "ubuntu.16.04-x64": {}
  },
 
  "dependencies": {
    "Microsoft.NETCore.App": {
      "version": "1.1.0"
    }
  },
 
  "frameworks": {
    "netcoreapp1.1": {
      
    }
  }
}
Here, first thing I did was removing the type=”platform” element. That is what specifies whether this is going to be a SCD or FDD. Here I have also specified the Ubuntu runtime (my Ubuntu installation is 16.04.1) as it’s mandatory when doing a SCD. You can find the list of .NET Core Runtime IDentifiers (RID) here).

Now I have modified program.cs to print "Hello World" to the console. Nothing fancy over there.
public class Program
{
    public static void Main(string[] args)
    {
        System.Console.WriteLine("Hello World");
    }
}
Now let’s move into dotnet CLI, and do the build and release. I am not going to run dotnet restore, as I was using Visual Studio and it was doing the package restoration upon project.json changes for me. If you are on VS Code or other editor run dotnet restore to restore the packages.

To build the application against my targeted runtime, I am running the following command.
dotnet build -r ubuntu.16.04-x64
image
Result: Build
Now to create the release package, I am running the following command.
dotnet publish -c Release -r ubuntu.16.04-x64
image
Result: Release
You can see that a folder named publish has been created under {project}\bin\Release\netcoreapp1.1\ubuntu.16.04-x64.

Now you just need to copy/move the publish folder into a Ubuntu machine. I have done that and here it is.
image
Published folder on Ubuntu
Now open up a terminal. You can see that I have not installed .NET Core over there.
image
dotnet
Now let’s try to run the application.
image
Running the application
Here I am thrown with an error “Failed to initialize CoreCLR, HRESULT: 0x8007001F”. And found out this was caused by a permission issue.

Let’s try giving all the permission to the executable and try back again.
image
Running the application
Everything is working great!

Happy Coding.

Regards,
Jaliya