Azure App Service CI/CD using AppVeyor

Publishing a web app to an Azure App Service is quite easy thing to do using Visual Studio but it certainly isn’t the best way to go with for enterprise solutions. Consider for example that you wish to deploy your application to different regions around the globe, using different application settings or build configurations. In case you choose Visual Studio this can be not only time consuming but also error prone. The real disadvantage though is that you don’t have full control of what is being deployed during the process. Ideally you would like to know more details about the deployment such as the build version to be released and if all the tests have been passed before the process starts. All these are possible using AppVeyor, a continuous integration solution capable of making the release process fast and more important reliable. AppVeyor is free for open-source projects but also provides several plans to meet the needs for enterprise solutions.

Integrating AppVeyor

There are 4 main steps you need to follow to configure CI/CD for your project in AppVeyor.

  1. Add the project to AppVeyor
  2. Create a build definition (appveyor.yml)
  3. Create a deployment environment
  4. Publish artifacts (either manually or automatically)

Before moving on to the next steps, visit AppVeyor and sign in. It is recommended that use your GitHub account and if you don’t have any simply create one, it’s free.

Add the project

For this tutorial we will be using a Web App built with .NET Core and Angular that you can find here. In case you wish to follow along with this app simply fork the repository. To fork the repository, sign in to your GitHub account and visit the repository’s URL. Click the Fork button on the upper right and that’s it. Back in AppVeyor, click Projects from the top menu, search for the forked repository in the GitHub tab and click the Add button on the right.

Notice that you can integrate projects from many other sources such as Bitbucket, Visual Studio Team Services, GitLab, Kiln, GitHub Enterprise, Stash, Git, Mercurial and Subversion

AppVeyor.yml build definition

AppVeyor requires to add an appveyor.yml file at the root of your repository that defines what do you want it to do with your project when you push changes. This file is already there for you so go ahead and open it. Following are the most important parts of the file.

version: '2.0.{build}'
image: Visual Studio 2017
  - master
  - develop

The above snipper tells AppVeyor to use the Visual Studio 2017 build worker image so that it can build the .NET Core application. An image has a pre-installed software ready to be used for processing your projects. It also informs AppVeyor to run a build every time you push a commit either in the master or the develop branches. Any commits to different branches will not trigger a build.

# Install scripts. (runs after repo cloning)
  # Get the latest stable version of Node.js or io.js
  - cd DotNetCoreAngularToAzure
  # install npm modules
  - ps: Install-Product node $env:nodejs_version
  - npm install
  - node node_modules/webpack/bin/webpack.js --config webpack.config.vendor.js

The install instruction prepares the environment before the actual build starts. After changing the working directory to DotNetCoreAngularToAzure web application project, it installs node
and runs the npm install command. Next it runs webpack to produce the vendors packages
file used by the Angular application.

The web app was created using the .NET Core – Angular template in Visual Studio 2017

  # Display minimal restore text
  - cmd: dotnet restore --verbosity m
  # output will be in ./DotNetCoreAngularToAzure/bin/Release/netcoreapp2.0/publish/
  - cmd: dotnet publish -c Release

Before building the project it restores packages using the .NET Core CLI. Next it runs the dotnet publish command to produce the artifacts.

 - path: '\DotNetCoreAngularToAzure\bin\Release\netcoreapp2.0\publish'
   name: WebSite
   type: WebDeployPackage

When dotnet publish -c Release command finishes, the produced artifacts are stored in the \Online.Store\bin\Release\netcoreapp2.0\publish folder. The instruction tells AppVeyor to name the artifacts WebSite and ZIP them in a file named These artifacts will be available for deployment using the Web Deploy method.

Build artifacts

Every build produces its own artifacts. This means that using the build number you can deploy any version of your software at any time you want

Try and push a simple change to your forked repository. AppVeyor will trigger a new build. To view your project’s build history, in the Projects page click the forked repository and select the History tab. You can check how a build looks like here. By default AppVeyor will send you an email saying if the build was successful or not.

Web Deploy

You will use the Web Deploy method to publish the artifacts of your builds up on your App Services in Azure. This will be done through AppVeyor Deployment Environments. A deployment environment’s role is to connect to a specific Azure App Service and publish the artifacts for the selected build. In order to connect though to an App Service it needs to know the web deploy‘s credentials for that service. These credentials can be found in the publish profile of an App Service slot. This means that there will be different deployment environments in AppVeyor for each App Service you create. Before continue on it’s good to know how an xml publish profile looks like. Assuming that you have already created an App Service in Azure Portal open the resource and in the main blade select Overview. Click the Get publish profile button to download the App Service’s publish profile.

Part of the xml file for the App Service I created looks like this:

    profileName="app-service-appveyor - Web Deploy" 
      <databases />

To create an AppVeyor’s deployment environment and publish build artifacts to an Azure App Service, you will use the following properties from the publish profile file:

  • msdeploySite
  • publishUrl
  • userName
  • userPWD

Deployment environment

Back in AppVeyor select ENVIRONMENTS from the top menu and click NEW ENVIRONMENT to create a deployment environment. Fill the form as follow:

  • Provider: Select Web Deploy
  • Environment name: Just give it a name such as Production
  • Server: This value has the following format:

    where you need to replace the <publishUrl> and the <msdeploySite> variables with the respective values existing in the publish profile file you saw before. In my case the value for the Server property was the following:
  • Webiste name: Use the msdeploySite value from the publish profile
  • Username: Use the userName value from the publish profile
  • Password: Use the userPWD value from the publish profile
  • Artifact to deploy: WebSite (this is the value you used in the artifacts section of the appveyor.yml file)
  • ASP.NET Core application: Checked
  • Force restarting ASP.NET Core application on deploy: Checked
  • Take ASP.NET application offline during deployment: Checked
  • Other settings: Leave all the other settings as are

After filling the form click the Add environment button to create the deployment environment.

Trigger a deployment

You can trigger a deployment in 3 different ways:

  1. Manually using AppVeyor’s interface
  2. Automatically after a push and a successful build, by configuring appveyor.yml file
  3. On-demand using REST APIs

To trigger a deployment manually, select the deployment environment you wish to use and click NEW DEPLOYMENT.

Next select the project and the build you want to be used for the deployment and click DEPLOY.

The deployment shouldn’t take more than a few seconds to finish. You can check a sample deployment here. If you wish to trigger a deployment automatically each time you push changes to a branch, you need to add a deploy section in the appveyor.yml file as follow:

  - provider: Environment
    name: Production
      branch: master

The snippet above declares that you wish to use the Production deployment environment to trigger a deployment each time you push changes to the master branch. This means that the build will be triggered when you push either in the master or develop branch but only changes in the master branch will trigger a deployment. On the other hand, in case you wish to take the full control of the deployments and trigger them on demand and optionally passing a build version number you have to leverage AppVeyor’s REST APIs. In the Globally-Distributed Applications with Microsoft Azure e-book you will find PowerShell scripts that automate creating, updating and triggering of deployment environments.

.\create-deployment-environment.ps1 `
          -token "<appveyor-api-token>" `
          -projectSlug "<project-slug>" `
          -webappName "<webappName>" `
          -resourceGroupName "<resourceGroupName>" `
          -slot "staging"

.\start-deployment.ps1  `
          -token "<appveyor-api-token>" -accountName "<accountName>" `
          -projectSlug "<project-slug>" `
          -webappName "<webappName>" `
          -resourceGroupName "<resourceGroupName>" `
          -deploymentEnvironment "<deploymentEnvironment>" `
          -slot "staging"

Notice that the scripts can take care to use specific deployment environments per App Service slots, meaning that each slot has each own deployment environment.

In case you find my blog’s content interesting, register your email to receive notifications of new posts and follow chsakell’s Blog on its Facebook or Twitter accounts.

Facebook Twitter
.NET Web Application Development by Chris S.
facebook twitter-small

Categories: core, Azure, Best practices

Tags: , ,

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your 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

Automating infrastructure one line at a time

Diary Of A Programmer

Because every day is worth noting

Chara Plessa

The purpose of this blog is to broaden my education, promote experimentation and enhance my professional development. Albert Einstein once said that “If you can’t explain it simply, you don’t understand it well enough” and I strongly believe him!

chsakell's Blog



A Front End Developer's Blog

Muhammad Hassan

Full Stack Developer | ASP.NET | MVC | WebAPI | Advanced Javascript | AngularJS | Angular2 | C# | ES6 | SQL | TypeScript | HTML5 | NodeJS, MS candidate @LUMS, Grad & EX-Adjunct Faculty @NUCES-FAST, seasonal blogger & open-source contributor. Seattle, WA.

Software Engineering

Web development


.NET, ASP.NET, C#, MVC, TypeScript, AngularJS

Dominick Baier on Identity & Access Control

Happy DotNetting

In Love with Technology


Knols of experience to your advantage


Search - Read - Request - Share

Rahul's space

Learn, Share and Grow with me !

Dhananjay Kumar

Developer Evangelist @Infragistics | MVP @Microsoft

SQL Authority with Pinal Dave

SQL Server Performance Tuning Expert

Conficient Blog

Random bits of tech from @conficient

Code! Code! Code!


Code Wala

Designing and coding

Microsoft Mentalist

A way to start with Microsoft Technologies

%d bloggers like this: