Click Once publishing using Visual Studio 2005 is an easy, quick and painless way to manage deployments. Painless, that is, if you are a cowboy developer who's stomach doesn't quiver at the thought of throwing non-integration tested code into production or if you're a coding monkey who enjoys the mindless monotony of manual builds.
For those of us enlightened in the art of automated builds and continuous integration, however, Click Once is a nightmare. Fortunately, there is a way to deploy Click once applications without becoming a Visual Studio monkey. Here are my lessons learned for Click Once deployements using NAnt.
First you must configure IIS with your deployment folder. For example I set up a virtual directory called http://server/clienttest to C:\Development\Deploy\ClickOnce on my deployment server. We have a windows file share pointing to C:\Development called \\server\Development. In NAnt the ${clickonce.dir} points to \\server\Development\Deploy\ClickOnce while the ${deploy.dir} variable points to a local folder containing the deployable outputs from the build.
Now, if you don't already have one you will have to create a certificate with which to sign the manifests. I used the makecert tool for this ensuring that I the private key was exported. I store this key in the file indicated in the ${certificate.filename} NAnt variable. Read http://msdn2.microsoft.com/en-us/library/bfsktky3.aspx for more info on makecert.
Next I have a NAnt build target that creates a new directory for the build version then copies the client dlls into that directory:
(pardon my obtuse XML, just can't figure out how to get the angle brackets and indentation on this site)
(target name="create.clickonce.dir")
(delete dir="${clickonce.dir}\${version}" failonerror="false" /)
(mkdir dir="${clickonce.dir}\${version}" /)
(copy todir="${clickonce.dir}\${version}" flatten="true" )
(fileset basedir="${deploy.dir}\client")
(include name="*.exe" /)
(include name="Dependant*.dll" /)
(/fileset)
(/copy)
Essentially, Click Once deployment is the creation of two manifest files. The first describes the contents of a specific version of your application the second describes the contents of your deployment and specifies the most recent version. Fortunately, Microsoft has a utility called mage that assists in generating and signing these manifests. In order to create these files as part of the build process I created a NAnt task that calls mage.
I had to do this in two steps. The first step is to create both the application manifest and the deployment manifest. For example I ended up adding a target that looks something like this:
(target name="create.clickonce")
(call target="create.clickonce.dir" /)
(exec program="mage" commandline="-New Application
-t ${clickonce.dir}\${version}\Client.exe.manifest
-fd ${deploy.dir}\client -Name Client" /)
(exec program="mage" commandline="-Sign ${clickonce.dir}\${version}\Client.exe.manifest
-CertFile ${certificate.filename} -Password ${certificate.password}" /)
(exec program="mage" commandline="-New Deployment
-t ${clickonce.dir}\Client.application
-pu http://server/clienttest/Client.application
-n Alpha -i false
-appm ${clickonce.dir}\${version}\Client.exe.manifest" /)
(exec program="mage" commandline="-Sign ${clickonce.dir}\Alpha.application
-CertFile ${certificate.filename} -Password ${certificate.password}" /)
(/target)
This target need only be called when you want to create your deployment manifest. Typically it will only be called once, but I like to throw it in the build script in case I ever need to rebuild my deployment server.
The second step is to create the application manifest for the most recent build and then update the deployment manifest. The following target copies the
(target name="deploy.clickonce")For more information on manual Click Once deployments have a read through http://msdn2.microsoft.com/en-us/library/xc3tc5xx.aspx.
(call target="create.clickonce.dir" /)
(exec program="mage" commandline="-New Application -t ${clickonce.dir}\${version}\Client.exe.manifest -fd ${deploy.dir}\client -Name Client -Version ${version}" /)
(exec program="mage" commandline="-Sign ${clickonce.dir}\${version}\Client.exe.manifest -CertFile ${certificate.filename} -Password ${certificate.password}" /)
(exec program="mage" commandline="-Update ${clickonce.dir}\Alpha.application -AppManifest ${clickonce.dir}\${version}\Alpha.exe.manifest -Version ${version}" /)
(exec program="mage" commandline="-Sign ${clickonce.dir}\Alpha.application -CertFile ${certificate.filename} -Password ${certificate.password}" /)
(/target)

7 comments:
Umm, how exactly did you create your certificate?
I keep getting the following error:
"This certificate does not contain a private key"
I've tried many variations on the commandline. I assume -pe since you say that the private key must be exportable.
Does it need to be in a keystore or something?
Neil,
Some of users of our Parabuild employ build configurations with parameters to control one-click deployment using NAnt through Web UI. This is a new feature in 3.0
Generally, once the parameter, let say DEPLOY_TO_QA is configured all NAnt needs is this
<target name="deploy" if="${env.DEPLOY_TO_QA}" >
...
</target>
Sort it by the way...
Used to following:
makecert -r -pe -n "CN=COMPANYNAME" -ss my -sr localMachine -sky exchange -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 DevBuild.cert
Am about to try using CertHash rather than CertFile, for signing with a "real" key.
Cheers
If you have a desktop icon which you want to place, an entry needs to be added in the manifest. I am hand editing the manifest to add this entry.
Can this somehow be included in nant bulid process?
I am using the IDE to publish my application and the published folder is showing me the manifest in the below format
Outpost_1_0_3_3565.application.
Now we have moved the publishing logic to a build script (NANT) which uses the msbuild /t publish ....etc command.But the manifest created is showing Outpost.application.
Because of this,the client is not getting the upgrade prompt.
I am new to Clickonce .Please help me.How can i get my build script create manifest in "Outpost_1_0_3_3565.application" format?
The first thing I'd try in your specific case is to open up your Outpost.application file in IE to see what happens. If it runs then you're doing things right just using the wrong link. If you are trying to use the publish.html file created by Visual Studio then that won't work for sure. You could always change the link in the publish.html file to point to Outpost.Application rather than Outpost_1_0_3_3565.application.
i was wondering why the publish from IDE creates a manifest with EXEname_version number.application and my build script creates just EXEname.application.is there any parameter i have missed when i did the publish.
Post a Comment