ASP.NET Core Web API · Quality & Delivery

Azure Deployment

Azure App Service runs ASP.NET Core APIs without managing servers: you push code, it handles scaling, TLS certificates and patching. This lesson deploys the ShopSmart API with secure, password-free access to Azure SQL and Key Vault, and zero-downtime releases with slots.

Advanced 6 min Lesson 35 of 37Examples target .NET 9.
Before you start:DockerAPI Testing
0/37 in ASP.NET Core Web API
On this page · 6 min · Advanced

In simple words#

Deploying to Azure App Service is renting a fully managed shop: Azure handles the building, power and security guard; you bring the goods (your API).

App Service
Managed hosting for web apps and APIs.
App settings
Configuration that overrides appsettings.json.
Managed identity
Access Azure SQL without passwords.

Learning objectives#

  • Create an App Service plan and web app with the Azure CLI
  • Configure app settings and secrets safely
  • Use managed identity for Azure SQL and Key Vault
  • Release with deployment slots and GitHub Actions

Explanation#

Create a resource group, an App Service plan (Linux, e.g. P0v3 or B1) and a web app with the DOTNETCORE:9.0 runtime. Deploy a published zip, a container image, or from GitHub Actions.

App settings become environment variables: ASPNETCORE_ENVIRONMENT=Production, ConnectionStrings__Shop=…, Cors__Origins__0=https://shop.example.com. Use Key Vault references (@Microsoft.KeyVault(SecretUri=…)) for secrets.

Enable a system-assigned managed identity. Grant it access to Key Vault and create a contained database user for it in Azure SQL; the connection string then uses Authentication=Active Directory Default — no password anywhere.

Deployment slots (Standard tier and up): deploy to “staging”, warm it up and run smoke tests, then swap with production — zero downtime and instant rollback by swapping back.

Turn on HTTPS only, minimum TLS 1.2, health checks (/health), and Application Insights for logs and metrics.

Syntax#

Shell Illustrative
az webapp create -g shopsmart-rg -p shopsmart-plan -n shopsmart-api --runtime "DOTNETCORE:9.0"
az webapp config appsettings set -g shopsmart-rg -n shopsmart-api --settings ASPNETCORE_ENVIRONMENT=Production
az webapp identity assign -g shopsmart-rg -n shopsmart-api
az webapp deployment slot swap -g shopsmart-rg -n shopsmart-api --slot staging

Code example: From zero to a deployed API with the Azure CLI#

Shelldeploy.sh Illustrative
# 1. Resource group, plan (Linux) and web app
az group create --name shopsmart-rg --location centralindia
az appservice plan create --name shopsmart-plan --resource-group shopsmart-rg --sku P0v3 --is-linux
az webapp create --name shopsmart-api --resource-group shopsmart-rg --plan shopsmart-plan --runtime "DOTNETCORE:9.0"


# 2. Security basics
az webapp update --name shopsmart-api --resource-group shopsmart-rg --https-only true
az webapp config set --name shopsmart-api --resource-group shopsmart-rg --min-tls-version 1.2 --generic-configurations '{"healthCheckPath": "/health"}'


# 3. Managed identity, then settings without passwords
PRINCIPAL_ID=$(az webapp identity assign --name shopsmart-api --resource-group shopsmart-rg --query principalId -o tsv)
az keyvault set-policy --name shopsmart-kv --object-id "$PRINCIPAL_ID" --secret-permissions get list
az webapp config appsettings set --name shopsmart-api --resource-group shopsmart-rg --settings \
  ASPNETCORE_ENVIRONMENT=Production \
  "ConnectionStrings__Shop=Server=tcp:shopsmart-sql.database.windows.net;Database=ShopSmart;Authentication=Active Directory Default" \
  "Jwt__Key=@Microsoft.KeyVault(SecretUri=https://shopsmart-kv.vault.azure.net/secrets/JwtKey/)"
# In Azure SQL (as the Entra admin):  CREATE USER [shopsmart-api] FROM EXTERNAL PROVIDER;
#                                     ALTER ROLE db_datareader ADD MEMBER [shopsmart-api]; ALTER ROLE db_datawriter ADD MEMBER [shopsmart-api];


# 4. Publish and deploy to a staging slot, test it, then swap
dotnet publish ShopSmart.Api -c Release -o publish && (cd publish && zip -r ../api.zip .)
az webapp deployment slot create --name shopsmart-api --resource-group shopsmart-rg --slot staging
az webapp deploy --name shopsmart-api --resource-group shopsmart-rg --slot staging --src-path api.zip --type zip
curl --fail https://shopsmart-api-staging.azurewebsites.net/health
az webapp deployment slot swap --name shopsmart-api --resource-group shopsmart-rg --slot staging --target-slot production
Expected output
After the swap, https://shopsmart-api.azurewebsites.net/health returns “Healthy”. The app reads its database through the managed identity and its JWT key from Key Vault; no secret appears in app settings or source control. Swapping back to the previous slot rolls back instantly.

This example is illustrative. Copy or download it and run it in your own environment; the expected output is shown above.

Step-by-step explanation#

  1. The CLI creates a Linux App Service plan and a web app with the .NET 9 runtime.
  2. HTTPS-only, TLS 1.2 and the /health path are configured for every instance.
  3. A managed identity gets Key Vault access; the JWT key is a Key Vault reference and the database connection string has no password.
  4. The API is deployed to a staging slot and checked with curl before anything reaches users.
  5. Swapping slots makes the tested build live with no downtime.

Real-world use case#

ShopSmart’s GitHub Actions workflow runs exactly these deploy, smoke-test and swap steps on every merge to main; a failed smoke test stops the workflow before the swap.

Common mistakes#

Connection strings with passwords in app settings

Anyone with portal read access sees them. Use managed identity or Key Vault references.

Deploying straight to production

A bad deploy hits users immediately. Deploy to a slot, test, swap.

Forgetting ASPNETCORE_ENVIRONMENT

The default is Production — fine — but staging slots should use slot-specific settings so they do not hit production resources.

Best practices#

  • Managed identity everywhere
  • Key Vault references for secrets
  • Staging slot + smoke test + swap
  • HTTPS only, TLS 1.2+, health checks, Application Insights

Remember this#

App settings = environment variables (use __ for nesting).

Managed identity → Azure SQL and Key Vault without passwords.

Deploy to staging, test, swap.

Practice exercise#

Your task: Write a GitHub Actions workflow that builds the API on push to main and deploys it to the staging slot with azure/webapps-deploy.

Need a hint?
Steps: checkout, setup-dotnet 9.0.x, dotnet publish, azure/login with OIDC, azure/webapps-deploy with slot-name: staging.
Show solution
YAML Illustrative
name: Deploy API
on:
  push:
    branches: [main]


permissions:
  id-token: write
  contents: read


jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: 9.0.x
      - run: dotnet publish ShopSmart.Api -c Release -o publish
      - uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
      - uses: azure/webapps-deploy@v3
        with:
          app-name: shopsmart-api
          slot-name: staging
          package: publish

Mini quiz#

Azure Deployment quizMultiple choice Question 1 of 3

How does a deployment slot swap help?

Score so far: 0/0

Want more? Practise all ASP.NET Core Web API MCQs · ASP.NET Core Web API interview questions

My notes#

Saved in this browser.

Progress is saved in this browser. Sign in to sync.