The AppLife Update solution is a perfect fit for maintaining applications that operate in multi-user terminal services environments. In a terminal services installation, there are likely many users simultaneously running your application. Application maintenance solutions must account for the fact that there can be multiple instances of an application running at one time as any running instance will maintain a lock on files and assemblies that must be replaced during an update process. The AppLife Update Solution ensures that all running instances of an application are shutdown prior to starting an update, and this is accomplished through a built-in Inter-process communications (IPC) feature. The IPC employed within AppLife Update communicates across all users and will shut down all instances of an application running in a terminal services environment, making the solution a perfect fit for maintaining terminal services hosted applications.
Out of the box, AppLife Update will shut down all instances of an application and allow you to update a terminal services application. There is however some customizations that can be applied to an application that is known to be targeting terminal services that will improve the users application updating experience.
Terminal Services Application Updating with AppLife Update
User Experience Customizations
The AppLife Update API provides an opportunity for the integrating developer to interact with the IPC process and update initiation (starting) procedure. We can use this opportunity to improve the user experience. For the instance that initiated the update, we’ll display an indeterminate progress dialog as all instances are being shut down, and for the non-initiating instances, we’ll display an informative dialog for a short period of time indicating that the application is about to be closed for maintenance. Further enhancements could allow terminal services users to cancel the update process, or perform additional work before the shutdown.
Code Snippet
1: private void checkForUpdatesToolStripMenuItem_Click_1(object sender,
2: EventArgs e) {
3: if(updateController1.ShowCheckForUpdateDialog(this,
4: ErrorDisplayLevel.ShowExceptionMessage) == DialogResult.OK) {
5: if(updateController1.ShowDownloadUpdateDialog(this,
6: ErrorDisplayLevel.ShowExceptionMessage) == DialogResult.OK) {
7: //Launch the update from another thread
8: //To better accomodate terminal services
9: //installations, the UI will remain
10: //responsive as all of the other
11: //instances of the application are closed.
12: BackgroundWorker worker = new BackgroundWorker();
13: worker.DoWork += new DoWorkEventHandler(worker_DoWork);
14: worker.RunWorkerAsync(updateController1);
15: ApplicationUpdateInitiatedDialog dlg =
16: new ApplicationUpdateInitiatedDialog(true);
17: dlg.ShowDialog(this);
18: }
19: }
20: }
21: private void worker_DoWork(object sender, DoWorkEventArgs e) {
22: //Since the ApplyUpdate method call is a
23: //blocking call, and we want the UI to remain
24: //response as the user waits for all instances
25: //to close, we'll initiate the update on a
26: //background thread.
27: UpdateController controller = e.Argument as UpdateController;
28: if(controller != null) {
29: controller.ApplyUpdate(ApplyUpdateOptions.AutoClose);
30: }
31: }
32: private void updateController1_UpdateStarting(object sender,
33: UpdateStartingEventArgs e) {
34: //An update has been an initated and this
35: //application will shutdown. This dialog will
36: //inform any other users that the application
37: //is about to shutdown on them. Showing this
38: //dialog is import for Terminal Services
39: //installations. Note: It is possible to
40: //allow other users to cancel the ongoing
41: //update process
42: //This dialog is shown for 5 seconds
43: //before it is closed automatically
44: if(!e.IsInitiatingController) {
45: ApplicationUpdateInitiatedDialog dlg =
46: new ApplicationUpdateInitiatedDialog(false);
47: dlg.ShowDialog(this);
48: }
49: }
50: }
Prevent Users from Restarting During the Update
During the actual update, the application files must be unlocked, and remain unlocked throughout the process. If a terminal services users attempts to start the application using their application shortcuts, the application assemblies could become locked and prevent the update form succeeding. To prevent this, we’ll make the first action taken during the update be to rename/remove the launching executable. If the launching executable is to be replaced during the update process, we’ll perform this action as the last step of the update. By taking this action, terminal services users will not be able to launch the application during the update process from existing shortcuts.