静观己心,厚积薄发

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

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.

<Windowx: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>
        <TextBoxTextWrapping="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>
        <sectionGroupname="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089" >

            <sectionname="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>
            <settingname="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.

<filename="ClickOnceDemo.exe.config" size="885">
  <hash>
    <dsig:Transforms>
      <dsig:TransformAlgorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
    </dsig:Transforms>
    <dsig:DigestMethodAlgorithm="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.

<filename="ClickOnceDemo.exe.config" size="890">
  <hash>
    <dsig:Transforms>
      <dsig:TransformAlgorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
    </dsig:Transforms>
    <dsig:DigestMethodAlgorithm="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>
  <dependentAssemblydependencyType="install" codebase="Application Files\ClickOnceDemo_1_0_0_0\ClickOnceDemo.exe.manifest" size="7111">
    <assemblyIdentityname="ClickOnceDemo.exe" version="1.0.0.0" publicKeyToken="2d4a5338af841c64" language="neutral" processorArchitecture="x86" type="win32" />
    <hash>
      <dsig:Transforms>
        <dsig:TransformAlgorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
      </dsig:Transforms>
      <dsig:DigestMethodAlgorithm="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>
  <dependentAssemblydependencyType="install" codebase="Application_Files\ClickOnceDemo_1_0_0_0\ClickOnceDemo.exe.manifest" size="7115">
    <assemblyIdentityname="ClickOnceDemo.exe" version="1.0.0.0" publicKeyToken="2d4a5338af841c64" language="neutral" processorArchitecture="x86" type="win32" />
    <hash>
      <dsig:Transforms>
        <dsig:TransformAlgorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
      </dsig:Transforms>
      <dsig:DigestMethodAlgorithm="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.

posted on 2013-05-02 12:47  猎人杰  阅读(1208)  评论(0编辑  收藏  举报