ClickOnce is a cool decentralized way of distributing applications on Windows. I’ll demonstrate distributing a Rust language application using ClickOnce. The game uses Rust/WinRT to build a UI on top of the Windows Runtime. ClickOnce shipped with .NET Framework 2.0 in January of 2006. Almost 15 years later, .NET 5.0 was announced with improved ClickOnce support. A simple .NET 5.0 app is used to launch the bundled game.

Published to GitHub Pages

The Application Files folder contains all the files with a .deploy extension. To avoid some checksum validation problems due to different line endings, I added a .gitattributes file.

The published files were copies from the ClickOnce the app.publish folder. The ClickOnce can be tested locally by double clicking on the Minesweeper.application. The .NET launcher can be tested without ClickOnce by just clicking on the Minesweeper.exe. The Rust app can be tested without the .NET launcher by clicking on the minesweeper-rs.exe.

ClickOnce Publishing

I put all the files needed to publish via ClickOnce in a folder named ClickOnce. After building the Rust app with cargo build --release, I just call .\ClickOnce\build.ps1. It launches msbuild to build the .NET launcher, create the ClickOnce Application Manifest, create the ClickOnce Deployment Manifest, and sign both of them, creating the app.publish folder above. The targets come with any version of Visual Studio, include Visual Studio Build Tools. The targets to sign the manifests do not work with dotnet msbuild yet, so stick to msbuild. In PowerShell, I can add add it to the PATH environment variable with $env:PATH

FYI, Visual Studio Build Tools are available using winget. Run winget install Microsoft.VisualStudio.BuildTools. There are a few ways to install winget, but I usually just download and launch the latest .appxbundle from the most recent release on the releases page. Running the Visual Studio Installer app will help you update if you wish to.

You could build the ClickOnce manifests by hand, but it is much easier to let the MSBuild targets do it for you using a publish profile. A publish profile is itself an MSBuild file containing a bunch of properties and items.

The ClickOnce\Properties\PublishProfiles\ClickOnceProfile.pubxml was generated from a Build > Publish wizard in Visual Studio. I’m not sure what the minimal set of properties are.

I moved a couple of the properties into a ClickOnceProfile.pubxml.user file that are specific to a particular user and shouldn’t be committed. The InstallUrl is the base URL for the deployments. The ManifestCertificateThumbprint is the certificate of my locally installed code signing certificate.

.NET Launcher

The project file is also straight forward, but take the time to read how .NET 5.0 has changed things, especially TargetFramework:

Windows desktop APIs (including Windows Forms, WPF, and WinRT) will only be available when targeting net5.0-windows. You can specify an operating system version, like net5.0-windows7 or net5.0-windows10.0.17763.0 ( for Windows October 2018 Update). You need to target a Windows 10 version if you want to use WinRT APIs.

I added the Configuration and PublishProfile properties to that project file, but you leave them out and pass them in or override them by passing them as parameters to msbuild on the command line, such as /p:Configuration=Release and /p:PublishProfile=ClickOnceProfile.

Wrapping it Up

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store