Next add a line / lines Debugger.Break(); in your code where you want the debugger to start. Now compile in debug mode clicking in Visual Studio menu: Build, Build Solution while the Configuration Manager is set to Debug.
After the application compiled successfully we can stop and start the service to ensure these modifications are run:
Right click the Visual Studio application and select more…, Run as administrator
Click Debug, Attach to Process in the Visual Studio menu.
This will open a dialog where you need to select the right process to debug. Check the Show processes from all users checkbox. Find your Service process and click Attach.
In Visual Studio it is really simple to add unit tests that are automatically run in your build script. Right click your solution to add a test project:
/// <summary> /// Test if flipcoins throws as many times as requested /// </summary> [TestMethod()] public void FlipCoinsTest1Times() { //Arrange int odd, even; int times = 1;
//Act CoinFlipper coinFlipper = new CoinFlipper(); coinFlipper.FlipCoins(times, out odd, out even); //Assert Assert.IsTrue(times == odd + even); }
Open Test explorer window
Right click a selection of tests and select “Run selected tests”.
When the tests are OK, we can check in the solution. Default the Build in Azure will run libraries with names containing *test*.
I was planning a migration for my solution from a build on my local machine to a build in Azure Devops. I want to use the Hosted VS2017 because then I do not have to worry about maintaining local Build servers.
When I added the solution to Azure and set up a build pipeline I encountered the following errors in the MSBuild log:
2019-01-10T10:11:49.9382855Z ##[error]Notepad\CrystalReportsViewer.cs(8,7): Error CS0246: The type or namespace name ‘CrystalDecisions’ could not be found (are you missing a using directive or an assembly reference?)
2019-01-10T10:11:49.9412999Z ##[error]Notepad\CrystalReport1.cs(153,53): Error CS0246: The type or namespace name ‘RequestContext’ could not be found (are you missing a using directive or an assembly reference?)
2019-01-10T10:11:49.9414407Z ##[error]Notepad\CrystalReportsViewer.cs(14,16): Error CS0246: The type or namespace name ‘ReportDocument’ could not be found (are you missing a using directive or an assembly reference?)
2019-01-10T10:11:49.9415960Z ##[error]Notepad\CrystalReport1.cs(19,35): Error CS0246: The type or namespace name ‘ReportClass’ could not be found (are you missing a using directive or an assembly reference?)
2019-01-10T10:11:49.9430403Z ##[error]Notepad\CrystalReport1.cs(24,32): Error CS0115: ‘CrystalReport1.ResourceName’: no suitable method found to override
2019-01-10T10:11:49.9432260Z ##[error]Notepad\CrystalReport1.cs(33,30): Error CS0115: ‘CrystalReport1.NewGenerator’: no suitable method found to override
2019-01-10T10:11:49.9433304Z ##[error]Notepad\CrystalReport1.cs(42,32): Error CS0115: ‘CrystalReport1.FullResourceName’: no suitable method found to override
I found a solution for this issue adding a pre-build event:
First I needed to add the CRRuntime msi and a pre-build.bat file to my solution:
The content for the pre-build file is an administrator installation of the CRRuntime msi. The command is: msiexec /a “%1CRRuntime_64bit_13_0_23.msi” /quiet /norestart /log “%1CRRuntime_64bit_13_0_23_install.log”. I only want this to be installed when building a release (in Azure). For this I added the condition to only install for release builds.
Goto Pipelines in your Azure Devops project and click on new pipeline. My example uses a project named WPFDatasetWithSQL.
*Important note: This solution will only work when you do NOT have a .gitignore file in your repository*
Click continue and choose .Net Desktop and click Apply.
If you want
to build the solution using a hosted machine keep the “Agent pool” set on
“Hosted VS2017”. If you need local components to build you could choose to use
a local machine or set up the required components in this build script.
For this
example I have no need for extra components and I will keep the Agent pool on
Hosted VS2017.
We are going
to change a few setps in this script:
1 Set the
MSBuild Arguments to /target:publish. This changes the MSBuild to add a
app.publish to the build directory for click once deployment.
2 Change the step Copy Files to add the app.publish folder to the artifacts folder. Display name = Copy Files to: $(build.artifactstagingdirectory) Source Folder = $(Build.SourcesDirectory)\src\BLM\bin\$(BuildConfiguration)\app.publish Contents = **\**
3 Change the artifact name. Display name = Publish Artifact: $(System.TeamProject)-$(Build.BuildNumber) Artifact name = $(System.TeamProject)-$(Build.BuildNumber)
Click Save and keep the default name.
Set up a release pipeline
Now we will
set up a release pipeline in which we can control and manage releases for this
application.
Click on Releases in the menu and click New pipeline.
Choose a Empty job template. The release pipeline is going to contain not much more than a few copy tasks.
For
starters we will have to choose an artifact. Choice is simple, we are going to
use the artifacts from the build pipeline. Select the Source Build pipeline set
up in the previous step and finish this by clicking the Add button below.
Next step in this release pipeline is a deployment to “Test”. For this purpose we will rename the default “Stage 1” to “Test”. For this, clicking the Stage1 image (not on the link to job with task) will open a properties window. Rename Stage1 to Test and click save right top in the corner.
Now
click the link to job and task in the Test stage. Click the agent job and
change the agent pool to the pool where you added the local agent. In my
example I added the local agent to a pool named “local machine”.
Now we will
add a job to copy the publish folder to a local directory. Click on the puls
sign next to “Agent job” and search for “Copy Files”
Select The task added below Job agent and fill in the details:
Select The task added below Job agent and fill in the details:
Display name = Copy Files to: c:\drop\$(System.TeamProject)\$(Release.EnvironmentName)\$(Release.ReleaseName)\
Source Folder = $(system.defaultworkingdirectory)_WPFDatasetWithSQL-.NET Desktop-CI * This last directory name is the build pipeline name
Target Folder = c:\drop\$(System.TeamProject)\$(Release.EnvironmentName)\$(Release.ReleaseName)\
The source
folder will contain the pipeline name for the build pipeline preceded by an
underscore:
Click save
in top right hand corner.
Now we are
going to add the production stage and the required copy jobs for this stage.
Click on
releases in the left menu and click edit.
Click “Clone” in Test stage. And rename this new stage “Copy of Test” to “Production”. Click the task details and here I added System.TeamProject to the source folder name. This removes the build number from the destination name.
Next click the plus sign for the “Agent job” to add a command line script. With this command line we will first clean the install folder before we copy the new release in that location. The command line script is rd /S /Q c:\drop\$(System.TeamProject)\Install\
Last task for this job is to add a second “Copy Files” task. This task will copy the publish content in the install folder.
For the first run disable the Command line script because the folder will not yet exist. This will cause an error if the command is executed while the directory does not exist. After the first run the command can be enabled.
Last
option is to add an approval trigger on production. A test manager or a group
of testers can be allowed to approve the release after testing.
Another nice feature is to enable continuous integration and continuous deployment in Azure. For this go to the build pipeline and click the checkbox for “Enable continuous integration” in the tab “Triggers”.
Second, go to release pipeline click the continuous deployment trigger and enable continuous deployment every time a new build is available. Click save.
First two times the deployment failed. I checked the logging and fixed some typing errors.
After approving the release the install folder will be updated with the required binaries.
Build and release pipelines are called definitions in TFS 2018 and in older versions. Service connections are called service endpoints in TFS 2018 and in older versions.
A release is a collection of artifacts in your DevOps CI/CD processes. An artifact is a deployable component of your application. Azure Pipelines can deploy artifacts that are produced by a wide range of artifact sources, and stored in different types of artifact repositories.
When authoring a release pipeline, you link the appropriate artifact sources to your release pipeline. For example, you might link an Azure Pipelines build pipeline or a Jenkins project to your release pipeline.
When creating a release, you specify the exact version of these artifact sources; for example, the number of a build coming from Azure Pipelines, or the version of a build coming from a Jenkins project.
After a release is created, you cannot change these versions. A release is fundamentally defined by the versioned artifacts that make up the release. As you deploy the release to various stages, you will be deploying and validating the same artifacts in all stages.
A single release pipeline can be linked to multiple artifact sources, of which one is the primary source. In this case, when you create a release, you specify individual versions for each of these sources.
Artifacts are central to a number of features in Azure Pipelines. Some of the features that depend on the linking of artifacts to a release pipeline are:
Auto-trigger releases. You can configure new releases to be automatically created whenever a new version of an artifact is produced. For more details, see Continuous deployment triggers. Note that the ability to automatically create releases is available for only some artifact sources.
Trigger conditions. You can configure a release to be created automatically, or the deployment of a release to a stage to be triggered automatically, when only specific conditions on the artifacts are met. For example, you can configure releases to be automatically created only when a new build is produced from a certain branch.
Artifact versions. You can configure a release to automatically use a specific version of the build artifacts, to always use the latest version, or to allow you to specify the version when the release is created.
Artifact variables. Every artifact that is part of a release has metadata associated with it, exposed to tasks through variables. This metadata includes the version number of the artifact, the branch of code from which the artifact was produced (in the case of build or source code artifacts), the pipeline that produced the artifact (in the case of build artifacts), and more. This information is accessible in the deployment tasks. For more details, see Artifact variables.
Work items and commits. The work items or commits that are part of a release are computed from the versions of artifacts. For example, each build in Azure Pipelines is associated with a set of work items and commits. The work items or commits in a release are computed as the union of all work items and commits of all builds between the current release and the previous release. Note that Azure Pipelines is currently able to compute work items and commits for only certain artifact sources.
Artifact download. Whenever a release is deployed to a stage, by default Azure Pipelines automatically downloads all the artifacts in that release to the agent where the deployment job runs. The procedure to download artifacts depends on the type of artifact. For example, Azure Pipelines artifacts are downloaded using an algorithm that downloads multiple files in parallel. Git artifacts are downloaded using Git library functionality. For more details, see Artifact download.
Artifact sources
There are several types of tools you might use in your application lifecycle process to produce or store artifacts. For example, you might use continuous integration systems such as Azure Pipelines, Jenkins, or TeamCity to produce artifacts. You might also use version control systems such as Git or TFVC to store your artifacts. Or you can use repositories such as Package Management in Visual Studio Team Services or a NuGet repository to store your artifacts. You can configure Azure Pipelines to deploy artifacts from all these sources.
By default, a release created from the release pipeline will use the latest version of the artifacts. At the time of linking an artifact source to a release pipeline, you can change this behavior by selecting one of the options to use the latest build from a specific branch by specifying the tags, a specific version, or allow the user to specify the version when the release is created from the pipeline.
If you link more than one set of artifacts, you can specify which is the primary (default).
The following sections describe how to work with the different types of artifact sources.
You can link a release pipeline to any of the build pipelines in Azure Pipelines or TFS project collection.
Note
You must include a Publish Artifacts task in your build pipeline. For XAML build pipelines, an artifact with the name drop is published implicitly.
Some of the differences in capabilities between different versions of TFS and Azure Pipelines are:
TFS 2015: You can link build pipelines only from the same project of your collection. You can link multiple definitions, but you cannot specify default versions. You can set up a continuous deployment trigger on only one of the definitions. When multiple build pipelines are linked, the latest builds of all the other definitions are used, along with the build that triggered the release creation.
TFS 2017 and newer and Azure Pipelines: You can link build pipelines from any of the projects in Azure Pipelines or TFS. You can link multiple build pipelines and specify default values for each of them. You can set up continuous deployment triggers on multiple build sources. When any of the builds completes, it will trigger the creation of a release.
The following features are available when using Azure Pipelines sources:
Feature
Behavior with Azure Pipelines sources
Auto-trigger releases
New releases can be created automatically when new builds (including XAML builds) are produced. See Continuous Deployment for details. You do not need to configure anything within the build pipeline. See the notes above for differences between version of TFS.
Artifact variables
A number of artifact variables are supported for builds from Azure Pipelines.
Work items and commits
Azure Pipelines integrates with work items in TFS and Azure Pipelines. These work items are also shown in the details of releases. Azure Pipelines integrates with a number of version control systems such as TFVC and Git, GitHub, Subversion, and external Git repositories. Azure Pipelines shows the commits only when the build is produced from source code in TFVC or Git.
Artifact download
By default, build artifacts are downloaded to the agent. You can configure an option in the stage to skip the download of artifacts.
Deployment section in build
The build summary includes a Deployment section, which lists all the stages to which the build was deployed.
TFVC, Git, and GitHub
There are scenarios in which you may want to consume artifacts stored in a version control system directly, without passing them through a build pipeline. For example:
You are developing a PHP or a JavaScript application that does not require an explicit build pipeline.
You manage configurations for various stages in different version control repositories, and you want to consume these configuration files directly from version control as part of the deployment pipeline.
You manage your infrastructure and configuration as code (such as Azure Resource Manager templates) and you want to manage these files in a version control repository.
Because you can configure multiple artifact sources in a single release pipeline, you can link both a build pipeline that produces the binaries of the application as well as a version control repository that stores the configuration files into the same pipeline, and use the two sets of artifacts together while deploying.
Azure Pipelines integrates with Team Foundation Version Control (TFVC) repositories, Git repositories, and GitHub repositories.
You can link a release pipeline to any of the Git or TFVC repositories in any of the projects in your collection (you will need read access to these repositories). No additional setup is required when deploying version control artifacts within the same collection.
When you link a Git or GitHub repository and select a branch, you can edit the default properties of the artifact types after the artifact has been saved. This is particularly useful in scenarios where the branch for the stable version of the artifact changes, and continuous delivery releases should use this branch to obtain newer versions of the artifact. You can also specify details of the checkout, such as whether check out submodules and LFS-tracked files, and the shallow fetch depth.
When you link a TFVC branch, you can specify the changeset to be deployed when creating a release.
The following features are available when using TFVC, Git, and GitHub sources:
Feature
Behavior with TFVC, Git, and GitHub sources
Auto-trigger releases
You can configure a continuous deployment trigger for pushes into the repository in a release pipeline. This can automatically trigger a release when a new commit is made to a repository. See Triggers.
Artifact variables
A number of artifact variables are supported for version control sources.
Work items and commits
Azure Pipelines cannot show work items or commits associated with releases when using version control artifacts.
Artifact download
By default, version control artifacts are downloaded to the agent. You can configure an option in the stage to skip the download of artifacts.
Jenkins
To consume Jenkins artifacts, you must create a service connection with credentials to connect to your Jenkins server. For more details, see service connections and Jenkins service connection. You can then link a Jenkins project to a release pipeline. The Jenkins project must be configured with a post build action to publish the artifacts.
The following features are available when using Jenkins sources:
Feature
Behavior with Jenkins sources
Auto-trigger releases
You can configure a continuous deployment trigger for pushes into the repository in a release pipeline. This can automatically trigger a release when a new commit is made to a repository. See Triggers.
Azure Pipelines cannot show work items or commits for Jenkins builds.
Artifact download
By default, Jenkins builds are downloaded to the agent. You can configure an option in the stage to skip the download of artifacts.
Artifacts generated by Jenkins builds are typically propagated to storage repositories for archiving and sharing. Azure blob storage is one of the supported repositories, allowing you to consume Jenkins projects that publish to Azure storage as artifact sources in a release pipeline. Deployments download the artifacts automatically from Azure to the agents. In this configuration, connectivity between the agent and the Jenkins server is not required. Microsoft-hosted agents can be used without exposing the server to internet.
Note
Azure Pipelines may not be able to contact your Jenkins server if, for example, it is within your enterprise network. In this case you can integrate Azure Pipelines with Jenkins by setting up an on-premises agent that can access the Jenkins server. You will not be able to see the name of your Jenkins projects when linking to a build, but you can type this into the link dialog field.
When deploying containerized apps, the container image is first pushed to a container registry. After the push is complete, the container image can be deployed to the Web App for Containers service or a Docker/Kubernetes cluster. You must create a service connection with credentials to connect to your service to deploy images located there, or to Azure. For more details, see service connections.
The following features are available when using Azure Container Registry, Docker, Kubernetes sources:
Feature
Behavior with Docker sources
Auto-trigger releases
You can configure a continuous deployment trigger for images. This can automatically trigger a release when a new commit is made to a repository. See Triggers.
Scenarios where you may want to consume Package Management artifacts are:
You have your application build (such as TFS, Azure Pipelines, TeamCity, Jenkins) published as a package (NuGet or npm) to Package Management and you want to consume the artifact in a release.
As part of your application deployment, you need additional packages stored in Package Management.
When you link a Package Management artifact to your release pipeline, you must select the Feed, Package, and the Default version for the package. You can choose to pick up the latest version of the package, use a specific version, or select the version at the time of release creation. During deployment, the package is downloaded to the agent folder and the contents are extracted as part of the job execution.
The following features are available when using Package Management sources:
Feature
Behavior with Package Management sources
Auto-trigger releases
You can configure a continuous deployment trigger for packages. This can automatically trigger a release when a package is updated. See Triggers.
Azure Pipelines cannot show work items or commits.
Artifact download
By default, packages are downloaded to the agent. You can configure an option in the stage to skip the download of artifacts.
External or on-premises TFS
You can use Azure Pipelines to deploy artifacts published by an on-premises TFS server. You don’t need to make the TFS server visible on the Internet; you just set up an on-premises automation agent. Builds from an on-premises TFS server are downloaded directly into the on-premises agent, and then deployed to the specified target servers. They will not leave your enterprise network. This allows you to leverage all of your investments in your on-premises TFS server, and take advantage of the release capabilities in Azure Pipelines.
Using this mechanism, you can also deploy artifacts published in one Azure Pipelines subscription in another Azure Pipelines, or deploy artifacts published in one Team Foundation Server from another Team Foundation Server.
To enable these scenarios, you must install the TFS artifacts for Azure Pipelines extension from Visual Studio Marketplace. Then create a service connection with credentials to connect to your TFS server (see service connections for details).
You can then link a TFS build pipeline to your release pipeline. Choose External TFS Build in the Type list.
The following features are available when using external TFS sources:
Feature
Behavior with external TFS sources
Auto-trigger releases
You cannot configure a continuous deployment trigger for external TFS sources in a release pipeline. To automatically create a new release when a build is complete, you would need to add a script to your build pipeline in the external TFS server to invoke Azure Pipelines REST APIs and to create a new release.
Azure Pipelines cannot show work items or commits for external TFS sources.
Artifact download
By default, External TFS artifacts are downloaded to the agent. You can configure an option in the stage to skip the download of artifacts.
Note
Azure Pipelines may not be able to contact an on-premises TFS server if, for example, it is within your enterprise network. In this case you can integrate Azure Pipelines with TFS by setting up an on-premises agent that can access the TFS server. You will not be able to see the name of your TFS projects or build pipelines when linking to a build, but you can type these into the link dialog fields. In addition, when you create a release, Azure Pipelines may not be able to query the TFS server for the build numbers. Instead, type the Build ID (not the build number) of the desired build into the appropriate field, or select the Latest build.
To consume TeamCity artifacts, start by creating a service connection with credentials to connect to your TeamCity server (see service connections for details).
You can then link a TeamCity build configuration to a release pipeline. The TeamCity build configuration must be configured with an action to publish the artifacts.
The following features are available when using TeamCity sources:
Feature
Behavior with TeamCity sources
Auto-trigger releases
You cannot configure a continuous deployment trigger for TeamCity sources in a release pipeline. To create a new release automatically when a build is complete, add a script to your TeamCity project that invokes the Azure Pipelines REST APIs to create a new release.
Azure Pipelines cannot show work items or commits for TeamCity builds.
Artifact download
By default, TeamCity builds are downloaded to the agent. You can configure an option in the stage to skip the download of artifacts.
Note
Azure Pipelines may not be able to contact your TeamCity server if, for example, it is within your enterprise network. In this case you can integrate Azure Pipelines with TeamCity by setting up an on-premises agent that can access the TeamCity server. You will not be able to see the name of your TeamCity projects when linking to a build, but you can type this into the link dialog field.
Other sources
Your artifacts may be created and exposed by other types of sources such as a NuGet repository. While we continue to expand the types of artifact sources supported in Azure Pipelines, you can start using it without waiting for support for a specific source type. Simply skip the linking of artifact sources in a release pipeline, and add custom tasks to your stages that download the artifacts directly from your source.
Artifact download
When you deploy a release to a stage, the versioned artifacts from each of the sources are, by default, downloaded to the automation agent so that tasks running within that stage can deploy these artifacts. The artifacts downloaded to the agent are not deleted when a release is completed. However, when you initiate the next release, the downloaded artifacts are deleted and replaced with the new set of artifacts.
A new unique folder in the agent is created for every release pipeline when you initiate a release, and the artifacts are downloaded into that folder. The $(System.DefaultWorkingDirectory) variable maps to this folder.
Note that, at present, Azure Pipelines does not perform any optimization to avoid downloading the unchanged artifacts if the same release is deployed again. In addition, because the previously downloaded contents are always deleted when you initiate a new release, Azure Pipelines cannot perform incremental downloads to the agent.
You can, however, instruct Azure Pipelines to skip the automatic downloadof artifacts to the agent for a specific job and stage of the deployment if you wish. Typically, you will do this when the tasks in that job do not require any artifacts, or if you implement custom code in a task to download the artifacts you require.
In Azure Pipelines, you can, however, select which artifacts you want to download to the agent for a specific job and stage of the deployment. Typically, you will do this to improve the efficiency of the deployment pipeline when the tasks in that job do not require all or any of the artifacts, or if you implement custom code in a task to download the artifacts you require.
Artifact source alias
To ensure the uniqueness of every artifact download, each artifact source linked to a release pipeline is automatically provided with a specific download location known as the source alias. This location can be accessed through the variable:
$(System.DefaultWorkingDirectory)\[source alias]
This uniqueness also ensures that, if you later rename a linked artifact source in its original location (for example, rename a build pipeline in Azure Pipelines or a project in Jenkins), you don’t need to edit the task properties because the download location defined in the agent does not change.
The source alias is, by default, the name of the source selected when you linked the artifact source, prefixed with an underscore; depending on the type of the artifact source this will be the name of the build pipeline, job, project, or repository. You can edit the source alias from the artifacts tab of a release pipeline; for example, when you change the name of the build pipeline and you want to use a source alias that reflects the name of the build pipeline.
The source alias can contain only alphanumeric characters and underscores, and must start with a letter or an underscore
Primary source
When you link multiple artifact sources to a release pipeline, one of them is designated as the primary artifact source. The primary artifact source is used to set a number of pre-defined variables. It can also be used in naming releases.
Artifact variables
Azure Pipelines exposes a set of pre-defined variables that you can access and use in tasks and scripts; for example, when executing PowerShell scripts in deployment jobs. When there are multiple artifact sources linked to a release pipeline, you can access information about each of these. For a list of all pre-defined artifact variables, see variables.
ClickOnce applications are a great and easy way to distribute your applications to many users, and have the advantage of offering automatic application updates out-of-the-box. Even though ClickOnce applications are super easy to deploy from Visual Studio (literally 3 clicks, just click Build –> Publish –> Finish), you may still want to have your build system publish the updates for various reasons, such as:
You don’t want you (or your team members) to have to remember to manually publish a new version all the time; even if it is very quick and easy.
If you are signing your ClickOnce application (to make your app more secure and avoid annoying Windows security warnings during every update), your team members may not have the certificate installed, or you may not want them to know the certificate password.
All of the other benefits of deploying automatically from a build server; you can be sure the project was built in Release mode, all unit tests have run and passed, you are only publishing a new version of the application from a specific branch (e.g. master), etc.
In this post I’m going to show how to continuously deploy your ClickOnce application using Visual Studio Team Services (VSTS), but you can adopt what’s shown here to work on any build system, such as Team City or Jenkins.
Step 1 – Configure and publish your ClickOnce application manually
Before we can publish a new version of the application from the build server, we first have to build the project to create the artifacts to publish. And even before that, we have to make sure the project is setup properly with all of the required ClickOnce metadata. You will typically do this by going into your project Properties page and going to the Publish tab. There are several other websites and blog posts that discuss configuring a project for ClickOnce deployment, including the official MSDN documentation for configuring and publishing ClickOnce applications, so I won’t go into it any further here.
Basically you should have your project in a state where you can easily publish a new version manually, and it is configured the way that you want (includes the necessary files, has the destination to publish to specified, specifies if the application is only available online or not, etc.). Once you’ve published your project manually and confirmed that it’s configured the way you like, we can move onto the next step.
Step 2 – Setup the build on your build server
On your build server you will want to configure a new vanilla build that builds your project/solution. There are a couple modifications you will need to make that are different from building a regular console app or class library project.
The first difference is that you will need to provide the “/target:Publish” argument to MSBuild when it builds your project. Here is what this looks like in VSTS:
This will cause MSBuild to build the required artifacts into an “app.publish” directory. e.g. bin\Debug\app.publish.
The next difference is that you will want to copy that “app.publish” directory to your build artifacts directory. To do this, you will need to add a Copy Files step into your build process that copies the “app.publish” directory from the ClickOnce project’s bin directory to where the build artifacts are expected to be. You will want to do this before the step that publishes your build artifacts. Here is what this looks like in VSTS:
So we copy the files into the build artifacts directory, and then the Publish Build Artifacts step at the end will copy those files to wherever you’ve specified; in my case it’s a network share.
For completeness sake, this is what my Publish Build Artifacts step looks like in VSTS, and you’ll also notice the “Import-PfxCertificate.ps1” step before the MSBuild step as well:
So we now have the ClickOnce artifacts being generated and stored in the appropriate directory. If you wanted, you could publish the build artifacts to the ClickOnce application’s final destination right now (instead of a file share as I’ve done here), but I’m going to follow best practices and separate the application “build” and “deployment” portions into their respective subsystems, as you may want separate control over when a build gets published, or maybe you don’t want to publish EVERY build; only some of them.
Hopefully at this point you are able to create a successful build, but we’re not done yet.
Step 3 – Publish the build artifacts to the ClickOnce application’s destination
Now that we have the build artifacts safely stored, we can publish them to the ClickOnce application’s destination. With VSTS this is done by using the Release subsystem. So create a new Release Definition and setup an Environment for it. By default it adds a “Copy and Publish Build Artifacts” step to the release definition. When configuring and using this default step, I received the error:
[error]Copy and Publish Build Artifacts task is not supported within Release
So instead I removed that default step and added a simple “Copy Files” step, and then configured it to grab the files from the file share that the build published the artifacts to, and set the destination to where the ClickOnce application was publishing to when I would do a manual publish from within Visual Studio. Here is what that step looks like in VSTS:
You should be able to run this release definition and see that it is able to post a new version of your ClickOnce application. Hooray! I setup my releases to automatically publish on every build, but you can configure yours however you like.
If you make changes and commit them, the build should create new artifacts, and the release should be able to publish the new version. However, if you launch your ClickOnce application, you may be surprised that it doesn’t actually update to the latest version that you just committed and published. This is because we need one additional build step to actually update the ClickOnce version so it can detect that a new version was published. If you launch another build and publish them, you’ll see that the files being published are overwriting the previous files, instead of getting published to a new directory as they are supposed to be.
You may be wondering why we need another build step to update the ClickOnce version. Part of the build artifacts that are created are a .application manifest file, and a directory that contains the applications files, both of which have the ClickOnce version in them. Can’t we just modify the directory name and .application manifest file to increment the old version number? This was my initial thought, but the .application manifest file contains a cryptography hash to ensure that nobody has tampered with it, meaning that it needs to contain the proper version number at the time that it is generated.
Step 4 – One more build step to update the ClickOnce version
The ClickOnce version is defined in your project file (.csproj/.vbproj) (as the <ApplicationVersion> and <ApplicationRevision> xml elements), and is different from the assembly version that you would typically set to version your .dll/.exe files via the AssemblyInfo.cs file. Unless you manually updated the ClickOnce version in Visual Studio, it will still have its original version. When publishing the ClickOnce version in Visual Studio, Visual Studio automatically takes care of incrementing ClickOnce version’s Revision part. However, because we’re publishing from our build system now, we’ll need to come up with an alternative method. To help solve this problem, I have created the Set-ProjectFilesClickOnceVersion GitHub repository. This repository houses a single Set-ProjectFilesClickOnceVersion.ps1 PowerShell script that we will want to download and add into our build process.
In order for the build system to access this Set-ProjectFilesClickOnceVersion.ps1 script you will need to check it into source control. Also, you need to make sure you add this build step before the MSBuild step. Here is what this step looks like in VSTS:
The Script Filename points to the location of the Set-ProjectFilesClickOnceVersion.ps1 script in my repository. Also note that I set the Working Folder to the directory that contains the .csproj project file. This is necessary since we are dealing with relative paths, not absolute ones.
For the Arguments I provide the name of the project file that corresponds to my ClickOnce application, as well as the VSTS Build ID. The Build ID is a globally unique ID that gets auto-incremented with every build, and most (all?) build systems have this. The script will translate this Build ID into the Build and Revision version number parts to use for the ClickOnce version, to ensure that they are always increasing in value. So you should never need to manually modify the ClickOnce version, and every build should generate a version number greater than the last, allowing the ClickOnce application to properly detect when a newer version has been published.
Maybe you update your application’s version number on every build, and want your ClickOnce version to match that version. If this is the case, then use the –Version parameter instead of –BuildSystemsBuildId. The other alternative is to use the –IncrementProjectFilesRevision switch to simply increment the ClickOnce Revision that is already stored in the project file. If you use this switch, you need to be sure to check the project file back into source control so that the Revision is properly incremented again on subsequent builds. I like to avoid my build system checking files into source control wherever possible, so I have opted for the BuildSystemsBuildId parameter here.
The last argument I have included is the UpdateMinimumRequiredVersionToCurrentVersion parameter, and it is optional. If provided, this parameter will change the ClickOnce application’s Minimum Required Version to be the same as the new version, forcing the application to always update to the latest version when it detects that an update is available. I typically use this setting for all of my ClickOnce applications. If you still plan on publishing your ClickOnce applications from Visual Studio, but want this functionality, simply install the AutoUpdateProjectsMinimumRequiredClickOnceVersion NuGet Package.
That’s it! Now if you launch another build it should create new artifacts with a larger ClickOnce version number, and once published your application should update to the new version.
Bonus – Displaying the ClickOnce version in your application
The ClickOnce application version number may be different than your assembly version number, or perhaps you don’t update your product’s version number on every publish; it’s easy to forget. I typically like to use semantic versioning for my projects, which only involves the first 3 version parts. This leaves the last version part, the Revision number, available for me to set as I please. I will typically use the ClickOnce Revision in my application’s displayed version number. This makes it easy to tell which actual release a client has installed in the event that the product version was not updated between releases. The code to do it is fairly simple.
public Version ApplicationVersion = new Version(“1.11.2”);
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
// If this is a ClickOnce deployment, append the ClickOnce Revision to the version number (as it gets updated with each publish).
if (ApplicationDeployment.IsNetworkDeployed)
ApplicationVersion = new Version(ApplicationVersion.Major, ApplicationVersion.Minor, ApplicationVersion.Build,
ApplicationDeployment.CurrentDeployment.CurrentVersion.Revision);
// Display the Version as part of the window title.
wndMainWindow.Title += ApplicationVersion;
}
Here I hard-code the product version that I want displayed in my application in a variable called ApplicationVersion. When the WPF application is launched, I obtain the ClickOnce Revision and append it onto the end of the version number. I then display the version in my application’s window title, but you might want to show it somewhere else, such as in an About window. If you want, you could even display both the full application version and full ClickOnce version.
We use cookies on our website to give you the most relevant experience by remembering your preferences and repeat visits. By clicking “Accept All”, you consent to the use of ALL the cookies. However, you may visit "Cookie Settings" to provide a controlled consent.
This website uses cookies to improve your experience while you navigate through the website. Out of these, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may affect your browsing experience.
Necessary cookies are absolutely essential for the website to function properly. These cookies ensure basic functionalities and security features of the website, anonymously.
Cookie
Duration
Description
cookielawinfo-checkbox-analytics
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Analytics".
cookielawinfo-checkbox-functional
11 months
The cookie is set by GDPR cookie consent to record the user consent for the cookies in the category "Functional".
cookielawinfo-checkbox-necessary
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookies is used to store the user consent for the cookies in the category "Necessary".
cookielawinfo-checkbox-others
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Other.
cookielawinfo-checkbox-performance
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Performance".
viewed_cookie_policy
11 months
The cookie is set by the GDPR Cookie Consent plugin and is used to store whether or not user has consented to the use of cookies. It does not store any personal data.
Functional cookies help to perform certain functionalities like sharing the content of the website on social media platforms, collect feedbacks, and other third-party features.
Performance cookies are used to understand and analyze the key performance indexes of the website which helps in delivering a better user experience for the visitors.
Analytical cookies are used to understand how visitors interact with the website. These cookies help provide information on metrics the number of visitors, bounce rate, traffic source, etc.
Advertisement cookies are used to provide visitors with relevant ads and marketing campaigns. These cookies track visitors across websites and collect information to provide customized ads.