Home

Awesome

<div align="center"> <img alt="NetSparkleUpdater logo" height="200" src="src/NetSparkle/ArtWork/software-update-available.png"> <h1>NetSparkleUpdater</h1> <p>An easily customizable software update framework for C# .NET projects with built-in UIs for WinForms, WPF, and Avalonia</p> <a href="https://gitter.im/NetSparkleUpdater/NetSparkle?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge"> <img alt="Gitter" src="https://badges.gitter.im/Join%20Chat.svg"> </a> <a href="https://github.com/NetSparkleUpdater/NetSparkle/issues"> <img alt="Gitter" src="https://img.shields.io/github/issues/NetSparkleUpdater/NetSparkle.svg?style=flat-square"> </a> </div>

NetSparkle is a software update framework for C# that is compatible with .NET Core 3+/.NET 5+ and .NET Framework 4.5.2+, has pre-built UIs for .NET Framework (WinForms, WPF) and .NET Core/.NET 5+ (WinForms, WPF, Avalonia), uses Ed25519 or other cryptographic signatures, and even allows for custom UIs or no built-in UI at all! You provide, somewhere on the internet, an app cast with update and version information, along with release notes in Markdown or HTML format. This library then helps you check for an update, show the user the release notes, and offer to download/install the new version of the software.

NetSparkle 2.0 brings the ability to customize most of NetSparkle -- custom UIs are now possible, you can have custom app cast downloaders and handlers (e.g. for FTP download or JSON app casts), and many more enhancements are available!

Built-in supported update download types:

Getting Started

Installing NetSparkle

NetSparkle is available via NuGet. To choose a NuGet package to use:

PackageUse CaseReleasePreviewDownloads
NetSparkleUpdater.SparkleUpdaterCore package; Use a 100% custom UI (nothing built-in)NuGetNuGetNuGet
WinForms UI (.NET Framework)NetSparkle with built-in WinForms UINuGetNuGetNuGet
WinForms UI (.NET Core)NetSparkle with built-in WinForms UINuGetNuGetNuGet
WPF UI (.NET Framework and Core)NetSparkle with built-in WPF UINuGetNuGetNuGet
Avalonia UINetSparkle with built-in Avalonia UINuGetNuGetNuGet
App Cast Generator Toolnetsparkle-generate-appcast CLI tool (incl. Ed25519 helpers)NuGetNuGetNuGet
DSA Helper Toolnetsparkle-dsa CLI tool (DSA helpers)NuGetNuGetNuGet

Quick info for tool installations:

How updates work

A typical software update path for a stereotypical piece of software might look like this:

  1. Compile application so it can be run on other computers (e.g. dotnet publish)
  2. Programmer puts app in some sort of installer/zip/etc. for distribution (e.g. InnoSetup for Windows)
  3. Programmer creates app cast file (see the app cast section of this document for more info on how to create this)
  4. Programmer uploads files for distribution (installer, app cast file, appCast-file.signature file) to their download site.
  5. Client opens app and is automatically notified of an available update (or the software otherwise detects there is an update)
  6. Client chooses to update (or update is downloaded if the software downloads it automatically)
  7. Update is downloaded and sitting on the user's disk
  8. User is asked to close the software so the update can run. User closes the software.
  9. Downloaded file/installer is run (or the update is otherwise performed)

Right now, NetSparkleUpdater does not help you with 1., 2., or 4. "Why not?", you might ask:

To create your app cast file, see the app cast section of this document.

We are open to contributions that might make the overall install/update process easier for the user. Please file an issue first with your idea before starting work so we can talk about it.

Basic Usage

Please look at the sample projects in this repository for basic, runnable usage samples!! There are samples on using each of the built-in UIs as well as a "do it yourself in your own UI" sample!

_sparkle = new SparkleUpdater(
    "http://example.com/appcast.xml", // link to your app cast file
    new Ed25519Checker(SecurityMode.Strict, // security mode -- use .Unsafe to ignore all signature checking (NOT recommended!!)
                       "base_64_public_key") // your base 64 public key -- generate this with the NetSparkleUpdater.Tools.AppCastGenerator .NET CLI tool on any OS
) {
    UIFactory = new NetSparkleUpdater.UI.WPF.UIFactory(icon), // or null or choose some other UI factory or build your own!
    RelaunchAfterUpdate = false, // default is false; set to true if you want your app to restart after updating (keep as false if your installer will start your app for you)
    CustomInstallerArguments = "", // set if you want your installer to get some command-line args
    ShowsUIOnMainThread = true, // required on Avalonia, preferred on WPF/WinForms
};
_sparkle.StartLoop(true); // `true` to run an initial check online -- only call StartLoop once for a given SparkleUpdater instance!

On the first Application.Idle event, your App Cast XML file will be downloaded, read, and compared to the currently running version. If it has a software update inside, the user will be notified with a little toast notification (if supported by the UI and enabled) or with an update dialog containing your release notes. The user can then ignore the update, ask to be reminded later, or download/install it now.

If you want to check for an update in the background without the user seeing anything, use

var updateInfo = _sparkle.CheckForUpdatesQuietly();

If you want to have a menu item for the user to check for updates so the user can see the UI while NetSparkle looks for updates, use

_sparkle.CheckForUpdatesAtUserRequest();

If you have files that need saving, subscribe to the PreparingToExit event:

_sparkle.PreparingToExit += ((x, cancellable) =>
{
	// ask the user to save, whatever else is needed to close down gracefully
});

Note that if you do not use a UIFactory, you must use the CloseApplication or CloseApplicationAsync events to close your application; otherwise, your downloaded update file will never be executed/read! The only exception to this is if you want to handle all aspects of installing the update package yourself.

The file that launches your downloaded update executable only waits for 90 seconds before giving up! Make sure that your software closes within 90 seconds of CloseApplication/CloseApplicationAsync being called if you implement those events! If you need an event that can be canceled, such as when the user needs to be asked if it's OK to close (e.g. to save their work), use PreparingForExit or PreparingToExitAsync.

App cast

The app cast is just an XML file. It contains fields such as the title and description of your product as well as a definition per release of your software.

We strongly recommend that you make use of the netsparkle-generate-appcast tool to (re)create the file because it correctly takes care of all signing requirements for you.

Install AppCast Generator Tool

  1. This tool requires the .NET 5, 6, or 7 Desktop Runtime to be installed.
  2. dotnet tool install --global NetSparkleUpdater.Tools.AppCastGenerator
  3. The tool is now available on your command line as the netsparkle-generate-appcast command. You can use netsparkle-generate-appcast --help to see a full list of options for this tool.

Sparkle Compatibility

NetSparkle uses Sparkle-compatible app casts for the most part. NetSparkle uses sparkle:signature rather than sparkle:dsaSignature so that you can choose how to sign your files/app cast. NetSparkle is compatible with and uses Ed25519 signatures by default, but the framework can handle a different implementation of the ISignatureVerifier class to check different kinds of signatures without a major version bump/update.

DSA vs Ed25519 Signatures

If your app has DSA signatures, the app cast generator uses Ed25519 signatures by default starting with preview 2.0.0-20200607001. To transition to Ed25519 signatures, create an update where the software has your new Ed25519 public key and a NEW url for a NEW app cast that uses Ed25519 signatures. Upload this update with an app cast that has DSA signatures so your old DSA-enabled app can download the Ed25519-enabled update. Then, future updates and app casts should all use Ed25519.

Here is a sample app cast:

<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" version="2.0">
    <channel>
        <title>NetSparkle Test App</title>
        <link>https://netsparkleupdater.github.io/NetSparkle/files/sample-app/appcast.xml</link>
        <description>Most recent changes with links to updates.</description>
        <language>en</language>
        <item>
            <title>Version 2.0 (2 bugs fixed; 3 new features)</title>
            <sparkle:releaseNotesLink>
            https://netsparkleupdater.github.io/NetSparkle/files/sample-app/2.0-release-notes.md
            </sparkle:releaseNotesLink>
            <pubDate>Thu, 27 Oct 2016 10:30:00 +0000</pubDate>
            <enclosure url="https://netsparkleupdater.github.io/NetSparkle/files/sample-app/NetSparkleUpdate.exe"
                       sparkle:version="2.0"
                       sparkle:os="windows"
                       length="12288"
                       type="application/octet-stream"
                       sparkle:signature="NSG/eKz9BaTJrRDvKSwYEaOumYpPMtMYRq+vjsNlHqRGku/Ual3EoQ==" />
        </item>
    </channel>
</rss>

App Cast Items

NetSparkle reads the <item> tags to determine whether updates are available.

The important tags in each <item> are:

By default, you need 2 (DSA/Ed25519) signatures (SecurityMode.Strict):

  1. One in the enclosure tag for the update file (sparkle:signature="...")
  2. Another on your web server to secure the actual app cast file. This file must be located at [AppCastURL].signature. In other words, if the app cast URL is http://example.com/awesome-software.xml, you need a valid (DSA/Ed25519) signature for that file at http://example.com/awesome-software.xml.signature.

Note: the app cast generator tool creates both of these signatures for you when it recreates the appcast.xml file.

Ed25519 Signatures

You can generate Ed25519 signatures using the AppCastGenerator tool (from this NuGet package or in the source code here). This tool requires the .NET 5, 6, or 7 Desktop Runtime to be installed. Please see below sections for options and examples on generating the Ed25519 keys and for using them when creating an app cast.

DSA Signatures

DSA signatures are not recommended when using NetSparkleUpdater 2.0+. They are considered insecure!

You can still generate these signatures, however, using the DSAHelper tool (from this NuGet package or in the source code here). Key generation only works on Windows because .NET Core 3 does not have the proper implementation to generate DSA keys on macOS/Linux; however, you can get DSA signatures for a file on any platform. If you need to generate a DSA public/private key, please use this tool on Windows like this:

netsparkle-dsa /genkey_pair

You can use the DSAHelper to get a signature like this:

netsparkle-dsa /sign_update {YourInstallerPackage.msi} {NetSparkle_PrivateKey_DSA.priv}

Installing the DSA Helper command-line tool

  1. dotnet tool install --global NetSparkleUpdater.Tools.DSAHelper
  2. The tool is now available on your command line as the netsparkle-dsa command

How can I make the app cast?

App Cast Generator Options

Missing some option you'd like to see? File an issue on this repo or add it yourself and send us a pull request!

General Options When Generating App Cast

Options for Key Generation

Private Key:
2o34usledjfs0
Public Key:
sdljflase;ru2u3

Options for Generating Signatures Without App Cast

Options for Verifying Signatures

Note that these options are only for verifying Ed25519 signatures. For DSA signatures, please use the DSAHelper tool. Both of the following options must be used together. You must have keys already generated in order to verify file signatures.

Example use: --verify my/path/MyApp.exe --signature 123l4ijsdfzderu23.

This will return either Signature valid (signature is good!) or Signature invalid (signature does not match file).

App Cast Generator Examples


#### Key Generation
# Generate Ed25519 keys for the first time
netsparkle-generate-appcast --generate-keys
# Store keys in a custom location
netsparkle-generate-appcast --key-path path/to/store/keys
# Pass in public key via command line
netsparkle-generate-appcast --public-key-override [YourPublicKeyHere]
# Pass in private key via command line
netsparkle-generate-appcast --private-key-override [YourPrivateKeyHere]

# By default, your Ed25519 signatures are stored on disk in your local 
# application data folder in a subdirectory called `netsparkle`. 
# If you want to export your keys to the console, you can do:
netsparkle-generate-appcast --export

# You can also store your keys in the following environment variables:
# set public key: SPARKLE_PUBLIC_KEY
# set private key: SPARKLE_PRIVATE_KEY

#### Generate a signature for a binary without creating an app cast:
netsparkle-generate-appcast --generate-signature path/to/binary.exe

#### Verifying Binaries
netsparkle-generate-appcast --verify path/to/binary.exe --signature base_64_signature

#### Using a custom key location:
# If your keys are sitting on disk somewhere
# (`NetSparkle_Ed25519.priv` and `NetSparkle_Ed25519.pub` -- both 
# in base 64 and both on disk in the same folder!), you can pass in 
# the path to these keys like this:
netsparkle-generate-appcast --key-path path/to/keys/

#### Generating an app cast

# Generate an app cast for Windows executables that are sitting in a 
# specific directory
netsparkle-generate-appcast -a directory/for/appcast/output/ -e exe -b directory/with/binaries/ -o windows

# Add change log info to your app cast
netsparkle-generate-appcast -b binary/folder -p change/log/folder

# Customize download URL for binaries and change logs
netsparkle-generate-appcast -b binary/folder -p change/log/folder -u https://example.com/downloads -p https://example.com/downloads/changelogs

# Set your application name for the app cast
netsparkle-generate-appcast -n "My Awesome App" -b binary/folder

# Use file versions in file names, e.g. for apps like "My App 1.2.1.dmg"
netsparkle-generate-appcast -n "macOS version" -o macos -f true -b binary_folder -e dmg

# Don't overwrite the entire app cast file
netsparkle-generate-appcast --reparse-existing

# Don't overwrite the entire app cast file, but do overwrite items that are still on disk
netsparkle-generate-appcast --reparse-existing --reparse-overwrite-old-items

Upgrading between major versions

Please see UPGRADING.md for information on breaking changes between major versions.

FAQ

Am I required to use a UI with NetSparkleUpdater?

Nope. You can just reference the core library and handle everything yourself, including any custom UI. Check out the code samples for an example of doing that!

How do I make my .NET Framework WinForms app high DPI aware?

See #238 and this documentation for the fix for making this work on the sample application. Basically, you need to use an app config file and manifest file to let Windows know that your application is DPI-aware. If that doesn't work for you, try some of the tips at this SO post.

NuGet has lots of packages when I search for "NetSparkle", which one do I use?

NetSparkleUpdater.SparkleUpdater is the right package if you want the library with no built-in UI. Otherwise, use NetSparkleUpdater.UI.{YourChoiceOfUI}, which will give you a built-in UI and the core library. Previous to 2.0, the UI libraries reference NetSparkle.New, which is now deprecated.

Here is the full list of deprecated packages:

Must I put all my release versions into a single app cast file?

No. If your app is just using NetSparkle to work out if there is a later release - and you are not using the app cast as a way to refer to historical versions of your app in any way - then you don't need to add all the released versions into the app cast file.

Having just the latest version of your software in the app cast has the added side effect that you won't need all the binaries & changelogs of all the versions to be available to the app cast generator tool. For example, this might make an automated release build easier via GitHub Actions - because the only data required is the generated .exe and changelogs from your git repository.

How can I use NetSparkleUpdater with AppCenter?

  1. Make sure you've read over the documentation here
  2. Decide if you want to generate signatures for your files. If so, make sure that works, and then use NetSparkleUpdater as normal.
  3. If you don't want to generate signatures because you trust your AppCenter builds, use SecurityMode.Unsafe or the following IAppCastHandler override:
public bool DownloadAndParse()
{
    try
    {
        _logWriter.PrintMessage("Downloading app cast data...");

        var appCast = _dataDownloader.DownloadAndGetAppCastData(_castUrl);
        if (!string.IsNullOrEmpty(appCast))
        {
            ParseAppCast(appCast);
            return true;
        }
    }
    catch (Exception e)
    {
        _logWriter.PrintMessage("Error reading app cast {0}: {1} ", _castUrl, e.Message);
    }

    return false;
}

Is reverting your application version supported?

The answer is both yes and no. No, because that is not the default behavior. Yes, because if you use installers for each of your versions, you can use your app cast to see which previous versions are available and download those versions. If your installers are standalone, they should install an old version just fine. Just keep in mind that if you install an old version and then there is a newer version in your app cast, after opening the older software, it will ask them if they want to update to the newer version!

Here's a summary of what you can do:

  1. Setup your SparkleUpdater object
  2. Call _updateInfo = await _sparkle.CheckForUpdatesQuietly(); (no UI shown) or _sparkle.CheckForUpdatesAtUserRequest() (shows UI). I would recommend checking quietly because the UI method will always show the latest version. You can always show your own UI.
  3. Look in _updateInfo.Updates for the available versions in your app cast. You can compare it with your currently installed version to see which ones are new and which ones are old.
  4. Call await _sparkle.InitAndBeginDownload(update); with the update you want to download. The download path is provided in the DownloadFinished event.
  5. When it's done downloading, call _sparkle.InstallUpdate(update, _downloadPath);

The "Handle Events Yourself" sample will be very helpful to you: https://github.com/NetSparkleUpdater/NetSparkle/tree/develop/src/NetSparkle.Samples.HandleEventsYourself

Does this work with Avalonia version XYZ?

Right now, we are compatible with 0.10. If you need to make changes, you can use your own IUIFactory implementation to fix any issues that come up.

Things aren't working. Help!

Here are some things you can do to figure out how to get your app running:

Are you accepting contributions?

Yes! Please help us make this library awesome!

What's the tagging scheme, here?

Requirements

License

NetSparkle is available under the MIT License.

Contributing

Contributions are ALWAYS welcome! If you see a new feature you'd like to add, please open an issue to talk about it first, then open a PR for that implementation. If there's a bug you find, please open a PR with the fix or file an issue! Thank you!! :) You can also join us in our Gitter chat room!

Areas where we could use help/contributions

Acknowledgements

Other Options

An incomplete list of other projects related to software updating that you might want to look at if NetSparkleUpdater doesn't work for you: