EngineeringSenior DeveloperTechnical Sessions

Session 19: Azure Platform cho .NET Developers

Mục tiêu: Overview các Azure services chính, compute options, data stores, và networking cho .NET projects.


1. Compute Options - Khi Nào Chọn Gì?

┌────────────────────────────────────────────────────────────────────┐
│                    Azure Compute Decision Tree                      │
│                                                                     │
│  Cần full control OS?                                               │
│  ├── YES → Virtual Machines (IaaS)                                  │
│  └── NO                                                             │
│      ├── Containerized? ───→ Container Apps (serverless containers) │
│      │                  ───→ AKS (full Kubernetes)                  │
│      ├── Web app? ─────────→ App Service (PaaS, simple)            │
│      ├── Event-driven? ───→ Azure Functions (serverless)            │
│      └── Background? ────→ WebJobs / Container Apps Jobs            │
└────────────────────────────────────────────────────────────────────┘
ServiceBest ForScaleCostComplexity
App ServiceWeb apps, APIsAuto (up to 30 instances)~$50-200/moThấp
Container AppsMicroservices, event-driven0-N replicas (scale to zero)Pay per useTrung bình
AKSLarge microservices, multi-teamManual/auto pods + nodes~$200+/moCao
FunctionsEvent handlers, scheduled jobs0-200 instancesPay per executionThấp
VMsLegacy, custom softwareVM Scale Sets~$100+/moCao
bicep
// Bicep template
resource containerApp 'Microsoft.App/containerApps@2023-05-01' = {
  name: 'order-service'
  location: location
  properties: {
    managedEnvironmentId: environment.id
    configuration: {
      ingress: {
        external: true
        targetPort: 8080
        transport: 'http'
      }
      secrets: [
        { name: 'db-connection', value: dbConnectionString }
      ]
      registries: [
        { server: 'myregistry.azurecr.io', username: acrUsername, passwordSecretRef: 'acr-password' }
      ]
    }
    template: {
      containers: [
        {
          name: 'order-service'
          image: 'myregistry.azurecr.io/order-service:latest'
          resources: { cpu: json('0.5'), memory: '1Gi' }
          env: [
            { name: 'ConnectionStrings__Default', secretRef: 'db-connection' }
          ]
        }
      ]
      scale: {
        minReplicas: 1
        maxReplicas: 10
        rules: [
          {
            name: 'http-scaling'
            http: { metadata: { concurrentRequests: '50' } }
          }
        ]
      }
    }
  }
}

2. Data Stores

Azure SQL vs Cosmos DB vs Redis

FeatureAzure SQLCosmos DBRedis Cache
ModelRelationalMulti-model (Document, Graph)Key-Value
ConsistencyStrong (ACID)Configurable (5 levels)Eventual
Latency~5-10ms~1-5ms (global)~1ms
ScaleVertical + Read replicasHorizontal (unlimited)Vertical
Cost~$50-500/moPay per RU~$50-200/mo
Use caseOLTP, complex queriesGlobal apps, flexible schemaCaching, sessions
csharp
// Azure SQL + EF Core
builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(
        builder.Configuration.GetConnectionString("Default"),
        sqlOptions =>
        {
            sqlOptions.EnableRetryOnFailure(maxRetryCount: 5);
            sqlOptions.CommandTimeout(30);
            sqlOptions.MigrationsAssembly("Infrastructure");
        }));

// Cosmos DB
builder.Services.AddDbContext<CosmosDbContext>(options =>
    options.UseCosmos(
        builder.Configuration["Cosmos:Endpoint"]!,
        builder.Configuration["Cosmos:Key"]!,
        "MyDatabase"));

// Redis Cache
builder.Services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = builder.Configuration.GetConnectionString("Redis");
    options.InstanceName = "myapp:";
});

// HybridCache (.NET 9) - L1 Memory + L2 Redis
builder.Services.AddHybridCache(options =>
{
    options.DefaultEntryOptions = new()
    {
        LocalCacheExpiration = TimeSpan.FromMinutes(5),
        Expiration = TimeSpan.FromMinutes(30)
    };
});
builder.Services.AddStackExchangeRedisCache(/* ... */);

3. Azure Key Vault & Managed Identity

csharp
// Zero secrets trong code!

// 1. Managed Identity (no credentials needed)
// App Service / Container Apps tự động authenticate với Azure resources
builder.Configuration.AddAzureKeyVault(
    new Uri("https://myapp-vault.vault.azure.net/"),
    new DefaultAzureCredential()); // Uses Managed Identity in Azure, Azure CLI locally

// 2. Truy cập secrets
var connectionString = builder.Configuration["ConnectionStrings:Default"];
// → Automatically pulled from Key Vault!

// 3. Dùng cho mọi Azure resources
builder.Services.AddDbContext<AppDbContext>(options =>
{
    // Connection string từ Key Vault
    var connStr = builder.Configuration["SqlConnectionString"];
    options.UseSqlServer(connStr);
});

// Service Bus with Managed Identity (no connection string!)
builder.Services.AddMassTransit(x =>
{
    x.UsingAzureServiceBus((context, cfg) =>
    {
        cfg.Host(new Uri("sb://myapp-bus.servicebus.windows.net"),
            h => h.TokenCredential = new DefaultAzureCredential());
    });
});

4. Azure Storage

csharp
// Blob Storage - files, images, documents
public class BlobStorageService(BlobServiceClient blobClient)
{
    public async Task<string> UploadAsync(
        Stream content, string fileName, string containerName = "uploads")
    {
        var container = blobClient.GetBlobContainerClient(containerName);
        await container.CreateIfNotExistsAsync();

        var blobName = $"{Guid.NewGuid()}/{fileName}";
        var blob = container.GetBlobClient(blobName);

        await blob.UploadAsync(content, new BlobHttpHeaders
        {
            ContentType = GetContentType(fileName)
        });

        return blob.Uri.ToString();
    }

    // Generate SAS URL cho secure download
    public Uri GetSecureUrl(string blobName, TimeSpan expiry)
    {
        var container = blobClient.GetBlobContainerClient("documents");
        var blob = container.GetBlobClient(blobName);

        var sasBuilder = new BlobSasBuilder
        {
            BlobContainerName = "documents",
            BlobName = blobName,
            Resource = "b",
            ExpiresOn = DateTimeOffset.UtcNow.Add(expiry)
        };
        sasBuilder.SetPermissions(BlobSasPermissions.Read);

        return blob.GenerateSasUri(sasBuilder);
    }
}

// Registration
builder.Services.AddSingleton(new BlobServiceClient(
    new Uri("https://myappstorage.blob.core.windows.net"),
    new DefaultAzureCredential()));

5. Networking

┌──────────────────────────────────────────────────────┐
│                   Azure Networking                    │
│                                                       │
│  Internet ──→ Front Door (CDN + WAF + Global LB)    │
│                    │                                  │
│              ┌─────▼──────┐                          │
│              │  VNet      │                          │
│              │  ┌────────┐│  Private                 │
│              │  │App Svc ││  Endpoint                │
│              │  └────┬───┘│     │                    │
│              │       │    │  ┌──▼────┐               │
│              │       │    │  │SQL DB │               │
│              │       │    │  └───────┘               │
│              │  ┌────▼───┐│                          │
│              │  │Redis   ││  ← Also Private Endpoint │
│              │  └────────┘│                          │
│              └────────────┘                          │
└──────────────────────────────────────────────────────┘

Tổng Kết Session 19

ServiceKey Takeaway
Container AppsBest for microservices, scale to zero
App ServiceSimple web apps, built-in CI/CD
Azure SQLOLTP, EF Core, complex queries
Cosmos DBGlobal distribution, flexible schema
Redis CacheSession, caching, pub/sub
Key VaultSecrets management, Managed Identity
Blob StorageFiles, SAS tokens cho secure access

Bài tập: Deploy .NET API lên Azure Container Apps với Managed Identity. Connect Azure SQL + Redis Cache. Sử dụng Key Vault cho connection strings.