On Auto-Updates

Despite my best googling efforts, I’ve yet to find any posting on designing an auto-update feature for my code, so in the traditions of NIH, I rolled my own.  It seems, ultimately, that the simplest solution is, well, the simplest solution.

Since I work on Windows, it is easy to get the current application’s name and version (provided you have set it and maintain it) from the resource file, either in .NET or Win32. So straight away you have your application name, and your current application version.   The next thing is to store the new version away somewhere. Going back to my comment about the simplest solution, parsing HTML is, to say the least, difficult. Putting updates on the web demand a web page, and hence HTML.

HTML can be tackled in a variety of ways, the worst of which is probably a regular expression, up to using something like http://htmlagilitypack.codeplex.com/. Either way, in HTML, you end up with a solution not dissimilar to:

<span class='name'> My App </span>
<span class='version'> My Version </span>

and parsing it relies on you trusting whoever edits the HTML to preserve the tags, classes and/or ids.

So back once again to ‘simple’. My solution is this: a text file containing comma separated values. Why? It is easy, it is human readable, and it is pretty near impossible to get wrong. When scanning it, you can just skip everything in there except your application information. It could contain a header, plus the information:

Name,Version,Installer
My App, 1.0, http://localhost/my_installer_1.0.msi

At this point someone reading this (yes, you!) will say: “but what about the web page?” Well, that is now fairly trivial with modern Javascript libraries. A little bit of jquery, and a little bit more, and you’re most of the way there. Making the installer a hyperlink is left as an exercise. Or you could simply then just maintain a static HTML page to go with the text file.

For C#, the code to get the file is remarkably trivial. For a blocking single-threaded web request:

System.Net.WebClient webClient = new System.Net.WebClient();
//  blocking...
webClient.DownloadFile(new System.Uri("http://localhost/updates.csv"), @"C:\updates.csv"));

Put this into the appropriate try catch block, and download to a file of your choosing.

On Version Naming.

What’s the difference between version 3.2 and version 3.12? For one thing, you might think 3.12 is later than version 3.2, but you would be wrong. A naive implementation of an auto-update system that checks versions would do this:

if (new_version > old_version) {  run_installer(); }

Except for two things:

1. You might have chosen new_version and old_version to be doubles. Then 3.2 is actually 3.20 which IS greater than 3.12 and your installer never gets run.

2. You might have been smarter and chosen new_version and old_version to be strings, so you could have 3.2a and 3.12b, but you would still be in trouble because a string comparison compares characters at a time, and once it gets to the ’1′ in 3.12, and the ’2′ in 3.2, it once again decides that 3.2 is greater that 3.12, and once again your installer doesn’t start.

So your run_installer clause ends up being:

if (new_version != old_version) { run_installer(); }

which has the side effect of allowing rollbacks to prior versions if you so choose (assuming of course that the MSI installers don’t prevent you from doing that).