Azure for Developers — The Services Every .NET Developer Needs to Know
A practical introduction to Azure for developers. App Service, Azure SQL, Storage, Key Vault, Application Insights — the core services you'll use on every project.
Azure for Developers — The Services You'll Actually Use
Most Azure tutorials start with a confusing 300-service catalogue. This one doesn't. We'll cover the eight services you'll use on almost every .NET project, why they exist, and how to get something running today.
By the end of this lesson you'll have a mental model of Azure that makes every other Azure tutorial easier to follow.
Why Azure?
Azure is Microsoft's cloud platform. For .NET developers it's the natural home because:
- Deep integration with Visual Studio, VS Code, and GitHub Actions
- Managed services for SQL Server, Redis, Service Bus — things you already know
- .NET runtime support is first-class, not an afterthought
- Enterprise adoption is massive — knowing Azure makes you employable
The core concept is simple: instead of managing servers, you deploy to managed services that scale, back up, and self-heal automatically.
The Eight Services You Need to Know
1. Azure App Service — Host Your Web App
App Service is where your ASP.NET Core API lives. You deploy your code; Azure runs it on managed infrastructure.
You push code → App Service pulls it → Your API is live at yourapp.azurewebsites.netKey features:
- Auto-scaling (scale out to multiple instances under load)
- Deployment slots (deploy to staging, then swap to production with zero downtime)
- Built-in SSL/TLS
- Custom domains
Deploy from VS Code:
# Install Azure CLI
winget install Microsoft.AzureCLI
# Login
az login
# Create resource group
az group create --name MyRG --location norwayeast
# Create App Service plan (B1 = cheapest paid tier)
az appservice plan create --name MyPlan --resource-group MyRG --sku B1 --is-linux
# Create web app for .NET 8
az webapp create \
--name my-api-app \
--resource-group MyRG \
--plan MyPlan \
--runtime "DOTNET|8.0"
# Deploy your published output
az webapp deploy \
--resource-group MyRG \
--name my-api-app \
--src-path ./publish.zip \
--type zip2. Azure SQL Database — Managed SQL Server
Azure SQL is SQL Server in the cloud. Zero schema migration needed if you're coming from SQL Server. Full T-SQL support, EF Core works identically.
Connection from .NET:
// appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Server=myserver.database.windows.net;Database=mydb;Authentication=Active Directory Default;"
}
}
// Program.cs
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));Pricing tip: Use Serverless tier for dev/test — you pay only when the database is actually executing queries. It auto-pauses after 1 hour of inactivity.
3. Azure Blob Storage — Store Files, Images, Backups
Blob Storage is Azure's object storage — for files, images, PDFs, backups, anything that's not relational data.
Container → Blob
(like Folder → File)Upload a file from .NET:
dotnet add package Azure.Storage.Blobsusing Azure.Storage.Blobs;
public class StorageService
{
private readonly BlobServiceClient _blobClient;
public StorageService(IConfiguration config)
{
_blobClient = new BlobServiceClient(
config.GetConnectionString("AzureStorage"));
}
public async Task<string> UploadFileAsync(
string containerName, string fileName, Stream content)
{
var container = _blobClient.GetBlobContainerClient(containerName);
await container.CreateIfNotExistsAsync(PublicAccessType.Blob);
var blob = container.GetBlobClient(fileName);
await blob.UploadAsync(content, overwrite: true);
return blob.Uri.ToString();
}
public async Task<Stream> DownloadFileAsync(
string containerName, string fileName)
{
var container = _blobClient.GetBlobContainerClient(containerName);
var blob = container.GetBlobClient(fileName);
var response = await blob.DownloadAsync();
return response.Value.Content;
}
}4. Azure Key Vault — Store Secrets Safely
Never store secrets in appsettings.json or environment variables. Azure Key Vault is the right place.
Key Vault stores: connection strings, API keys, certificates, TLS certs
App Service reads them: at startup, with no secrets in your codebaseAccess Key Vault from .NET:
dotnet add package Azure.Extensions.AspNetCore.Configuration.Secrets
dotnet add package Azure.Identity// Program.cs — load all Key Vault secrets as configuration
using Azure.Identity;
var builder = WebApplication.CreateBuilder(args);
var keyVaultUrl = builder.Configuration["KeyVault:Url"];
if (!string.IsNullOrEmpty(keyVaultUrl))
{
builder.Configuration.AddAzureKeyVault(
new Uri(keyVaultUrl),
new DefaultAzureCredential() // uses Managed Identity in production
);
}DefaultAzureCredential tries multiple auth methods in order: Managed Identity, Visual Studio, Azure CLI, etc. In production (App Service with Managed Identity), it just works with zero credentials in code.
5. Application Insights — Observability for Free
Application Insights is Azure's monitoring service. Add it to any .NET app and instantly get:
- Request/response tracing
- Dependency tracking (SQL queries, HTTP calls, Redis)
- Exception capturing with full stack traces
- Performance dashboards
- Custom metrics and events
dotnet add package Microsoft.ApplicationInsights.AspNetCore// Program.cs
builder.Services.AddApplicationInsightsTelemetry(options =>
{
options.ConnectionString = builder.Configuration["ApplicationInsights:ConnectionString"];
});That's it. No other code needed. Every HTTP request is automatically traced. Every SQL query duration is logged. Every unhandled exception is captured.
Custom events and metrics:
public class OrderService
{
private readonly TelemetryClient _telemetry;
public OrderService(TelemetryClient telemetry)
=> _telemetry = telemetry;
public async Task<Order> CreateOrderAsync(CreateOrderRequest request)
{
var order = /* create order */;
// Track a custom event
_telemetry.TrackEvent("OrderCreated", new Dictionary<string, string>
{
["CustomerId"] = order.CustomerId,
["Total"] = order.Total.ToString("F2")
});
// Track a custom metric
_telemetry.TrackMetric("OrderTotal", (double)order.Total);
return order;
}
}6. Azure Service Bus — Async Messaging Between Services
When Service A needs to tell Service B something happened, without waiting for a response, use Service Bus.
OrderAPI publishes "OrderCreated" → Service Bus → EmailService processes itThis decouples services. If EmailService is down, the message waits in the queue and gets processed when it comes back up.
dotnet add package Azure.Messaging.ServiceBus// Publisher
public class OrderPublisher
{
private readonly ServiceBusSender _sender;
public OrderPublisher(ServiceBusClient client)
=> _sender = client.CreateSender("orders");
public async Task PublishOrderCreatedAsync(Order order)
{
var message = new ServiceBusMessage(JsonSerializer.Serialize(new
{
OrderId = order.Id,
CustomerId = order.CustomerId,
Total = order.Total,
CreatedAt = order.CreatedAt
}))
{
Subject = "OrderCreated",
ContentType = "application/json"
};
await _sender.SendMessageAsync(message);
}
}
// Consumer (background service)
public class OrderMessageConsumer : BackgroundService
{
private readonly ServiceBusProcessor _processor;
private readonly ILogger<OrderMessageConsumer> _logger;
public OrderMessageConsumer(ServiceBusClient client, ILogger<OrderMessageConsumer> logger)
{
_processor = client.CreateProcessor("orders", "email-subscription");
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_processor.ProcessMessageAsync += HandleMessageAsync;
_processor.ProcessErrorAsync += HandleErrorAsync;
await _processor.StartProcessingAsync(stoppingToken);
}
private async Task HandleMessageAsync(ProcessMessageEventArgs args)
{
var json = args.Message.Body.ToString();
_logger.LogInformation("Processing order message: {Body}", json);
// Send email, update inventory, etc.
await args.CompleteMessageAsync(args.Message);
}
private Task HandleErrorAsync(ProcessErrorEventArgs args)
{
_logger.LogError(args.Exception, "Service Bus error on {EntityPath}", args.EntityPath);
return Task.CompletedTask;
}
}7. Azure Cache for Redis — Speed Up Your App
Azure Cache for Redis is a fully managed Redis instance. Use it for:
- Caching database results
- Session storage
- Rate limiting counters
- Pub/Sub messaging
dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis// Program.cs
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = builder.Configuration["Redis:ConnectionString"];
options.InstanceName = "MyApp:";
});
// Usage
public class ProductService
{
private readonly IDistributedCache _cache;
private readonly IProductRepository _products;
public async Task<Product?> GetProductAsync(string id)
{
var cacheKey = $"product:{id}";
var cached = await _cache.GetStringAsync(cacheKey);
if (cached is not null)
return JsonSerializer.Deserialize<Product>(cached);
var product = await _products.GetByIdAsync(id);
if (product is not null)
{
await _cache.SetStringAsync(cacheKey,
JsonSerializer.Serialize(product),
new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(15)
});
}
return product;
}
}8. Azure Container Registry + Container Apps — Modern Deployment
For containerised apps, Azure Container Registry (ACR) stores your Docker images and Azure Container Apps runs them with auto-scaling.
# Build and push image to ACR
az acr create --name myregistry --resource-group MyRG --sku Basic
az acr login --name myregistry
docker build -t myregistry.azurecr.io/my-api:latest .
docker push myregistry.azurecr.io/my-api:latest
# Deploy to Container Apps
az containerapp create \
--name my-api \
--resource-group MyRG \
--environment my-env \
--image myregistry.azurecr.io/my-api:latest \
--target-port 8080 \
--ingress external \
--min-replicas 1 \
--max-replicas 10Container Apps automatically scales to zero when idle (great for cost) and scales out under load.
The Architecture Pattern for a Typical .NET App on Azure
Browser / Mobile
↓
Azure App Service (ASP.NET Core API)
├── Azure SQL Database (relational data)
├── Azure Cache for Redis (caching + sessions)
├── Azure Blob Storage (files, images)
├── Azure Service Bus (async events)
└── Azure Key Vault (secrets)
↓
Application Insights (monitoring everything)Local Development with Azure Services
You can use Azure services locally with the Azurite emulator (Storage) and real Azure dev resources:
# Azurite — local Azure Storage emulator
npm install -g azurite
azurite --loose
# For other services, create a dev resource group
az group create --name dev-MyProject --location norwayeastFor auth, DefaultAzureCredential picks up your Azure CLI session automatically:
az login
# Your app now authenticates to Azure services automatically from local devKey Takeaways
- App Service — deploy your API, handles SSL, scaling, and deployment slots
- Azure SQL — managed SQL Server with zero ops overhead
- Blob Storage — anything that isn't relational: files, images, backups
- Key Vault — secrets, never in config files
- Application Insights — observability, add it to every project from day one
- Service Bus — async decoupled communication between services
- Redis Cache — cache hot data, 100× faster than a database hit
- Container Apps — Kubernetes without the complexity
The next lesson covers deploying a .NET API to Azure App Service step by step — including CI/CD with GitHub Actions, environment-specific config, and production monitoring setup.
Enjoyed this article?
Explore the Backend Systems learning path for more.
Found this helpful?
Leave a comment
Have a question, correction, or just found this helpful? Leave a note below.