The 9.5 steps to deploy your ASP.NET Core 1.0 application to Azure from VSTS

Now that ASP.NET Core 1.0 is released, you should have converted your projects to RTM bits. But what about your automated builds in VSTS? Well, since yesterday, the Hosted Build Pool has been updated to support .NET Core 1.0. So it is time to wake up your Continuous Deployment pipeline!

You might find some articles about how to deploy an ASP.NET Core app to Azure. But there were so many breaking changes across .NET Core prereleases that it could be difficult to find out which step is crucial, which one can be ignored, and which one is deprecated.

In this article, I'll describe you the 9.5 required steps to deploy your ASP.NET Core 1.0 application to Azure from Visual Studio Team Services.

We will cut the deployment into a build definition and a release definition, as is only proper.

Build definition

You'll need 5 steps to build your application and prepare the publishing package that will be used by the release definition.

Define custom build variables

This build definition will use 2 custom variables, and 2 optional variables to increase build performance.

  • BuildConfiguration = Release: used to define the build configuration for your solution.
  • BuildPlatform = Any CPU: used to define the build platform for your solution.
  • DOTNET_SKIP_FIRST_TIME_EXPERIENCE = true: as Donovan Brown explains it in his blog post, usefull to avoid package caching on Hosted build agents. You shouldn't use this if your build will be executed on your custom agent.
  • NUGET_XMLDOC_MODE = skip: skip download of XML documentation for restored packages, will speed up your build.

1. Restore dependencies

To restore dependencies as well as project-specific tools, you can use the .NET Core Command Line Interface.

  • Task type: Command Line
  • Tool: dotnet
  • Arguments: restore

2. Build solution

This step will simply build your Visual Studio solution.

It is better to not use the .NET Core CLI here, as you may have other project types in your solution (for example a database project) and you may want to build them all together.
Plus, you would have to run the CLI from each project folder, so you would have to loop into your folders with a custom script, which is less readable.

  • Task type: Visual Studio Build
  • Solution: **\*.sln
  • Platform: $(BuildPlatform)
  • Configuration: $(BuildConfiguration)

3. Pack the application

You can now pack the application and all of its dependencies into a folder getting it ready for publishing. Again, we will use the .NET Core CLI to do this.

  • Task type: Command Line
  • Tool: dotnet
  • Arguments: publish -c $(BuildConfiguration) -f .NETCoreApp,Version=v1.0 -o $(Build.BinariesDirectory)\publish-output
    • -c $(BuildConfiguration) is to ensure that the publication is done for the same configuration you just built.
    • -o $(Build.BinariesDirectory)\publish-output is to isolate the ouput of the publication.
  • -f .NETCoreApp,Version=v1.0 specifies the framework you want to target. This is optional if you do not target multiple frameworks. use -f .NETFramework,Version=v4.6 to target net461
  • Advanced
    • Working folder: Select or type the path to the folder that contains your application (for example src/GeekLearning.Tasks.Web)

Update : We recently had a very unpleasant day with the publishing command with a project targeting both netcoreapp and net461. The thing is it will silently publish both targets in the same output directory and of course dll will conflict. In order to avoid that you must specify the framework you want to publish for using -foptions.

4. Create the application package

To create the application package which will be deployed later, you have to ZIP the folder generated just before.

You can use one of our task published on the Visual Studio MarketPlace: ZIP Files.

  • Task type: ZIP Files
  • Copy Root: $(Build.BinariesDirectory)\publish-output
  • Contents: **/*.*
  • Zip Name: publish-package.zip
  • Path: $(Build.ArtifactStagingDirectory)

5. Publish build artifact

All you have to do now is to publish the generated ZIP file as a build artifact.

  • Task type: Publish Build Artifacts
  • Path to Publish: $(Build.ArtifactStagingDirectory)
  • Artifact Name: PublishPackages
  • Artifact Type: Server

Your build is ready to compile and package!
If you queue a build from this definition, it should succeed and you should see the following artifacts: only one ZIP file.

Release definition

The release definition must consume the previous build as an artifact source.

You'll need 4.5 more steps to deploy your application to Azure.
Wait... Why so much? And what is this half step?

Well, the answer of the first question is in another article: A successful Azure Web App deployment process.
TL;DR: we are going to deploy to a specific deployment slot, stop it before publication, start it after, and swap it with the production one.

The second one is a little more tricky.
There is at the moment an issue with the "AzureRM Web App Deployment": it will fail if the package does not contain a parameters.xml file with a parameter IIS Web Application Name inside. This file was used to replace values in the Web.config at deploy time, but is now totally useless for an ASP.NET Core 1.0 application. So, we will generate a fake parameters.xml file with a simple command line task.
Temporary workaround, half step! :)

Define custom environment variables

This release definition will use 4 custom variables to identify the Azure resources.

  • AzureResourceGroup: the Azure Resource Group which contains your Web App.
  • AzureWebAppName: the name of your Web App.
  • AzureDeploymentSlot: the slot where to deploy the application.
  • AzureFinalSlot: the destination final slot where the deployment will be swapped from the AzureDeploymentSlot.

6. Stop staging slot

  • Task type: Azure Web App Stop
  • Azure RM Subscription: Your Azure RM endpoint
  • Web App Name: $(AzureWebAppName)
  • Slot: $(AzureDeploymentSlot)

6.5. Create a fake parameters.xml

This half step will echo a fake parameters.xml file to satisfy the AzureRM Web App Deployment task.

  • Task type: Command Line
  • Tool: echo
  • Arguments: ^<parameters^>^<parameter name="IIS Web Application Name" defaultValue="appname" tags="IisApp" ^/^>^<^/parameters^> > $(System.DefaultWorkingDirectory)\fake.xml

7.5. Deploy the application

The deployment itself!
The task will take a package file (along with a SetParameters.xml file) and publish it to the configured Azure Web App.

  • Task type: AzureRM Web App Deployment
  • Azure RM Subscription: Your Azure RM endpoint
  • Web App Name: $(AzureWebAppName)
  • Deploy to Slot: Checked
  • Resource Group: $(AzureResourceGroup)
  • Slot: $(AzureDeploymentSlot)
  • Package: $(System.DefaultWorkingDirectory)\**\PublishPackages\publish-package.zip
  • SetParameters File: $(System.DefaultWorkingDirectory)\fake.xml
  • Remove Additional Files at Destination: Checked

8.5. Start staging slot

  • Task type: Azure Web App Start
  • Azure RM Subscription: Your Azure RM endpoint
  • Web App Name: $(AzureWebAppName)
  • Slot: $(AzureDeploymentSlot)

9.5. Swap slot

  • Task type: Azure Web App Stop
  • Azure RM Subscription: Your Azure RM endpoint
  • Web App Name: $(AzureWebAppName)
  • Source Slot: $(AzureDeploymentSlot)
  • Destination Slot: $(AzureFinallot)

You have now the shortest, the fastest, and the safest ASP.NET Core 1.0 deployment process in Visual Studio Team Services!

Updated: change screenshots to match VSTS new UI, change PowerShell scripts with our Azure tasks, add performance improvements thanks to Donovan Brown.