How to build ClickOnce applications with TeamBuild for multiple environments

  

In ths post I will show how to build ClickOnce applications with TeamBuild for multiple environments in Team Foundation Server.

I have been trying to build ClickOnce applications in our TeamBuild for some time now and only after long ours of googling and trial and error was I successful. The most useful information I found on this blog:

Publish ClickOnce project with Team Build?

Made some modifications and refactoring and here are the code we currenlty use:

This is how you call the ClickOnce build from you TeamBuild project file (line breaks added for readability):

    <Msbuild
          Projects="$(SolutionRoot)ConfigFilesBuildClickOnce.targets"
          Targets="BuildClickOnce"
          Properties="SourceDir=$(SourceDir);PublishDir=$(PublishDir);                      ClickOnceAppName=$(ClickOnceAppName);ClickOnceExeFile=$(ClickOnceExeFile);                      ClickOnceProduct=$(ClickOnceProduct);Company=$(Company);                      ClickOnceDescription=$(ClickOnceDescription);ClickOnceUrl=$(ClickOnceUrl);                      VersionNumber=$(VersionNumber);SigningCert=$(SigningCert);                      SigningCertPassword=$(SigningCertPassword)"
            />

For every environment or configuration change you want you use this. Below you find the BuildClickOnce.targets file (line breaks added for readability):

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <Import Project="$(MSBuildExtensionsPath)MicrosoftVisualStudioTeamBuildMicrosoft.TeamFoundation.Build.targets" />
    <Import Project="$(MSBuildExtensionsPath)MSBuildCommunityTasksMSBuild.Community.Tasks.Targets"/>
    <Import Project="$(MSBuildExtensionsPath)MicrosoftSDCMicrosoft.Sdc.Common.tasks"/>

    <Target Name="BuildClickOnce" DependsOnTargets="">

        <PropertyGroup>
            <ClickOnceApplicationUrl>$(ClickOnceUrl)$(ClickOnceAppName).application</ClickOnceApplicationUrl>
            <AppPublishDir>$(PublishDir)</AppPublishDir>
            <SdkPath>C:Program FilesMicrosoft SDKsWindowsv6.0A</SdkPath>
        </PropertyGroup>

        <BuildStep
          TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
          BuildUri="$(BuildUri)"
          Message="Buildning $(ClickOnceAppName) ClickOnce version: $(VersionNumber)">
            <Output TaskParameter="Id" PropertyName="StepId" />
        </BuildStep>

    <CallTarget Targets="UpdateWebPage" />

        <!--
  ************************************************
  Generate application manifest
  ************************************************
  -->
        <Exec
        Command="mage.exe -New Application -TrustLevel FullTrust                  -ToFile &quot;$(AppPublishDir)$(ClickOnceExeFile).manifest&quot;                  -Name &quot;$(ClickOnceAppName)&quot; -Version &quot;$(VersionNumber)&quot;                 -FromDirectory &quot;$(AppPublishDir)&quot;"
        WorkingDirectory="$(SdkPath)Bin"/>

        <!--
  ************************************************
  Signing application manifest
  ************************************************
  -->
        <Exec Condition="'$(SigningCertPassword)'==''"
          Command="mage.exe -Sign &quot;$(AppPublishDir)$(ClickOnceExeFile).manifest&quot;                    -CertFile &quot;$(SigningCert)&quot;"
          WorkingDirectory="$(SdkPath)Bin"  />

        <Exec Condition="'$(SigningCertPassword)'!=''"
            Command="mage.exe -Sign &quot;$(AppPublishDir)$(ClickOnceExeFile).manifest&quot;                      -CertFile &quot;$(SigningCert)&quot; -Password &quot;$(SigningCertPassword)&quot;"
            WorkingDirectory="$(SdkPath)Bin"/>

        <!--
  ************************************************
  Renaming source files to .deploy
  ************************************************
  -->
        <ItemGroup>
            <SourceFilesToRename Include="$(AppPublishDir)***.*"                  Exclude="$(AppPublishDir)*.manifest;$(AppPublishDir)*.htm"/>
            <SourceFilesToDelete Include="$(AppPublishDir)***.*"                  Exclude="$(AppPublishDir)*.application;$(AppPublishDir)*.manifest;$(AppPublishDir)*.htm"/>
        </ItemGroup>

        <Copy
            SourceFiles="@(SourceFilesToRename)"
            DestinationFiles="@(SourceFilesToRename->'$(AppPublishDir)%(RecursiveDir)%(Filename)%(Extension).deploy')"
        />

        <Delete Files="@(SourceFilesToDelete)"/>


        <!--
  ************************************************
  Generating deployment manifest
  ************************************************
  -->

        <GenerateDeploymentManifest
          MapFileExtensions="true"
          AssemblyName="$(ClickOnceAppName).application"
          AssemblyVersion="$(VersionNumber)"
          MinimumRequiredVersion="$(VersionNumber)"
          DeploymentUrl="$(ClickOnceApplicationUrl)"
          Description="$(ClickOnceDescription)"
          Product="$(ClickOnceProduct)"
          Publisher="$(Company)"
          SupportUrl="$(SupportUrl)"
          EntryPoint="$(AppPublishDir)$(ClickOnceExeFile).manifest"
          Install="true"
          UpdateEnabled="true"
          UpdateMode="Foreground"
          OutputManifest="$(PublishDir)$(ClickOnceAppName).application"/>

        <!--
  ************************************************
  Signing application manifest
  ************************************************
  -->
        <Exec Condition="'$(SigningCertPassword)'==''"
            Command="mage.exe -Sign &quot;$(PublishDir)$(ClickOnceAppName).application&quot;                     -CertFile &quot;$(SigningCert)&quot;"
            WorkingDirectory="$(SdkPath)bin"/>
        <Exec Condition="'$(SigningCertPassword)'!=''"
            Command="mage.exe -Sign &quot;$(PublishDir)$(ClickOnceAppName).application&quot;                     -CertFile &quot;$(SigningCert)&quot; -Password &quot;$(SigningCertPassword)&quot;"
            WorkingDirectory="$(SdkPath)bin"/>


        <!--
  ************************************************
  Generating Bootstrapper
  ************************************************
  -->
        <ItemGroup>
            <BootstrapperFile Include="Microsoft.Net.Framework.2.0">
                <ProductName>Microsoft .NET Framework 2.0</ProductName>
            </BootstrapperFile>
        </ItemGroup>

        <GenerateBootstrapper
          ApplicationFile="$(ClickOnceAppName).application"
          ApplicationName="$(ClickOnceAppName)"
          ApplicationUrl="$(ClickOnceUrl)"
          BootstrapperItems="@(BootstrapperFile)"
          Culture="en"
          FallbackCulture="en-US"
          CopyComponents="true"
          Validate="false"
          Path="$(SdkPath)Bootstrapper"
          OutputPath="$(PublishDir)"/>


        <BuildStep
          TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
          BuildUri="$(BuildUri)"
          Id="$(StepId)"
          Status="Succeeded"/>

        <OnError ExecuteTargets="MarkBuildStepAsFailed" />
    </Target>

    <!--
  ************************************************
  Marks a buildstep as failed
  ************************************************
  -->
    <Target Name="MarkBuildStepAsFailed">
        <BuildStep
          TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
          BuildUri="$(BuildUri)"
          Id="$(StepId)"
          Status="Failed"/>
    </Target>

    <!--
  ************************************************
  Updating web page
  ************************************************
  -->
    <Target Name="UpdateWebPage">
        <ItemGroup>
            <WebPage Include="$(PublishDir)publish.htm" />
        </ItemGroup>

        <RegEx
          Condition="Exists(@(WebPage))"
          Path="@(WebPage)"
          RegularExpression="#VERSION#"
          NewValue="$(VersionNumber)"
          Force="true"/>
    </Target>
</Project>

2 thoughts on “How to build ClickOnce applications with TeamBuild for multiple environments

  1. Oleg 2009-07-16 / 19:37

    Thanks for the great post!Could you please share implementation steps also?

  2. Hakan 2009-07-16 / 21:03

    What implementation step are are you looking for?

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