Azure PaaS & CI/CD β Hosting, Deploying, and Automating .NET Apps
Learning Context: Part of Phase 2 (Cloud-Native & DevOps) in the Senior .NET Engineer Learning Path 2026.
Prerequisites: NET Internals β How It All Works, EF Core & SQL Deep Dive β Change Tracker, N+1, and Performance
π§Έ Baby Explanation: The Hotel vs Apartment Analogy
When you want to run a .NET application on the internet, you need a computer somewhere thatβs always on. There are three ways to do it:
IaaS β Renting an Apartment π’
You get an empty room (a Virtual Machine). You must:
- Install Windows/Linux yourself
- Install .NET runtime yourself
- Apply security patches yourself
- Handle backups yourself
- Set up networking yourself
You have full control, but full responsibility.
PaaS β Staying in a Hotel π¨
You bring your luggage (your code). The hotel handles:
- Room cleaning (OS patches)
- Security (firewalls)
- Breakfast (.NET runtime)
- Backup generator (high availability)
You just bring your code. They handle the rest.
SaaS β Eating at a Restaurant π½οΈ
Everything is done for you. You just use the app (Gmail, Teams, etc.).
Part 1: Azure PaaS Services for .NET
Azure App Service β The Main One
This is where most .NET APIs and web apps live. Itβs PaaS β you deploy your code, and Azure runs it.
What it gives you:
| Feature | What It Means |
|---|---|
| Auto-scaling | If traffic spikes, Azure spins up more instances automatically |
| Staging slots | Deploy to βstagingβ first, swap to βproductionβ with zero downtime |
| Custom domains | api.christianjeremia.com instead of myapp.azurewebsites.net |
| SSL/TLS | Free HTTPS certificate, auto-renewed |
| CI/CD integration | Connect to GitHub β push code, auto-deploy |
How deployment works:
You push code β GitHub β Azure picks it up β Builds β Deploys to App Service
Your code goes into a folder on Azureβs servers, and a process called w3wp.exe (IIS) runs it. But you never see that β Azure handles everything.
Azure SQL Database
A managed SQL Server in the cloud. No need to:
- Install SQL Server
- Apply security patches
- Manage backups (Azure does it automatically)
Connection string looks like:
Server=mydb.database.windows.net;Database=MyDb;User Id=admin;Password=...;
Same EF Core code as your local SQL Server β just change the connection string.
Azure Service Bus
A message queue β services send messages to each other without waiting for a response.
Service A sends "OrderPlaced" β [Azure Service Bus] β Service B receives "OrderPlaced"
Service A continues working immediately β Service B processes the order
This is what makes microservices work. You used this in your Mango project β thatβs a real senior-level experience.
Azure Container Apps
The modern way to deploy microservices. You package your app as a Docker container, and Azure runs it.
Your code β Docker image β Container Registry β Azure Container Apps β Running!
No Kubernetes complexity. Azure handles scaling, load balancing, and networking.
Application Insights
Monitoring and diagnostics. It answers questions like:
- βWhy is my API slow today?β π
- βWhich endpoint is failing?β β
- βHow many users are active?β π
// Add to Program.cs
builder.Services.AddApplicationInsightsTelemetry();Then you see everything in the Azure portal β response times, failure rates, dependency calls (SQL, HTTP), and live logs.
Part 2: The Deployment Pipeline β From Code to Running
When you deploy a .NET app, hereβs what happens step by step:
ββββββββββββββ ββββββββββββ βββββββββββββ ββββββββββββββ
β You push β βββΆ β Build β βββΆ β Test β βββΆ β Deploy to β
β to GitHub β β .NET β β xUnit β β Azure β
ββββββββββββββ ββββββββββββ βββββββββββββ ββββββββββββββ
Step 1: Build
dotnet restore # Download NuGet packages
dotnet build # Compile the codeStep 2: Test
dotnet test # Run all unit testsIf tests fail β stop deployment. Never deploy broken code.
Step 3: Publish
dotnet publish -c Release -o ./publishThis creates a folder with your compiled app and all its dependencies β ready to run.
Step 4: Deploy
Upload the published files to Azure App Service. Azure detects the new files and restarts the app.
Part 3: What is CI/CD?
CI β Continuous Integration
Every time you push code, the system:
- Downloads your code
- Restores packages
- Builds the project
- Runs all tests
If the build or tests fail, you get an email/Slack notification immediately. You fix it before it reaches production.
Without CI: You write code for 2 weeks, then try to build β 50 errors β panic π±
With CI: You get errors within 5 minutes of writing them β fix immediately β
CD β Continuous Delivery/Deployment
After CI passes, the code is automatically deployed.
- Continuous Delivery: Code is deployed to staging automatically, but someone must click βApproveβ before going to production.
- Continuous Deployment: Code goes all the way to production automatically after tests pass.
Part 4: GitHub Actions β How It Works
GitHub Actions is a CI/CD system built into GitHub. You define a pipeline in a YAML file.
The Anatomy of a Pipeline
name: Deploy .NET API
# π When does this run?
on:
push:
branches: [main]
# π What jobs run?
jobs:
build-and-deploy:
runs-on: ubuntu-latest
# π What steps inside the job?
steps:
- name: Get code
uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: '10.0'
- name: Build
run: dotnet build --configuration Release
- name: Test
run: dotnet test --configuration Release --no-build
- name: Publish
run: dotnet publish -c Release -o ./publish
- name: Deploy to Azure
uses: azure/webapps-deploy@v2
with:
app-name: my-dotnet-api
publish-profile: ${{ secrets.AZURE_PUBLISH_PROFILE }}Key Concepts
| Concept | What It Is | Analogy |
|---|---|---|
Trigger (on:) | What starts the pipeline | Like setting an alarm |
| Job | A unit of work (build, test, deploy) | Like a recipe step |
| Step | One command inside a job | Like an instruction in that step |
Action (uses:) | Pre-built reusable step | Like a library function |
Runner (runs-on:) | The VM that executes the job | Like the kitchen where you cook |
| Secret | Encrypted password/connection string | Like a locked safe in the kitchen |
Secrets β How to Handle Passwords
Never put passwords in your code. Instead, store them in GitHub Secrets:
GitHub β Settings β Secrets and variables β Actions β New repository secret
Then use them in your pipeline:
run: dotnet run --connection-string "${{ secrets.DB_CONNECTION_STRING }}"The value is encrypted and never appears in logs.
Part 5: Deployment Slots β Zero-Downtime Deployments
This is a senior-level concept. It solves the problem:
βHow do I deploy new code without users seeing errors during the restart?β
Without Slots (Downtime β)
1. User is using the app β "Working"
2. You deploy new code β App restarts β "Error 503"
3. User sees error β "This site is broken!" π‘
4. App finishes restarting β "Working again"
With Slots (Zero Downtime β )
Production Slot Staging Slot
ββββββββββββββββββ ββββββββββββββββββ
β Old version β β New version β
β (users here) β β (nobody here) β
β β β Deploy to HERE β
β my-api β β my-api-stagingβ
ββββββββββββββββββ ββββββββββββββββββ
β β
β SWAP! β
βΌ βΌ
ββββββββββββββββββ ββββββββββββββββββ
β New version β β Old version β
β (users here) β β (ready to rollback) β
ββββββββββββββββββ ββββββββββββββββββ
The swap is instant. Users never see an error.
Bonus: If the new version has a bug, you can swap back immediately β no redeployment needed.
Part 6: Putting It All Together β A Real Workflow
Hereβs how a professional .NET team deploys:
Developer pushes to GitHub
β
βΌ
GitHub Action triggers
β
βΌ
Step 1: dotnet restore + build
β
βΌ
Step 2: dotnet test (if any fail β stop here!)
β
βΌ
Step 3: dotnet publish
β
βΌ
Step 4: Deploy to Azure App Service (Staging slot)
β
βΌ
Step 5: Run smoke tests on staging URL
β
βΌ
Step 6: Swap staging β production (zero downtime)
β
βΌ
Done! π
If anything goes wrong at Step 5: swap back to old version immediately.
π Cheat Sheet
| Concept | Key Thing to Remember |
|---|---|
| PaaS | Bring code, not servers |
| App Service | Main .NET hosting β auto-scale, slots, HTTPS |
| Azure SQL | Managed SQL Server β same EF Core, different connection string |
| Service Bus | Message queue for microservices |
| CI | Build + test every push |
| CD | Auto-deploy after CI passes |
| GitHub Actions | Pipeline defined in .github/workflows/*.yml |
| Secrets | Passwords stored in GitHub, never in code |
| Deployment Slots | Staging β Swap β Prod = zero downtime |
| Rollback | Swap back to old slot = instant fix |
π§ͺ Build Challenges
Challenge 1: Deploy POS API to Azure
This is the real one. Deploy your POS API to Azure App Service:
- Create a free Azure account (if you donβt have one)
- Create an App Service via the portal
- Deploy your POS API using Git deploy or ZIP deploy
- Verify the API works at
https://your-api.azurewebsites.net
Challenge 2: Add CI/CD with GitHub Actions
- Create
.github/workflows/deploy.ymlin your POS API repo - Add steps: build β test β publish β deploy
- Store the publish profile as a GitHub Secret
- Push to
mainand watch the pipeline run
Challenge 3: Set Up Staging and Production Slots
- Add a staging slot to your App Service
- Deploy new code to staging
- Verify it works on the staging URL
- Swap staging β production
- Test a rollback by swapping back
Rules:
- β Donβt ask Jeri for code
- β Understand each concept before deploying
- β Show Jeri your running Azure URL
- β Show Jeri a successful GitHub Action run
Related:
- Senior .NET Engineer Learning Path 2026 β Phase 2: Cloud-Native & DevOps
- NET Internals β How It All Works β The apps youβll deploy