Coder Social home page Coder Social logo

netsparkleupdater / netsparkle Goto Github PK

View Code? Open in Web Editor NEW
558.0 15.0 81.0 7.51 MB

NetSparkle is a C# cross-platform software update framework for .NET developers compatible with .NET 4.6.2/.NET 6+, WinForms, WPF, and Avalonia; uses Ed25519 or DSA signatures! View basic usage here in the README or visit our website for code docs.

Home Page: https://netsparkleupdater.github.io/NetSparkle/

License: MIT License

C# 97.70% CSS 1.31% HTML 0.69% Batchfile 0.30%
csharp update-service update sparkle winforms wpf windows-desktop windows software-update netsparkle

netsparkle's Introduction

NetSparkleUpdater logo

NetSparkleUpdater

An easily customizable software update framework for C# .NET projects with built-in UIs for WinForms, WPF, and Avalonia

Gitter Gitter

NetSparkle is a software update framework for C# that is compatible with .NET 6+ and .NET Framework 4.6.2+, has pre-built UIs for .NET Framework (WinForms, WPF) and .NET 6+ (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:

  • Windows -- .exe, .msi, .msp
  • macOS -- .tar, .tar.gz, .zip, .pkg, .dmg
  • Linux -- .tar.gz, .deb, .rpm

Getting Started

Installing NetSparkle

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

  • Reference the core NetSparkleUpdater.SparkleUpdater package (old package had 28,949 downloads! Thank you!) if you don't care about having a built-in UI and can manage things yourself
  • Choose one of the other packages if you want a built-in UI or want to create your UI based on one of the other UIs
Package Use Case Release Preview Downloads
NetSparkleUpdater.SparkleUpdater Core package; Use a 100% custom UI (nothing built-in) NuGet NuGet NuGet
WinForms UI (.NET Framework) NetSparkle with built-in WinForms UI NuGet NuGet NuGet
WinForms UI (.NET Core) NetSparkle with built-in WinForms UI NuGet NuGet NuGet
WPF UI (.NET Framework and Core) NetSparkle with built-in WPF UI NuGet NuGet NuGet
Avalonia UI NetSparkle with built-in Avalonia UI NuGet NuGet NuGet
App Cast Generator Tool netsparkle-generate-appcast CLI tool (incl. Ed25519 helpers) NuGet NuGet NuGet
DSA Helper Tool netsparkle-dsa CLI tool (DSA helpers) NuGet NuGet NuGet

Quick info for tool installations:

  • App cast generator -- dotnet tool install --global NetSparkleUpdater.Tools.AppCastGenerator; available as netsparkle-generate-appcast on your command line after installation
  • DSA Helper -- dotnet tool install --global NetSparkleUpdater.Tools.DSAHelper; available as netsparkle-dsa on your command line after installation

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:

    1. We can't compile your application for you since we don't know (or care) how you are compiling or packaging your application! :)
    1. A cross-platform installer package/system would be difficult and may not feel normal to end users, although a system that uses Avalonia could maybe work I suppose (might take a lot of work though and make downloads large!). We do not provide support for getting your installer/distribution ready. To generate your installer/distribution, we recommend the following:
    1. We don't know where your files will live on the internet, so you need to be responsible for uploading these files and putting them online somewhere.

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:

  • <description>
    • A description of the update in HTML or Markdown.
    • Overrides the <sparkle:releaseNotesLink> tag.
  • <sparkle:releaseNotesLink>
    • The URL to an HTML or Markdown document describing the update.
    • If the <description> tag is present, it will be used instead.
    • Attributes:
      • sparkle:signature, optional: the DSA/Ed25519 signature of the document; NetSparkle does not check this signature for you unless you set ReleaseNotesGrabber.ChecksReleaseNotesSignature to true, but you may manually verify changelog signatures if you like or set ReleaseNotesGrabber.ChecksReleaseNotesSignature = true in your UI.
  • <pubDate>
    • The date this update was published
  • <enclosure>
    • This tag describes the update file that NetSparkle will download.
    • Attributes:
      • url: URL of the update file
      • sparkle:version: machine-readable version number of this update
      • length, optional: (not validated) size of the update file in bytes
      • type: ignored
      • sparkle:signature: DSA/Ed25519 signature of the update file
      • sparkle:criticalUpdate, optional: if equal to true or 1, the UI will indicate that this is a critical update
      • sparkle:os: Operating system for the app cast item. Defaults to Windows if not supplied. For Windows, use "win" or "windows"; for macOS, use "macos" or "osx"; for Linux, use "linux".

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?

  • Use the AppCastGenerator tool (from this NuGet package or in the source code here) to easily create your app cast file. Available options are described below. You can install it on your CLI via dotnet tool install --global NetSparkleUpdater.Tools.AppCastGenerator.
  • Rig up a script that generates the app cast for you in python or some other language (string.Format or similar is a wonderful thing).
  • Or you can just copy/paste the above example app cast into your own file and tweak the signatures/download info yourself, then generate the (Ed25519/DSA) signature for the app cast file manually! :)

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!

  • --show-examples: Print examples of usage to the console.
  • --help: Show all options and their descriptions.

General Options When Generating App Cast

  • -a/--appcast-output-directory: Directory in which to write the output appcast.xml file. Example use: -a ./Output
  • -e/--ext: When looking for files to add to the app cast, use the given extension. Defaults to exe. Example use: -e exe
  • -b/--binaries: File path to directory that should be searched through when looking for files to add to the app cast. Defaults to .. Example use: -b my/build/directory
  • -r/--search-binary-subdirectories: True to search the binary directory recursively for binaries; false to only search the top directory. Defaults to false. Example use: -r.
  • -f/--file-extract-version: Whether or not to extract the version of the file from the file's name rather than the file itself. Defaults to false. Use when your files that will be downloaded by NetSparkleUpdater will have the version number in the file name, e.g. "My App 1.3.2.exe". Example use: -f true
  • -o/--os: Operating system that the app cast items belong to. Must be one of the following: windows, mac, linux. Defaults to windows. Example use: -o linux
  • -u/--base-url: Beginning portion of the URL to use for downloads. The file name that will be downloaded will be put after this portion of the URL. Example use: -u https://myawesomecompany.com/downloads
  • -l/--change-log-url: Beginning portion of the URL to use for your change log files. The change log file that will be downloaded will be put after this portion of the URL. If this option is not specified, then the change log data will be put into the app cast itself. Example use: -l https://myawesomecompany.com/changes
  • -p/--change-log-path: Path to the change log files for your software. These are expected to be in markdown format with an extension of .md. The file name of the change log files must contain the version of the software, e.g. 1.3.2.md. Example use: -p path/to/change/logs. (Note: The generator will also attempt to find change logs whose file names are formatted like so: MyApp 1.3.2.md.)
  • --change-log-name-prefix: Prefix for change log file names. By default, the generator searches for file names with the format "[Version].md". If you set this parameter to (for example) "My App Change Log", it will search for file names with the format "My App Change Log [Version].md" as well as "[Version].md".
  • -n/--product-name: Product name for your software. Used when setting the title for your app cast and its items. Defaults to Application. Example use: -n "My Awesome App"
  • -x/--url-prefix-version: Add the version number as a prefix to the file name for the download URL. Defaults to false. For example, if --base-url is www.example.com/downloads, your version is 1.4.2, and your app name is MyApp.exe, your download URL will become www.example.com/downloads/1.4.2/MyApp.exe. Example use: -x true.
  • --key-path: Path to NetSparkle_Ed25519.priv and NetSparkle_Ed25519.pub files, which are your private and public Ed25519 keys for your software updates, respectively. Example use: --key-path my/path/to/keys
    • If you want to use keys dynamically, you can set the SPARKLE_PRIVATE_KEY and SPARKLE_PUBLIC_KEY environment variables before running generate_appcast. The tool prioritizes environment keys over keys sitting on disk!
  • --signature-file-extension: Extension (WITHOUT the .) to use for the appcast xml signature file. Defaults to signature. Example use: --signature-file-extension txt.
  • --file-version: Use to set the version for a binary going into an app cast. Note that this version can only be set once, so when generating an app cast, make sure you either: A) have only one binary in your app cast | B) Utilize the --reparse-existing parameter so that old items get picked up. If the generator finds 2 binaries without any known version and --file-version is set, then an error will be emitted.
  • --critical-versions: Comma-separated list of versions to mark as critical in the app cast. Must match version text exactly. E.g., "1.0.2,1.2.3.1".

Options for Key Generation

  • --generate-keys: If set, will attempt to generate NEW Ed25519 keys for you. Can be used in conjunction with --key-path. Once keys are successfully (or unsuccessfully) generated, the program ends without generating an app cast. By default, existing keys are not overwritten. This option defaults to false.
  • --force: If set to true, will overwrite existing keys on disk. WARNING: THIS COULD RESULT IN A LOSS OF YOUR PUBLIC AND PRIVATE KEYS. USE WITH CAUTION. DO NOT USE IF YOU DO NOT KNOW WHAT YOU ARE DOING! THIS WILL MAKE NO ATTEMPT TO BACK UP YOUR DATA. This option defaults to false. Example use: --generate-keys --force true.
  • --export: Export keys as base 64 strings to the console. Defaults to false. Example use: --export true. Output format:
Private Key:
2o34usledjfs0
Public Key:
sdljflase;ru2u3

Options for Generating Signatures Without App Cast

  • --generate-signature: Generate a signature for a file and output it to the console. Example use: --generate-signature path/to/app/MyApp.exe. Outputs in format: Signature: seljr13412zpdfj.

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.

  • --verify: Path to the file that has a signature you want to verify.
  • --signature: Base 64 signature of the file.

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 version 11. 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:

  • Make sure you have enabled and debugged your application thoroughly. A great way to do this is to set SparkleUpdater.LogWriter = new LogWriter(true) and then watch your console output while debugging.
  • Look at the NetSparkleUpdater samples by downloading this repo and running the samples. You can even try putting your app cast URL in there and using your public key to debug with the source code!
  • Ask for help in our Gitter
  • Post an issue and wait for someone to respond with assistance

Are you accepting contributions?

Yes! Please help us make this library awesome!

What's the tagging scheme, here?

  • 2.x.y (Core)
  • 2.x.y-app-cast-generator
  • 2.x.y-dsa-helper
  • 2.x.y-UI-Avalonia
  • 2.x.y-UI-WinForms
  • 2.x.y-UI-WPF

Requirements

  • .NET Framework 4.6.2+ | .NET 6+

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

  • Unit tests for all parts of the project
  • Extensive testing on macOS/Linux
  • More built-in app cast parsers (e.g. natively support using/creating JSON feeds) -- possible via interfaces but not built-in yet
  • More options in the app cast generator
  • See the issues list for more

Acknowledgements

  • The original NetSparkle library, found at dei79/netsparkle
  • A function for finding the base directory was taken from MIT-licensed WalletWasabi
  • MarkdownSharp is from here
  • We got our starting README layout from MahApps.Metro, an awesome UI framework for WPF

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:

netsparkle's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

netsparkle's Issues

WindowsForms in UI interfaces

Is there an actual reason to why there is a DialogResult used in UI interfaces? As I am looking at it, there are only two interfaces, where DialogResult is used:

  • IUpdateAvailable.Result - where DialogResult signalises, whether the update should be handled; where, it might be better to have a separate enum with required values and let the implementation of the interface do the translation; this way, it will be separated from a UI framework;
  • IDownloadProgress.ShowDialog() - where DialogResult signalises a boolean (Abort || Result -> cancel, otherwise continue).

My solution proposal would be to have IUpdateAvailable.Result return custom enum with values InstallUpdate, SkipUpdate, InstallLater and IDownloadProgress.ShowDialog() return just boolean, indicating success.

Tweaks to the existing default forms are trivial, but it is a breaking change for existing custom-UI code, yet the changes are trivial as well (it may even be viable to include some simple converters to help with converting code to default behaviour).

As for the implementation, I am going to implement these changes to the code anyway for my project, but I would kind of like to see it in public release as well, as in my opinion, the changes make sense.

Update NetSparkle NuGet package

The owners of the more-well-loved-and-used NetSparkle NuGet package have graciously given me owner access, so we need to update the code there so that everyone can take advantage of the latest code enhancements -- and so that there's not duplicate NuGet lookalikes!

  • Make names of fields, events, etc. consistent
  • Finish any refactoring work
  • Create update guide from whatever version is there to this version (can probably just crawl through repo histories / fork history to do this)
  • Make sure documentation for this project is good enough for new users who will be investigating things from NuGet
  • Bump this version up to "2.0" so that it looks like an upgrade from random folks who don't know the fork of a fork of a fork history of NetSparkle, especially since it probably breaks compatibility
  • Update README.md appropriately (badge for NuGet repo, etc.)
  • Update repo releases
  • Publish 2.0 beta to NuGet
  • Wait for a bit to see if there are any complaints (and address them as necessary), then publish 2.0 official to NuGet

Roadmap!

Current item being worked on: finishing up! Creating update guide (half done), deprecating old NuGet for NetSparkle.New, etc. Almost there!

Hi everyone,

This repo has been around for quite some time, and I've never gotten around to making a 2.0 version of NetSparkle.

Here are my goals starting in August 2019 (not given in order):

Complete

  • Go through the code and clean it up
  • Make names of fields, events, etc. consistent
  • Finish any refactoring work
  • Totally, 100% separate the UI from the update logic. Have two separate UI DLLs: one for WinForms and one for WPF. The UI Factory can always be utilized for your own UI.
  • Create a NetSparkle organization and move this repo there for easier discoverability (See #73 -- name chosen; just need to create it and move repo)
  • Push an update to the original repo here that points people to the new organization (Waiting on above bullet point)
  • Start pushing 2.0 alpha/beta builds to the NetSparkle NuGet repo for testing and better Google-ing (See #84 -- about 50-75% done)
  • Other enhancements to NetSparkle
    • Allow for custom object that will download app cast
    • Allow for custom object that will download update file(s)
    • Allow for custom object that handles app cast downloading and parsing
  • Update this SO post via a comment so that people can see from there that new things are happening
  • Test (and fix if necessary) SecurityMode.UseIfPossible based on the report in #89 -- may not work when a signature isn't available
  • Create update guide from whatever version is there to this version (can probably just crawl through repo histories / fork history to do this) [WIP already, see README.md]
  • Make sure documentation for this project is good enough for new users who will be investigating things from NuGet (Update: Good enough for now. We've got docs up on the website now as well as XML docs most everywhere, plus gitter and other things here in README.md)
  • Create new logo/icon (tracking this in #100)
  • Update README.md appropriately (badge for NuGet repo, etc.)
  • Bump this version up to "2.0" so that it looks like an upgrade from random folks who don't know the fork of a fork of a fork history of NetSparkle, especially since it probably breaks compatibility
  • Deprecate NetSparkle.New.Tools in lieu of NetSparkleUpdater.Tools and remove from search results

Not complete

  • Decide if core package will be NetSparkleUpdater.Core or NetSparkleUpdater.SparkleUpdater.
  • Create NetSparkleUpdater.SparkleUpdater feed and update all refs in projects, etc. to point to that package (tools & WinForms .NET Framework nuspec updating too)
  • Deprecate NetSparkle nuget feed and point people to NetSparkleUpdater.NetSparkle (I did not originally create this feed but have been given rights to write to it)
  • Deprecate NetSparkle.New nuget feed and point people to NetSparkleUpdater.SparkleUpdater -- add new version with just a readme.txt pointing people to the new repo/nuget or something
  • Consider manually adding a new version with a readme to point people to the new version along with deprecation (see tutorial here)
  • Unlist old NetSparkle packages under our control to remove confusion
  • Update repo releases page with info on v2.0 and binaries to download (can manually grab these from NuGet for now)
  • Update Microsoft docs and the WinSparkle issue I filed to point to NetSparkleUpdater

System.IO.FileNotFoundException: Could not load file or assembly 'AppLimit.NetSparkle

Our WPF App (x86) has been encountering an error multiple times with FileNotFoundException for AppLimit.NetSparkle even though the DLL being present.

System.IO.FileNotFoundException: Could not load file or assembly 'AppLimit.NetSparkle, Version=1.0.84.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
at BibaApplication.Managers.BibaUpgradeManager.<>c__DisplayClass8_0.b__0()
at BibaApplication.Managers.BibaUpgradeManager.d__10.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.b__6_1(Object state)
at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

If there is any pointer to get around this.

appcast: the type attribute is never used

The type attributes of the appcast <item>s are never stored or checked. Should we verify that the media type (MIME type) offered by the server matches the type attribute before downloading the update?

Buttons not showing in the update window

I have installed the library in my C# project through NuGet, but every time there is an update the buttons to start downloading, to skip, or to remind the user to download later do not show up in the window, making the library impossible to use.

Here is an example of my code:

var sparkle = new Sparkle(
                Misc.Util.getUrl() + "/core/windows/agent/appcast.xml",
                Properties.Resources.Befective,
                NetSparkle.Enums.SecurityMode.Unsafe
            );
sparkle.StartLoop(true,true);

how the window looks

Add an appcast generator

We should create an appcast generator program that, at the very least, scans an EXE and outputs the applicable appcast info to an XML file or format. Preferably, it'd scan a folder of EXEs like the Sparkle generate_appcast tool and create a file that is updated over time and can just be plopped on the server.

[Input Wanted] Organization Name

Hi anyone who reads this!

In working on a 2.0 version of NetSparkle, this library really needs to be moved off of my fork to a GitHub organization for easier discoverability and searching.

Unfortunately, the name "NetSparkle" (github.com/NetSparkle) is already taken. I am looking for ideas on what to call the GitHub organization.

Should we rename NetSparkle entirely? (I don't know if this is a good idea.) Add a prefix/suffix? I want to keep spaces and punctuation out if we can so that URL stuff is easy.

Ideas:

  • NewNetSparkle
  • NetSparkle.New
  • NetSparkle-vNext
  • NetSparkle Reborn
  • NetSparkleShine
  • ???

Any input appreciated. I'd like to stick close to the original NetSparkle name so we can keep the NetSparkle NuGet repo and not make it look like NetSparkle (which has Google results, etc.) is dead.

appcast: the length attribute is never verified

The length attributes of the appcast <item>s (stored in AppCastItem.UpdateSize) are never checked. The size of the update file should be checked against this attribute before installation.

WPF-Based GUI

Need to create and maintain a WPF-based GUI. Probably want to have the option of using MahApps.Metro for the UI.

Show "Checking for Update" Screen On User Update Request

We shouldn't make the UI appear as though it is doing nothing when the user explicitly asks for an update request. Need to pop up (and therefore auto dismiss as needed) a window with an indeterminate progress bar that says something along the lines of "Checking for update...".

Refactor WPF code to use ViewModels

The WPF code should be refactored to use ViewModels so that the creation of new views by developers is a lot easier and doesn't contain any (or very little) copied business code.

I'm keeping this as a separate line item from #3 as it is more of a "step 2" after the initial WPF UI is working.

  • CheckingForUpdatesWindow [not really necessary; hardly has need for binding]
  • DownloadProgressWindow
  • MessageNotificationWindow
  • ToastNotification [not really necessary; mostly UI code]
  • UpdateAvailableWindow

[Discussion] Split UI entirely off of main NetSparkle project

@cjmurph has made a proposal that even more UI code be split off into their own projects. His code is here: https://github.com/cjmurph/NetSparkle/tree/seperate-ui Regardless of the outcome of this discussion, I want to thank him for the time and effort he's put into this. (I'm also sorry for the wait!)

The proposal is essentially that the UI projects respond to NetSparkle's event handlers rather than implementing a UI Factory. This cleans up the main NetSparkle project from dealing with all the intricacies of being compatible with both WinForms and WPF. However, it sort of results in a lot of duplicated ideas/code between the NetSparkleForms and NetSparkleWPF projects.

Personally, I like the idea of cleaning up the main NetSparkle project. I cringe a bit with all the threading and other weirdness. cjmurph also did some valuable work on splitting out WPF code to ViewModels as well as some other valuable refactoring work that we could / should bring in regardless. However, I think that this proposal adds potential increased complexity to creating a custom UI, and I don't prefer to keep up the duplicated code/ideas between the two UI projects. In addition, I think the current way the UI is setup, while blah in some regards, might be easier for forward compatibility -- you can just keep using the same UI factory and get compile-time warnings/errors when things change rather than "oops I didn't implement a new event that's necessary".

I would like to personally propose not making the overall change and just keep the status quo, but I'd like to also submit that we have a sample project that only hooks into events and not the UI Factory to demonstrate how users can do that. That sample project could show everything in the same window just as a proof of concept on how to hook into events.

I am open to other sides of the issue! Please let me know if you have other thoughts.

NetSparkle doesn't correctly handle Sparkle items that use a redirect

The InitDownloadAndInstallProcess function assumes that the path that is given in the xml is a valid final filename and sets _downloadTempFileName to be that filename and creates a temporary directory to contain it.

There is a problem with sparkle app feeds that use a redirect mechanism like Microsoft AppCenter - for example the feed https://api.appcenter.ms/v0.1/public/sparkle/apps/c27e6512-ceae-4665-82c5-c0d7f6a27f30 suggests a download enclosure location of https://rink.hockeyapp.net/api/2/apps/c27e6512ceae466582c5c0d7f6a27f30/app_versions/5789?format=zip&avtoken=26b4ee8fcdfde2e89ce5d7b54ad61f43172a32de&download_origin=hockeyapp&mctoken=ed71c9ffae166f2bfbfaf1335fcbaedb17cb0b0e however this location is actually then redirected to download the final MSI file.

The issue is that the file is successfully downloaded by WebClient.DownloadFileAsync, but _downloadTempFileName has not been set to match the redirected filename, so GetInstallerCommand does not know how to call the downloaded file.

I've tried checking the response headers that WebClient returns but there doesn't seem to be any that show the "actual" filename that should be used, so I suspect it might need a rewrite to use an HTTP WebRequest instead as this can apparently retrieve the correct filename. I'm afraid that is beyond my abilities though!

Multiple Hosts for AppCast file

Hi Folks,

in my project I have some sort of load balancing between multiple server hosts. In my case it should be possible to load updates from each of the configured hosts;

e.g.
server1, server2, server3

server1 gets a new appcast xml so the new version should be pulled from that current server by a number of clients (or all of them - depends on the interval check)

when server1 gets a new version shortly after that server2 and server3 gets the new version of the software as well.

is something like that possible?

TIA & best regards
Christian

Document fact that ProgressWindow needs to set DialogResult

ProgressWindow (thing that is returned by IDownloadProgress CreateProgressWindow(AppCastItem item, Icon applicationIcon in IUIFactory) needs to set DialogResult in order for the update to execute and not be deleted!

Pertinent NetSparkle code:

        private void showProgressWindow()
        {
            if (!isDownloadingSilently() && ProgressWindow != null)
            {
                DialogResult result = ProgressWindow.ShowDialog();
                if (result == DialogResult.Abort || result == DialogResult.Cancel)
                {
                    CancelFileDownload();
                }
            }
        }

Help with translation

Hello,

I need help with translation, trying to use spanish translation "es-MX" but no success, still showing up english strings.

This is my XML Appcast:

<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="es" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" version="2.0">
    <channel>
        <title>RENIEC - NetSparkle Test App</title>
        <link>http://npalominop.reniec.gob.pe/update.xml</link>
        <description>Most recent changes with links to updates.</description>
        <language>es-MX</language>
        <item>
            <title>Version 2.0 (2 bugs fixed; 3 new features)</title>
            <sparkle:releaseNotesLink>http://npalominop.reniec.gob.pe/2.0-release-notes.md</sparkle:releaseNotesLink>
            <pubDate>Thu, 28 Feb 2019 10:30:00 +0000</pubDate>
            <enclosure url="http://npalominop.reniec.gob.pe/dl/CamaraCapturaImagen_v1.3.1.exe"
                       sparkle:version="2.0"
                       length="6115328"                       
                       type="application/octet-stream" />
            <!--sparkle:dsaSignature="NSG/eKz9BaTJrRDvKSwYEaOumYpPMtMYRq+vjsNlHqRGku/Ual3EoQ==" -->
        </item>
    </channel>
</rss> 

Compatibility with Visual Basic on Visual Studio 2017 .NET 4.7.2

Dear mantainer,

I'm trying to use NetSparkle.New with a project made in Visual Basic .NET 4.7.2, everything goes fine until I click on "Install update" button after seen an update, and throws this error on console:

[Log] Preparing to download http://ws.reniec.gob.pe:7003/updater/dl/my-update.exe
[Log] Error showing sparkle form: Object reference not set to an instance of object

https://github.com/Deadpikle/NetSparkle/blob/master/NetSparkle/NetSparkle.cs#L968

Any ideas what it could be?

Thanks.

Resume downloads

When checking to see if a file on disk can be DSA-verified, remember if a file actually finished downloading or not and resume the file download if possible.

system profiling can't be enabled

The Sparkle.EnableSystemProfiling and Sparkle.SystemProfileUrl properties have private setters, and aren't set in the constructor. This means that they can't be enabled or configured.

Relative URLs for Items

Hi!

Sorry to bother you again; I have an issue with relative URLs for the items in the appcast.xml file.

As the appcast file for all servers would very much look the same I figured with relative paths they would be 100% be the same so I would be able to generate one appcast.xml file at build time, not for each server at install time.

The update mechanism works with absolute paths in the URLs of course.

My AppCast.xml would look like this:

<?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>starter</title>
        <language>en</language>
        <item>
            <title>starter app version 21.0.2</title>
            <pubDate>2019.02.08 11:56:53 MEZ</pubDate>
            <enclosure url="installer.exe"
                       sparkle:version="21.0.3"
                       type="application/octet-stream"/>
        </item>
    </channel>
</rss>

The installer.exe is located in the very same Directory where the appcast.xml is located.

Now I instantiate Spakle like

Sparkle sparkle = new Sparkle("http://localhost/aliasmatch/appcast.xml", this.Icon, SecurityMode.Unsafe);
sparkle.CheckForUpdatesQuietly();
sparkle.HideReleaseNotes = true;
sparkle.SilentMode = Sparkle.SilentModeTypes.DownloadAndInstall;
sparkle.CustomInstallerArguments = "/VERYSILENT";
sparkle.RelaunchAfterUpdate = true;
sparkle.AboutToExitForInstallerRun += BeforeRunInstaller;
sparkle.CloseApplication += CloseApplication;

When an Upgrade is attempted I get an Exception:

System.UriFormatException
  HResult=0x80131537
  Message=Ungültiger URI: Das URI-Format konnte nicht bestimmt werden.
  Source=System
  StackTrace:
   at System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind)
   at System.Uri..ctor(String uriString)
   at NetSparkle.Sparkle.InitDownloadAndInstallProcess(AppCastItem item)
   at NetSparkle.Sparkle.Update(AppCastItem[] updates)
   at NetSparkle.Sparkle.OnWorkerProgressChanged(Object sender, ProgressChangedEventArgs e)
   at NetSparkle.Sparkle.<OnWorkerDoWork>d__208.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.<ThrowAsync>b__6_1(Object state)
   at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

(Sorry for the German Error Message; it basically tranlsates to invalid URI Format - as the Exception says ;-)).

I took a look at GetAbsoluteUrlString which should return an Absolute URL for a relative item url:
https://github.com/Deadpikle/NetSparkle/#systemuri-getabsoluteurlstring

seems to be right; however; I looked further and in NetSparkle.cs Method InitDownloadAndInstallProcess

Line 1094 there is

Uri url = new Uri(item.DownloadLink);
[...]
_webDownloadClient.DownloadFileAsync(url, _downloadTempFileName);

Please correct me if I am wrong - but item.DownloadLink is a relative URL in my case - and the code should call GetAbsoluteUrl (or something similar)? Am I getting this right?

thanks & regards
Christian

UpdateAvailableWindow sometimes shows two different version strings (with/without revision)

UpdateAvailableWindow.getVersion function returns wrong number of fields.

private string getVersion(Version version)
{
    if (version.Build != 0) // should be Revision
        return version.ToString();
    if (version.Revision != 0) // should be Build
        return version.ToString(3);
    return version.ToString(2);
}

According to AssemblyInfo.cs the format of a version string is: Major.Minor.Build.Revision
So currently the function returns all components for a version string like 1.0.1.0 but only three components for a version string like 1.0.0.1

Line ending problems

It appears as though the .gitattributes file is not set up properly. Somehow, #47 got a bunch of EOL changes that were unexpected. .gitattributes is supposed to fix these sorts of things. I'm not sure what the issue is.

The current repo seems to have crlf as a line ending rather than lf, which is what I'd expect based on my own system setting of core.autocrlf true.

See this article. Perhaps text=auto should be text eol=crlf?

Seperate UI and Core Logic More

This is already sort of done with the UI factory stuff, but the main Sparkle project could be cleaned up more to have multiple projects under the main solution -- one for the core logic, one for a WinForms GUI, and one for a WPF GUI (and more for other GUIs). That way we don't have the strange conglomeration of WPF and WinForms GUI code that we have now.

Be able to override the registry key used to store the Configuration

I'm really loving Netsparkle I have to say - really great work. One thing that we've spotted coming from Winsparkle over to Netsparkle is the ability to override the registry key used to store the config.

With Winsparkle you can call win_sparkle_set_registry_path and having a property we can use or a method to call on Netsparkle would be great just so we can keep the reg key info for all our different applications alongside our usual user data

Just an idea, keep up the good work!

Text wrapping on Software Download (and no available update) dialog in 0.18

Hi,

We're using the 0,18 Nuget package, and we have an issue with the text in the dialogs wrapping on longer captions and it overlaying the Icon.

I know you're doing a lot of refactoring for v2, but would it be possible to get an updated fix and buget for 0.19 (yes, a cheeky request i know!) :)

Thanks,

image

.NET Core 3 Compatibility

.NET Core 3 is now out! Create UIs for .NET Core 3 for WPF and WinForms, and also make sure that the core NetSparkle is .NET Core 3 compatible.

feature request: make RunDownloadedInstaller method virtual & protected

I'm trying to integrate NetSparkle in my app, but i need to overwrite this method for customize the final step of installation.
I would like to execute custom code so i'll be able to manage other files type than .exe, .msi and so on.
The method GetInstallerCommand is yet protected and virtual but is not enough to reach my goal.

isReflectionBasedAssemblyAccessorUsed dosn't work

Hi, i need to use your app without reflection, but seems doesn’t work in my case, i try to use this code in my app

Sparkle sparkleUpdateDetector = new Sparkle(user_appcastUrl, icon, SecurityMode.Unsafe, "",
                @"C:\xxxx\xxx.exe")
            {
                TmpDownloadFilePath = Path.Combine(@"C:\xxxx", "Update")
            };
            sparkleUpdateDetector.Configuration = new RegistryConfiguration(@"C:\xxxxxx\xxxx.exe", false);

but when i set the isReflectionBasedAssemblyAccessorUsed = false, for use AssemblyDiagnosticsAccessor class, doesn’t work

i updated the source code, and i maked this modification

  1. In the constructor of Configuration class first invoke the InitWithDefaultValues() method, and then set the property UseReflectionBasedAssemblyAccessor, otherwise this property remain true.

  2. In case of use AssemblyDiagnosticsAccessor (Configuration.cs - row 93) the AssemblyProduct isn't the ApplicationName but the product version, i change the AssemblyDiagnosticsAccessor.cs and the property AssemblyProduct return the variable productName

I attached the two class so, you can compare with the original code and verify if my modification it's right or not, thank you so much

sparkleModification.zip

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.