dan
dan

Reputation: 9852

Simplified application updating in .NET

Automatically updating a desktop application seems to be a hard problem in .NET. There are a number of solutions, from microsoft's clickonce, to various open source and paid solutions. The pattern in all of these is:

1 check remote server for version to run
2 download the new version
3 unpack to a temp folder
4 start a shim process to replace the old files with the new after the app shuts down
5 kill the running app so the shim process can begin working
6 restart the main app

This process seems to have a lot of moving parts and points of failure. However, you can write your application to be a simple loop that downloads and executes a remote dll. It seems this avoids a lot of the complexity involved in automatically updating your application, like user permissions, uac, antivirus programs, etc.

It seems solid and futureproof to me. My app doesn't need lots of large support files, so is there a reason I shouldn't use this approach? Are there ways this can go terribly wrong? If so, how do these complexities compare to the complexities of other auto-updating solutions?

for example:

Thread helper;
int currentVersion=0;

static void Main()
{
  //dumb loop, functions as a loader
  while(true)
  {
      var remoteVersion = GetRemoteVersion();
      if(remoteVersion > currentVersion)
      {
         if(helper != null)
         {
            //kill thread gracefully :)
         }

         currentVersion = remoteVersion;
         byte[] bytes = GetRemoteDllAsByteArray();
         var asm = Assembly.Load(bytes);
         var t = asm.GetType("a known type with a static method called Start()");
         var mi = t.GetMethod("Start");

         //run this on a helper thread outside the main loop:
         // the start method is the entry point to your application
         helper= new Thread(() => mi.Invoke(null,null));
         helper.SetApartmentState(ApartmentState.STA); //for winforms/wpf
         helper.Start();
      }


      Thread.Sleep(1 day);//only check for new versions once a day
  }   
}

The extra complexity in my example is you have to package all your dependencies as resources in the downloaded dll, but that can be set up as a build step, and it avoids messing with the user's filesystem.

Upvotes: 0

Views: 254

Answers (1)

Felix K.
Felix K.

Reputation: 6281

Your solution should work and if you want to keep it simple it seems to be a good approach.

Note

You should load your assemblies in another domain because of the fact that, if you update your application, you gonna load the same types at the same namespaces. This gonna lead to conflicts. The other way is to restart your application.

Dependencies

You do not need to package all dependencies as a resource. Use a binary file which is downloaded, unpacked ( zip ) and contains all assemblies.

To do this you can use a simple approach( Pack / Unpack ):

  • Write / Read ( client-side ) the name of the assembly
  • Write / Read the byte-size of the binary file as Int32
  • Write the bytes of the assembly into the file / Read the bytes of the assembly and write it to disk or a custom file system
  • Continue this until each file is packed / unpacked

When resolving the dependencies you could use something similarly to this sample: Assembly loaded using Assembly.LoadFrom() on remote machine causes SecurityException

Updates

Its also possible to use this system to create update packages for each version update ( e.g. 1.0 -> 1.5 or 1.3 -> 1.5 ). This avoids a lot of traffic if you check the deprecated files first and create a package for each version update.

Upvotes: 1

Related Questions