Udostępnij za pośrednictwem


Simple Auto Update, auto patch, for WPF Apps, without the Updater Block

I am writing some smaller WPF apps, and I want them to automatically update themselves, or automatically patch themselves, something like Lutz Roeder's Reflector or Paint.NET does.   Scott Hanselman has commented on this previously, and he's right. Every app ought to be able to do this.

I looked into the Application Update Block, which was last updated I think in 2005, and is at version 2.0.  This is a thorough application block (a body of reusable code) that seems to do "everything".  But it's a little too much for me.  It requires the .NET Enterprise Library, which is free, but a lot of extra code. It all feels like too much work.  Too much configuration, too many options, too much flexibility.   It's too much for what I want.

My apps are small, single EXEs, no installation, no config files, and so on.  This is a very very simple scenario.  The Updater Block is overkill.

I looked into using AppDomains and getting fancy that way, but I didn't like that approach either. Too complicated, too unnecessary.  The AppDomain is a nice structure if I want the process to continue living through the update lifecycle.  But I don't need the process to live forever.  I don't care about re-cycling the process.  So AppDomains seem like the wrong approach too.  

I also looked around for some biolerplate code produced by someone else, something I could re-use.  But I couldn't find anything accessible.  I think there are commercial third-party components that do this, but this was just for some really basic apps, I didn't want a commercial solution.  So, I built it myself.

A Simple Approach to Self Patching Apps

There are really two steps to the auto-update, or auto-patch trick.   First is to find out the latest version of the app, Second is to get the latest version and replace the old version with your new version.  The first problem is simple, just an HTTP GET (in the REST tradition) on a text file containing the version number. The second problem is more challenging.

The EXE starts up, and it can do the HTTP GET to find out it needs to be updated.  But then what?  Of course, the app could go get the updated version of the app image, with the same kind of HTTP GET.  For a reasonably sized app (let's say up to 1mb EXE image size), this will be reasonably fast, well within the realm of acceptable performance. Even for a 20mb download, it's still acceptable.  BUT, while the EXE is running, the EXE Image on disk is locked.  It cannot be overwritten. This second problem is trickier.   

What I settled on was this: have the executing application replicate itself.  The App starts up.  Let's say it runs in process 1.  checks for available updates.  If it finds an update, it replicates - copies its EXE image to another location, a temporary location.  The original  process then does a Process.Start() on that copy of the EXE, we now have process #2.   Then the original process (#1) exits!.   This unlocks the original EXE image on disk, so that it can be overwritten.   The process running from the temporary copy location, now downloads the latest, updated EXE image, and copies it to the original location.  The Updater clone process then does a Process.Start() on the original EXE location.  This creates process #3.  Then Process #2 exits.  When process #3 starts up, it checks for updates and finds none, since it is the running from the latest EXE image. Process #3  then tries to clean up any EXE "updater clone" images - this last step is just good manners and not strictly necessary for correctness.

This should work with any WPF application.  The approach will also work for WinForms applications, but the code I have here, will not.

Here's what the code looks like in your app; you embed this in the code-behind of your WPF Window class:

 public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        if (UpdaterCheck())
            this.Hide();
    }
    private Ionic.AppUpdater.Wpf.Updater _updater; 
    private string _manifestUrl =
        "https://example.org/AppUpdates/MyApplication/Manifest.xml";
    private string _infoUrl = 
        "https://example.org/MyApplication.html";
    private string _description =
        "MyApplication is a delightful application; it does x, y, and z. " +
        "It uses the Ionic AppUpdater module for WPF for auto-update " +
        "capability.";
    // Obtain the publicKey XML from the ManifestTool that ships with Ionic AppUpdater.
    // The following string is Ionic's public key.  You will need a different one.
    // Consult the Readme for more information. 
    private string _publicKeyXml = "<RSAKeyValue><Modulus>sZqhvF0KX6m4blah..blah...=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
    private bool UpdaterCheck()
    {
        _updater = new Ionic.AppUpdater.Wpf.Updater("This is MyApplication.",
                                                    _infoUrl,
                                                    _description,
                                                    _manifestUrl,
                                                    _publicKeyXml);
        return _updater.Status.IsUpdating; 
    }
    ...   

When this runs, the Updater() will check for updates and will inform the user if a more recent version is available.  

When it starts up, the sample app looks like this  :

auto updating app

 

Not very fancy. But this is just an example. It can be any WPF application. If there is an update, then automatically, this UI is presented:

update notification

This UI is not something you have to code;  It is generated by the AppUpdater module, based on strings your app passes in to the AppUpdater constructor.  If the user clicks the "Get Update" button, then the app automatically begins downloading.  There's no code required for that, either.    It looks like this: 

update progress

You don't have to code any of this.

When the download completes, that window disappears, and then the app starts up again.  It all happens pretty fast for a small app.  For my sample app of around 28k, it happens in less than a second. 

Now, in general, people will want different user interaction models.  The code above will nag the user, every time the app starts. You might want to be more in the background - and only tell the user if there is an update when they ask. Maybe you notify about updates based on a click on a menu item, maybe it's a button click.  This is easy to do, too. Just put the call to the Updater() constructor in the code-behind for the button or menu item. The UI will look the same.

I hope this is useful.

The source is attached here.  It is all C#.  This requires the .NET Framework v3.5, and WPF.

Hmmm, what about Security? 

My first crack at this just used a text file holding the Version tuple (1.2.3.4), and if the version was different, the app would download itself and there ya go.  But the security of that approach was pretty loose.  I saw an older comment from some guy named Mike, who described an approach to signing an XML manifest file, and including an MD5 hash in that manifest.  So I adopted that approach (except I use a SHA256 hash).  I used this codeproject article as a hint for how to sign the XML and verify the signatures.

The tool emits a signed XML manifest that looks like this:

 <UpdateInfo xmlns="urn:Ionic.Apps.Updates">
  <LatestAvailableVersion>1.2.5.4</LatestAvailableVersion>
  <ImageName>MyApplication.exe</ImageName>
  <AssemblyFullName>MyApplication, Version=1.2.5.4, Culture=neutral, PublicKeyToken=null</AssemblyFullName>
  <TimeStamp>2009-08-11T02:31:43.2320026-04:00</TimeStamp>
  <Hash>8BA50BC233CB70478E04D6A740358E3DD0F30C78988BFC22D4AC58A8D777A8FE</Hash>
  <HashType>System.Security.Cryptography.SHA256CryptoServiceProvider</HashType>
  <DownloadLocation>https://example.org/AppUpdates/MyApplication/MyApplication.exe</DownloadLocation>
  <Signature xmlns="https://www.w3.org/2000/09/xmldsig#">
    <SignedInfo>
      <CanonicalizationMethod Algorithm="https://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
      <SignatureMethod Algorithm="https://www.w3.org/2000/09/xmldsig#rsa-sha1" />
      <Reference URI="">
        <Transforms><Transform Algorithm="https://www.w3.org/2000/09/xmldsig#enveloped-signature" /></Transforms>
        <DigestMethod Algorithm="https://www.w3.org/2000/09/xmldsig#sha1" /><DigestValue>cUxRXJ0lcVcAB7cdWkRdyggAVEM=</DigestValue>
      </Reference>
      </SignedInfo>
      <SignatureValue>CheE/WCcHvbsZr9Y3ACpX4Wqp9e/0cpUpEE6JYtjl2dZdr606xIcGsouUnjOBNfEPs02neRIuVMrGMCo/4ImkbSlprroQY6/Yd9ne7LXytBd1/5+RfJzHoKMM7/Nnoc2A3eP7wBpEtGgMJZ3VFrDHxLRJSpaEKpWdOPO6EIEmGk=
      </SignatureValue>
  </Signature>
</UpdateInfo>

 

The source for the Updater module, as well as a sample app demonstrating its use, and the manifest tool, is all attached here.

This really has nothing to do with Interop, but it's a handy thing to have.  Now, go and be cool, and build self-patching, auto-updating applications.

 

WpfAppUpdater-1.4-2009-October-09.zip

Comments

  • Anonymous
    April 14, 2008
    Thanks, just what I was looking for in a nice package.

  • Anonymous
    August 05, 2009
    What happened to the source code link? Can you please make it available again? Thanks!

  • Anonymous
    August 10, 2009
    The source code is still available, as an attachment.

  • Anonymous
    October 08, 2009
    This is a great package that works slick.   There appears to be an issue though if your installed application is below a sub directory containing a space (like Program Files).    This will cause an update to crash.

  • Anonymous
    October 09, 2009
    This is great!  Thanks for sharing!

  • Anonymous
    October 22, 2009
    I fixed the problem with the sub-directories that contain spaces.

  • Anonymous
    December 02, 2009
    Do you also copy .config files and all other assemblies under the directory subtree rooted at the folder which contains your original exe? Your particular solution cannot know all dependencies code takes without doing full transitive analysis of binds.

  • Anonymous
    December 03, 2009
    As I said, it's for a single-exe deployment.  Also, if you update a .config file in the install, I think you're doing something wrong.

  • Anonymous
    July 22, 2010
    First thank you for your useful application,second i want to know where manifest.xml will be saved because i tried to find it in the code and i couldnt find,thanks

  • Anonymous
    December 10, 2010
    Hi, Thanks for the post. I am new to Windows development. I am trying to understand your code, but its not clear, is there any more detailed explaination of it apart from here? Thanks