Continuous Delivery (CD) for .NET applications using Jenkins

The key to delivering software more rapidly and more frequently is having a continuous delivery process which makes deploying your application as easy as pushing a button. When it's easy to deploy your application, bugfixes and new features end up in production way faster and in a more agile way than the old fashion way of manually creating a package and handing it over to someone from the ops team who would then deploy it to the requested environment.

Delivering software the old fashion way is often prone to human error and takes a lot more time forcing developers to create bigger releases with a larger number of features and bugfixes which in turn also takes more time. This is obviously bad for business because end-users will have to wait much longer to be able to enjoy new releases, and in the meantime they could be getting frustrated by potential bugs which aren't going to be resolved very quickly.

One-click deploy

The main goal is to be able to deploy our application by the click of a button. To do that, we're going to be using Jenkins and add a deployment process to our previous CI job to deploy our application to Microsoft Azure.


We're going to use the Promoted Builds plugin to create a build artifact of our application and deploy it to Azure via Web Deploy. Because the Azure App Service we've created already supports Web Deploy, there is no need to install it. In this case Azure is our production environment. I recommend also having a development, test and acceptance environment to be able to test and preview your application before it gets deployed to production.

Artifact repositories

Because we're creating a build artifact, it is wise to store that artifact in a binary repository or on a shared location. This way you're not only able to keep track of all your releases, but also to rollback a previous version. There are a few good repositories out there such as Archiva, Artifactory, Nexus and Package Drone. Here is a good comparison chart for you to decide which repository suits you best.

Step 1: Create a promotion process

Navigate using your favorite browser to the Jenkins job you've created and tick the Promote builds when... checkbox. The following section appears:
In this case we're going to create the process of deploying our application to a production environment so the name of this process is going to be Production. Tick the Only when manually approved checkbox because we don't want to trigger the process automatically.

Typically you can tick the Promote immediately once the build is complete checkbox for a development promotion process. This means that when a build is succeeded and all unit tests pass, a build artifact is created immediately and is then deployed to the development environment.

If you have multiple promotion processes, i recommend ticking the When the following upstream promotions are promoted checkbox and fill in the previous promotion process name (e.g. Acceptance) that has to be successfully executed before being able to approve the next promotion process. This way you will force your application being deployed to other environments first such as development, test and acceptance before reaching production. An example would be Development > Test > Acceptance > Production.

Step 2: Create a build artifact

To create a build artifact click the Add action button in the Actions region of your promotion process and select Build a Visual Studio project or solution using MSBuild:
Jenkins build artifact This step is almost equal to our build step which we created in our CI process, but now we're going to create a web deploy package in stead of compiling the solution. To create that package, we have to add a few command line arguments:

  • /T:Clean;Build;Package to create a Web Deploy package.
  • /p:Configuration=Release to use the release configuration.
  • /p:OutputPath="obj\Release" to put the artifact in the obj\Release folder of the current project.
  • /p:PrecompileBeforePublish=true to precompile our application.
Step 3: Store the build artifact

Next we have to store our build artifact we've just created. In this case we will keep it simple and just copy it to a shared network location. Click the Add action button again and select Execute Windows batch command:
Jenkins copy build artifact Because we're just copying the artifact to another location, i've created a xcopy command that copies the build artifact to a specified network location and create a folder with the Jenkins build number.

Step 4: Deploy the build artifact

To be able to deploy to Azure via Web Deploy you first have to download the Publish Profile of your Azure App Service. Go to the Azure Portal, navigate to your App Service and click the Get Publish Profile button. You should get something like this:

    <publishProfile profileName="YourProject - Web Deploy" 
        <databases />
            profileName="YourProject - FTP" 
        <databases />

We are going to use the Web Deploy profile in our next action. Because there is no MSDeploy plugin for Jenkins click Add action and select Execute Windows batch command:
Jenkins deploy build artifact This is a pretty large command using the MSDeploy executable, so let's go over the command line arguments:

  • -verb:sync to update our web application.
  • -source:package="YourProject\obj\Release\_PublishedWebsites\YourProject_Package\" to use the build artifact for deployment.
  • -dest:auto,computerName='',UserName='$YourProject',Password='someRandomPassword',AuthType='Basic',includeAcls='false' to set the destination for our deployment using the data from the downloaded Publish Profile. includeAcls is set to false because we don't want to deploy file ownership information.
  • -setParam:name='IIS Web Application Name',value='yourproject' to override the web application name with the one specified in the Azure App Service.
  • -disableLink:AppPoolExtension to disable setting the AppPool because it is already set by Azure.
  • -disableLink:ContentExtension to disable deploying the contents of optionally configured virtual directories.
  • -disableLink:CertificateExtension to disable deploying optionally included certificates.

That's it for the production process. Once a build is completed and successfully passed the configured unit tests, the only thing you have to do to deploy your application is go to your build in Jenkins, click the Promotion Status button in the left option pane and click the Approve button of the promotion process you want to execute.


But what about rollback? A similar promotion process can be created. Instead of creating and copying a build artifact, we are only going to deploy an archived artifact.

Click the button Add another promotion process and call it Rollback production. Again tick the Only when manually approved checkbox. But now we are going to add a parameter to our process by clicking the button Add Parameter and selecting String Parameter:
Jenkins Rollback step Because we want to rollback a specific release, we're going to use the Jenkins build number to select an artifact from the shared network location. Again click Add action and select Execute Windows batch command:
Jenkins rollback artifact command Copy the MSDeploy command from Step 4 and change the -source parameter to point to the artifact from the shared network location in stead of the one created in the obj folder: -source:package="\\neworklocation\Production\#%BuildVersion%\". As you can see, the BuildVersion parameter is used in the path to point to the artifact created from that specific build. You can pass the parameter when approving your promotion process at the Promotion Status screen.


Instead of deploying to Azure, you could also deploy to a local server or even to a docker or windows container using an orchestration tool such as Microsoft Azure Service Fabric or Pivotal Cloud Foundry.

As i mentioned earlier, create several promotion processes for your environments. Be sure to archive artifacts if needed, as archiving development releases is not really necessary. Make promotion processes dependent on each other to ensure your application is always being deployed though your entire DTAP street before reaching production.