One of the great things about developing applications using the Windows .NET Framework is the deployment model. Because managed code supports XCOPY deployment, an application can be deployed simply by copying the directory in which it lives to another computer. No registration required.
While the Framework automatically supports this form of no-touch deployment when running a Windows forms application from a browser, there are security restrictions that by default only allow the application to run in a "sand box" with limited permissions. As a result, many organizations that want to deploy updates from a central server to multiple workstations have embarked on creating their own system to update managed applications on the fly. If your organization hasn't rolled its own solution, you should take a look at the Microsoft Updater Application Block released in June of 2003 on MSDN.
The Updater Application Block
The Updater is one of eight application blocks released by Microsoft in the last year, which serve as Reference Building Blocks, and that were developed by the Patterns and Practices group as discussed in a previous article. At least two other application blocks articles have been featured on Builder.com, including the Exception Management Application Block and the Aggregation Application Block.
The Updater ships with source code in both VB and C# for its two class library assemblies, one Windows utility and its Application Launcher, three complete demonstration applications in both languages, and a nicely written help file that should make it easier to get started.
The Updater implements a pull model where a process (either the application itself or a service running on the workstation) running on the workstation called the controller periodically checks with a central sever to see if updates are available. If updates are available, they are downloaded to the workstation (as shown in Figure A).
The Updater first checks the manifest file on the server to see if a new update is available and then downloads and verifies the files. The location of the server and other information is stored in the application configuration file of the controller.
This process has a number of interesting features and components that you'll want to be aware of, including:
- Updates are listed in a manifest file (an XML document) for the application and include the list of files that comprise the update and a hashed signature for each file. The manifest file can be created using the ManifestUtility that ships along with its source code with the Updater.
- Settings in the controller's application configuration file determine how often the update process is run.
- When the update process runs and finds that a new version is available by checking the manifest, the download process begins.
- To download the files in the manifest, the Updater uses the downloader component referenced in the controller's configuration file. The Updater ships with one such component that uses the Background Intelligent Transfer Service (BITS) to copy the files to the workstation. However, custom downloaders can be developed and used by inheriting from the IDownloader interface that ships in one of the Updater's assemblies and then by registering the downloader in the controller's application configuration file.
- Once the files are downloaded, they can be optionally validated using the signature placed from the manifest file. This ensures that the files have not been tampered with on the server since the manifest was built. When the manifest is created with the ManifestUtility, the signature is created based on the chosen validator component and optional key. The Updater ships with both a KeyValidator that validates using a symmetric cryptographic key and an RSAValidator that uses a public/private key pair to perform the validation.
As with the downloaders, this process is extensible by inheriting from the IValidator interface and registering the validator in the controller's application configuration file. Of course, the key information needs also must be present in the controller's configuration file so that the validation can proceed on the workstation. So the RSAValidator is more secure since the private key used to generate the signature can be kept secret while the public key used to validate the signature is well known.
- If the files are valid (although validation can also be skipped by changing a setting in the controller's configuration file), they are then copied to a new directory on the workstation. This ensures that, if the application is currently running, it won't be disrupted by the download process. This implies, however, that the next time the application runs, it may run from a different directory because of the update process.
To execute the appropriate version, the Updater relies on an Application Launcher (i.e., bootstrapper) called AppStart.exe. This executable reads its application configuration file (AppStart.exe.config) to determine the current version and to determine from where it should execute. Shortcuts and program group icons can then point to AppStart. As a result, the controller's application configuration file includes an <application> element that points to the application launcher's configuration file so that the current version and path can be recorded.
- After the new update has been copied to the appropriate directory and the configuration files have been updated, an optional post processor component can be executed. The post processor is any component that implements the IPostProcessor interface and can be used to perform post-installation tasks such as writing data to the registry.
- A log file is written to during the entire process to record all of the activities of the Updater. The location and name of the file can be specified in the controller's application configuration file.
Designing with the Updater
As I mentioned, to use the Updater, you need to create a controller. The controller simply needs to reference the Updater assemblies and place some entries into its application configuration file. To kick off the update process, the controller then instantiates the ApplicationUpdateManager and calls its StartUpdater method. The controller can also be notified through events (not all of which are shown) as the updater finds and downloads updates as shown in Listing A.
To stop the update process, the StopUpdater method can then be called (e.g., in the OnUpdaterUpdateAvailable method) to stop the download and validation from commencing. This allows the controller to prompt the user or consult other configuration information to determine if the download should proceed.
The architecture of the Updater allows you to create two kinds of controllers, Self Updating Clients or Updating Services.
Self Updating Client
In this design, the controller and the application being updated are the same. When the application initializes, it also starts the Updater and then waits for the Updater events to fire. If updates are found (in response to the UpdateAvailable event) the application can prompt the user to continue and proceed to download and verify the update. Once completed (in response to the FilesValidated event), the application can prompt the user to exit and start the new version by executing the Application Launcher (AppStart.exe) and by closing the current instance of the application. In this scenario, you'll want to encapsulate the Updater into a reusable assembly that you can simply reference in multiple projects within VS .NET.
In this design, you create a single controller that runs in the background on each workstation. This kind of controller can look for updates from multiple applications by including more than one <application> element in its configuration file. Typically, this kind of application would run in the system tray and could take advantage of the NotifyIcon control, which ships with Windows Forms. When activated from the tray, the application could then present a user interface that displays which applications have been updated. A context menu could also be associated with the application to start and stop the Updater. In this way, your service would be very similar to the Windows Update Service used by Microsoft.
By publishing the Updater Application Block, Microsoft has lightened your load and provided a solid base for creating updateable smart client applications. By plugging the Updater into your applications or creating your own updating service, you'll be better able to keep your clients up to date.