Execute Windows Installer (MSI) Installs during Application Updates

Has your product prerequisites ever changed between versions and therefore required you to deploy a new Windows Installer package before your new product version can function? Have you ever needed to deploy a companion application along with your previously installed and AppLife Update maintained application? With AppLife Update, these challenges can be overcome by executing a Windows Installer package as part of your application update.

Packaging and Executing an MSI in an AppLife Update

It’s very easy to include a Windows Installer package with your application update and then execute that Msi on all of your remote systems. To accomplish this, all that needs to be done is to include the Msi file with your update by using an Add & Replace files action, and then run the Msi using the Execute Msi action.

clip_image001

The Update Package Directory is the temporary directory that the update engine creates and removes for the currently executing update and is easily accessed by other actions. If you want your Msi file to remain on the remote system after the update completes you would choose a different folder, such as a subdirectory of your application directory.

After this update action executes, the Windows Installer package will be present on the remote system. To execute the Msi we’ll add an Execute Msi action. The Execute Msi action lets your define a <path> variable and then use that variable within an msiexec.exe command line. When defining the path variable, you can choose any of the available local paths, including the Update Package Directory path that we placed the Msi file in with the previous update action. To complete the path to the Msi file, any subdirectories as well as the Msi file name can be added to the subdirectory property. With the <path> variable defined, the msiexec command line can be constructed. To install the Msi, the /i command line option can be used. A command line of /i “<path>” is equivalent to the default Msi file behavior.

clip_image002

When this action executes, the Msi is executed on the deployed client.

Conditionally Update Based on Local Information

In the case of prerequisites, it might be necessary to first verify that the prerequisites are not already present before executing the installer package. There are a number of methods that can be employed for this purpose. With the Windows Installer product code, we can look up information about the product. For example, if I wanted to first verify that AppLife Update was installed before taking action on the client, I could look up the AppLife Update product code in the uninstall registry key. Using a Read Registry Key action, we can look up the uninstall string and even use it to uninstall. If the string is not present, we can use the information to infer that the product is not installed.

HKEY_LOCAL_MACHINE\SOFTWARE \Microsoft\Windows\CurrentVersion\Uninstall\{0c2b1285-5119-44f5-9b68-edc749f18967}

Using a Read Registry Value action, we can set a Shared Property to the value of the uninstall string, and default the value if the string cannot be read.

clip_image004

If we wanted to make the execution of the Msi action conditional on AppLife Update being installed (or not installed) we can add a conditional statement to the update action.

clip_image006

Uninstalling First

Windows Installers can be configured to first uninstall the application, but this is not usually the default behavior when using Windows Installer creation tools. If you would like your update to first uninstall, we can use the uninstall string we just read from the registry using a Command Line Action. Alternatively, we can also use the Msi Action directly.

clip_image008

Silent Updating when Using the Elevated Permissions Service

When your application is using the AppLife Update Windows Service for permissions elevation, it’s important to recognize that the Windows Installer will be executing under the Local System account user, and won’t be able to interact directly with the logged on user. For some installers, this could impact the way they operate. Running under the service, the installer must be able to run silently (using /q). In the event that the installer must interact with a user, the elevation service cannot be used for that update. When publishing the update, select the option to override the controller elevation settings and use the UAC elevation option instead. This will require an administrator to apply the update, but will allow the Msi to interact with them as they do so.

Disabling the Elevation Service

clip_image009

Troubleshooting Updates that Deploy an Msi

The AppLife Update engine logs activity to an event log as the update executes. However, when an Execute Msi action is executed, the log will only include information indicating the exact command line used and the msiexec return value. In order to investigate what actions the Msi performs, it is necessary to use the msiexec command line option to log the Msi operation. This option can take an explicit path. To write a log file to the install directory, you can use a Set Shared Property action to define a Share Property with the application directory path.

clip_image011

And use it to define where to write the log file to.

clip_image013

Conclusion

In the course of maintaining an application, it is sometimes necessary to install new prerequisites or companion installers. Using AppLife Update, automating these actions and ensuring an effortless transition for your end-users is very easy. The update actions available within AppLife Update lets you package and deploy new Windows Installer packages, conditionally execute update actions, uninstall existing packages if necessary, and troubleshoot the update process before widespread distribution.

Accessing Local Directories during an Application Update

Most application files reside in the installation directory, referred to within AppLife Update as the Application Directory. The AppLife Update execution engine determines the Application Directory from the physical location of the executable that launches the update. When any of the file related update actions are added to an update action list, the default directory that is targeted is the Application Directory.

clip_image001

This is most often the location where files need to be added or replaced during an application update. Accessing paths relative to the Application Directory can be accomplished using the subdirectories property.

clip_image002

And navigating up the directory tree…

clip_image003

In addition to the Application Directory, you can target any of the well-known named folder locations as well, such as the current user’s profile directories.

clip_image004

UsinganExplicitPath

You’ll notice in the list of directories, there is an Explicit Path option. This option lets you specify the entire path to use for the file action. At first glance, this feature doesn’t look all that useful, but when combined with Shared Properties, it becomes a very nice feature.

Expanding Shared Properties in Place

Shared Properties can be used in many action properties. Most of the properties of built-in actions have the ability to expand a Shared Property in place. These properties are adorned with a blue icon indicating their support of this feature. A Shared Property is inserted using $$ delimiters, and during update execution, the value of the designated Shared Property is inserted in-place of the delimiter.

clip_image005

So for file actions, we can use a Shared Property to target an explicit folder, which opens up lots of possibilities because Shared Property values can be passed in from the host application, set by other update actions that can read from a database, the registry, xml config files, or custom actions running your own code.

clip_image006

An Example–MaintainingOfficeTemplates

Say your application installs templates for Microsoft Office and you need to maintain those templates during an application update. There is a default location for Office templates however this location is user configurable, so it could be different on every system. The default template location is located in the current user’s roaming application directory.

CurrentUserRoamingAppDataFolder\Microsoft\Templates

If the user has specified a custom template location, we can find this path in the registry.

HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\Common\General – UserTemplates

One caveat is that if the user has not specified a custom location, this registry key is not present. So in order to target the correct folder, we’ll need to read the user configured location from the registry, and then use that location with an Add & Replace files action. If the registry value is not present, we’ll also set the default value of this shared property to the correct default location by expanding another Shared Property.

Action 1 – Add a Set Shared Property action and set a Shared Property to the current user’s local roaming AppData folder path. We’ll use this to set the default value in the next action.

clip_image008

Action 2 – Add a Read Registry Value action to get the User Configured template directory from the registry and assign the value to a new Shared Property. If the value doesn’t exist, we’ll set the default value with the path identified in action 1.

clip_image010

Action 3 – Add an Add & Replace Files action and use an explicit path to target the correct templates folder.

clip_image012

Using Shared Properties and explicit paths, we can easily access and maintain files and assemblies in any local directory that our application uses.

Conditionally Perform Update Tasks using Shared Properties

In order to maintain an installed software application on different hardware and operating environments, it is sometimes necessary to perform update actions based on the conditions at the local site or system. An example of this is when your application uses both 64 bit and 32 bit assemblies. Your installer places the appropriate assembly during initial installation, but in order to maintain that installation during updates we might need to take different action based on the local architecture. Another example might be maintaining different configurations, such as a Dev, QA, or Production installations. We might want to place debug symbols on a dev update, but not in production. Or we might set specific configuration settings differently, based on the environment. With AppLife Update, we can use information from the local installation to conditionally control the actions taken during the application update. We accomplish this by defining and setting Shared Properties based on the local system information and then using those Shared Properties to conditionally execute update actions.

Shared Properties

The AppLife Update engine execution context hosts a collection of name/value pairs, and this collection is named the Shared Properties collection. Shared Properties can be accessed by any Update Action in the update action list, hence the name Shared Properties.

Shared Properties can be defined and set in a many different ways. The initial collection of shared properties can be passed into the update context from the host application. The ApplyUpdate method of the Update Controller has an overload that takes an IDictionary object of string values. The contents of this object are used to populate the collection of Shared Properties.

1:  Dictionary<string, string> sharedProperties = new Dictionary<string, string>();  
2:  sharedProperties.Add("MyData1", mMyData1);  
3:  this.updateController1.ApplyUpdate(ApplyUpdateOptions.None, sharedProperties);  

If you are using the built-in user experience controls, your code doesn’t call the ApplyUpdatemethod directly. All of the user experience controls have a property called InitialSharedProperties that can be used to add values to prior to applying an update.

1:  updateDisplay1.InitialSharedProperties.Add("MyData1", mMyData1);  

Many of the built-in update actions that read information can set shared properties. The Database actions can read query results into a shared property. The Read Registry Value action, Read Xml Node action, and the Set Shared Property action can all set shared property values. Custom actions, most easily created using the C#/VB.Net dynamic code action, can access the Shared Properties collection directly through the context parameter.

clip_image001

It’s worth noting that while most of the actions read and write string values to the Shared Properties collection, custom actions can set and access any object data.

Conditional Updating Based on Shared Properties

Say we want to replace 64 bit or 32 bit assemblies, depending on the architecture of the system being updated. To accomplish this, we’ll add two Add & Replace files actions to our update action list, and then conditionally execute each action based on the value of a Shared Property. We can define the Shared Property with a Set Shared Property action. Processor type is one of the values that are available to set using this action. We’ll name the Shared Property ProcessorType.

clip_image002

After the action executes, the Shared Property named ProcessorType will contain a value of either 32 or 64, based on the current processor architecture. We can now use this value in the Conditional Statement of the two file actions.

clip_image003

This action will only be executed if the value of the ProcessorType Shared Property is “64”. The conditional for the 32 bit assemblies is obviously “32”. By using a Shared Property and conditional statements, we can use local system information to control the execution of the update.

Updating Software Operating on Erratic and Unreliable Networks

Download:
Example Project Source Code

 

When your software operates in an unreliable networking environment, it can be very challenging to automatically maintain your software installation. These environments are quite common. Police cruisers and ambulances use laptops to run software in the field, relying on cellular technology to distribute updates. Traveling salesmen use proprietary laptop business software and are constantly going in and out of network coverage. Medical staff use their mobile pc’s in large medical facilities, where dropping connections in elevators and dead Wi-Fi spots is common place. In scenarios like these, professionals are using software that must be maintained. In today’s professional environments, software maintenance is expected to “just happen”, without interrupting the work of the professionals using the software. Software publishers who create software that operate in environments like these all face the same challenge of maintaining their software without requiring support staff to take possession of the hardware. The AppLife Update Solution provides the answer for many software publishers whose applications operate in environments like this.

With the AppLife Update solution, software publishers create and publish self-contained update packages that migrate an installation from one version to another. These update packages are retrieved by the client software when network connectivity is present. Once the update package is retrieved, network connectivity is no longer required and the update can be applied, performing the work necessary to maintain the deployed installation. As the update package is downloaded, the partial download is cached locally so that any interruption in network connectivity will not require restarting from the beginning.

The flexibility of the AppLife Update solution provides the ability to change the behavior based on known circumstances. When it is known that the software being maintained is going to operate in an unreliable networking environment, it is possible to handle network connectivity errors differently than normal. Normally a network connectivity error would be unexpected and the user would be notified of the situation. Instead, the application can postpone the update retrieval operation for a short period of time and try again. And try again. And try again, until the update retrieval succeeds and can be applied.

Example Implementation

In the example project accompanying this post, the updating functionality is completely automated. The implemented updating process can be described as:

When the application launches, a background update check is performed. If an update(s) is available, the update packages are retrieved in the background and without user interaction. If network connectivity is lost, the retrieval is postponed and continually retried in the background without user interaction until the update is successfully retrieved. Once retrieved the user is prompted to either apply the update now, or when the application is closed. If the user elects to apply the update, the update is applied and the application restarted. If the update is deferred until the application exits, the update is applied as the application exits and the application is not restarted.

The example project contains an Updater class that controls the update check and retrieval process. Inspecting the Updater class, you’ll see that the class maintains an AppLife Update Controller and uses the API methods and events of the update controller to pause and retry as network errors occur. When an update package is successfully downloaded, an event is raised, alerting the primary application that an update is ready to be applied. The implementation code in the primary application is very simple. An Updater class is instantiated and the Update Controller properties are configured. Once configured, the GetUpdateCompleted and GetUpdateProgressChanged events are hooked before calling the GetUpdateAsync method. That’s it. Any updates will be retrieved as the network allows. When the completed event fires, the Updater status is checked and the user is prompted to apply the update now or when the application exits.

Implementation Details

 

The Updater class is the heart of the implementation. It has a very simple interface:

clip_image001

The Updater class wraps an AppLife Update Controller and exposes a single method that implementing code will call to perform the entire update process.

We want to take a look at the GetUpdateAsyncmethod. This method calls the Update Controller’s CheckForUpdateAsync method and then returns. The update process continues in the CheckForUpdateAsyncCompleted event handler. If an update is present, the DownloadUpdateAsync method is called. When the download completes, the GetUpdateCompleted event is raised. When these asynchronous methods are called, any network errors will cause the completed event to fire, and the event argument’s Error property will indicate the cause of the error. Based on the error information, we can take appropriate action. In this example, we are considering any WebException or IOException to indicate a network error. Your implementation can improve on this, based on environment specifics. At any rate, when a network error is detected, the updater class goes into a wait mode and try’s the check/download again after a period of time. Eventually, the update download is completed, and the GetUpdateCompleted event is raised, triggering the client application to prompt the user.

Of course, the user experience behavior is completely customizable with just basic coding. The AppLife Update Controller performs the heart of the technical challenges involved in this implementation, and the Update Engine is what lets you package up any work that is necessary to maintain and migrate your deployed installations. So I invite you to take a look at the example and evaluate it for suitability in your own environment. Feel free to contact our technical support team with any questions.

Weve Moved!

Kinetic Jump has a new home! We’ve moved down the road about 5 miles to a new office building with more space and a better landlord (us!). Moving day was Friday June 28th, and by Monday July 2nd we were back up and running! Hats off to the guys from Two Men and a Truck and all the people who helped out in this endeavor. Aside from a dead power supply on a server, all of our equipment came back to life without issues. Unfortunately our phone numbers couldn’t make the move with us, so please take note of the new phone number.

Kinetic Jump Software
8746 Egan Drive
Savage, MN  55378
(952) 496-2921

###

Easily Modify .Config Files During an Application Update

The beauty of .Net configuration files (.config) is that they let you easily change the behavior of your application for individual installations. This allows for a great deal of flexibility, especially with service related settings. With this flexibility though, also comes a maintenance challenge. Unlike all of your other application files, configuration files usually can’t be simply replaced during a maintenance update. Doing so would lose any customizations made to support the specific application installation. As your application evolves, it is inevitable that your configuration files will require modification. With AppLife Update, you can easily maintain .Net configuration files without replacing them by modifying the existing files. I’ll cover three different methods that you can use, based on the type and scope of the config file modification that is necessary.

  • Modify the existing config file directly using Xml Update Actions
  • Migrate specific settings from an existing config file to a new config file using Shared Properties and Xml Update Actions
  • Utilize custom .Net code to manipulate the config file during an update

Modify the Existing Config File

Using Xml Update Actions is great for adding elements and updating attributes. As an example, let’s say that we use appSettings in our application and we need to add a new appSettings value in support of a new feature. We can use an Add Xml Element update action to insert a new appSettings value into the existing config file.

This is what the v1 application configuration file might look like:

clip_image001

But for v2, the configuration file might need to look like this:

clip_image002

To migrate version 1 installations to version 2, in addition to replacing the application assemblies we must add a new entry to the appSettings collection. To do this, we’ll use an Add Element update action.

clip_image003

When configuring Xml update actions, XPath expressions are used to reference the specific Xml elements that you are interested in reading and writing. To accomplish our goal, we will use an XPath expression to access the appSettings node, and then add a new element to that node. The config file is located in the Application Directory and is named Simple.exe.config.

The XPath expression is /configuration/appSettings. The element that we are adding is:

<add key=”key2” value=”value2” />

The name of the element is add, and the new element has two attributes, key and value. Add a new Add Element update action to your update project and configure it as below.

clip_image004

With this action in place, the new element will be added to the configuration file when the update is executed.

Another scenario where Xml actions are great is when we need to update a specific attribute. Using a Change Node action, the value of an existing appSettings entry is easily accomplished. For instance, consider the situation where in v3 of our application, we needed the key2 value to be modified to value3. This can be accomplished in a very similar process. Instead of adding an Xml Element, we can use the Change Node update action to modify an existing value. To accomplish this, we need to know the XPath that references the specific value that needs to be changed. In this case, the XPath expression is /configuration/appSettings/add[@key=”key2”]/@value.

clip_image005

Adding a Change Node action configured like this will modify the attribute value to “value3”.

Migrate Existing Values to a new Config File

In some circumstances where there are wholesale changes to a config file that would require extensive modifications to the existing file, it could require less effort to extract specific values that are unique to the installation and migrate them to a new config file. In this scenario we use Xml Actions to read specific information from the existing config file and store that information in Shared Properties. We can then replace the config file with an Add & Replace Files update action, and finally use Xml actions to write the information that we stored into the new config file.

Revisiting the previous example, we’ll take this approach for the necessary modifications. We’ll read and store the value of the key1 appSetting, then replace the config file and modify that value in the newly replaced configuration file.

Reading the existing value, we’ll add and configure a Read Xml Node Action. Using this action, we set the config file name and XPath just as before. We’ll also designate a Shared Property to store the attribute value. Shared Properties are essentially variables that are scoped across the context of the executing updates. They allow for information to be shared between update actions. The Read Xml Node action will assign the string value of the designated attribute to the designated Shared Property.

clip_image006

With the value of the existing attribute stored, we can replace the application configuration file using an Add & Replace Files action.

clip_image007

After this action executes, the application configuration file will be replaced with a new updated version. However, the value of the attribute we are interested in will also have been reset to its default, non-customized value. To complete the update process we need to use the value that we previously stored to change the new configuration file. A Change Xml Node update action will update the attribute value. When using string value Shared Properties, the value of the Shared Property can be expanded using $SharedProperty$ syntax.

clip_image008

The Change Xml Node action restores the value originally set on the specific client and completes the update process.

Utilize .Net Code to Modify an Existing Config File

When using Xml Actions and Shared Properties, we read and write string values to the config file. In some circumstances, it can be beneficial to approach the Xml maintenance process within code, where the Xml can be manipulated in fragments. This too can be easily accomplished during an update using the Dynamic Code Action. A Dynamic Code action allows you to easily create a custom update action, which extends the UpdateAction class and overrides, at a minimum, the Execute and RollbackExecute methods.

clip_image009

With a Dynamic Code action you can use C# or VB.Net code to manipulate the deployed client. Here we use the context parameter to access the information we need to accomplish our goal in code. You can access local directory information as well as the Shared Properties collection. With this information, we load an XmlDocument and manipulate the file within our custom code.

clip_image011

Summary

During software maintenance updates, application configuration files that are uniquely modified for each installation cannot be simply replaced as changes are made to support new versions. These config files must be modified in-place during the maintenance process. Using AppLife Update, application configuration files can be easily maintained throughout the life of the application and we present three different approaches to accomplishing the goal.

Updating a Windows Service

For applications that deploy a Windows Service, updating the installed service can present a maintenance challenge. This is a scenario where integrating AppLife Update makes a difficult task extremely easy to accomplish. Using AppLife Update actions, a Windows Service can be updated in three easy steps.

  1. Stop the Service using a Stop Service update action.
  2. Replace the Service assemblies using one of the available file replacement actions.
  3. Restart the Service using a Start Service update action.

Tada! Big maintenance challenge accomplished.

An Example

The release of AppLife Update 4.5 included a few very small changes to our AppLife Update Windows Service. Specifically, in previous versions, if the Windows Application Event Log was full and not configured to replace old events, our service would not apply an update.  Here’s how to update a service using AppLife.

Stop the Service

To stop the service, we need to know the service name. If you don’t already know the name of the service you are updating, it can be found in the Windows Service Manager.

Add a Stop Service action to your AppLife package. Set the Service to Stop property to the name of your service. In this case, the service name is KjsUpdateService2.

Replace the Service Assemblies

Use an Add & Replace files on Restart action to update the assemblies. The AppLife Update Windows service is initially deployed using an MSI merge module, and is always installed to the Common Files Folder\AppLifeUpdateService2 folder. To update the service, we’ll select the Common Program Files (x86) client folder and set the appropriate sub-directory, and then add the two assemblies that constitute the service. Choosing the x86 variant of the Common Program Files folder will ensure we target the x86 common files folder on x64 operating systems. Using the non x86 Common Program Files directory targets the x64 folder on 64-bit operating systems. On x86 operating systems, there is only one common program files directory, and either variant will target the correct folder.

Note: When updating most Windows Services, even when a service updates itself, the service assemblies can be replaced immediately, without deferring to a restart. The AppLife Update service core assembly houses a class used to marshal information between the User Interface process and the service started worker process. For this reason, even though the service is successfully stopped, a lock is still being maintained on the core service assembly while the update is executed. Because this lock is not released until the update completes, the file replacement is deferred until restart. We do not need to force an operating system restart, as the previous update service can be restarted and function properly until the system is restarted. If a restart were necessary, we could include a Restart Operating System action to accomplish this.

The service assemblies ship with AppLife Update already embedded into the AppLifeUpdateService.msm merge module. After an installation, the assemblies will be in the common program files folder and can be extracted from there. After this action executes, the Windows Service will be updated. Now we just need to restart the service.

Restarting the Service

The service is restarted by adding a Start Service update action. The action is configured by defining the name of the service to restart. In this case it is again, KjsUpdateService2.

That’s it! Windows Service update completed.

But My Service is My Application?

This example assumes an existing update process exists and can be utilized to update the Windows Service. This is usually an installed application that utilizes the Windows Service, and can take responsibility for updating it. A stand-alone Windows Service can become “Self Updating” just as easily by integrating an update process using the AppLife API. There is one point to make in this scenario. When applying an update, you want to use the option to instruct the update controller not to shut down the host application (the service). The Stop Service update action performs a proper service shutdown through the use of the Windows Service Control Manager, and is the recommended method to use when stopping a service for an update.

Using AppLife Manager is also an excellent option for deploying and maintaining Windows Services.  AppLife Manager is turn-key and requires zero code integration.

Using Callable Action Lists Part II

In my previous post I used a callable action list along with Xml Update Actions to read all of the database connection strings identified in an app.config file, then iterate and update each one of the databases during an application update. The approach I took to accomplish the goal only used built-in Update Actions that are available to me in the Actions Palette. I purposefully chose not to use dynamic code actions (custom update actions) to make a point of what we can accomplish without resorting to writing our own code. However, what can be accomplished with a little custom code is extremely powerful, so now I’m going to revisit the objective, removing the intent of relying only on built-in actions.

Identifying the Databases to Update

In this scenario, the local databases that need to be updated during our application update are listed in the application configuration file. This is very convenient, especially when I want to use built-in actions to find the information. But what if the databases were not so conveniently discoverable? What if you first had to connect to a database server and search through all of the databases on the server for a specific naming convention? What if the databases were passed into the update process from the host application? Using a dynamic code action, scenarios like this can be easily handled.

Custom Update Actions and Shared Properties

The feature duo that makes what might initially sound difficult to accomplish during an application update magically easy using AppLife Update are Custom Actions and Shared Properties. Custom Actions are simply classes that inherit from an UpdateAction base class and implements at a minimum, an Execute method and a Rollback method. Shared Properties are a collection of objects that are scoped to the context of the update and can be accessed from any update action.

For our purposes, we want a custom update action that will read the list of databases from an application configuration file. The C#/VB.NET Code action lets me write this custom action directly within the update creation software.

Note:  Custom Actions can also be created in Visual Studio and compiled to an assembly.  Custom Action assemblies can be added to an update project through the Project..Settings dialog, or added the Custom Actions folder located within the AppLife Update install directory.

clip_image001

Here is the code:

Code Snippet

1:  using System;  
2:  using System.Collections.Generic;  
3:  using System.Text;  
4:  using Kjs.AppLife.Update.Engine.Core;  
5:  using System.Xml;  
6:  using System.IO;  
7:  namespace DynamicCodeActions {  
8:    public class DynamicAction1 : UpdateAction {  
9:      public override void Execute(UpdateContext context) {  
10:        //Read connection strings from app.config  
11:        XmlDocument configDoc = new XmlDocument();  
12:        configDoc.Load(Path.Combine(context.ApplicationDirectory, "CallActionListExample.exe.config"));  
13:        XmlNodeList connStrings = configDoc.SelectNodes("/configuration/connectionStrings/*");  
14:        List<string> connectionStrings = new List<string>();  
15:        foreach(XmlNode node in connStrings) {  
16:          connectionStrings.Add(node.Attributes["connectionString"].Value);  
17:          context.Log.WriteLine(string.Format("Added connStr: {0}", node.Attributes["connectionString"].Value));  
18:        }  
19:        if(connectionStrings.Count > 0) {  
20:          context.SharedProperties.Add("ConnectionStrings", connectionStrings);  
21:          context.SharedProperties.Add("ExecuteDBUpdate", true);  
22:          context.SharedProperties.Add("CurrentConnectionString", "");  
23:        } else {  
24:          context.SharedProperties.Add("ExecuteDBUpdate", false);  
25:        }  
26:      }  
27:      public override void RollbackExecute(UpdateContext context) {  
28:        //Add code here to undo work that was performed in the Execute  
29:        //method. The method is not performed if the Execute method  
30:        //is not completed.  
31:        context.SharedProperties.Remove("ConnectionStrings");  
32:        context.SharedProperties.Remove("ExecuteDBUpdate");  
33:      }  
34:    }  
35:  }  

Notice that through the context parameter, the code can access the Shared Properties collection as well as other properties, such as the physical path to the host application. This code simply opens the application configuration file and reads the database connection strings. These strings are then added to a generic List of strings, and that List is added to the Shared Properties collection. If the list is not empty, another Shared Property is added that will be used in a conditional statement.

Manipulating the List from other Actions

With the list of database connection strings in the Shared Properties collection, we can call the recursive callable update action list to update the databases. This in-memory list takes the place of the copied app.config file used in the original post. From within the Update Databases action list, we can read and manipulate the Shared Properties collection with other custom update actions.

Read the Next Connection String

clip_image002

Remove the Item after the Database is Updated

clip_image003

Conclusion

Using Update Actions and Shared Properties during an application update allows you to very easily accomplish complicated processing on deployed clients. The C# / VB.NET update action lets you add your own code logic to your update, and using Shared Properties, your code can easily interact with built-in actions as well as other custom actions.

Download Example AppLife Update Project

Using Callable Action Lists to Update Multiple Databases During a Client Update

The recently released AppLife Update 4.5 includes many new features, one of which is the ability to create independent, callable action lists. By combining callable action lists with Shared Properties and applying conditional statements to update actions we can more easily accomplish advanced updating activity. One scenario which we can use to demonstrate this functionality is when an application uses multiple local databases. In order to update the installed application, all of the databases that are present must be updated. In this scenario an update will need to be able to:

  1. Identify all of the databases that are present.
  2. Iterate each of the local databases, applying the necessary change script to each one.
  3. Update the application assemblies.

For this example, the list of databases will be discovered by inspecting the application configuration file. Each database connection string is listed in the connectionStrings segment of the configuration file. For each of the listed databases, we’ll connect to the database, start a transaction, run a SQL script, commit the transaction and close the connection.

Note that all of the update actions and logic is packaged into a single, stand-alone update package. The update process embedded into the application discovers the new update, downloads it, and then initiates it. Once initiated, the Update Engine executes the update actions that perform the work. This example focuses completely on the update actions. No mention is made of the update process integrated into the application.

Identify and Manage the Local Database List

To read the databases that are present and manage the list as the databases are updated, I am going to read an item from the connectionStrings configuration element, update the database identified within it, and then remove the element from the configuration file. Using this method, I can accomplish all of the work using built-in update actions. This is not the only option available. Using Dynamic Code Actions offers more flexibility and an alternative approach. I’ll perform the same work using Dynamic Code actions in my next blog post.

Now, I mentioned that as we update the databases I am going to remove the element from the config file. We don’t want to modify the actual application configuration file so the first thing that I am going to do is copy the config file to the working update directory. This is a directory created by the update engine and it is deleted when the update ends. I’ll accomplish this by using a Run command line update action. This action includes a helper feature that allows us to use common directories to define two path variables. The Application Directory is the physical path of the application that launched the update. This is where the application configuration file resides. The Update Package Directory is the physical path to the temporary working directory that is created for this update by the update engine. I define <path1> to be the path to the application configuration file, and I define <path2> to be the path of my copy of the config file. I’ll call it config.xml. With the two paths specified, I’ll use them in the actual command line that copies the config file:

copy “<path1>” “<path2>”

clip_image001

To read the entries in the config file, I’ll use a Read Xml Node action. To use this action we specify an Xml file to read, define an XPath expression to identify the node value we are interested in, and then provide a name of a Shared Property to hold the string value of the Xml Node. The Shared Property can then be accessed and used by other actions as well as in conditional statements. I’ll be doing both with this Shared Property.

clip_image002

Here is what the config file section looks like:

<configuration>

<connectionStrings>

<add name=”Db1″ connectionString=”Data Source=.\SQLEXPRESS;Initial Catalog=TestDb1;Integrated Security=True”/>

<add name=”Db2″ connectionString=”Data Source=.\SQLEXPRESS;Initial Catalog=TestDb2;Integrated Security=True”/>

</connectionStrings>

</configuration>

I am interested in the connectionString, so my XPath expression is /configuration/connectionStrings/add/@connectionString

If multiple nodes are found, the action is configured to read the first node, and if no node is present a default value of None is assigned. We’ll use this in a conditional statement. If a node is present, a Shared Property with a key of ConnStr will be populated with a local database connection string. Next we’ll use a callable action list to update this database using SQL Server update actions, remove the connection string from our working config file, and recursively call itself until all of the databases represented in the config file are updated. If the ConnStr Shared Property does not equal the value “None”, we call the action list.

clip_image003

Update the Database

The databases I am updating are SQL Server databases. Therefore I am using the SQL Server Update Actions that are also new to AppLife Update 4.5. Note that there are separate provider-Independent database actions available that can be used for updating any type of database. Using the SQL Server Actions, for each database we are going to:

  1. Open a Database Connection. I’ll configure the action to place the database in single-user mode.
  2. Begin a SQL Server Transaction.
  3. Execute a database query.
  4. Commit the SQL Server transaction
  5. Close the SQL Connection

To open the connection, I set the connection string directly, and then use the ConnStr Shared Property we already defined. For many built-in actions, you can use Shared Properties that are strings by using a $SharedPropertyKey$ syntax. Wherever this is used, the Shared Property string value is expanded in-line during update execution. Notice that the connection itself is added to the Shared Properties collection using the defined key. Here the key is named SqlConection. We’ll use this Shared Property in the other database actions.

clip_image004

With a SQL Connection open, I’ll start a transaction using the Begin SQL Server Transactionaction. To use this action we specify the connection to use and provide a Shared Property key name for the transaction. The transaction Isolation Level can also be specified. If the update fails, this transaction will be rolled back automatically unless the transaction is committed by a Commit SQL Server transaction action.

clip_image005

With the transaction started, it can be used by one or more Run SQL Server query actions. In this example, I’ll just add a table.

clip_image006

Next, I’ll commit the SQL transaction and close the database connection. Taking this approach means that should any of the database updates fail, the database changes made in all previously updated databases would not be rolled back because they have already been committed. I chose this approach for simplicity, however the update could be refactored to maintain all transactions open until all of the databases have been updated, then iterate the transactions and commit each one. Using this alternate approach, should any SQL query fail, all databases would roll back their changes.

clip_image007

Closing the connection by specifying the Shared Property key…

clip_image008

Remove the Database from the Working Xml File

With the designated database updated, I am going to remove the connection string from the working Xml file using a Delete Xml Node action. To use this action, I specify the Xml file and as XPath expression identifying the node of interest, just like we did when defining the connection string. The node we are interested in is the connection string entry with the attribute value that matches the connection string of the database that we just updated.

clip_image009

With the node removed from the working file, we’ll again use a Read Xml Node action to read the next connection string in the file. If there is another connection string available, we’ll assign it to the ConnStr Shared Property. Otherwise, just like before, if no connection strings are left the value of the Shared Property will be set to “None”.

clip_image010

And now as long as the value of the ConnStr Shared property is not “None” we’ll call this same action list again, updating the next database in the list.

clip_image011

This process is repeated for all of the databases identified in the connectionStringsconfiguration element.

Replace the Application Assemblies

To complete this update, I’ll use an Add & Replace Files action to replace the main application executable.

clip_image012

Summary

By using the new callable action list feature and the Shared Properties collection, we are able to read the list of local databases from the application configuration file and iteratively update each one. The new features of AppLife Update 4.5 provide more power and flexibility while maintaining the robust, transactable operation of the AppLife updating engine. In a follow-up blog post, I’ll use Dynamic Code actions and custom C# code instead of Xml Actions to read the connection strings and use a collection object instead of a temporary file to manage the databases.

Download Example Project

View Execution Log

Terminal Services Application Updating

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.

clip_image001

Download Terminal Services Example Project