Channels ▼
RSS

Tools

Quick Apps With ClickOnce


ClickOnce in a Continuous Integration Scenario

Publishing a ClickOnce-based application in Visual Studio is very easy, as opposed to the automated deployment. But it's still tricky and, if you want to do it, you can either use a command-line tools like mage.exe or you can have MSBuild to do the work for you. As we are the masters of MSBuild now, we will use this build tool.

You can generate the publication files using MSBuild by using the Publish target on the solution file, like this:


msbuild CiDotNet.sln /t:Publish 

There are several problems with this approach:

  • The version number is not incremented.
  • The publication files are created in the bin\$(Configuration)\app.publish folder and not on the destination location.
  • The web site HTML file is not generated

Let's deal with these issues one at the time. The version number could be set from outside by providing the ApplicationVersion property on the MSBuild command line:


Msbuild CiDotNet.sln /t:Publish /p:ApplicationVersion=1.0.0.3

But how do we get the version number on the build server? Visual Studio takes it from the ApplicationRevision property inside the .csproj file and it will not be a good idea to mess with it on the server. But how about combining the ApplicationVersion number with the revision number?

First, make sure the MSBuild community tasks have been copied into the tools directory. Next, get the svn.exe and copy it to svn subdirectory in the tools folder. We'll use them both, as shown in Listing 1.


<Project DefaultTargets="Publish" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
      <UsingTask AssemblyFile="tools\MSBuildCommunityTasks\MSBuild.Community.Tasks.dll"   TaskName="MSBuild.Community.Tasks.Subversion.SvnInfo"></UsingTask>
     <PropertyGroup> 
        <ApplicationVersion Condition=" '$(ApplicationVersion)' == '' ">  <b>1</b>
          1.0.0.  
        </ApplicationVersion>                                     <b>1</b> 
        <RevisionNumber Condition=" '$(RevisionNumber)' == '' "> <b>2</b> 
          0 2 
        </RevisionNumber> <b>2</b> 
        </PropertyGroup>    <b>2</b>
     <Target Name="Publish"> 
    <SvnInfo RepositoryPath="http://ci1/svn/CiDotNetCh10/trunk" 
        Username="user" Password="password" ToolPath="tools\svn"> 
       <Output TaskParameter="Revision" PropertyName="RevisionNumber" /> <b>3</b>  
       </SvnInfo>    
       <MSBuild Targets="Publish" Projects="CiDotNet.sln" <b>4</b>  
             ContinueOnError="false" Properties=                         <b>4</b> 
            "ApplicationVersion=$(ApplicationVersion)$(RevisionNumber)"/> <b>4</b> 
    </Target> 
</Project> 

<b>
1 Defines the immutable version part
2 Defines the mutable version part 
3 Gets the version number from Subversion 
4 Generates publish files 
</b>

Listing 1: Publishing an application versioned with SVN revision number

After importing the SvnInfo MSBuild Community task we define the immutable #1 and mutable #2 version number parts. In the Publish target, we get the RevisionNumber #3 using the SvnInfo task and apply it to the ApplicationVersion property #4. Problem one, setting the version number, is now solved.

The second problem is that the files are not copied to the target location. The ClickOnce files are created in bin\$(Configuration)\app.publish folder. They need to be copied to the web server. The easiest way is to define the target location like:


 <DeploymentFolder>\\ci1\WinCalc\</DeploymentFolder>

Then gather the source files:


 <ItemGroup> 
   <DeploymentSourceFiles Include="CiDotNet.WinCalc\bin\$(Configuration)\app.publish\**\*.*" />
</ItemGroup> 

After the publishing files are created they can be copied:


<Copy 
      SourceFiles="@(DeploymentSourceFiles)" 
     DestinationFiles="@(DeploymentSourceFiles->'
[CA]$(DeploymentFolder)\%(RecursiveDir)%(Filename)%(Extension)')"/> 

The last problem is the lack of the HTML website. There is no elegant way to deal with that. The best solution is to take the created index.html Web site and create a kind of template with it. Let's copy the index.html file to the solution project folder and change the current version to a string stored in the ApplicationVersion variable. We will use the FileUpdate task from the MSBuild Community Tasks. Check out Listing 2 for the file update usage.




<Copy SourceFiles="index.htm" 
   DestinationFiles="$(DeploymentFolder)\index.htm"/> 
<Copy SourceFiles="wincalc.png" <b>1</b> 
   DestinationFiles="$(DeploymentFolder)\wincalc.png"/> <b>1</b> 
<FileUpdate Files="$(DeploymentFolder)\index.htm" 
     IgnoreCase="true" 
     Multiline="true" 
     Singleline="false" 
     Regex="ApplicationVersion" 
     ReplacementText="$(ApplicationVersion)$(RevisionNumber)"/> <b>2</b> 

<b>
1 Copy template files 
2 Update version number
</b>

Listing 2: Updating publication version in ClickOnce HTML self-made template file

The use of the HTML template gives you one more opportunity to customize the ClickOnce website to suit your needs. For example, you can provide additional information to the user. First, we take the custom-made HTML "template" file together with an application screenshot and copy it to the destination folder #1. Afterward we apply the FileUpdate task, search for the ApplicationVersion string, and replace it with the version number #2. Don't forget to import the FileUpdate task from MSBuild Community Tasks. Your ClickOnce Web site could look like that in Figure 4.

[Click image to view at full size]
Figure 4: A customized ClickOnce website generated directly from the build server.

You can take this build script and set it to make your Continuous Integration server use it every time something changes in the repository. You will get a brand new application deployed every time something changes in the repository.

Summary

Automating delivery and deployment and incorporating it into the Continuous Integration process is a very natural thing to do. It feels quite right to take the compiled, tested, analyzed and documented code that looks like a delicious sweet candy and wrap it up with colorful wrapping.

The delivery and deployment scenarios depend on your individual needs. You can, for example, provision some Virtual PC setups just like the physical ones. You might want to add the automatically generated documentation to the package. You may also need to take into account laws, such as Sarbanes/Oxley (SOX) in the United States, which prohibit development from touching QA or production servers. In this case, you can use agents on QA and production servers to get the latest build. Finally, you might want to create some safety net functionality in your build script to redo the changes if something goes wrong.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video