Building ClickOnce Applications with NAnt

Since I don’t like to actually do any work, and would much rather automate everything I’m required to do, I decided to automate a ClickOnce application build, because doing it manually was taking me literally, er, seconds, and this is waaaaaay too much like hard work. So, I naturally turned to NAnt, which is so often the answer to all my deployment questions….The answer came in the form of using NAnt to call MSBuild and pass the publish target, along with the version number. So, this is what you need to do:

Add a property to your nant script containing your build number (you can get this from CruiseControl.Net if you’re using CCNet to do your builds)
<property name=”version.num” value=”″/>
Then just compile the project using NAnt’s MSBuild task, and call the publish target:

<target name=”publish” >

<msbuild project=”${base.dir}\ClickOnce.vbproj”>

<arg value=”/property:Configuration=Release”/>

<arg value=”/p:ApplicationVersion=${version.num}”/>

<arg value=”/t:publish” />



The next thing you need to do is create or update the publish.htm file. What I’ve done for this is to take a copy of a previously generated publish.htm, and replace the occurrences of the application name with a token. Then in the NAnt script, I replace the token with the relevant application name with a version number. I do this because the version number will change with each build, and rather than manually update it, which is much too complicated for me, I’d rather just automate it so that I can go back to sleep while it builds.I tokenised the application name because of a much darker, more sinister reason that I’ll maybe explain at another time, but the world’s just not ready for that yet.
Anyway, here’s all that in NAntish:

<copy todir=”${config.dir}\${}”>

<fileset basedir=”.”>

<include name=”publish.htm” />




<token key=”VERSION” value=”${version.num}” />

<token key=”APPNAME” value=”${appname}” />






  1. Sray · January 20, 2013

    jon, what do you need to test with the Page subclasses? i think they’re pttery hard to test without the necessary context (being in a running web server) and that’s a testability-killer. what you need is to abstract the functionality of those pages into context-agnostic objects like plain old CLR objects (POCO). a good way of doing this is by implementing you guessed it model-view-presenter (MVP).you should also ask yourself, do you need to test the framework? that’s not your app, so why test it? you should only test your OWN classes. if you really want to test a framework, you can build facade classes in front of them, and that is what you will be able to test. for example, do you want to be able to test email sending functionality? Sure you can do MailMessage and SmtpMail testing but you’ll need a live mail server for that, and testing will slow down to a crawl because you’re accessing real SMTP. So you build an interface or facade to represent the mail sending functionality, then you test that if it’s the framework you’re making and you wish to test it, you need to zero in on the collaboration between objects in your framework. then you test them via mock objects. i wish i could demonstrate these to you personally

  2. Devi · January 22, 2013

    * CCNET supports CVS.* a cmomon way to test abstract classes is to test a subclass which has no override from its base class* testing subclasses is just the same as testing ordinary classes, do you need to test the base class implementation, not if there’s no change, yes if it’s overridden* hopefully i can share what we do in our company in our upcoming tech-share* build numbers and revision numbers from source control, we use them as version of the built assemblies

  3. Pingback: Automating ClickOnce Deployment - Joe Wrobel

Leave a Reply

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

You are commenting using your 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