Core Developers
Core Developers
PUBLISHED BY
All rights reserved. No part of the contents of this book may be reproduced or transmitted in any
form or by any means without the written permission of the publisher.
This book is provided “as-is” and expresses the author’s views and opinions. The views, opinions, and
information expressed in this book, including URL and other Internet website references, may change
without notice.
Some examples depicted herein are provided for illustration only and are fictitious. No real association
or connection is intended or should be inferred.
Microsoft and the trademarks listed at https://www.microsoft.com on the “Trademarks” webpage are
trademarks of the Microsoft group of companies.
The Docker whale logo is a registered trademark of Docker, Inc. Used by permission.
All other marks and logos are property of their respective owners.
Credits
Authors:
Cam Soper
Scott Addie
Colin Dembovsky
Welcome
Welcome to the Azure Development Lifecycle guide for .NET! This guide introduces the basic concepts
of building a development lifecycle around Azure using .NET tools and processes. After finishing this
guide, you’ll reap the benefits of a mature DevOps toolchain.
This guide targets Windows developers. However, Linux and macOS are fully supported by .NET Core.
To adapt this guide for Linux/macOS, watch for callouts for Linux/macOS differences.
Next steps
Other learning paths for the ASP.NET Core developer learning Azure.
Summary .................................................................................................................................................................................. 10
i Contents
Create an Azure DevOps organization .................................................................................................................... 31
Environments ..................................................................................................................................................................... 61
Azure authentication....................................................................................................................................................... 62
Deploy to staging............................................................................................................................................................. 65
ii Contents
Final workflow file ............................................................................................................................................................ 73
Logging ..................................................................................................................................................................................... 87
Alerts .......................................................................................................................................................................................... 88
Conclusion ............................................................................................................................................................................... 89
Identity ...................................................................................................................................................................................... 90
Mobile ....................................................................................................................................................................................... 90
iii Contents
CHAPTER 1
Tools and downloads
Azure has several interfaces for provisioning and managing resources, such as the Azure portal, Azure
CLI, Azure PowerShell, Azure Cloud Shell, and Visual Studio. This guide takes a minimalist approach
and uses the Azure Cloud Shell whenever possible to reduce the steps required. However, the Azure
portal must be used for some portions.
Prerequisites
The following subscriptions are required:
• Git — A fundamental understanding of Git is recommended for this guide. Review the Git
documentation, specifically git remote and git push.
• .NET Core SDK — Version 2.1.300 or later is required to build and run the sample app. If
Visual Studio is installed with the .NET Core cross-platform development workload, the
.NET Core SDK is already installed.
Verify your .NET Core SDK installation. Open a command shell, and run the following
command:
[!div class=“checklist”]
Feel free to review the code, but it’s important to understand that there’s nothing special about this
app. It’s just a simple ASP.NET Core app for illustrative purposes.
From a command shell, download the code, build the project, and run it as follows.
Note
Linux and macOS users should make appropriate changes for paths, for example, using forward slash
(/) rather than back slash (\).*
2. Change your working folder to the simple-feed-reader folder that was created.
5. Open a browser and navigate to http://localhost:5000. The app allows you to type or paste a
syndication feed URL and view a list of news items.
1. Sign in to the Azure Cloud Shell. Note: When you sign in for the first time, Cloud Shell
prompts to create a storage account for configuration files. Accept the defaults or provide a
unique name.
a. Declare a variable to store your web app’s name. The name must be unique to be
used in the default URL. Using the $RANDOM Bash function to construct the name
guarantees uniqueness and results in the format webappname99999.
:::{custom-style=CodeBox} console webappname=mywebapp$RANDOM :::
The az command invokes the Azure CLI. The CLI can be run locally, but using it in the Cloud
Shell saves time and configuration.
c. Create an App Service plan in the S1 tier. An App Service plan is a grouping of web
apps that share the same pricing tier. The S1 tier isn’t free, but it’s required for the
staging slots feature.
:::{custom-style=CodeBox} azurecli az appservice plan create --name $webappname --
resource-group AzureTutorial --sku S1 :::
d. Create the web app resource using the App Service plan in the same resource group.
:::{custom-style=CodeBox} azurecli az webapp create --name $webappname --resource-
group AzureTutorial --plan $webappname :::
f. Set the deployment credentials. These deployment credentials apply to all the web
apps in your subscription. Don’t use special characters in the user name.
:::{custom-style=CodeBox} azurecli az webapp deployment user set --user-name
REPLACE_WITH_USER_NAME --password REPLACE_WITH_PASSWORD :::
h. Display the web app URL. Browse to this URL to see the blank web app. Note this
URL for reference later.
:::{custom-style=CodeBox} console echo Web app URL:
http://$webappname.azurewebsites.net :::
3. Using a command shell on your local machine, navigate to the web app’s project folder (for
example, *.-feed-reader). Execute the following commands to set up Git to push to the
deployment URL:
b. Push the local default branch (main) to the azure-prod remote’s deployment branch
(main).
:::{custom-style=CodeBox} console git push azure-prod main :::
You’ll be prompted for the deployment credentials you created earlier. Observe the output in
the command shell. Azure builds the ASP.NET Core app remotely.
4. In a browser, navigate to the Web app URL and note the app has been built and deployed.
Additional changes can be committed to the local Git repository with git commit. These
changes are pushed to Azure with the preceding git push command.
This section applies to Windows only. Linux and macOS users should make the change described in
step 2 below. Save the file, and commit the change to the local repository with git commit. Finally,
push the change with git push, as in the first section.*
The app has already been deployed from the command shell. Let’s use Visual Studio’s integrated tools
to deploy an update to the app. Behind the scenes, Visual Studio accomplishes the same thing as the
command line tooling, but within Visual Studio’s familiar UI.
Visual Studio builds and deploys the app to Azure. Browse to the web app URL. Validate that the
<h2> element modification is live.
c. Configure the staging slot to use deployment from local Git and get the staging
deployment URL. Note this URL for reference later.
:::{custom-style=CodeBox} azurecli echo Git deployment URL for staging: $(az webapp
deployment source config-local-git --name $webappname --resource-group AzureTutorial --
slot staging --query url --output tsv) :::
d. Display the staging slot’s URL. Browse to the URL to see the empty staging slot. Note
this URL for reference later.
3. In a text editor or Visual Studio, modify Pages/Index.cshtml again so that the <h2> element
reads <h2>Simple Feed Reader - V3</h2> and save the file.
4. Commit the file to the local Git repository, using either the Changes page in Visual Studio’s
Team Explorer tab, or by entering the following using the local machine’s command shell:
5. Using the local machine’s command shell, add the staging deployment URL as a Git remote
and push the committed changes:
a. Add the remote URL for staging to the local Git repository.
:::{custom-style=CodeBox} console git remote add azure-staging
<Git_staging_deployment_URL> :::
b. Push the local default branch (main) to the azure-staging remote’s deployment
branch (main).
:::{custom-style=CodeBox} console git push azure-staging main :::
6. To verify that V3 has been deployed to the staging slot, open two browser windows. In one
window, navigate to the original web app URL. In the other window, navigate to the staging
web app URL. The production URL serves V2 of the app. The staging URL serves V3 of the
app.
7. In the Cloud Shell, swap the verified/warmed-up staging slot into production.
8. Verify that the swap occurred by refreshing the two browser windows.
Summary
In this section, the following tasks were completed:
Additional reading
• Web Apps overview
• Build a .NET Core and SQL Database web app in Azure App Service
• Configure deployment credentials for Azure App Service
• Set up staging environments in Azure App Service
This section details continuous integration and deployment with Azure DevOps. You can achieve that
with GitHub Actions as well. GitHub Actions is a workflow engine built into GitHub that can also be
used for continuous integration and deployment. To follow the guide for building and deploying to
Azure using GitHub, complete the Publish the app’s code to GitHub and Disconnect local Git
deployment sections below and then proceed to the GitHub Actions section.
In the previous chapter, you created a local Git repository for the Simple Feed Reader app. In this
chapter, you’ll publish that code to a GitHub repository and construct an Azure DevOps Services
pipeline using Azure Pipelines. The pipeline enables continuous builds and deployments of the app.
Any commit to the GitHub repository triggers a build and a deployment to the Azure Web App’s
staging slot.
[!div class=“checklist”]
1. Select your account in the Owner drop-down, and enter simple-feed-reader in the Repository
name textbox.
3. Open your local machine’s command shell. Navigate to the directory in which the simple-feed-
reader Git repository is stored.
4. Rename the existing origin remote to upstream. Execute the following command:
5. Add a new origin remote pointing to your copy of the repository on GitHub. Execute the
following command:
6. Publish your local Git repository to the newly created GitHub repository. Execute the following
command:
1. Navigate to the mywebapp App Service. As a reminder, the portal’s search box can be used to
quickly locate the App Service.
2. Click Deployment Center. A new panel appears. Click Disconnect to remove the local Git
source control configuration that was added in the previous chapter. Confirm the removal
operation by clicking the Yes button.
Go to Organization Settings and then Pipelines > Parallel jobs. If you see value 0 under Microsoft-
hosted that means you need a Self-hosted agent to run your pipeline.
1. Authorization is required before Azure DevOps can access your GitHub repository. Enter
GitHub connection in the Connection name textbox. For example:
1. The template search results appear. Hover over the ASP.NET Core template, and click the
Apply button.
2. The Tasks tab of the build definition appears. Select the self-hosted Agent pool if you have
created that in the earlier step.
> [!NOTE]
> If you are using MS-hosted agent then select the *Hosted > Azure Pipelines* from
drop down.
These settings cause a build to trigger when any change is pushed to the default
branch (*main*) of the GitHub repository. Continuous integration is tested in the
[Commit changes to GitHub and automatically deploy to Azure](#commit-changes-to-
github-and-automatical) section.
1. Click the Save & queue button, and select the Save option:
Use the default folder of *\\*, and click the **Save** button.
1. From the template selection page, enter App Service Deployment in the search box:
1. The template search results appear. Hover over the Azure App Service Deployment with
Slot template, and click the Apply button. The Pipeline tab of the release pipeline appears.
1. Select the Build tile from the Source type section. This type allows for the linking of the
release pipeline to the build definition.
2. Select MyFirstProject from the Project drop-down.
3. Select the build definition name, MyFirstProject-ASP.NET Core-CI, from the Source (Build
definition) drop-down.
4. Select Latest from the Default version drop-down. This option builds the artifacts produced
by the latest run of the build definition.
With this option enabled, a deployment occurs each time a new build is available.
1. A Continuous deployment trigger panel appears to the right. Click the toggle button to
enable the feature. It isn’t necessary to enable the Pull request trigger.
2. Click the Add drop-down in the Build branch filters section. Choose the Build Definition’s
default branch option. This filter causes the release to trigger only for a build from the
GitHub repository’s default branch (main).
3. Click the Save button. Click the OK button in the resulting Save modal dialog.
4. Click the Stage 1 box. An Stage panel appears to the right. Change the Stage 1 text in the
Stage name textbox to Production.
1. Click the Deploy Azure App Service to Slot task. Its settings appear in a panel to the right.
2. Select the Azure subscription associated with the App Service from the Azure subscription
drop-down. Once selected, click the Authorize button.
3. Select Web App from the App type drop-down.
4. Select mywebapp/ from the App service name drop-down.
5. Select AzureTutorial from the Resource group drop-down.
6. Select staging from the Slot drop-down.
7. Select Run on agent* under Tasks. On the right pane, you’ll see Agent Job.
8. Select the self-hosted Agent pool if you have created that in the earlier step.
> [!NOTE]
> If you are using MS-hosted agent then select the *Hosted > Azure Pipelines* from
drop down.
4. Commit the file to the GitHub repository. Use either the Changes page in Visual Studio’s
Team Explorer tab, or execute the following using the local machine’s command shell:
5. Push the change in the default branch (main) to the origin remote of your GitHub repository.
In the following command, replace the placeholder {BRANCH} with the default branch (use
main):
The commit appears in the GitHub repository’s default branch (main). You’ll be able to see the
commit history in https://github.com/<GitHub_username>/simple-feed-
reader/commits/main.
The build is triggered, since continuous integration is enabled in the build definition’s
Triggers tab:
1. Similarly, go to the Releases tab to see the details of CD pipeline. You can always drill down
further to see more details of each step.
1. Once the build succeeds, a deployment to Azure occurs. Navigate to the app in the browser.
Notice that the “V4” text appears in the heading:
The build definition’s Tasks tab lists the individual steps being used. There are five build tasks.
2. Build — Executes the dotnet build --configuration release command to compile the app’s
code. This --configuration option is used to produce an optimized version of the code, which
is suitable for deployment to a production environment. Modify the BuildConfiguration
variable on the build definition’s Variables tab if, for example, a debug configuration is
needed.
3. Test — Executes the dotnet test --configuration release --logger trx --results-directory
<local_path_on_build_agent> command to run the app’s unit tests. Unit tests are executed
within any C# project matching the **/Tests/.csproj glob pattern. Test results are saved in a .trx
file at the location specified by the --results-directory option. If any tests fail, the build fails
and isn’t deployed.
5. Publish Artifact — Publishes the .zip file produced by the Publish task. The task accepts the
.zip file location as a parameter, which is the predefined variable
$(build.artifactstagingdirectory). The .zip file is published as a folder named drop.
Click the build definition’s Summary link to view a history of builds with the definition:
On the resulting page, click the individual build for more details.
A summary of this specific build is displayed. Click the published link, and notice the drop folder
produced by the build is listed:
Release pipeline
A release pipeline was created with the name MyFirstProject-ASP.NET Core-CD:
The two major components of the release pipeline are the Artifacts and the Stages. Clicking the box
in the Artifacts section reveals the following panel:
The release pipeline consists of two tasks: Deploy Azure App Service to Slot and Manage Azure App
Service - Slot Swap. Clicking the first task reveals the following task configuration:
Clicking the slot swap task reveals the following task configuration:
Additional reading
• Create your first pipeline with Azure Pipelines
• Build and .NET Core project
• Deploy a web app with Azure Pipelines
This section details continuous integration and deployment with Azure DevOps. You can achieve that
with GitHub Actions as well. GitHub Actions is a workflow engine built into GitHub that can also be
used for continuous integration and deployment. To follow the guide for building and deploying to
Azure using GitHub, complete the Publish the app’s code to GitHub and Disconnect local Git
deployment sections below and then proceed to the GitHub Actions section.
In the previous chapter, you created a local Git repository for the Simple Feed Reader app. In this
chapter, you’ll publish that code to a GitHub repository and construct an Azure DevOps Services
pipeline using Azure Pipelines. The pipeline enables continuous builds and deployments of the app.
Any commit to the GitHub repository triggers a build and a deployment to the Azure Web App’s
staging slot.
[!div class=“checklist”]
3. Open your local machine’s command shell. Navigate to the directory in which the simple-feed-
reader Git repository is stored.
4. Rename the existing origin remote to upstream. Execute the following command:
5. Add a new origin remote pointing to your copy of the repository on GitHub. Execute the
following command:
6. Publish your local Git repository to the newly created GitHub repository. Execute the following
command:
1. Click Deployment Center. A new panel appears. Click Disconnect to remove the local Git
source control configuration that was added in the previous chapter. Confirm the removal
operation by clicking the Yes button.
2. Navigate to the mywebapp App Service. As a reminder, the portal’s search box can be used to
quickly locate the App Service.
3. Click Deployment Center. A new panel appears. Click Disconnect to remove the local Git
source control configuration that was added in the previous chapter. Confirm the removal
operation by clicking the Yes button.
Go to Organization Settings and then Pipelines > Parallel jobs. If you see value 0 under Microsoft-
hosted that means you need a Self-hosted agent to run your pipeline.
You can create that by following details mentioned in Self-hosted agents. After successful
configuration, you’ll be able to see available agent under Organization Settings > Agent pools >
{youragentname}
1. Authorization is required before Azure DevOps can access your GitHub repository. Enter
GitHub connection in the Connection name textbox. For example:
The template search results appear. Hover over the ASP.NET Core template, and click
the Apply button.
1. The Tasks tab of the build definition appears. Select the self-hosted Agent pool if you have
created that in the earlier step.
These settings cause a build to trigger when any change is pushed to the default
branch (*main*) of the GitHub repository. Continuous integration is tested in the
[Commit changes to GitHub and automatically deploy to Azure](#commit-changes-to-
github-and-automatical) section.
1. Click the Save & queue button, and select the Save option:
Use the default folder of *\\*, and click the **Save** button.
1. From the template selection page, enter App Service Deployment in the search box:
1. The template search results appear. Hover over the Azure App Service Deployment with
Slot template, and click the Apply button. The Pipeline tab of the release pipeline appears.
1. Click the Add button in the Artifacts box. The Add artifact panel appears:
With this option enabled, a deployment occurs each time a new build is available.
1. A Continuous deployment trigger panel appears to the right. Click the toggle button to
enable the feature. It isn’t necessary to enable the Pull request trigger.
2. Click the Add drop-down in the Build branch filters section. Choose the Build Definition’s
default branch option. This filter causes the release to trigger only for a build from the
GitHub repository’s default branch (main).
3. Click the Save button. Click the OK button in the resulting Save modal dialog.
4. Click the Stage 1 box. An Stage panel appears to the right. Change the Stage 1 text in the
Stage name textbox to Production.
1. Click the Deploy Azure App Service to Slot task. Its settings appear in a panel to the right.
2. Select the Azure subscription associated with the App Service from the Azure subscription
drop-down. Once selected, click the Authorize button.
3. Select Web App from the App type drop-down.
4. Select mywebapp/ from the App service name drop-down.
5. Select AzureTutorial from the Resource group drop-down.
6. Select staging from the Slot drop-down.
7. Select Run on agent* under Tasks. On the right pane, you’ll see Agent Job.
8. Select the self-hosted Agent pool if you have created that in the earlier step.
4. Commit the file to the GitHub repository. Use either the Changes page in Visual Studio’s
Team Explorer tab, or execute the following using the local machine’s command shell:
5. Push the change in the default branch (main) to the origin remote of your GitHub repository.
In the following command, replace the placeholder {BRANCH} with the default branch (use
main):
The commit appears in the GitHub repository’s default branch (main). You’ll be able to see the
commit history in https://github.com/<GitHub_username>/simple-feed-
reader/commits/main.
The build is triggered, since continuous integration is enabled in the build definition’s
Triggers tab:
1. Similarly, go to the Releases tab to see the details of CD pipeline. You can always drill down
further to see more details of each step.
1. Once the build succeeds, a deployment to Azure occurs. Navigate to the app in the browser.
Notice that the “V4” text appears in the heading:
Build definition
A build definition was created with the name MyFirstProject-ASP.NET Core-CI. Upon completion, the
build produces a .zip file including the assets to be published. The release pipeline deploys those
assets to Azure.
The build definition’s Tasks tab lists the individual steps being used. There are five build tasks.
2. Build — Executes the dotnet build --configuration release command to compile the app’s
code. This --configuration option is used to produce an optimized version of the code, which
is suitable for deployment to a production environment. Modify the BuildConfiguration
variable on the build definition’s Variables tab if, for example, a debug configuration is
needed.
3. Test — Executes the dotnet test --configuration release --logger trx --results-directory
<local_path_on_build_agent> command to run the app’s unit tests. Unit tests are executed
within any C# project matching the **/Tests/.csproj glob pattern. Test results are saved in a .trx
file at the location specified by the --results-directory option. If any tests fail, the build fails
and isn’t deployed.
5. Publish Artifact — Publishes the .zip file produced by the Publish task. The task accepts the
.zip file location as a parameter, which is the predefined variable
$(build.artifactstagingdirectory). The .zip file is published as a folder named drop.
Click the build definition’s Summary link to view a history of builds with the definition:
On the resulting page, click the individual build for more details.
A summary of this specific build is displayed. Click the published link, and notice the drop folder
produced by the build is listed:
Release pipeline
A release pipeline was created with the name MyFirstProject-ASP.NET Core-CD:
The two major components of the release pipeline are the Artifacts and the Stages. Clicking the box
in the Artifacts section reveals the following panel:
The release pipeline consists of two tasks: Deploy Azure App Service to Slot and Manage Azure App
Service - Slot Swap. Clicking the first task reveals the following task configuration:
Clicking the slot swap task reveals the following task configuration:
Additional reading
• Create your first pipeline with Azure Pipelines
• Build and .NET Core project
• Deploy a web app with Azure Pipelines
GitHub Actions
GitHub Actions is a workflow engine that can automate workflows for nearly all events that occur on
GitHub. Actions is a great solution for Continuous Integration/Continuous Deployment (CI/CD)
pipelines.
In this section of articles, you’ll learn how to create an Actions workflow. The workflow will build, test,
and deploy a .NET web app to Azure Web Apps.
Note
Before you begin, complete the Publish the app’s code to GitHub and Disconnect local Git
deployment sections of the Continuous integration and deployment with Azure DevOps section to
publish your code to GitHub. Then proceed to the Build article.
In the Build article, you’ll create the initial workflow to build and test the .NET app. You’ll:
[!div class=“checklist”]
[!div class=“checklist”]
GitHub Actions
GitHub Actions is a workflow engine that can automate workflows for nearly all events that occur on
GitHub. Actions is a great solution for Continuous Integration/Continuous Deployment (CI/CD)
pipelines.
In this section of articles, you’ll learn how to create an Actions workflow. The workflow will build, test,
and deploy a .NET web app to Azure Web Apps.
Note
Before you begin, complete the Publish the app’s code to GitHub and Disconnect local Git
deployment sections of the Continuous integration and deployment with Azure DevOps section to
publish your code to GitHub. Then proceed to the Build article.
In the Build article, you’ll create the initial workflow to build and test the .NET app. You’ll:
[!div class=“checklist”]
[!div class=“checklist”]
[!div class=“checklist”]
Pipelines as code
Before you compare GitHub Actions and Azure Pipelines, you should consider the benefits of pipelines
as code. Pipelines as code:
[!div class=“checklist”]
• Benefit from standard source control practices (such as code reviews via pull request and
versioning).
• Can be audited for changes just like any other files in the repository.
• Don’t require accessing a separate system or UI to edit.
• Can fully codify the build, test, and deploy process for code.
Note
The term “pipelines” can also be referred to by several different interchangeable words: pipeline,
workflow, and build are common terms. In this article, references to Azure Pipelines are referring to
YAML Pipelines, and not the older UI-based Classic Pipelines.
Azure Pipelines run on agents. The agent is written in .NET, so it will run wherever .NET can run:
Windows, macOS, and Linux. Agents can even run in containers. Agents are registered to a pool in
Azure Pipelines or to a repository or organization in GitHub. Agents can be hosted or private.
GitHub Workflows execute on runners. The runner code is essentially a fork of the Azure Pipelines
code, so it’s very similar. It’s also cross-platform and you can also use hosted or self-hosted runners.
Note
The list of software installed on Azure Pipelines images is listed in this repository. You can select the
platform folder and examine the README.md files. You can find information on GitHub hosted
runners.
It’s possible to install tools and SDKs when running pipelines on hosted agents. If the install steps
don’t take long, this is viable. However, if the tools/software take a long time to install, then you may
be better off with a private agent or self-hosted runner, since the install steps will need to execute for
every run of the workflow.
Comparison of agents
Feature GitHub Azure Pipelines Links
Hosted agents for Free Up to 10 free Microsoft-hosted parallel jobs Azure
public that can run for up to 360 minutes (6 hours) Pipelines
repos/projects each time with no overall time limit per GitHub
month. You aren’t given this free grant by
default, you have to submit a request
Hosted agents for 2,000 minutes One free parallel job that can run for up to
private free per month, 60 minutes each time, until you’ve used
repos/projects 3,000 minutes 1,800 minutes (30 hours) per month. You
for Pro and can pay for additional capacity per parallel
Team licenses, job. Paid parallel jobs remove the monthly
50,000 minutes time limit and allow you to run each job for
for Enterprise up to 360 minutes (6 hours).
license.
Additional
minutes may be
purchased.
Cross-platform Yes Yes
Scale set agents No Yes Azure virtual
machine
scale set
agents
• Approvals
• Artifact storage
GitHub Actions are evolving rapidly and provide features such as triggers for almost all GitHub events,
artifact storage, environments and environment rules, starter templates, and matrices. Read more
about the entire feature set refer GitHub Actions.
Feature comparison
The following table is current as of January 2023 and is not an exhaustive list of features.
Important
GitHub Actions is rapidly evolving. Be sure to check documentation carefully before deciding which
platform is right for you.
To explore moving code to the cloud, you’ll build a GitHub Actions workflow file. The workflow file will
be used for the Simple Feed Reader app you’ve already deployed to Azure App Service.
In this article, you will: > [!div class=“checklist”] > > * Learn the basic structure of a GitHub Action
workflow YAML file. > * Use a template to create a basic build workflow that builds the .NET app and
executes unit tests. > * Publish the compiled app so that it’s ready for deployment.
Workflow structure
Workflows are defined in YAML files, and contain several common nodes:
• a name
• a trigger, defined by an on section
• one or more job sections composed of one or more steps
• optional attributes such as environment variables
Jobs are run on runners. You can use hosted runners, which are spun up by GitHub during the
workflow and then thrown away. Hosted runners are great because you don’t have to maintain your
own build infrastructure. For workflows that require a specific build environment, or for running
workflows on a private network, you can also use private runners. To create a private runner, install the
runner on any machine that supports .NET.
Each job will specify what runner GitHub should use to execute the steps. You can also specify
dependencies between jobs using the needs attribute. Deployment jobs can also specify an
environment to target.
Tip
From a workflow file, you’re able to run any of the available .NET CLI commands. For example, if you’re
required to build, test, and deploy an ASP.NET Core Blazor WebAssembly app with Ahead-of-Time
(AoT) compilation, you’d use the following commands:
1. Select the Actions tab again. You should see a running workflow. Once the workflow has
completed, you should see a successful run.
1. Opening the logs, you can see that the .NET build succeeded and the tests ran and passed.
name: .NET
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 6.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore
- name: Test
run: dotnet test --no-build --verbosity normal
1. Navigate to the .github/workflows/dotnet.yml file and select the pencil icon to edit
1. Add the following Publish step below the Test step. The step runs the dotnet publish
command to publish the web app:
:::{custom-style=CodeBox} ```yml
– name: Test run: dotnet test –no-build –verbosity normal # <– this is the current
bottom line
2. This publishes the web app to a folder on the hosted agent. Now you’ll want to upload the
site as a build artifact that can be deployed to Azure. To complete this activity, you’ll use an
existing action.
3. On the list of actions in the Actions Helper pane on the right, search for artifact. Select on
the Upload a Build Artifact (By actions) action.
:::{custom-style=CodeBox} ```yml
3. Once the workflow completes, you’ll see the artifact from the Home tab:
name: .NET
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 6.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore
- name: Test
run: dotnet test --no-build --verbosity normal
- name: Publish
run: dotnet publish SimpleFeedReader/SimpleFeedReader.csproj -c Release -o website
- name: Upload a Build Artifact
uses: actions/upload-artifact@v3
with:
name: website
path: SimpleFeedReader/website/**
if-no-files-found: error
In this article, you’ll: > [!div class=“checklist”] > > * Learn about Environments in GitHub Actions. > *
Create two environments and specify environment protection rules. > * Create environment secrets
for managing environment-specific configuration. > * Extend the workflow YAML file to add
deployment steps. > * Add a manual dispatch trigger.
Environments
Now that you’ve published an artifact that’s potentially deployable, you’ll add deployment jobs to the
workflow. There’s nothing special about a deployment job, other than the fact that it references an
In this walkthrough, you’ll be deploying to two environments: PRE-PROD and PROD. In a typical
development lifecycle, you’ll want to deploy the latest code to a soft environment (typically DEV) that
is expected to be a bit unstable. You’ll use PRE-PROD as this soft environment. The “higher”
environments (like UAT and PROD) are harder environments that are expected to be more stable. To
enforce this, you can build protection rules into higher environments. You’ll configure an approval
protection rule on the PROD environment: whenever a deployment job targets an environment with
an approval rule, it will pause until approval is granted before executing.
GitHub environments are logical. They represent the physical (or virtual) resources that you’re
deploying to. In this case, the PRE-PROD is just a deployment slot on the Azure Web App. PROD is the
production slot. The PRE-PROD deployment job will deploy the published .NET app to the staging
slot. The PROD deployment job will swap the slots.
Once you have these steps in place, you’ll update the workflow to handle environment-specific
configuration using environment secrets.
Note
Azure authentication
To perform actions such as deploying code to an Azure resource, you need the correct permissions.
For deployment to Azure Web Apps, you can use a publishing profile. If you want to deploy to a
staging slot, then you’ll need the publishing profile for the slot too. Instead, you can use a service
principal (SPN) and assign permission to this service principal. You can then authenticate using
credentials for the SPN before using any commands that the SPN has permissions to perform.
Once you have an SPN, you’ll create a repository secret to securely store the credentials. You can then
refer to the secret whenever you need to authenticate. The secret is encrypted and once it has been
saved, can never be viewed or edited (only deleted or re-created).
Create an SPN
1. In your terminal or Cloud Shell, run the following command to create a service principal with
contributor permissions to the web app you created earlier:
1. Copy and paste the JSON from the az ad sp create-for-rbac command into the body of the
secret. You can create this JSON by hand too if you have the relevant fields for your SPN. The
secret should be named AZURE_CREDENTIALS. Select Add secret to save the new secret:
1. You’ll consume this secret in a workflow in later steps. To access it, use the variable notation
${{}}. In this case, ${{ AZURE_CREDENTIAL }} will be populated with the JSON you saved.
Add environments
Environments are used as a logical boundary. You can add approvals to environments to ensure
quality. You can also track deployments to environments and specify environment-specific values
(secrets) for configuration.
In this case, the only difference between the environments is the slot that you’re deploying to. In real
life, there would typically be different web apps (and separate web app plans), separate resource
groups, and even separate subscriptions. Typically, there’s an SPN per environment. You may want to
override the AZURE_CREDENTIAL value that you saved as a repository secret by creating it as an
environment secret.
Note
Precedence works from Environment to repository. If a targeted environment has a secret called
MY_SECRET, then that value is used. If not, the repository value of MY_SECRET (if any) is used.
1. Select Settings and then Environments in your repository. Select New Environment:
[!NOTE] If you target an environment in a workflow and it does not exist, an “empty”
environment is created automatically. The environment would look exactly the same as the
PRE-PROD environment - it would exist, but would not have any protection rules enabled.
2. Select Environments again and again select New Environment. Now enter PROD as the
name and select Configure environment.
3. Check the Required reviewers rule and add yourself as a reviewer. Don’t forget to select
Save protection rules:
Deploy to staging
You can now add additional jobs to the workflow to deploy to the environments! You’ll start by
adding a deployment to the PRE-PROD environment, which in this case is the web app staging slot.
1. Navigate to the .github/workflows/dotnet.yml file and select the pencil icon to edit the file.
2. You’re going to use the web app name a few times in this workflow, and will need the name
of the resource group too. You’ll define the app and resource group names as variables. With
the variables, you can maintain the values in one place in the workflow file.
3. Add this snippet below the on block and above the jobs block:
[!WARNING] You’ll need to replace <name of your web app> with the actual name of your
web app, and <name of your resource group> with the actual name of your resource group.
environment:
name: PRE-PROD
url: ${{ steps.deploywebapp.outputs.webapp-url }}
steps:
- name: Download a Build Artifact
uses: actions/download-artifact@v3
with:
name: website
path: website
``` :::
3. This job also runs on the latest Ubuntu hosted agent, as specified with the runs-on
attribute.
4. You specify that this job is targeting the PRE-PROD environment using the
environment object. You also specify the url property. This URL will be displayed in
the workflow diagram, giving users an easy way to navigate to the environment. The
value of this property is set as the output of the step with id deploywebapp, which is
defined below.
5. You’re executing a download-artifact step to download the artifact (compiled web
app) from the build job.
6. You then login to Azure using the AZURE_CREDENTIALS secret you saved earlier.
Note the ${{ }} notation for dereferencing variables.
7. You then perform a webapp-deploy, specifying the app-name, slot-name, and path to
the downloaded artifact (package). This action also defines an output parameter that
you use to set the url of the environment above.
6. When the run completes, you should see two successful jobs. The URL for the PRE-PROD
stage has been set and selecting it will navigate you to your web app staging slot:
1. You can also now see deployments. Navigate to https://{your repository url}/deployments to
view your deployments:
Deploy to production
Now that you’ve deployed successfully to PRE-PROD, you’ll want to deploy to PROD. Deployment to
PROD will be slightly different since you don’t need to copy the website again - you just need to swap
the staging slot with the production slot. You’ll do this using an Azure CLI (az) command.
1. Navigate to the .github/workflows/dotnet.yml file and select the pencil icon to edit the file.
:::{custom-style=CodeBox} ```yml run: az logout # <– last line of previous job: insert below this
line
environment:
name: PROD
url: ${{ steps.slot_swap.outputs.url }}
steps:
- name: Login via Azure CLI
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
1. Once again, you specify a new job deploy_prod that needs deploy_staging to
complete before starting.
2. You’re targeting the PROD environment this time. Also, the url value is different from
before.
4. Let the workflow run for a couple minutes until it has deployed to PRE-PROD. At this point,
the workflow will pause and wait for the required approval since you’re targeting the PROD
environment, which requires an approval as defined earlier:
1. Select Review deployments, select the PROD checkbox, optionally add a comment, and then
select Approve and deploy to start the PROD job.
1. The deployment should only take a few seconds. Once it has completed, the URL for the
PROD environment will update.
1. Selecting the PROD URL will navigate you to the PROD site.
1. Navigate to the .github/workflows/dotnet.yml file and select the pencil icon to edit the file.
:::{custom-style=CodeBox} yml on: workflow_dispatch: # <-- this is the new line push: :::
3. The workflow_dispatch trigger displays a Run workflow button in the Actions tab of the
repository—but only if the trigger is defined in the default branch. However, once this trigger is
defined in the workflow, you can select the branch for the run.
For this simple app, there’s no database connection string. However, there’s an example configuration
setting that you can modify for each environment. If you open the simple-feed-
reader/SimpleFeedReader/appsettings.json file, you’ll see that the configuration includes a setting for
the Header text on the Index page:
"UI": {
"Index": {
"Header": "Simple News Reader"
}
},
To show how environment configuration can be handled, you’re going to add a secret to each
environment and then substitute that value into the settings as you deploy.
1. Repeat these steps to add a secret called index_header with the value PROD News Reader for
the PROD environment.
2. If you select Settings > Secrets in the repository, you’ll see the changes. They should look
something like this:
2. Add the following step before the az cli logout step in the deploy_staging job:
``` :::
``` :::
5. Let the workflow run and approve the deployment to PROD once the approval is reached.
6. You should see the following headers on the index page for both sites:
name: .NET
on:
workflow_dispatch:
inputs:
reason:
description: 'The reason for running the workflow'
required: true
default: 'Manual build from GitHub UI'
push:
branches: [ main ]
pull_request:
branches: [ main ]
env:
app-name: "cd-simplefeedreader"
rg-name: "cd-dotnetactions"
jobs:
build:
steps:
- uses: actions/checkout@v3
- name: 'Print manual run reason'
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
echo 'Reason: ${{ github.event.inputs.reason }}'
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 6.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore
- name: Test
run: dotnet test --no-build --verbosity normal
- name: Publish
run: dotnet publish SimpleFeedReader/SimpleFeedReader.csproj -c Release -o website
- name: Upload a Build Artifact
uses: actions/upload-artifact@v3
with:
name: website
path: SimpleFeedReader/website/**
if-no-files-found: error
deploy_staging:
needs: build
runs-on: ubuntu-latest
environment:
name: STAGING
url: ${{ steps.deploywebapp.outputs.webapp-url }}
steps:
- name: Download a Build Artifact
uses: actions/download-artifact@v3
with:
name: website
path: website
deploy_prod:
needs: deploy_staging
runs-on: ubuntu-latest
environment:
name: PROD
url: ${{ steps.slot_swap.outputs.url }}
steps:
- name: Login via Azure CLI
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
[!div class=“checklist”]
• C/C++
• Java
• C#
• Python
• Go
• JavaScript
• TypeScript
CodeQL is a powerful language and security professionals can create custom queries using CodeQL.
However, teams can benefit immensely from the large open-source collection of queries that the
security community has created without having to write any custom CodeQL.
In this article, you’ll set up a GitHub workflow that will scan code in your repository using CodeQL.
You will:
[!div class=“checklist”]
Note
To see security alerts for your repository, you must be a repository owner.
1. Navigate to your GitHub repository and select the Security > Code Scanning Alerts. The top
recommended workflow should be CodeQL Analysis. Select Set up this workflow.
1. Select the Actions tab. In the left-hand tree, you’ll see a CodeQL node. Select this node to
filter for CodeQL workflow runs.
Take a look at the workflow file while it runs. If you remove the comments from the file, you’ll see the
following YAML:
name: "CodeQL"
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
schedule:
- cron: '40 14 * * 6'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Autobuild
uses: github/codeql-action/autobuild@v1
2. This workflow triggers on push and pull_request events to the main branch. There’s also a
cron trigger. The cron trigger lets you define a schedule for triggering this workflow and is
randomly generated for you. In this case, this workflow will run at 14:40 UTC every Saturday.
[!TIP] If you edit the workflow file and hover over the cron expression, a tooltip will show you
the English text for the cron expression.
3. There’s a single job called analyze that runs on the ubuntu-latest hosted agent.
4. This workflow defines a strategy with a matrix on the array of language. In this case, there’s
only csharp. If the repository contained other languages, you could add them to this array.
This causes the job to “fan out” and create an instance per value of the matrix.
6. The second step initializes the CodeQL scanner for the language this job is going to scan.
CodeQL intercepts calls to the compiler to build a database of the code while the code is
being built.
7. The Autobuild step will attempt to automatically build the source code using common
conventions. If this step fails, you can replace it with your own custom build steps.
8. After building, the CodeQL analysis is performed, where suites of queries are run against the
code database.
[!INFORMATION] For other CodeQL configuration options, see Configuring CodeQL code scanning in
your CI system.
1. Navigate to the .github folder in the Code tab and select Add File:
1. Enter codeql/codeql-config.yml as the name. This creates the file in a folder. Paste in the
following code:
queries:
This sample repository is small. As such, it doesn’t contain any major security or quality issues.
However, “real world” repositories will likely have some issues.
When the last CodeQL workflow run completes, you should see two issues in the Security tab:
[!div class=“checklist”]
1. Open the Azure portal, and then navigate to the mywebapp<unique_number> App Service.
2. The Overview tab displays useful “at-a-glance” information, including graphs displaying
recent metrics.
Several self-service tools for troubleshooting and optimization are also found on this
page.
Advanced monitoring
Azure Monitor is the centralized service for monitoring all metrics and setting alerts across Azure
services. Within Azure Monitor, administrators can granularly track performance and identify trends.
Each Azure service offers its own set of metrics to Azure Monitor.
1. Open the Azure portal, and then navigate to the mywebapp<unique_number> App Service.
2. From the Overview tab, click the Application Insights tile.
As the app is used, data accumulates. Select Refresh to reload the blade with new data.
Logging
Web server and app logs are disabled by default in Azure App Service. Enable the logs with the
following steps:
1. Open the Azure portal, and navigate to the mywebapp<unique_number> App Service.
2. In the menu to the left, scroll down to the Monitoring section. Select Diagnostics logs.
1. Turn on Application Logging (Filesystem). If prompted, click the box to install the
extensions to enable app logging in the web app.
2. Set Web server logging to File System.
3. Enter the Retention Period in days. For example, 30.
4. Click Save.
ASP.NET Core and web server (App Service) logs are generated for the web app. They can be
downloaded using the FTP/FTPS information displayed. The password is the same as the deployment
credentials created earlier in this guide. The logs can be streamed directly to your local machine with
PowerShell or Azure CLI. Logs can also be viewed in Application Insights.
Log streaming
App and web server logs can be streamed in real time through the portal.
1. Open the Azure portal, and navigate to the mywebapp<unique_number> App Service.
2. In the menu to the left, scroll down to the Monitoring section and select Log stream.
Alerts
Azure Monitor also provides real time alerts based on metrics, administrative events, and other
criteria.
Note
Currently alerting on web app metrics is only available in the Alerts (classic) service.
The Alerts (classic) service can be found in Azure Monitor or under the Monitoring section of the App
Service settings.
Live debugging
Azure App Service can be debugged remotely with Visual Studio when logs don’t provide enough
information. However, remote debugging requires the app to be compiled with debug symbols.
Debugging shouldn’t be done in production, except as a last resort.
[!div class=“checklist”]
Additional reading
• Troubleshooting ASP.NET Core on Azure App Service and IIS
• Common errors reference for Azure App Service and IIS with ASP.NET Core
• Monitor Azure web app performance with Application Insights
• Enable diagnostics logging for web apps in Azure App Service
• Troubleshoot a web app in Azure App Service using Visual Studio
• Create classic metric alerts in Azure Monitor for Azure services - Azure portal
Beyond web hosting and DevOps, Azure has a wide array of Platform-as-a-Service (PaaS) services
useful to ASP.NET Core developers. This section gives a brief overview of some of the most commonly
used services.
Azure Storage is Azure’s massively scalable cloud storage. Developers can take advantage of Queue
Storage for reliable message queuing, and Table Storage is a NoSQL key-value store designed for
rapid development using massive, semi-structured data sets.
Azure SQL Database provides familiar relational database functionality as a service using the Microsoft
SQL Server Engine.
Cosmos DB globally distributed, multi-model NoSQL database service. Multiple APIs are available,
including SQL API (formerly called DocumentDB), Cassandra, and MongoDB.
Identity
Azure Active Directory and Azure Active Directory B2C are both identity services. Azure Active
Directory is designed for enterprise scenarios and enables Azure AD B2B (business-to-business)
collaboration, while Azure Active Directory B2C is intended business-to-customer scenarios, including
social network sign-in.
Mobile
Notification Hubs is a multi-platform, scalable push-notification engine to quickly send millions of
messages to apps running on various types of devices.
Azure Search is used to create an enterprise search solution over private, heterogenous content.
Service Fabric is a distributed systems platform that makes it easy to package, deploy, and manage
scalable and reliable microservices and containers.