09/25/2015

"Check for Updates" for an Application

Background

In this article I explore a simple mechanism to check if an update is available by querying a server. My use case was that I've been writing a C# Application and I wanted to include a quick "Check for Updates" functionality that would inform the user if an update is available.

Additionally, I wanted a simple upgrade process, so that I can upload a new setup file and it's picked up by the webserver automatically, so the requirements were quickly formulated:

Requirements

  • The client application should be able to detect if a new version is available
  • Publishing a new update should be painless

Formulating a plan

  1. The Client App reads it's version number
  2. Client App sends the version number to the Webserver
  3. Webserver compares the version number with the latest available version and returns the result
  4. Client displays the result and asks the user to upgrade

Step 0 - Versioning the Application

As it turns out, there is a Step 0 associated with this process and that is versioning the application in the first place.

The simplest way to version your app is probably using the System.Reflect.AssemblyVersionAttribute as used in the auto-generated AssemblyInfo.cs file in your application.

I personally prefer to let the build process increment the build and revision parts of the version, so I've changed the use of the AssemblyVersion attribute in AssemblyInfo.cs to:

[assembly: AssemblyVersion("0.7.*")]
That way, even if I forget to manually increment the version number, the versions differ between each build which adds an additional safety net when diagnosing problems.

On top of that I removed the [assembly: AssemblyFileVersion("1.0.0.0")] declaration, as I prefer to keep them in sync.

After rebuilding the application I checked the generated version by right-clicking the file and selecting "Properties" -> "Details", as you can see in the screenshot.

Step 1 - Reading the Application Version

Reading the version of the Application is a one-liner:

var version = Assembly.GetExecutingAssembly().GetName().Version;

Step 2 - Sending the Version to the Webserver

Sending the version to the webserver and retrieving the result is done using a simple WebRequest:

  var baseUrl = "http://yourdomain.com/yourapp";
  var url = Path.Combine(baseUrl, string.Format("isupdateavailable?v={0}", version));
  var request = (HttpWebRequest)WebRequest.Create(url);
  if (((HttpWebResponse)request.GetResponse()).StatusCode == HttpStatusCode.OK)
  {
    /* update is available... */
  }
The above code snippet assumes that you have a webserver that returns OK when an update is available. We'll see about that in the next step. In a production ready case you might want to use GetResponseAsync and return an Task.

Step 3 - The Webserver compares versions

The webserver retrieves the version from the parameter, creates a Version object and compares the Version object with that of the current file.

In my case, I chose to encode the version in the setup file name like so: 'setup_0.8.5742.26637.exe' and read it back in using a regular expression. My reasons for not using the same process as on the client were the following:

  • You can upload multiple setup files, which is handy if you want to be able to keep older versions
  • As the generated setup file is native code (I am using NSIS to create the installer), not a managed assembly, reading the product version breaks down on a linux server (which I happen to use). The reason is, that the Product Version is encoded in the PE-Header of the file and while mono allows reading the version from a .NET assembly it does not work with a native file as it would on windows.

So the code to retrieve the current version looks something like this:


private static Regex SetupFileRegex = new Regex("Setup_(?.*?)\\.exe");
private Version GetVersionFromFileName(string fileName)
{
  var m = SetupFileRegex.Match(fileName);
  return m.Success ? new Version(m.Groups["Version"].Value) : null;
}
private Version GetLatestVersion()
{
  string[] files = Directory.GetFiles(GetSetupFolder(), "Setup_*.exe");
  return files.Select(f => new {
    File = f,
    Version = GetVersionFromFileName(Path.GetFileName(f))
  })
  .Where(f => f.Version != null)
  .OrderByDescending(f => f.Version)
  .First()
  .Version;
}

Returning the correct status code becomes easy then, simply compare the versions. For example like:

var clientVersion = new Version(this.Request.Query["v"]);
  var latestVersion = GetLatestVersion();
  return clientVersion < latestVersion ? HttpStatusCode.OK : HttpStatusCode.NotFound;
  
In a solid web framework, returning the status code should be as easy as that. I personally use NancyFx for all Serverside coding and warmly recommend it, the SDHP is true, it's really a pleasure to work with.

Step 4 - Display "Update available"

In my use case, I chose to simply display an "update available" button in my application that takes the user to the download page, which I find is the most flexible solution, as I can keep the updating process itself and change and release notes separate from the application.

Take care,
Martin

References

Last updated 10/21/2018 21:46:15
blog comments powered by Disqus
Questions?
Ask Martin