Reputation: 9852
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
Reputation: 6281
Your solution should work and if you want to keep it simple it seems to be a good approach.
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.
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 ):
When resolving the dependencies you could use something similarly to this sample: Assembly loaded using Assembly.LoadFrom() on remote machine causes SecurityException
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