Publishing ClickOnce Applications to Run Side-by-side for Different Environments from the Command Line using Nant

Note:
The following information relates to .NET 3.5 and NAnt 0.85.
 
Preamble
I struggled with this for quite some time. I was trying to run a command-line, clickonce deployment of my application to enable it to run side-by-side for the different environments (development, quality assurance, user acceptance testing, and production). Kavinda Munasinghe’s blog post, Deploying ClickOnce on Multiple Environments was a fantastic start. It also referenced a former coworker, Neil Bourgeois, and his post, Click Once deployment using NAnt. Neil’s article looked like too much manual lifting as MSBuild should have the ability to take in some command-line parameters to do this properly as it is possible to accomplish the goal os side-by-side applications if performed within visual studio. The problem was figuring out which command-line switches to pass to MSBuild to get it to work.
 
The Keys are 3
  1. ProductName – This will identify each instance uniquely. I would recommend indicating each instance by its target environment to help users know which one they are running as well as knowing which one they are uninstalling if using Add/Remove Programs. e.g. <Product Name> – Development
  2. SignManifests – This was the one parameter missing from Kavinda‘s post that was forcing the value for publicKeyToken (a part of the application identity that must be unique to allow the applications to run side-by-side) to always remain at a value of "0000000000000000".
  3. ManifestKeyFile and ManifestCertificateThumbprint – These values are what are used to actually sign the manifest. These were what Kavinda was correctly noting in the article.

The Result

I have one exec task in my nant script that takes in parameters that are set by running a target specific to the intended environment:

<!– deployment properties –>
<
property name="publisher.name" value="My Company Name" />
<
property name="publish.output.base.dir" value="\UNCLocationDeploymentProductName" />
<
property name="product.name.base" value="ProductName" />
<
property name="product.name" value="SET_BY_TARGET__DO_NOT_CHANGE_HERE" />
<
property name="build.label" value="SET_BY_TARGET__DO_NOT_CHANGE_HERE" />
<
property name="publish.output.dir" value="SET_BY_TARGET__DO_NOT_CHANGE_HERE" />
<
property name="manifest.certificate.thumbprint" value="SET_BY_TARGET__DO_NOT_CHANGE_HERE" />
<
property name="manifest.key.file" value="SET_BY_TARGET__DO_NOT_CHANGE_HERE" />

<target name="deploy.to.dev">
    <
property name="publish.output.dir" value="${publish.output.base.dir}Development"
/>
    <
property name="manifest.certificate.thumbprint" value="003dd8c1fca443b398d240a54a7e47f2"
/>
    <
property name="manifest.key.file" value="certificatesdevelopment.pfx"
/>
    <
property name="product.name" value="${product.name.base} – Development"
/>
    <
call target ="deploy.common"
/>
</
target

 <target name="deploy.common">
    <
exec program="MSBuild.exe"  
              commandline=MyProject.csproj /target:rebuild;publish /property:ProductName="${product.name}";
                                     PublisherName="${publisher.name}";
                                     SignManifests=True;
                                     ManifestKeyFile=${manifest.key.file};
                                     ManifestCertificateThumbprint=${manifest.certificate.thumbprint};
                                     BootstrapperEnabled=True;
                                     CreateDesktopShortcut=True;
                                     UpdateRequired=True;
                                     UpdateMode=Foreground;
                                     MinimumRequiredVersion=${build.label};
                                     AssemblyVersion=${build.label};
                                     ApplicationVersion=${build.label};
                                     Install=True;
                                     Configuration=Release;
                                     Platform="Any CPU";
                                     OutDir=……${build.dir;
                                     OutputPath=${publish.output.dir};
                                     PublishDir=${publish.output.dir};
                                     PublishUrl=${publish.output.dir};
                                     InstallUrl=${publish.output.dir};
                                     UpdateUrl=${publish.output.dir}
                                      /nologo /verbosity:quiet basedir="${framework.dir}"/>
</target>

There are a few extra items in there that force this application to be installed locally as well as always remain at the latest version that are not applicable to this post, but I am leaving them in there for completeness.

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s