For my current client we have an environment where the application is handed over to a deployment team that installs it onto varying test servers. For good reason these servers are locked down and the development teams can not access them. This ensures a clean install and ensures that the version in the test environments gets moved forward only if there are no issues.

Problem 1 - Setup.exe has "baked in" URL

This plays a bit of havoc when deploying smart client applications. One of the reasons for this is that the setup.exe bootstrapper has the URL baked into it so when we try it on a development machine it is actually looking for the install files on the machine that the click once application was developed on!

Now one way to get around this is to set the Installation Folder URL in the click once projects "publish" tab but that would mean we would need to create unique assemblies with the URL baked into them for each environment.

I did happen upon a way to change the setup.exe bootstrapper to have a variable URL though. On the server that the click once application is being deployed from run:

setup.exe /url=http://mytestserver/testfolder/

This will cause the exe to "patch" itself with the new URL.

Problem 1 solved!


Problem 2 - Changing a config file on the server invalidates the application.manifest

Once we have the files installed onto the deployment server we need our deployment team to adjust the WCF bindings in the client.exe.config file that gets downloaded so that the client application talks to the right WCF service. A neat thing with smart client applications is that it generates a manifest file stating all the files the application needs to run and a checksum of those files. Because the team is changing one of those files the checksum of the file changes and so we need to generate a new manifest file with the new checksum for the file in it. This leads to a new problem as there is a deployment file that has a checksum of the applications manifest in it as well so we need to regenerate that as well! Here are the steps I took to create this application:

In Visual Studio:

  1. Goto Project Properties -> Publish
  2. Set the publishing folder to a local folder
  3. Set the install URL to "http://dummy" (this is to prevent the app from running if a later step is not completed)
  4. Click "Options"
  5. Uncheck the "Use .deploy file extension" (this is not 100% necessary but made my life easier when generating the manifests later)
  6. Publish the application

Creating The Deployment Package

For me I then added the outputed files from the publish into my WCF deployment project. This allows me to have one deploy package that installs my WCF service and my smart client to the same spot easily

  1. Added the setup.exe file outputed from the publish tab
  2. Added mage.exe from the Windows SDK (we will need this to recreate our manifest files)
  3. Added configure.bat (see below)
  4. I created a "Client" folder
  5. added all .exe, .config, and .dll files to the "Client" folder. I did not include the .manifest and .application files as I we are going to recreate them with our configure.bat file
  6. Build the project

Now all our team needs to do is:
1. Open the [pathtoapplication]\Client\[appname].config file
2. Adjust any settings
3. Change the app url in the configure.bat file
4. Run [pathtoapplication]\Configure.bat

Configure.bat will use the mage.exe application (found in the windows SDK) to generate all application manifest for the client, the deployment manifest for our deployment, and repath the bootstrapper


Contents of Configure.bat

set Version="1.0.0.11"
setup.exe /url=http://mytestserver/appname/
del ".\Client\myapp.exe.manifest"
mage -new Application -fd ".\Client" -ToFile ".\Client\myapp.exe.manifest" -name "My Smart Client App" -version %version%
mage -new Deployment -ToFile myapp.Application -AppManifest ".\Client\myapp.exe.manifest" -install true -name "My Smart Client App" -version %version%

"setup.exe /url=...." sets the URL that the setup.exe file will be accessed on
I then delete the old manifest (might be there from previous runs)
"mage -new Appliction ... " generates our new application manifest with new checksums for the config files
"mage -new Deployment ..." generates the deployment file (sits next to setup.exe) so that the application can be installed. This has a checksum in it for the application file we just generated.

Now one of the things I have completely removed from this is signing of our files (Done by unchecking the "Sign the clickonce manifests" checkbox under the "Signing" tab of the project). This should be on but unfortunately I have about 60 minutes left of my current contract and do not have time to implement signing on the manifests which is a very very very good security practice for this type of thing.