In my company, we have a lot of separate tools for monitoring machines, flows, etc., for altering or viewing DB data, and you name it.


As lead .Net developer for my company, I decided to embed all windows applications in the same framework, making it easy to add functionality.   Every PC needed a simple installation and they could use all the functionalities. As the application grew, there was a need to embed security, because not all users have access  to all functionality. So I build in log-in and enhanced security, making it possible to hide each sub application according to the users role. But each time I made these changes to the program, I needed to update all the clients.

At first I was thinking of deploying via IIS (click-once), so we 1 central version, but this was not possible. The security was too tight. Using web-services or remoting could be a solution, but it was too slow. So a windows application was the best in this situation. 

The solution to all these problems was: creating a self updatable program. This challenge was tackled and solved. Not using application blocks, just a very simple solution. Here it is:   

The idea was to place the latest version on a drive map, and all programs would check before starting up if their version was up to date.   The biggest problem you encounter when writing an update procedure is that when you want to copy files, the program needs to be shutdown. You could write a wrapper that handles the update, but then, when the wrapper needs to be updated, you have the same problem. So I found another way. I guess many people have done it this way before, but I couldn't find it on Google.   At the start-up I have this code that calls the check version method:

Assembly asm = Assembly.GetExecutingAssembly();
//Check registration and version
CheckRegistration(asm.GetName().Version.ToString());
 
 

The checkregistration method handles the actual update, also writes the version to the database, so I can track the installed versions. 

       BU_BRSApps.Logic.BRSData data = new BU_BRSApps.Logic.BRSData();
       string compName = System.Windows.Forms.SystemInformation.ComputerName;
       if (!CheckVersion(currentVersion, ref string newVersion )){ 
DialogResult res = MessageBox.Show("Program needs to be updated, update now?", 
"Update",MessageBoxButtons.YesNo);
        if (res == DialogResult.Yes)
        {
MessageBox.Show("Program will restart automatically in a few seconds.");
               data.DeleteRegistration(compName);
               GeneralFunctions.ProcessBatchFile("updater.bat");
               data.InsertRegistration(compName, newVersion);
               this.Dispose(true);
               this.Close();
        }
}
 

The first methods you encounter is the CheckVersion method, this is to check the current version against the one on the file share. Here's the code for that: 

 
private bool CheckVersion(string currentVersion, ref string newVersion)
{
        BU_BRSApps.Logic.BRSData data = new BU_BRSApps.Logic.BRSData();
        newVersion = data.GetRegistration("LatestVersion");
        if (newVersion == currentVersion)
        {
               return true;
        }
        return false;
}
 
 
 

If the assemblies are different, it means that a new version is available on the file share and the current version needs to be updated. Now the trick on how to do the actual update:    

 MessageBox.Show("Program will restart automatically in a few seconds.");
data.DeleteRegistration(compName);
GeneralFunctions.ProcessBatchFile("updater.bat");
data.InsertRegistration(compName, currentVersion);
this.Dispose(true);
this.Close();
 
 
 
 

First I delete the current version in the database, then I open the updater.bat file in a new process. When this process is started I insert the new version and close the current application. The ProcessBatchFile method opens the updater.bat file, this bat file is copied to the output directory and looks like this:   

 
 
ping 127.0.0.1
copy M:\MRD\BRSSupport
BRSupport.exe
exit
 
 

The first thing the bat file does is ping to the local adress, so the program has time to close down. Then it starts to copy the new files and when this is finished, it opens the application again. This process only takes a few seconds. During this time the user has no interaction because I set the process to run in the background. But I warn the user of this before they choose to update. After some testing it appears to be working fine. I'm going to test it some more to see if the time the ping takes is long enough for the slowest systems on the network.  

I know there are better solutions, I also know this works for me. If you have suggestions or ways to self-update a program better, please post comments. One thing I thaught of was: instead of using the .bat, a seperate exe file that does the work. This way I could interact better with the user. But no time for this yet.   In my company, fast and good solutions are needed, this one I had to think of and develop in 1 or 2 days max.