Craft a .NET app¶
This how-to guide covers the steps, decisions, and implementation details that are unique when crafting a snap of an app built using .NET. We’ll work through the aspects unique to .NET-based apps by examining two existing project files: a .NET command-line tool and an Avalonia desktop app.
Command-line apps¶
The whatime example targets core22, where .NET parts use the original .NET plugin. For core24 and newer bases, see the Avalonia example below.
Example whatime project file¶
The following code comprises the project file of a .NET tool, whatime. This project is a CLI command for returning the current time in cities across the globe.
whatime project file
name: whatime
version: "1.0.0"
grade: devel
summary: Get the current time in various cities around the world
description: |
Whatime is able to get you the current time in several different cities
around the world.
base: core22
confinement: devmode
parts:
whatime:
plugin: dotnet
dotnet-build-configuration: Release
dotnet-self-contained-runtime-identifier: linux-x64
source: .
build-packages:
- dotnet-sdk-6.0
stage-packages:
- libicu70
apps:
whatime:
command: Whatime
Add a part written for .NET¶
parts:
whatime:
plugin: dotnet
dotnet-build-configuration: Release
dotnet-self-contained-runtime-identifier: linux-x64
source: .
build-packages:
- dotnet-sdk-6.0
stage-packages:
- libicu70
.NET parts are built with the .NET plugin.
To add a .NET part:
Declare the general part keys, such as
source,override-build, and so on.Set the
pluginkey todotnet.By default, the plugin builds with the
Releaseconfiguration, which is what you want for a published snap. If you’re iterating on a development snap and need the extra debugging symbols and unoptimized code of theDebugconfiguration, set thedotnet-build-configurationkey toDebug.If you need to build the project as a single binary:
In the
.csprojfile, add the following to the<PropertyGroup>tag:<PublishSingleFile>true</PublishSingleFile>
Set
dotnet-self-contained-runtime-identifierto the target architecture’s runtime identifier.
For
build-packages, list any required .NET SDK packages needed for build time.
Avalonia apps¶
Avalonia is a cross-platform UI framework for building .NET desktop apps. Unlike command-line tools, Avalonia apps need access to the desktop session and display server, and require extra rendering libraries at runtime.
On core24 and higher bases, the .NET plugin downloads the .NET SDK itself, and the .NET extensions connect the app to a shared .NET runtime snap. Together, they remove the need to declare the SDK as a build package or bundle the runtime inside the snap.
Example XamlPlayground project file¶
The following code comprises the project file of an Avalonia app, XamlPlayground. This project is a desktop app for experimenting with XAML markup and seeing the results in real time. It’s published on the Snap Store, and its snap is maintained in the community snap repository.
XamlPlayground project file
name: avalonia-xaml-playground
base: core24
adopt-info: xaml-playground
icon: snap/gui/avalonia-xaml-playground.png
summary: Avalonia XAML and C# playground
description: |
The Avalonia XAML Playground application allows you to write
XAML and code-behind pieces of code, with Avalonia controls,
and seeing the results in real time.
grade: stable
confinement: strict
platforms:
amd64:
arm64:
parts:
xaml-playground:
plugin: dotnet
source: https://github.com/AvaloniaUI/XamlPlayground
source-type: git
dotnet-version: "10.0"
dotnet-configuration: Release
dotnet-project: src/XamlPlayground.NetCore/XamlPlayground.NetCore.csproj
dotnet-verbosity: minimal
override-build: |
version=$(git show -s --format=%h)
craftctl set version="${version}"
craftctl default
organize:
"*": opt/xamlplayground/
prereqs:
plugin: nil
after:
- xaml-playground
stage-packages:
- fontconfig
- libfontconfig1
- libice6
- libsm6
- libx11-6
apps:
avalonia-xaml-playground:
command: opt/xamlplayground/XamlPlayground.NetCore
desktop: meta/gui/avalonia-xaml-playground.desktop
extensions: [dotnet10]
plugs:
- desktop
- desktop-legacy
- home
- opengl
- unity7
- wayland
lint:
ignore:
- library:
- usr/lib/**/libICE*
- usr/lib/**/libicu*
- usr/lib/**/liblttng-ust-*
- usr/lib/**/libSM*
- usr/lib/**/libX11*
- usr/lib/**/libXau*
- usr/lib/**/libxcb*
- usr/lib/**/libXdmcp*
Declare the supported platforms¶
platforms:
amd64:
arm64:
The dotnet plugin builds with a .NET SDK that’s only published for the
amd64 and arm64 architectures, so an Avalonia snap can only target those
architectures.
To declare the supported platforms, list amd64 and arm64 in the
top-level platforms key. See Select platforms for the
available ways to declare platforms.
Add the .NET part¶
parts:
xaml-playground:
plugin: dotnet
source: https://github.com/AvaloniaUI/XamlPlayground
source-type: git
dotnet-version: "10.0"
dotnet-configuration: Release
dotnet-project: src/XamlPlayground.NetCore/XamlPlayground.NetCore.csproj
dotnet-verbosity: minimal
override-build: |
version=$(git show -s --format=%h)
craftctl set version="${version}"
craftctl default
organize:
"*": opt/xamlplayground/
On core24 and higher bases, .NET parts are built with the .NET plugin (v2).
To add the .NET part:
Declare the general part keys, such as
source,override-build, and so on.Set the
pluginkey todotnet.Set the
dotnet-versionkey to the version of the .NET SDK to download and build with. It must match the framework version the project targets, as declared by the<TargetFramework>tag in the.csprojfile. XamlPlayground targetsnet10.0, so the version is"10.0".If the repository contains multiple projects, set
dotnet-projectto the path of the project file that builds the app.By default, the plugin builds with the
Releaseconfiguration, which is what you want for a published snap. If you’re iterating on a development snap and need the extra debugging symbols and unoptimized code of theDebugconfiguration, set thedotnet-configurationkey toDebug.The plugin publishes the app directly into the part’s install directory. To keep the published files separate from the system directories of the snap, use the
organizekey to move them into a dedicated directory, such asopt/xamlplayground/.
Stage the rendering dependencies¶
prereqs:
plugin: nil
after:
- xaml-playground
stage-packages:
- fontconfig
- libfontconfig1
- libice6
- libsm6
- libx11-6
Avalonia apps need font and X11 client libraries at runtime that the .NET runtime content snap doesn’t provide. Stage them with a separate part that runs after the .NET part:
Declare a new part and set its
pluginkey tonil.List the .NET part with the
afterkey to ensure the runtime libraries aren’t overwritten.Declare the following font and X11 client libraries with the
stage-packageskey:fontconfiglibfontconfig1libice6libsm6libx11-6
Declare the Avalonia app¶
apps:
avalonia-xaml-playground:
command: opt/xamlplayground/XamlPlayground.NetCore
desktop: meta/gui/avalonia-xaml-playground.desktop
extensions: [dotnet10]
plugs:
- desktop
- desktop-legacy
- home
- opengl
- unity7
- wayland
Avalonia apps must use the .NET extension that matches their target framework.
Apps targeting the net10.0 framework, for example, must use the dotnet10
extension. The extension configures the app’s runtime environment and connects
it to the shared .NET runtime snap. The .NET extensions reference
provides details on how the extensions modify snap project files.
To add the Avalonia app:
Declare the general app keys, such as
command. The command is the path of the published binary inside the snap, including the directory set with the part’sorganizekey.Set the
desktopkey to the path of the app’s.desktopfile so the app appears in the desktop environment’s app grid.List the .NET extension that matches the app’s target framework with the
extensionskey.List the interfaces the app needs to access the desktop session and render its windows with the
plugskey:desktopanddesktop-legacyfor integration with the desktop session.waylandandopenglfor display output and graphics acceleration.homefor access to the user’s files.unity7for desktop integration on X11 sessions.
If the app needs network access, such as to fetch online content, add the
network interface as well.
Silence the library linter warnings¶
lint:
ignore:
- library:
- usr/lib/**/libICE*
- usr/lib/**/libicu*
- usr/lib/**/liblttng-ust-*
- usr/lib/**/libSM*
- usr/lib/**/libX11*
- usr/lib/**/libXau*
- usr/lib/**/libxcb*
- usr/lib/**/libXdmcp*
Avalonia apps ship some libraries, such as the .NET runtime’s own copies of
libicu, that the library linter reports as unused or conflicting. These
warnings are expected, and you can silence them with the top-level lint
key. The Linters references contains more details on the linters
Snapcraft runs.