If you've worked along with this article, by now you should have set up and configured the Updater for your application and created a network share or virtual directory that you can use to deploy updates. Your app is almost ready to be deployed, but you need to complete the AppStart component provided by Microsoft with the block code so that it will launch the Updater block and manage downloads.
The AppStart code, as provided with the Updater block, is incomplete; AppStart's Main()
method checks to make sure your app isn't already running, and launches your app in a new process. It doesn't contain any code to manage the Updater and download updates. This is to ensure that AppStart remains generic so it can be used in a variety of different deployment scenarios. Microsoft has provided several QuickStart samples with the Updater Block installation to illustrate each usage scenario.
As you're building a self-updating Windows Forms app, the Self Updating QuickStart is the place to begin (you'll find the code in the SelfUpdating2.cs
file in the QuickStart SelfUpdating
folder with the rest of the Updater block source). Have a look through the code for this version of AppStart and familiarize yourself with it; you'll need to create your own version of AppStart or your application, using this as a template. I'm not going to reproduce the code in the QuickStart hereI'll leave you to create your own AppStart using the information in the next few sections.
The first thing to notice is that AppStart launches the Updater on a new thread; the code in AppStart's Initialize()
method calls into ApplicationUpdateManager.StartUpdater()
. After launching, all subsequent communication is triggered via events raised from the Updater. You may be aware that Windows Forms controls aren't thread safe, which means that you can only access Win Forms controls from the thread on which they were created. To ensure that this rule isn't broken (which can lead to random deadlocks, InvalidOperation exceptions and other strange and difficult to reproduce behavior), the Updater events are handled using the AppStart form's Invoke()
method which uses a delegate to a method that is guaranteed to be invoked on the UI thread. There is an excellent discussion of the Win Forms thread safety issue, along with sample code at: http://www.devx.com/dotnet/article/11358/0/page/3.
To summarize then, AppStart launch your application in a new process, which ensures that the user can continue on with working in your application while AppStart drives the Updater. The MS-supplied code lacks a means to exit AppStart when the user terminates your app; without this, AppStart will get "stranded", and continue running. To prevent this, you need to change the StartApp_Process()
method in AppStart, as follows (note that I take no responsibility for the coding standards in use by the authors of the application blockfew of the MS App Blocks conform to the .NET Design Guidelines, and I usually have to exclude them from my FxCop
ProcessStartInfo p = new ProcessStartInfo (_exePath);
p.WorkingDirectory = Path.GetDirectoryName(_exePath);
_process = Process.Start(p);
// Add the following lines to ensure that AppStart
// terminates when the app process exits:
_process.EnableRaisingEvents = true;
_process.Exited += new EventHandler(process_Exited);
method (helpfully created for you by Visual Studio) should stop the Application Updater if it is running, and also kill the AppStart process with the line:
Now that you've ensured that both AppStart and the Updater will be cleaned up when a user closes your application, you can get on with wiring up the Updater's events. The Updater events all provide an ApplicationUpdaterEventArgs class argument, which supplies comprehensive information about the new version, derived from the server manifest file. The available information includes the application name, the new version number, the location of the new version on the network, and even information about the files included in the update.
You should subscribe to the Updater events shown in Table 2:
Table 2. The table shows the Updater events that you should subscribe to, along with a description and a usage scenario for each.
||Fires when the Updater reads the server manifest for your app and the version number of the update is greater than the version installed.
||Use this event to notify users that an update is available; you might display a MessageBox giving them the option of downloading the update (you should never force an update on the user), and perhaps provide a link to information about the benefits of upgrading to the new version.
Note that unless you prevent it, the Updater will continue to run, downloading the updated files after raising the UpdateAvailable event. To prevent this, you must block the Updater thread in your handler for the event (the best way is to use a modal dialog or MessageBox), and call the ApplicationUpdateManager.StopUpdater() method if the user decides to reject the update.
||Fires when the Updater begins to download the update.
||You might want to take advantage of this method to provide feedback to the user on the progress of the download. To provide this kind of feedback, you ideally need to know how many files are to be downloaded, and some way of calculating how long it takes each to download.
The ApplicationUpdaterEventArgs class provides you with a Files array from which you can obtain the number of files to be downloaded. It's a bit trickier to work out when each has been successfully downloaded, but you can use a FileSystemWatcher on the download temp directory (you set this in the <tempDir> element of the Updater <application> config section). Note that the downloader will generate .tmp files as it streams down the bits, and you may find that the FileWatcher will notify you two or three times per file as the .tmp files are downloaded and transformed into the actual application files. I recommend you wire up both the Created and Changed events of the FileSystemWatcher to ensure you receive proper notifications during the download.
Using this information, you could set the Maximum property of a Progress Bar control to the number of files, and call the Increment() method in the handler for the FileSystemWatcher events.
||Fires when the application files have been downloaded and moved from the temporary download folder into the new application folder.
||You can use this event to close down any dialogs you displayed to indicate download progress, and ask users if they want to close the application and launch the new version (the QuickStart shows you how to do this). Likewise, if your update made changes that require a reboot, this is the time to ask users if they want to reboot right away or later.