Automating a ClickOnce Deployment – Part1
In our build process, using Team Foundation Build, we decided to use ClickOnce for application deployment. In this post I’ll try to set the lay of the land. In the following couple of posts I will take you through the process of setting up a clickonce deployment.
Choosing the deployment strategy
There are essentially two different ways to deploy clickonce applications. They are:
- Physical media such as CD or DVD
- Network share or web
Deciding on the strategy that will work for you is largely determined by the available bandwidth at the client site. If there is none to very little bandwidth, or no internet connectivity, choose CD / DVD. Otherwise choose Network share or web.
We opted for the web strategy and so I will base the series around this strategy.
Lay of the land
Assume that we have one build server and one deployment server. The build server will push the build artifacts to the deployment server from where clients will use clickonce to install the application. The application is pushed to the deployment server after every build with a new version number.
To make the explanations easier we will setup a hypothetical configuration and base the deployment configuration on it. Our hypothetical solution consists of a single application, which we will call App. Below is a diagram that demonstrates this configuration:
Note: To hide the published share simply name it with a trailing dollar sign i.e. “Published$”.
Initial configuration
First of all we need a folder on the deployment server to push the build artifacts to. For this, create a published folder on the deployment server and share it with modify permissions granted to the TFSSERVICE account. Remember the TFSSERVICE account that TFS uses for the build service?
Furthermore, we need to configure Internet Information Services (IIS) to interpret the clickonce files correctly according to their extension. For this, add the following MIME types in IIS:
.application application/x-ms-application .manifest application/x-ms-manifest .deploy application/octet-stream
If you are using IIS 6.0, have a look at this article “IIS 6.0 Does Not Serve Unknown MIME Types”.
In the next installment I’ll discuss the different files that describe the application and deployment.
Team Foundation Server Build Notification
Included in the Team Foundation Server Tools download is an absolute must-have, Team Foundation Build Notification. If you have are making use of continuous integration chances are that you are building often. Instead of keeping an eye out for the latest build report in your email or constantly checking it in Visual Studio, use this notification utility. It has little popups that appear when someone requested a build either via checkin or ad hoc, which is configurable. It has a notification icon in the system tray (one the few that I will tolerate) and changes whenever one of the builds succeeds, fails or starts. It gives immediate access to the build log which you would normally have to browse for. It is also able to monitor multiple builds. A definite win!
XML Intellisense for NHibernate
Using NHibernate requires the writing of some tedious XML-based configuration mapping files. Remembering all the tags and attributes can sometimes be overwhelming. Thankfully the contributors decided to include intellisense hints, which are in nhibernate-configuration.xsd and nhibernate-mapping.xsd.
In order to have the hints available in Visual Studio 2008 copy the files into C:\Program Files\Microsoft Visual Studio 9.0\XML\Schemas and restart Visual Studio.
Personal Knowledge Management with a Wiki
In the excellent book Pragmatic Thinking and Learning: Refactor Your Wetware (Pragmatic Programmers) by Andy Hunt, he suggests that every programmer should have a personal wiki in order to manage knowledge effectively. A sort of exocortex. A place where you can keep ideas, thoughts and nearly anything you want outside your brain.
Ever received one of those emails that you just have to keep somewhere? That snippet of source code that might come in handy? That chocolate muffin recipe? Why not put all of it into your wiki?
My personal choice of this kind of wiki is TiddlyWiki. Simply because all of the content is in a single HTML file. Fan of Getting Things Done? TiddlyWiki can easily be configured to support the Getting Things Done methodology. Have a look at d-cubed for example.
Bear in mind that it has a learning curve to it, but if you are willing to stick to it you will surely reap the benefits.
Some of the features include:
- Tagging
- Searching
- Text formatting, including support for monospace
- Highlighting
- Block quotes
- Tables
- Headers
- Save with backups
- RSS feeds
I would suggest the following plugins to really spice-up TiddlyWiki:
Check out TiddlyTools and TiddlyVault for other plugins. It supports themes, which can be downloaded from TiddlyThemes. There is also a great cheat sheat available.
Rollback Changesets
In Team Foundation Server 2008, there doesn’t seem an easy way to simply perform a rollback on a comitted changeset. Well, that is until you discover the power of the updated Team Foundation Server Power Toys.

Rollback command
Before rolling back a changeset, the local workspace must have no pending changes. After issuing the rollback command, tfpt rollback a dialog will appear asking whether you want the local workspace brought up to date with the repository. After affirming the dialog, a get command will be issued for your workspace and updated with the latest changes.
After the get operation completed successfully, another dialog will appear asking you to identify the changeset that you want to rollback. Note: Make sure that you have the correct changeset before continuing.
Select the files that you want to rollback in the changeset and click on “Roll Back”. After the rollback completed, you might have to resolve some conflicting changes. Now that the rollback is complete, you will still need to commit the new changeset, which is the latest code, without the changeset that was rolled back.
If you want to skip all of the GUI stuff, then you can simply execute the rollback command this way: tfpt rollback /changeset:4018.
AWOL CD-ROM
For the second time now I have had the CD-ROM drive on my HP nw8440 disappear from Windows. The Device Manager reports the following for the CD-ROM drive: “Windows cannot load the device driver for this hardware. The driver may be corrupted or missing. (Code 39)”. Why? It was perfect yesterday and today it is missing or corrupted? Weird. According to the Microsoft Knowledge Base article it can happen after removing a CD or DVD burning program.
Although the error is rather annoying, there is a simple fix for it. I have replicated the steps here for your convenience:
Step 1: Start Registry Editor
Start Registry Editor.
Step 2: Delete the UpperFilters registry entry
- In Registry Editor, expand My Computer, and then expand HKEY_LOCAL_MACHINE.
- Expand SYSTEM, and then expand CurrentControlSet.
- Expand Control, and then expand Class.
- Under Class, click {4D36E965-E325-11CE-BFC1-08002BE10318}.
- In the details pane of Registry Editor, on the right side, click UpperFilters.Note You may also see an UpperFilters.bak registry entry. You do not have to remove that entry. Click UpperFilters only.
- If you see the UpperFilters registry entry in the details pane of Registry Editor, go to step 6.
- If you do not see the UpperFilters registry entry, you still might have to remove the LowerFilters registry entry. To do this, go to “Step 3: Delete the LowerFilters registry entry.”
- On the Edit menu, click Delete.
- Click Yes when you receive the following message:
The UpperFilters registry entry is removed.
Step 3: Delete the LowerFilters registry entry
- In the details pane of Registry Editor, on the right side, click LowerFilters.Note You might see a LowerFilters.bak registry entry. You do not have to remove that entry. Click LowerFilters only.
If you do not see the LowerFilters registry entry, unfortunately this content is unable to help you any more. Go to the “Next Steps” section for information about how you can find more solutions or more help on the Microsoft Web site.
- On the Edit menu, click Delete.
- Click Yes when you receive the following message:
The LowerFilters registry entry is removed.
- Exit Registry Editor.
The article recomends restarting the computer after deleting the two registry entries, but I have found that it works fine without restarting.
Workplace Morale
Lately I’ve been thinking on morale in the workplace. What is morale? According to Alexander H. Leighton, “morale is the capacity of a group of people to pull together persistently and consistently in pursuit of a common purpose“.
From this quote, it is evident that if morale decreases, people will no longer pull together in pursuit of the common purpose. Following from that, we can then say that morale is the glue that keeps people united and focused on the given task.
Sustaining a healthy level of morale in the workplace should be one of the primary concerns of managers. I’d like to think that every workplace has a set of morale pumps that help to maintain a certain level of morale, whether it be great coffee, job security or an energizing work culture, which contribute to keeping employees focused and united.
In the current economic environment where most businesses have to consider cutting costs on most levels, be careful when cutting costs on the morale pumps. Consider the cost of reducing and taking away that which maintains this level of morale. I think investing into keeping morale high is probably more needed now than ever before.
Here are some factors that influence morale in the workplace, either positively or negatively :
- Job security;
- Management style;
- Staff feeling that their contribution is valued by their employer;
- Realistic opportunities for merit-based promotion;
- Team composition;
- The work culture;
- Compensation;
- Recognition and rewards;
- Work that isn’t challenging;
- Limited growth opportunities;
- Fun environment to work in
Customising Work Item Templates
Making use of either Team System Web Access or Team Explorer you might find it necessary to edit some of the work item templates. At first it might seem very confusing but is quite straight forward.
When editing work item templates there are two tools that you need to know about, witimport and witexport. They are used to import and export specific work item templates from an existing Team Foundation Server project.
First, you need to export the bug work item template by using the following command line:
witexport /f <work item templates folder>
/t <tfs server>:8080 /p <project name> /n bug
This will create a bug.xml template file in the work item templates folder specified, which could be any folder that you have access to.
The first part of the XML file defines the fields (indicated by the fields tag) that describe the bug. A workflow process (indicated by the workflow tag) is described in the middle of the file and the bottom part of the file describes the layout (indicated by the form tag) of the bug submission form.
Let’s add an environment field to the template that will indicate the environment where the bug occurred with the following values, tip, pre-stage, stage and live:
<field name="Environment" refname="TfsProject.Environment" type="String"> <required /> <helptext>Was the bug found in tip, pre-stage, stage or live?</helptext> <allowedvalues> <listitem value="Tip"/> <listitem value="Pre-stage"/> <listitem value="Stage"/> <listitem value="Live"/> </allowedvalues> <default from="value" value="Pre-Stage"/> </field>
The above piece of XML can be put anywhere after a closing field tag or the opening fields tag and must be somewhere before the workflow opening tag.
Name is obviously the name of the field that we are giving the additional piece of information. RefName is the name of this field that we are going to use to refer to when setting up the control in the layout section of the file. The presence of required tag says that a value must be specified for this field and will be validated automatically when a new bug is submitted. Next, we supply a list of values that will appear in the drop down list. Finally we provide a default value that will automatically be selected for each bug submission.
We now have to specify the new look of the form with our additional field and is done with the following XML definition:
<group>
<column PercentWidth="50">
<control Type="FieldControl" FieldName="TfsProject.Environment" Label="&Environment:" LabelPosition="Left" />
</column>
<column PercentWidth="50">
...
</column>
</group>
A group defines a collection of controls that are related. The column tag has an attribute that states the percentage space that the control should occupy. Each group should add up to to 100% but do not have to. The fieldname should be set to the field that we have just created in the fields section of the template. The label attribute is set to the label that we want to show in front of the control. In this case it is “Environment:”.
After placing the control, all that is left is to save the bug.xml file and import it back into Team Foundation Server. This is accomplished by the following command line:
witimport /f <work item templates folder>\bug.xml
/t <tfs server>:8080 /p <project name>
After a successful import the changes should be visible from both TSWA (Team System Web Access) and Team explorer, by double clicking on the Bug work item template.
Go customise those work item templates!
Customer Service
Recently, I walked into a store and saw the following saying, apparently by Mahatma Ghandi:
“A Customer is the most important visitor on our premises.
He is not dependent on us. We are dependent on him.
He is not an interruption in our work – he is the purpose of it.
He is not an outsider on our business. He is a part of it.
We are not doing him a favour by serving him.
He is doing us a favour by giving us an opportunity to do so.”
- Mahatma Gandhi
Source Code Promotion Model
At work we make use of a source code promotion model. What this means is that we promote source code through the various stages of product development.
All new development is done at the tip level. Once development is completed; and I’ll leave the definition up to you; the source code is promoted to the pre-stage level. It is at this level where our internal testers can begin testing the latest release of the product.
Only when the internal testers are satisfied, is the pre-stage source code promoted to the stage level. This is the level where our business users have access to the latest product release. They will in turn begin their testing. Once the business users are satisfied with the release, the stage source code will be promoted to the live or production level.
All this is accomplished by means of source code labels in Team Foundation Server Version Control and in a moment I’ll show you how to setup an MSBuild target that will take care of performing this type of promotion for you.
Note that although the source code is promoted, the labels in the version control system are in fact being shifted downwards, as shown in the picture. Also note that for every source code promotion there is a corresponding build process that kicks-off.
The first thing that we need is a set of label names that we will use to identify the various promotion levels. For this post I’m going to use the following label names: pre-stage, stage and live. You might wonder where the label is for tip – there isn’t one. We make use of the special version spec called T, which marks the latest version of the source code in Team Foundation Server Version Control by default and is always present.
I suggest creating a property group for these labels in case they need to change at some later stage.
<propertygroup> <prestagelabel>pre-stage</prestagelabel> <stagelabel>stage</stagelabel> <livelabel>live</livelabel> </propertygroup>
There are rules that we need to have in place before any source code promotion can happen. Here is a summarized list of rules:
- A valid FromLabel parameter must be specified;
- A valid ToLabel parameter must be specified;
- The pre-stage label can only be moved to tip;
- The stage label can only be moved to pre-stage;
- The live label can only be moved to stage.
Here they are represented in the build file:
<error Condition="'$(FromLabel)'==''" Text="The FromLabel property has not been specified." /> <error Condition="'$(ToLabel)'==''" Text="The ToLabel property has not been specified." /> <!-- check that the label name we are going to move is valid --> <error Condition="'$(FromLabel)'!='$(PreStageLabel)' and '$(FromLabel)'!='$(StageLabel)' and '$(FromLabel)'!='$(LiveLabel)'" Text="Valid FromLabel values are $(PreStageLabel), $(StageLabel) or $(LiveLabel)" /> <!-- check sanity : pre-stage label can only move to tip --> <error Condition="'$(FromLabel)'=='$(PreStageLabel)' and '$(ToLabel)'!='T'" Text="$(PreStageLabel) can only be moved to tip (T)." /> <!-- check sanity : stage label can only move to pre-stage --> <error Condition="'$(FromLabel)'=='$(StageLabel)' and '$(ToLabel)'!='$(PreStageLabel)'" Text="$(StageLabel) can only be moved to $(PreStageLabel)." /> <!-- check sanity : live label can only move to stage --> <error Condition="'$(FromLabel)'=='$(LiveLabel)' and '$(ToLabel)'!='$(StageLabel)'" Text="$(LiveLabel) can only be moved to $(StageLabel)." />
At this point we can be fairly sure that we are going to move labels to where they are supposed to be. On with the promotion. The actual process of moving the labels is fairly straight forward.
There are three different cases to consider when moving labels:
Special case #1 – Moving the live label:
I have not yet spoken about the labels that are attached to previously live versions. It might be necessary to track the source code version that was previously live, just in case the product needs to be rolled back for some or other reason. I term this label the previous-live label. If you need to keep track of all the previous live source code, then I suggest creating a custom build task that simply returns a current date/timestamp and mangle this with the previous-live label. If you only need to keep track of the previous version, you can simply just add it to the property group with all the other label names.
If we are moving the live label which is indicated by the FromLabel property, we first need to label the version at the current live label with the previous-live label. This is done with the following command:
<!-- Create a previous live label -->
<exec Condition="'$(FromLabel)'=='$(LiveLabel)' and '$(ToLabel)'=='$(StageLabel)' and '$(LiveLabelExists)'=='true'"
WorkingDirectory="$(SolutionRoot)"
Command=""$(TfCmd)" label /server:$(TeamFoundationServerName) "$(PreviousLiveLabel)@$(ProjectSourceRootPath)" $(ProjectSourceRootPath) /version:L$(LiveLabel)@$(ProjectSourceRootPath) /recursive"
/>
Property values in the command line:
- $(TfCmd) points to the location, including tf.exe.
- $(TeamFoundationServerName) is machine name where Team Foundation Server is installed on.
- $(ProjectSourceRootPath) is the source control folder of the project, for example $/MyProject.
Note the L in /version:L – which means that we are referring to the source code version labeled with the label that follows L.
Our next step is to move the live label to the stage label, which is done with the following command:
<!-- Move Live to Stage --> <exec Condition="'$(FromLabel)'=='$(LiveLabel)' and '$(ToLabel)'=='$(StageLabel)'" WorkingDirectory="$(SolutionRoot)" Command=""$(TfCmd)" label /server:$(TeamFoundationServerName) "$(PreviousLiveLabel)@$(ProjectSourceRootPath)" $(ProjectSourceRootPath) /version:L$(LiveLabel)@$(ProjectSourceRootPath) /recursive" />
Special case #2 – Moving the pre-stage label to tip:
When moving the pre-stage label to the tip, there is a small change that has to be made to the command line. Referring to the tip version in the versionspec is simply a T and is not prefixed with L – which indicates a label.
Below is the command line that has to be executed when moving from pre-stage to tip:
<exec Condition="'$(ToLabel)'=='T'"
WorkingDirectory="$(SolutionRoot)"
Command=""$(TfCmd)" label /server:$(TeamFoundationServerName) $(FromLabel)@$(ProjectSourceRootPath) $(ProjectSourceRootPath) /version:$(ToLabel) /child:replace /recursive"
/>
General case:
In all the other cases we simply move the source code labels based on the criteria given. The command line for this general case is shown below:
<exec Condition="'$(FromLabel)'!='$(LiveLabel)' and '$(ToLabel)'!='T'"
WorkingDirectory="$(SolutionRoot)"
Command=""$(TfCmd)" label /server:$(TeamFoundationServerName) $(FromLabel)@$(ProjectSourceRootPath) $(ProjectSourceRootPath) /version:L$(ToLabel)@$(ProjectSourceRootPath) /child:replace /recursive"
/>
Note: The above command lines, with the exception of Special case #1, will overwrite previous applied labels. It will also perform a recursive labeling of all the items in the source path with the new label.
And that is all that there is to it!


leave a comment