Some updates on NAppUpdate

.NET, English posts, NAppUpdate, WinForms, WPF Comments (3)

After having several issues with their auto-update mechanism, 2 weeks ago the Hibernating Rhinos profilers were updated to use NAppUpdate. Once again it was proven to be a very flexible and robust library, and several updates were already pushed to hundreds (thousands?) of users without any problem.

Before the profilers could start using NAppUpdate I had to make some updates to the library, namely: catch and expose the last error thrown (if any); fix an issue with UAC popping for updates on Windows 7 and Vista; better support for promptly cancelling a download mid-way; and a few other fixes and updates. These fixes are already available on github, and probably invalidate the 0.1 release...

Implementing NAppUpdate required custom implementation of a FeedReader and a Task, and the whole process didn't take more than one hour to code (testing is another story...). The profiler's AutoUpdateFeedReader makes a simple check against a very simple one-liner feed with the profiler's current version, and the it's AutoUpdateTask downloads the latest build as a zip file from the server, extracts it to a temporary folder and when told to overwrites the old files with the new ones in a bulk.

The actual task looks something like this - note the logical separation into steps, which are executed sequentially:

public bool Prepare(IUpdateSource source)
{
    // Clear temp folder
    if (Directory.Exists(updateDirectory))
    {
        try
        {
            Directory.Delete(updateDirectory, true);
        }
        catch {}
    }

    Directory.CreateDirectory(updateDirectory);

    // Download the zip to a temp file that is deleted automatically when the app exits
    string zipLocation = null;
    try
    {
        if (!source.GetData(LatestVersionDownloadUrl, string.Empty, ref zipLocation))
            return false;
    }
    catch (Exception ex)
    {
        Log.Error("Cannot get update package from source", ex);
        throw new UpdateProcessFailedException("Couldn't get Data from source", ex);
    }

    if (string.IsNullOrEmpty(zipLocation))
        return false;

    // Unzip to temp folder; no need to delete the zip file as this will be done by the OS
    return Extract(zipLocation);
}

public bool Execute()
{
    // since all we do is a cold update, nothing other than backup needs to happen here

    return true;
}

public IEnumerator<KeyValuePair<string, object>> GetColdUpdates()
{
    if (filesList == null)
        yield break;

    foreach (var file in filesList)
    {
        yield return new KeyValuePair<string, object>(file, Path.Combine(updateDirectory, file));
        Log.DebugFormat("Registering file {0} to be updated with {1}", file, Path.Combine(updateDirectory, file));
    }
}

Triggering the actual check for updates is a one-liner (after configuring the UpdateManager instance with a feed URL, a FeedReader and all that; the task is created and returned by the custom FeedReader):

UpdateManager.Instance.updateManager.CheckForUpdateAsync(StartDownloadingUpdate);

// ...

private void StartDownloadingUpdate(int updates)
{
    if (updates == 0) // no updates are available
        return;

    if (updates < 0) // an error has occurred
    {
        Log.ErrorFormat("Error while checking for updates: {0}", UpdateManager.Instance.LatestError);
        return;
    }

    // If updates are found, start downloading them async
    UpdateManager.Instance.PrepareUpdatesAsync(success =>
    {
        if (!success)
        {
            if (UpdateManager.Instance.LatestError != null)
            {
                Log.ErrorFormat("Error downloading updates: {0}", UpdateManager.Instance.LatestError);
            }
            return;
        }

        // Notify the user of the update, and call UpdateManager.Instance.ApplyUpdates() when ready
    });
}

It couldn't be simpler than that, and it just works...

This has triggered some interest in the project, and wheels are now in motion again and hopefully new features will be introduced soon, followed by a 0.2 release.

As always, you can grab the sources and file bugs here. Bugs and feature-requests can also be submitted to the mailing list.

Comments

  • Oscar

    Hi, thanks for all your job, I've searching for this V0.2, but I can't find it. Could you tell where can I download it?

  • Myth

    Hey,

    I can't find this in the sources. What i'd like to have is just a remote check to the remote file 'currentVersion.txt', and if it's higher than the local build, it should download and extract a zip file to overwrite the local copy. My app uses way to many files to actually add a per-file check.

    Kind regards, Stijn

  • Konstantin

    Hello You have done a great job!

    Unfortunately WPF sample does not work :( 1) Please, include SampleApp1.2.zip to the downloading package on github 2) When you create task (FileUpdateTask) using AppcastReader, task's LocalPath field is not initialized. Then when you do the preparation of FileUpdateTask you check if LocalPath is null and if it is you return. In this case it is always null and it should not be like that

Leave a Comment