Thursday, February 12, 2009

Continuous Installation and ClickOnce setup

When you read my previous posts on the Continuous Installation setup, and know how ClickOnce works, you know that I had to do some stuff to get this working. A small introduction into ClickOnce, for the ones that are not familiar with it.
From the site of MS :

Simply stated, a ClickOnce application is any Windows Presentation Foundation, Windows Forms, or console application published using ClickOnce technology. You can publish a ClickOnce application in three different ways: from a Web page, from a network file share, or from media such as a CD-ROM. A ClickOnce application can be installed on an end user's computer and run locally even when the computer is offline, or it can be run in an online-only mode without permanently installing anything on the end user's computer.
ClickOnce applications can be self-updating; they can check for newer versions as they become available and automatically replace any updated files. The developer can specify the update behavior; a network administrator can also control update strategies, for example, marking an update as mandatory. Updates can also be rolled back to an earlier version by the end user or by an administrator.
Because ClickOnce applications are isolated, installing or running a ClickOnce application cannot break existing applications. ClickOnce applications are self-contained; each ClickOnce application is installed to and run from a secure per-user, per-application cache. By default, ClickOnce applications run in the Internet or Intranet security zones. If necessary, the application can request elevated security permissions.

How ClickOnce Deployment Works

The core ClickOnce deployment architecture is based on two XML manifest files: an application manifest and a deployment manifest.

The application manifest describes the application itself. This includes the assemblies, the dependencies and files that make up the application, the required permissions, and the location where updates will be available. The application developer authors the application manifest by using the Publish Wizard in Visual Studio 2008 or the manifest generation tool (Mage.exe) in the Windows Software Development Kit (SDK).

The deployment manifest describes how the application is deployed. This includes the location of the application manifest, and the version of the application that clients should run. An administrator authors the deployment manifest using the manifest generation tool (Mage.exe) in the Windows SDK.



Now this sounds rather logical, but there are a few catches, the deployment manifest is secured/signed with a key, so far so good. One part of the security is a hash of the needed files (crc or something) and the deployment manifest itself, which contains from which servername the ClickOnce is authorised to run. This is problem 1.
When you develop your application, you deploy it to your companies test server, and when it is ok, you can deploy it again to a production server. But when you must have this ClickOnce setup on 100+ servers, you're not going to do this by hand ;-) So I must do this within a script.
You can create these 2 manifests totally from scratch with mage, but this is more difficult than it needs be(you must specify all dependent dll's + location, ...) My solution is a mix of MSBuild and Mage. To generate a ClickOnce setup via MSBuild, the help says compile your solution with msbuild /t:publish. There are a few properties that you can/must set. You can find some (incomplete) information about them here.

Problem 2 : when you do msbuild /t:publish /p:(new properties), the values of the new properties are not taken if there are already assemblies created! you must do msbuild /t:clean /t:publish /p:(new properties)
I use the following msbuild command (we use web based installations) :
msbuild /t:clean /t:publish
/p:ApplicationVersion=${CCNetLabel}
/p:PublishVersion=${CCNetLabel}
/p:PublishUrl=${publishUrl}
/p:InstallUrl=${publishUrl}
/p:GenerateManifests=true
/p:IsWebBootstrapper=true
/p:TargetZone=LocalIntranet
/p:PublisherName=TheCompany
/p:Install=true
/p:InstallFrom=Web
/p:UpdateEnabled=true
/p:UpdateRequired=false
/p:BootstrapperEnabled=true
/p:MapFileExtensions=true
/p:UseApplicationTrust=false
/p:BootstrapperComponentsLocation=Relative

Now we finally have deployed to a test server. Problem 3 : This does NOT generate the html file showing the version and so, this is done in the VS interface, and not by MSBuild. But the html page is an easy one, so I took one generated by VS as a template, and adjusted my buildscript so it also creates one.
PS.: is you want to install via a fileshare, you must adjust the following properties :
/p:InstallFrom=Unc
/p:IsWebBootstrapper=false
/p:PublishUrl=${publishUNC}
/p:InstallUrl=${publishUNC}

Now I zip the generated ClickOnce folder, so it is easier to update this specific version later on.

Problem 4 :getting this click once to run from a different folder.
When you read the pages about Mage, it just says that you only have to update the deployment manifest and resign it. WRONG
If you do it this way, you'll end up in trouble. The ClickOnce installation made by MSBuild did come clever tricks, if you take a look in the 'Application Files' folder, you see that there is a subfolder for every build(which is ok). But the contents of these subfolders do NOT contain any .exe or .dll file, it only contains .deploy files. This is done because IE makes trouble in downloading .exe or .dll files. That's why a simple update of the deployment manifest with Mage does not work. The deployment manifest can not find the files anymore! I hacked around this with the following procedure :
  • rename every .deploy file to the correct name (strip the .Deploy extention)
  • update the app.config files if needed
  • update the application manifest with mage (because the app.config file could be changed)
  • re-sign the application manifest with mage
  • update the deployment manifest : update the url from where to install
  • update the deployment manifest with mage
  • resign the deployment manifest with mage
  • re-add the deployment extention to the files where it was removed from

Command for updating the application manifest with mage:
mage -Update ApplicationManifestFile -FromDirectory BinFolder (Binfolder is where the application manifests resides.)
Command for re-signing the application manifest with mage:
mage -Sign ApplicationManifestFile -CertFile applicationManifestKey -Password ThePassword
Command for updating the deployment manifest with mage :
mage -Update DeployManifestFile -appm ApplicationManifestFile -appc ApplicationCodeRelativeBasePath (ApplicationCodeRelativeBasePath is the relative location of the ApplicationManifest from the DeploymentManifest.)

Now you have a Web enabled ClickOnce installation. And with this procedure it is very easy to adjust the settings for 100+ servers. Keep in mind that the copying is not done by MSBuild, this must still be done!

1 comment:

  1. Thank you for this post. You are my god. Finally someone found the solution :)
    I wrote a tool to do this steps simply, just a command line tool. if somebody is interessted in it: devcare |√ĄT| yooapps.com

    ReplyDelete