Introduction
One problem with using an MSI installer for installing a WPF application is the difficulty
in updating the deployed application. If a WPF application is installed using
an MSI installer and a new version becomes available, the user may have to uninstall
the previous version before installing the new one. If the user does not have
administrator privileges, then he might not be able to continue installation.
A system administrator will have to facilitate the installation. This could be
manageable if the application needs to be installed on a small number of PCs.
Doing this for many PCs will be time-consuming and unproductive.
These problems can be addressed by using ClickOnce. By using ClickOnce, applications
can check first if there is an available update. If the update is required, the
application will download and install the new version automatically. The problem
with using ClickOnce is the difficulty to modify the application configuration
file. Changing settings (e.g. connection string) in the configuration file is
not as straightforward as updating these setting in Notepad.
Getting Started with ClickOnce
In this article, we have demo WPF application containing a text box that shows a
database connection string although the application will not actually connect
to a database. The connection string is stored in a configuration file. The following
listing shows the application’s main window XAML code.
<Window x:Class="ClickOnceDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:properties="clr-namespace:ClickOnceDemo.Properties"
Title="MainWindow" Height="150" Width="250">
<Grid>
<TextBox TextWrapping="Wrap" Text="{Binding Source={x:Static properties:Settings.Default}, Path=ConnectionString,
Mode=OneWay}"/>
</Grid>
</Window>
Listing 1. Main Window XAML
The connection string is bound to the Text property of the TextBox via data binding.
The following figure shows the running demo application.
Figure 1. Demo App
The connection string in the example is usually used for connecting to an SQL Server
Express database on the local machine. The connection string must be updated
to point to the machine containing the database server when the application gets
deployed. We will get to this later. First, we have to update the settings for
publishing the ClickOnce application, under the project properties in Visual
Studio.
Figure 2. ClickOnce Deployment Default Settings
There are three options for the publishing folder location: web site, ftp server,
and file path. In our example, we would use a file path as the publishing folder
location. We can then copy the published files onto a central server and share
the folder to client computers in the local network. Let’s change the publishing
folder location to C:\publish\ClickOnceDemo\. Since the supplied location is
not a URL or UNC path, the installation folder URL is required. For now, this
can be set to a non-existent directory like \\localhost\ClickOnceDemo\. The following
files and folders are generated in the C:\publish directory after clicking the
Publish Now button.
C:.
└───ClickOnceDemo
│ ClickOnceDemo.application
│ setup.exe
│
└───Application Files
└───ClickOnceDemo_1_0_0_0
ClickOnceDemo.application
ClickOnceDemo.exe.config.deploy
ClickOnceDemo.exe.deploy
ClickOnceDemo.exe.manifest
Listing 2. Published ClickOnce Files
Since a non-existent folder was used as the installation folder location, a warning
is generated by Visual Studio when it tries to open the installation folder for
viewing: “Unable to view published application at \\localhost\ClickOnceDemo\.”
To remove this warning, we can create a shared folder named ClickOnceDemo and
set it as the publishing folder location. Notice how easy it is to publish ClickOnce
applications. The prerequisites are already detected and necessary assemblies
are added. However, you may want to change different settings like the publisher’s
name, minimum version that must be installed, etc. Just a side note: if your
project builds successfully and you get the error “Cannot publish because a project
failed to build”, then it might be due to the installed Visual Studio add-ons.
These can be disabled using the Add-in Manager under the Tools menu.
Using MageUI
In the example, there is the ClickOnceDemo.exe.config.deploy file. This file contains
the application configuration.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089" >
<section name="ClickOnceDemo.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<applicationSettings>
<ClickOnceDemo.Properties.Settings>
<setting name="ConnectionString" serializeAs="String">
<value>Data Source=.\SQLEXPRESS;Initial Catalog=MyDB;Integrated Security=True</value>
</setting>
</ClickOnceDemo.Properties.Settings>
</applicationSettings>
</configuration>
Listing 3. ClickOnceDemo Application Configuration
Let’s say we changed the connection string to “server\SQLEXPRESS;Initial Catalog=MyDB;Integrated
Security=True” and run the ClickOnceDemo setup file. During installation, a dialog
will appear containing the following message: “Application validation did not
succeed. Unable to continue.” Clicking on the Details… button shows the summary
of errors. By examining the details, we can identify the cause of the error:
ClickOnceDemo.exe.config, has a different computed hash than specified in manifest.
If we open the ClickOnceDemo.exe.manifest file, we can see the following section.
<file name="ClickOnceDemo.exe.config" size="885">
<hash>
<dsig:Transforms>
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<dsig:DigestValue>0A8ua48YAIJ/gSgKay7NO5HZSJo=</dsig:DigestValue>
</hash>
</file>
Listing 4. ClickOnceDemo Configuration File Hash
Before installing the ClickOnce application, the setup checks first if the computed
hash is the same with the one specified in the manifest file. To modify the application
manifest, we can either use either Mage or MageUI. These tools are part of the
Windows SDK so the SDK must be installed on the machine where the manifest will
be modified. Since we are using Visual Studio 2010, these tools are already available
and are under the C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\NETFX 4.0
Tools directory. Let’s try MageUI first, which can also be run using the Start
Menu (Microsoft Windows SDK Tools under Microsoft Visual Studio 2010). Open the
ClickOnceDemo.exe.manifest file using MageUI.
Figure 3. ClickOnceDemo.exe.manifest in MageUI
The stored hash in the manifest file must be updated. To do this, just save the manifest
file and we will be prompted with a dialog to sign the manifest, wherein a certificate
must be specified. When we published the ClickOnce application the first time,
a temporary certificate is generated and is included in the Visual Studio project.
Enter the path to the certificate and the password in the dialog.
Figure 4. Signing the Manifest
After saving, the hash should be recomputed. Looking again at the ClickOnceDemo.exe.manifest
file, you will notice some changes in the ClickOnceDemo.exe.config section. The
file size is now set to 890. The digest value is also different.
<file name="ClickOnceDemo.exe.config" size="890">
<hash>
<dsig:Transforms>
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<dsig:DigestValue>r2orHPO3nSzRVsRJeML+c1OnB1k=</dsig:DigestValue>
</hash>
</file>
Listing 5. Updated ClickOnceDemo Configuration File Hash
When we try to run the setup file again, we are prompted with the same dialog telling
us that the application validation did not succeed. We will see the following
error messages when we checked the details:
Application manifest has either a different computed hash than the one specified
or no hash specified at all.
File, ClickOnceDemo.exe.manifest, has a different computed hash than specified in
manifest.
Since we modified the ClickOnceDemo.exe.manifest file after signing it, the contents
now produce a different hash. The original hash is stored in the ClickOnceDemo.application
deployment manifest. We can see the following section in the deployment manifest.
<dependency>
<dependentAssembly dependencyType="install" codebase="Application Files\ClickOnceDemo_1_0_0_0\ClickOnceDemo.exe.manifest" size="7111">
<assemblyIdentity name="ClickOnceDemo.exe" version="1.0.0.0" publicKeyToken="2d4a5338af841c64" language="neutral" processorArchitecture="x86" type="win32" />
<hash>
<dsig:Transforms>
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<dsig:DigestValue>5CADcXRvaZEZCPLrvsJLCHFs5NU=</dsig:DigestValue>
</hash>
</dependentAssembly>
</dependency>
Listing 6. ClickOnceDemo.Exe Manifest Hash
The same thing we did with the application manifest, we can open the deployment manifest
in MageUI, save and then re-sign. However, there is an extra step that should
be done. That is, we should select the updated application manifest using the
Select Manifest button in the Application Reference section. This is shown in
the figure below. If we do not do this, the hash will not be recomputed when
the ClickOnceDemo.application manifest is saved.
Figure 5. Select Updated Application Manifest
Unfortunately, the spaces in the specified path will be converted to %20. If we saved
the manifest and continue on running the setup file, a dialog will appear with
the following message: “Cannot download the application. The application is missing
required files. Contact application vendor assistance.” Clicking on the Details…
button shows us the problem.
Downloading file://localhost/ClickOnceDemo/Application%20Files/ClickOnceDemo_1_0_0_0/ClickOnceDemo.exe.manifest
did not succeed.
One workaround is before clicking on the Select Manifest button, we have to remove
the spaces in the path or replace it with another character like an underscore.
Let’s replace the space with an underscore and select the manifest. Save the
file and sign it using the same certificate we used with the ClickOnceDemo.exe.manifest
file. You can compare the updated section of the ClickOnceDemo.application file
with Listing 6.
<dependency>
<dependentAssembly dependencyType="install" codebase="Application_Files\ClickOnceDemo_1_0_0_0\ClickOnceDemo.exe.manifest" size="7115">
<assemblyIdentity name="ClickOnceDemo.exe" version="1.0.0.0" publicKeyToken="2d4a5338af841c64" language="neutral" processorArchitecture="x86" type="win32" />
<hash>
<dsig:Transforms>
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<dsig:DigestValue>cF+joyNcuTUKYvawEJGwJtc4YcQ=</dsig:DigestValue>
</hash>
</dependentAssembly>
</dependency>
Listing 7. Updated ClickOnceDemo.Exe Manifest Hash
The setup will now run successfully and the configuration is modified.
Figure 6. ClickOnce WPF Application with Modified Configuration
Let’s take a look at how these steps are done using the Mage command-line tool.
Using Mage
Rather than specifying the full file path just to execute Mage, we can add the path
to Mage under the Path environment variable. To update the manifests, we just
need to run the following command: mage -Update <manifest> -CertFile <certificate
> -Password <password>. Using the ClickOnceDemo.exe.manifest file as
an example, the command would look like the following, assuming that the certificate
is located in C:\ClickOnce\ClickOnceDemo directory and password is not required
(although your certificate will most likely have a password).
mage –Update “C:\publish\ClickOnceDemo\Application Files\ClickOnceDemo_1_0_0_0\ClickOnceDemo.exe.manifest” -CertFile
“C:\ClickOnce\ClickOnceDemo\ClickOnceDemo.pfx”
When executed, you might encounter the following output:
Error MSB3113: Could not find file ‘ClickOnceDemo.exe’.
Error MSB3113: Could not find file ‘ClickOnceDemo.exe.config’.
ClickOnceDemo.exe.manifest successfully updated. However, some errors were encountered.
The problem is, by default, a “.deploy” extension is added to the executable and
the configuration file when the application is published. Thus, Mage cannot find
these files that are specified in the manifest. Fortunately, we can just remove
the “.deploy” extension from the said files and the manifest will be updated
successfully. We can also disable adding of the “.deploy” extension using the
Options dialog in the Publish section of the project properties. For more information
regarding the “.deploy” extension and why it is enabled by default, you can refer
to this link: http://msdn.microsoft.com/en-us/library/ms228998.aspx. Anyway,
after updating the manifests, we can add the “.deploy” extension back again.
After updating the application manifest, next to update is the deployment manifest.
This is just the same thing we did with MageUI. As you saw before when using
MageUI, just saving the deployment manifest won’t update the hash value. We have
to select the application manifest using the Select Manifest button. This also
holds true for the Mage command-line tool. Thus, the command to update the deployment
manifest is as follows: mage -Update <deployment_manifest> -CertFile <certificate>
-Password <password> -AppManifest <application_manifest>. Here is
the command for our example.
mage –Update “C:\publish\ClickOnceDemo\ClickOnceDemo.application” -CertFile “C:\ClickOnce\ClickOnceDemo\ClickOnceDemo.pfx”
-AppManifest “C:\publish\ClickOnceDemo\Application Files\ClickOnceDemo_1_0_0_0\ClickOnceDemo.exe.manifest”
After this, we add the “.deploy” extension back, run setup and install the application
and that’s it. ClickOnce is a great technology for deploying applications, although
changing application configuration is not as straightforward as compared with
using an MSI installer. Fortunately, Mage and MageUI are there to help us modify
application configuration.