Search code examples
c#visual-studiomsbuildmage

How can I get the clickonce build script used by visual studio to publish my application


I have a pretty large multi-project solution. I currently build it in Visual Studio, and then publish using the right-click=> publish option. This works very well.

I am now in the position where I need to automate at least the clickonce publishing beyond what I can do in Visual Studio. I have successfully created a publish.xml file which I can use with msbuild and mage to create something that looks like a clickonce. However, there is a lot of complexity in the config I have in the visual studio interface that I would like to simply be able to copy into my publish.xml file.

Is it possible to get visual studio to generate a file that provides the properties used by MSBuild and/or Mage when visual studio publishes from the right click=> publish process?

Basically, I would like a configuration file that I could use to do something like msbuild publish.xml (or similar) and get exactly the publish result that visual studio makes.

I currently use VS2017. The application is winforms using c#

Here is my publish.xml. It is not supposed to be anything beyond a test

<Project> 
    <PropertyGroup>
        <OutputPathBuild>C:\Users\d_000\Documents\Visual Studio 2017\Projects\CP\CP.UI.Winforms\bin\x86\Debug</OutputPathBuild>
        <Version>1.0.0.0</Version>
        <OutputPathDeployment>C:\Users\d_000\Documents\CP Deploy\test</OutputPathDeployment>
        <Mage>C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\mage.EXE</Mage>
    </PropertyGroup>
  <Target Name="Deployment">
    <Error Condition="'$(Version)'==''" Text="The Version property must be defined in order to build the Deployment task."/>

    <ItemGroup>
      <DeploySource Include="$(OutputPathBuild)\**"/>
    </ItemGroup>
    <Copy SourceFiles="@(DeploySource)" DestinationFolder="$(OutputPathDeployment)\v$(Version)\%(RecursiveDir)"/>
    <Exec Command='"$(Mage)" -New Application -ToFile "$(OutputPathDeployment)\v$(Version)\MyApp.manifest" -Name MyApp -Version $(Version) -Processor X86 -FromDirectory "$(OutputPathDeployment)\v$(Version)" -IconFile Resources\CPIcon.ico'/>
    <Exec Command='"$(Mage)" -New Deployment -ToFile "$(OutputPathDeployment)\MyApp.application" -Name MyApp -Version $(Version) -Processor X86 -AppManifest "$(OutputPathDeployment)\v$(Version)\MyApp.manifest" -IncludeProviderURL true -ProviderURL "http://example.com/download/MyApp/MyApp.application" -Install true'/>
    <!-- Grr... Mage tool has a bug whereby -MinVersion only works in Update mode... -->
    <Exec Command='"$(Mage)" -Update "$(OutputPathDeployment)\MyApp.application" -MinVersion $(Version)'/>
    <Copy SourceFiles="$(OutputPathDeployment)\MyApp.application" DestinationFiles="$(OutputPathDeployment)\MyApp.v$(Version).application"/>
  </Target>
  </Project>

EDIT:

I need to customize what is in the publish process, so I am looking to find out what Visual Studio is doing. Essentially I want to get the commands run in visual studio, copy them and tweak them so I can automate several different builds with different delpoy URLs and update URLs


Solution

  • If you want to create ClickOnce for different stages you have to manipulate the proj file before you call MSBuild.

    1) Read your .proj file

    $projFilePath = Get-ChildItem $sourceRootDirectory -Filter $ProjectFileName -Recurse 
    $XmlDocument = [xml] (Get-Content -Path $projFilePath.FullName -Encoding UTF8) 
    

    2) You have to update this attributes in your proj files:

    $ClickOnceForStages.Split("Dev", "Test", "UAT", "Prod") | Foreach { 
    
      $XmlDocument.project.PropertyGroup[0].ApplicationRevision = $BuildRevision
      $XmlDocument.project.PropertyGroup[0].ApplicationVersion = $BuildVersion
      $XmlDocument.project.PropertyGroup[0].ProductName = "MyProductName.$_" 
      $XmlDocument.project.PropertyGroup[0].AssemblyName = "MyAssemblyName.$_"
      $XmlDocument.project.PropertyGroup[0].PublishUrl = "MyClickOnceDropUncPath_$_"
    }      
    

    You have to make sure that:

    $BuildRevision and $BuildVersion 
    

    have a increased version for each build.

    3) Save the document without manipulating the orginal proj file.

    $currentProjFilePath = $projFilePath.FullName +"_" + $_ + ".proj"
    $XmlDocument.Save($clickOnceProjFilePath)
    

    4) Call MSBuild to create a ClickOnce installer.

    "C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe"
    

    The combination of your proj file with the ClickOnce configuration and the MSBuild parameter:

    "/target:publish"
    

    creates a ClickOnce installer.

    This is the full MSBuild statement which I use to create a ClickOnce installer:

    "$clickOnceProjFilePath", 
    "/target:publish", 
    "/p:PublishDir=$outputDirectory", 
    "/p:Configuration=Release"