Skip to content

Bundling .NET Core apps

Philipp Gillé edited this page Jun 10, 2017 · 1 revision

Contents

  • Introduction
  • Bundling an AppImage
    • Prerequisites
    • Bundling
    • TODO
  • Bundling within a Docker container

Introduction

.NET Core is a new .NET platform that's open source, modular, and runs on various operating systems like:

  • Windows 7, 8, 10, both x86 and x64
  • Windows 10 on ARM
  • Ubuntu 14.04, 16.04, 16.10
  • Other Linux distributions: Red Hat Enterprise Linux 7 Server, Linux Mint 17, 18, Debian 8, Fedora 23, 24, CentOS 7.1, openSUSE 13.2, 42.1
  • macOS 10.11 or higher
  • Docker (microsoft/dotnet)

.NET Core apps can be distributed as framework-dependent deployments (FDD) and self-contained deployments (SCD). Read more about that here.

While an SCD already is self-contained, which means the .NET Core framework doesn't need to be installed on the system where the app is supposed to run, an AppImage still has advantages:

  • It's just one file. The SCD on the other hand contains lots of files in one directory and the user either has to create a symlink in /usr/local/bin for example, or create an alias or something alike.
  • There's desktop integration: MIME type registration, inclusion in the start menu
  • Delta updates with zsync
  • Standard compliant package meta info with AppStream

And as with .NET Core SCDs, there's no need to install a runtime, which is an advantage in comparison to Snap or Flatpak packages.

Bundling an AppImage

Prerequisites

Prior to bundling, you created your .NET Core app and checked that it worked. Like:

dotnet new console -o hwapp
cd hwapp
dotnet restore
dotnet run
Hello World!

Add some runtime identifiers (RIDs) to the hwapp.csproj, like <RuntimeIdentifiers>win10-x64;ubuntu.16.04-x64;osx.10.12-x64</RuntimeIdentifiers>. For more RIDs, see the catalog.

Create an SCD for ubuntu.16.04-x64:

# After adding RIDs to the csproj, you need to restore some packages again
dotnet restore -r ubuntu.16.04-x64
dotnet publish -c Release -r ubuntu.16.04-x64

Bundling

Now you want to bundle the ubuntu.16.04-x64 release files. They're located in bin/Release/netcoreapp1.1/ubuntu.16.04-x64/publish/ and contain 123 files (this number might be different on your system, and certainly when your app is more than a Hello World-app).

  1. Create a directory AppDir

  2. Create some files inside that directory:

    1. Create usr/bin/ and copy all those 123 files from the above mentioned .../publish directory into it:
    mkdir -p AppDir/usr/bin
    cp bin/Release/netcoreapp1.1/ubuntu.16.04-x64/publish/* AppDir/usr/bin/
    1. Create a file AppDir/AppRun with the contents:
    #!/bin/sh
    HERE="$(dirname "$(readlink -f "${0}")")"
    export PATH="${HERE}"/usr/bin/:"${PATH}"
    EXEC=$(grep -e '^Exec=.*' "${HERE}"/*.desktop | head -n 1 | cut -d "=" -f 2 | cut -d " " -f 1)
    exec "${EXEC}" $@
    1. Make it executable: chmod 755 ./AppDir/AppRun
    2. Create a file AppDir/hwapp.desktop with the contents:
    # Desktop Entry Specification: https://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html
    [Desktop Entry]
    Type=Application
    Name=hwapp
    Comment=Self-contained .NET Core console application that prints Hello World
    Icon=hwapp
    Exec=hwapp
    Path=~
    Terminal=true
    Categories=Development;
    
    1. Create an icon for your app, AppDir/hwapp.png or AppDir/hwapp.svg (48x48 pixels)
  3. You should now have the following file structure:

AppDir
|-- AppRun
|-- hwapp.desktop
|-- hwapp.png
|-- usr
    |--bin
       |-- ...snip (all SCD files)
bin
hwapp.csproj
obj
Program.cs
  1. Download the AppImage creation tool and make it executable:
wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage"
chmod a+x appimagetool-x86_64.AppImage
  1. Create the AppImage:
./appimagetool-x86_64.AppImage ./AppDir
ls
AppDir  appimagetool-x86_64.AppImage  bin  hwapp.csproj  hwapp-x86_64.AppImage  obj  Program.cs
  1. Test the AppImage:
./hwapp-x86_64.AppImage
Hello World!

TODO

The previous steps were just sample steps to your first .NET Core AppImage. For a production setup, you would also:

  • Have a proper directory structure for having all AppImage related files in one directory (also the downloaded appimagetool and the created AppImage of your app)
  • Have a build script that does all the above mentioned steps for you
  • Have your AppImage deployed somewhere, like GitHub Releases or Bintray
  • Look into AppStream meta data
  • Look into zsync delta updates
  • Consider using an AppImage recipe build script

You should also read AppImage/AppImageKit/wiki/Creating-AppImages.

Bundling within a Docker container

When building a .NET Core app with Docker, you're probably using Microsoft's official containers. These containers currently don't contain fuse and libglib2.0-0.

Regarding fuse: See AppImage/AppImageKit/wiki/FUSE

In short, don't use the appimagetool-x86_64.AppImage directly, but first extract it with appimagetool-x86_64.AppImage --appimage-extract and then execute ./squashfs-root/AppRun in place of the AppImage.

Regarding libglib2.0-0: You need to install this in your container. For example when having a buildscript that you execute in the Container, you can use something like:

docker run --rm \
    ...snip (mount source code directory etc)
    microsoft/dotnet:1.1-sdk \
    bash -c "apt update && apt install -y libglib2.0-0 && build.sh"