AZ-204 Cheatsheet — Code Snippets, Tables, and High-Yield Azure Developer Patterns

Comprehensive AZ-204 quick reference: App Service, Functions, containers, Cosmos DB, Blob Storage, Entra ID auth, Key Vault/App Configuration, API Management policies, Event Grid/Hubs, Service Bus/Queues, and Application Insights. Includes code, tables, charts, and diagrams.

On this page

Use this for last‑mile review. Pair it with the Syllabus for coverage, the Study Plan for structure, and Practice for speed.


AZ-204 at a glance (what Microsoft tests)

AZ-204 is less about memorizing product lists and more about choosing the right service + configuration for a scenario.

Domain weighting chart (official ranges)

DomainWeightVisual (relative)
Develop Azure compute solutions25–30%██████████
Develop for Azure storage15–20%██████
Implement Azure security15–20%██████
Monitor and troubleshoot Azure solutions5–10%███
Connect/consume Azure + third-party services20–25%████████

Always look for the hidden requirement: private vs public, ordering, idempotency, throughput, RTO/RPO, least privilege, cost controls.


1) Compute service picker (most-tested table)

NeedBest fitWhy
Managed web app/API with easy deploymentApp ServiceBuilt-in scaling, TLS/custom domains, slots
Event-driven code, bursty trafficFunctionsTriggers/bindings, scale-to-zero (Consumption)
Containerized microservices with revisions + KEDAContainer AppsManaged env, ingress, traffic splitting
“Run a container now” without orchestrationContainer InstancesSimple container group execution
    flowchart TD
	  Q{"Do you need triggers\nand bindings?"} -->|Yes| F["Azure Functions"]
	  Q -->|No| C{"Do you need\na container image?"}
	  C -->|No| AS["App Service"]
	  C -->|Yes| O{"Need revisions\n+ autoscaling rules?"}
	  O -->|Yes| CA["Container Apps"]
	  O -->|No| ACI["Container Instances"]

2) Containers (ACR → ACI / Container Apps)

ACR quick CLI

1# Create ACR
2az acr create -g RG -n myregistry --sku Basic
3
4# Login and push
5az acr login -n myregistry
6docker build -t myregistry.azurecr.io/myapi:1.0.0 .
7docker push myregistry.azurecr.io/myapi:1.0.0

ACR authentication options (pick least-privilege)

OptionBest whenNotes
Entra ID (AAD)humans/devsRole assignments; best default
Managed identityAzure-hosted workloadsGreat for pull access (no secrets)
Scoped tokenslimited automationNarrow scope + expiry
Admin userlast resortShared credential; avoid for prod

Dockerfile (multi-stage, small runtime)

 1FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
 2WORKDIR /src
 3COPY . .
 4RUN dotnet publish -c Release -o /out
 5
 6FROM mcr.microsoft.com/dotnet/aspnet:8.0
 7WORKDIR /app
 8COPY --from=build /out .
 9ENV ASPNETCORE_URLS=http://+:8080
10EXPOSE 8080
11ENTRYPOINT ["dotnet","MyApi.dll"]

ACR Tasks / CI: automate builds

1# Example: build on source context (conceptual)
2az acr build -r myregistry -t myapi:<build-id> .

Container Apps: why it’s different

FeatureContainer AppsACI
Revision-based deploys
Traffic splitting
Event-based scaling (KEDA)
“Just run a container” simplicity⚠ (more setup)

Container Apps: key knobs to remember

  • Ingress (external vs internal), custom domains
  • Revisions (single vs multiple) + traffic weights
  • Secrets and environment variables (avoid baking secrets into images)
  • Scaling rules (HTTP concurrency, queue length, event-based via KEDA)
1# Minimal Container Apps flow (conceptual)
2az containerapp env create -g RG -n ca-env --location eastus
3az containerapp create -g RG -n myapi --environment ca-env \\
4  --image myregistry.azurecr.io/myapi:1.0.0 --ingress external --target-port 8080
    flowchart LR
	  DEV["Dev pushes image"] --> ACR["ACR"]
	  ACR --> CA["Container Apps"]
	  CA --> REV{"Revisions"}
	  REV -->|blue| R1["rev-1"]
	  REV -->|green| R2["rev-2"]
	  R1 --> TR["Traffic split"]
	  R2 --> TR

Common gotcha: container apps and private registries require correct auth (managed identity or registry credentials) and correct image reference.


3) App Service (Web Apps) — deploy, diagnose, scale, slots

Deployment options (know the trade-offs)

MethodWhen it’s bestNotes
Zip deploy / run-from-packageFast + simpleGreat for CI/CD artifacts
GitHub Actions / Azure DevOpsRepeatableBuild → test → deploy pipelines
Container from ACRContainerized web appsControl image tag/version

Quick CLI: create + deploy + slots (conceptual)

 1# Plan + web app
 2az appservice plan create -g RG -n plan-az204 --sku P1v3 --is-linux
 3az webapp create -g RG -p plan-az204 -n mywebapp --runtime \"DOTNETCORE:8.0\"
 4
 5# App settings (configuration) + connection strings
 6az webapp config appsettings set -g RG -n mywebapp --settings ASPNETCORE_ENVIRONMENT=prod
 7az webapp config connection-string set -g RG -n mywebapp -t SQLAzure --settings Db=\"<conn-string>\"
 8
 9# Zip deploy (one option)
10az webapp deploy -g RG -n mywebapp --src-path ./artifact.zip --type zip
11
12# Slots (safe releases)
13az webapp deployment slot create -g RG -n mywebapp --slot staging
14az webapp deployment slot swap -g RG -n mywebapp --slot staging --target-slot production

GitHub Actions (minimal pattern)

 1name: build-and-deploy
 2on: [push]
 3jobs:
 4  deploy:
 5    runs-on: ubuntu-latest
 6    steps:
 7      - uses: actions/checkout@v4
 8      - uses: azure/login@v2
 9        with:
10          creds: ${{ secrets.AZURE_CREDENTIALS }}
11      - uses: azure/webapps-deploy@v3
12        with:
13          app-name: mywebapp
14          package: ./artifact.zip

Configuration: where to put what

ItemBest homeWhy
Feature flags / non-secret settingsApp ConfigurationCentralized, environment-aware
Secrets (API keys, passwords)Key VaultRotation + auditing
App runtime env varsApp settingsStandard platform config
Database connection stringsConnection stringsSeparate slot settings + tooling support

Slots: safe deployment pattern

    flowchart LR
	  U["Users"] --> P["Prod slot"]
	  S["Staging slot"] --> SW["Swap"]
	  SW --> P

Slot rules of thumb

  • Put env-specific config in slot settings so it doesn’t swap.
  • Use staging for warm-up, then swap for near-zero downtime.
  • Always validate connection strings and auth settings post-swap.

Diagnostics checklist (fast)

  • App Service logs: application logs + web server logs
  • Log stream for “what’s happening now”
  • Application Insights for traces/dependencies/exceptions

4) Azure Functions — triggers, bindings, retries

Trigger/binding cheat table (high yield)

PatternTypical triggerTypical output
HTTP APIHTTP triggerStorage/Cosmos/Service Bus
Background processingQueue/Service Bus triggerBlob/Cosmos/Service Bus
Event routingEvent Grid triggerService Bus / storage
Scheduled jobTimer triggerBlob/Cosmos

Hosting plan picker (cold start vs scale vs networking)

PlanBest whenNotes
Consumptionbursty workloadsscale-to-zero; watch cold start
Premiumlow-latency + scalereduced cold start; more features
Dedicated (App Service plan)steady loadpredictable capacity; you manage scaling

Retry / resilience knobs (conceptual)

1{
2  "version": "2.0",
3  "retry": {
4    "strategy": "fixedDelay",
5    "maxRetryCount": 5,
6    "delayInterval": "00:00:10"
7  }
8}

Key exam idea: many triggers are at-least-once. Design processing to be idempotent.

C# example: Service Bus trigger (peek-lock) + output

 1using Azure.Messaging.ServiceBus;
 2using Microsoft.Azure.Functions.Worker;
 3using Microsoft.Extensions.Logging;
 4
 5public class ProcessOrders
 6{
 7    private readonly ILogger _logger;
 8    public ProcessOrders(ILoggerFactory loggerFactory) => _logger = loggerFactory.CreateLogger<ProcessOrders>();
 9
10    [Function("ProcessOrders")]
11    public async Task Run(
12        [ServiceBusTrigger("orders", Connection = "ServiceBusConnection")]
13        ServiceBusReceivedMessage message,
14        ServiceBusMessageActions messageActions)
15    {
16        try
17        {
18            var body = message.Body.ToString();
19            _logger.LogInformation("Order received: {Body}", body);
20
21            // Do work...
22
23            await messageActions.CompleteMessageAsync(message);
24        }
25        catch (Exception ex)
26        {
27            _logger.LogError(ex, "Failed processing message");
28            await messageActions.AbandonMessageAsync(message);
29        }
30    }
31}

Function gotchas

  • Consumption plan cold starts: reduce heavy startup and reuse clients.
  • Queue-based triggers: design for idempotency and retries.
  • Poison messages: plan a dead-letter or poison queue strategy (Service Bus DLQ, storage queue patterns).

Durable Functions (high-level mental model)

    flowchart LR
	  START["Starter (HTTP/Timer)"] --> ORCH["Orchestrator"]
	  ORCH --> A1["Activity: step 1"]
	  ORCH --> A2["Activity: step 2"]
	  A1 --> ORCH
	  A2 --> ORCH
	  ORCH --> DONE["Complete"]

5) Cosmos DB — partitioning, consistency, change feed

Partition key rules of thumb

  • Choose a key that spreads writes/reads (avoid “all to one partition”).
  • Prefer keys you already filter on (queries become cheaper).

Consistency level quick table

LevelStrengthTypical use
StrongHighestSingle region, strict correctness
Bounded stalenessHighControlled lag
SessionMediumMost apps (user session correctness)
Consistent prefixLowerOrdered but potentially stale
EventualLowestHighest availability/lowest latency

RU & throttling: what questions are really asking

  • 429 (Too Many Requests) → you exceeded provisioned throughput (RU/s).
  • Fix levers: increase RU (manual/autoscale), improve partitioning, reduce query cost, cache results, avoid cross-partition scans.

Optimistic concurrency (ETag) pattern

1var read = await container.ReadItemAsync<MyItem>(id, new PartitionKey(pk));
2var etag = read.ETag;
3
4item.Version = item.Version + 1;
5await container.ReplaceItemAsync(item, id, new PartitionKey(pk), new ItemRequestOptions
6{
7    IfMatchEtag = etag
8});

C# example: query with pagination

 1var client = new CosmosClient(endpoint, credential);
 2var container = client.GetContainer("db", "items");
 3
 4var query = new QueryDefinition("SELECT * FROM c WHERE c.type = @t")
 5    .WithParameter("@t", "invoice");
 6
 7using var iterator = container.GetItemQueryIterator<dynamic>(query);
 8while (iterator.HasMoreResults)
 9{
10    foreach (var item in await iterator.ReadNextAsync())
11    {
12        Console.WriteLine(item);
13    }
14}

Change feed (concept)

    flowchart LR
	  CDB["Cosmos DB container"] --> CF["Change Feed"]
	  CF --> FN["Function / Worker"]
	  FN --> OUT["Downstream system"]

Change feed gotcha: you need leases/checkpointing so processors can scale safely.

Change feed processor (conceptual C# skeleton)

 1var processor = container
 2    .GetChangeFeedProcessorBuilder<MyItem>(
 3        processorName: "proc",
 4        onChangesDelegate: async (changes, cancellationToken) =>
 5        {
 6            foreach (var doc in changes)
 7            {
 8                // react to changes
 9            }
10        })
11    .WithInstanceName("worker-1")
12    .WithLeaseContainer(leaseContainer)
13    .Build();
14
15await processor.StartAsync();

6) Blob Storage — metadata, lifecycle, SAS

Blob SDK: upload + properties + metadata (C#)

 1using Azure.Storage.Blobs;
 2using Azure.Storage.Blobs.Models;
 3
 4var container = new BlobContainerClient(connectionString, "docs");
 5await container.CreateIfNotExistsAsync();
 6
 7var blob = container.GetBlobClient("reports/2025-q4.pdf");
 8await blob.UploadAsync(fileStream, new BlobHttpHeaders { ContentType = "application/pdf" });
 9
10await blob.SetMetadataAsync(new Dictionary<string, string>
11{
12    ["owner"] = "finance",
13    ["classification"] = "internal"
14});

Blob features that show up in scenarios

FeatureWhy it mattersTypical scenario
Soft deleterecover from deletes“accidental deletion”
Versioningrecover previous versions“rollback changes” / ransomware
ImmutabilityWORM retentioncompliance retention
Access tierscost optimizationlogs/archives

Blob lifecycle policy (example)

 1{
 2  "rules": [
 3    {
 4      "name": "tier-old-logs",
 5      "enabled": true,
 6      "type": "Lifecycle",
 7      "definition": {
 8        "filters": { "blobTypes": ["blockBlob"], "prefixMatch": ["logs/"] },
 9        "actions": {
10          "baseBlob": {
11            "tierToCool": { "daysAfterModificationGreaterThan": 30 },
12            "tierToArchive": { "daysAfterModificationGreaterThan": 180 },
13            "delete": { "daysAfterModificationGreaterThan": 365 }
14          }
15        }
16      }
17    }
18  ]
19}

SAS quick table

SAS typeBest whenNotes
Service SASScoped to a resourceMost common “least privilege” SAS
Account SASBroadEasy to over-permission
User delegation SASBest securitySigned by Entra ID; no account key exposure

Common gotcha: SAS failures are often clock skew, expired token, or missing permissions on the exact resource path.

SAS generation (C# quick patterns)

 1using Azure.Storage.Sas;
 2
 3var builder = new BlobSasBuilder
 4{
 5    BlobContainerName = "docs",
 6    BlobName = "reports/2025-q4.pdf",
 7    Resource = "b",
 8    ExpiresOn = DateTimeOffset.UtcNow.AddMinutes(15)
 9};
10builder.SetPermissions(BlobSasPermissions.Read);
11
12var sasUri = blob.GenerateSasUri(builder);
13Console.WriteLine(sasUri);

7) Security — Identity platform, Entra ID, Graph, Key Vault

OAuth flow picker

ScenarioFlowWhy
Web app signing in a userAuthorization codeStandard OIDC pattern
Service-to-service (daemon)Client credentialsNo user context
CLI/device sign-inDevice codeWorks without browser redirect

MSAL (C#) — client credentials token

 1using Microsoft.Identity.Client;
 2
 3var app = ConfidentialClientApplicationBuilder
 4  .Create(clientId)
 5  .WithClientSecret(clientSecret)
 6  .WithAuthority($"https://login.microsoftonline.com/{tenantId}")
 7  .Build();
 8
 9var result = await app.AcquireTokenForClient(new[] { "https://graph.microsoft.com/.default" })
10  .ExecuteAsync();
11
12Console.WriteLine(result.AccessToken);

Microsoft Graph permissions (common confusion)

Permission typeUsed whenExample
Delegateduser is signed inUser.Read to call /me
Applicationdaemon/no user.default for app-only permissions

Call Microsoft Graph (HTTP example)

1using System.Net.Http.Headers;
2
3using var http = new HttpClient();
4http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
5
6var json = await http.GetStringAsync("https://graph.microsoft.com/v1.0/me");
7Console.WriteLine(json);

Managed identity + Key Vault (C#)

1using Azure.Identity;
2using Azure.Security.KeyVault.Secrets;
3
4var vaultUri = new Uri("https://myvault.vault.azure.net/");
5var client = new SecretClient(vaultUri, new DefaultAzureCredential());
6KeyVaultSecret secret = await client.GetSecretAsync("DbPassword");
    sequenceDiagram
	  participant App as "App Service / Function"
	  participant MSI as "Managed Identity"
	  participant AAD as "Entra ID"
	  participant KV as "Key Vault"
	  App->>MSI: Request token for Key Vault
	  MSI->>AAD: Get access token
	  AAD-->>MSI: Access token
	  MSI-->>App: Access token
	  App->>KV: GetSecret (Bearer token)
	  KV-->>App: Secret value

Key Vault vs App Configuration (fast picker)

StoreBest forWhy
Key Vaultsecrets/keys/certsrotation + auditing + access controls
App Configurationapp settings + feature flagscentralized config + refresh

8) API Management — the “policy exam”

High-yield policy snippets

Rate limiting

1<rate-limit-by-key calls="10" renewal-period="60" counter-key="@(context.Subscription.Key)" />

Validate JWT

1<validate-jwt header-name="Authorization" failed-validation-httpcode="401">
2  <openid-config url="https://login.microsoftonline.com/{tenantId}/v2.0/.well-known/openid-configuration" />
3  <required-claims>
4    <claim name="aud">
5      <value>{api-app-id-uri}</value>
6    </claim>
7  </required-claims>
8</validate-jwt>

CORS

1<cors allow-credentials="false">
2  <allowed-origins>
3    <origin>https://example.com</origin>
4  </allowed-origins>
5  <allowed-methods>
6    <method>GET</method>
7    <method>POST</method>
8  </allowed-methods>
9</cors>

Rewrite URL (common “legacy backend” fix)

1<rewrite-uri template="/v2/{uri}" />

Set backend (multi-backend routing)

1<set-backend-service base-url="https://mybackend.azurewebsites.net" />

Response caching

1<cache-lookup vary-by-developer="false" vary-by-developer-groups="false" />
2<cache-store duration="60" />

Policy scopes: global → product → API → operation (more specific overrides earlier scopes).

    flowchart LR
	  C["Client"] --> APIM["API Management"]
	  APIM --> POL["Policies (auth, throttling, transform)"]
	  POL --> BE["Backend API"]

Policy order matters: inbound runs before backend; outbound after backend response.


9) Eventing and messaging — choose the right service

The must-know chooser table

ServiceBest forKey traits
Event Gridevent routingpush, fan-out, filtering
Event Hubsstreaming ingestionpartitions, high throughput
Service Busenterprise messagingDLQ, sessions, transactions
Storage Queuessimple queuesbasic, cheap, fewer features

Feature matrix (what the question is usually testing)

FeatureEvent GridEvent HubsService BusStorage Queues
Primary jobroute eventsingest streamsreliable messagingsimple queue
Push vs pullpushpullpullpull
Orderingwithin partitionsessions/FIFO patternsbest-effort
Dead-letter queuedead-letteringconsumer designbuilt-in DLQcustom pattern
Transactions
Typical workloadapp/resource eventstelemetry/logscommands/work itemslightweight jobs
    flowchart LR
	  SRC["Source system"] --> EG["Event Grid"]
	  EG --> FN["Function handler"]
	  FN --> SB["Service Bus queue"]
	  SB --> WK["Worker"]

Event Grid: filter + dead-letter (conceptual)

  • Use filters to avoid “every event triggers everything.”
  • Use dead-lettering for undeliverable events (e.g., endpoint down long enough).

Event Hubs: producer (C# skeleton)

1using Azure.Messaging.EventHubs;
2using Azure.Messaging.EventHubs.Producer;
3
4await using var producer = new EventHubProducerClient(connectionString, "telemetry");
5using EventDataBatch batch = await producer.CreateBatchAsync();
6batch.TryAdd(new EventData(System.Text.Encoding.UTF8.GetBytes("{\"ok\":true}")));
7await producer.SendAsync(batch);

Service Bus: send (C# skeleton)

1using Azure.Messaging.ServiceBus;
2
3await using var client = new ServiceBusClient(connectionString);
4ServiceBusSender sender = client.CreateSender("orders");
5await sender.SendMessageAsync(new ServiceBusMessage("hello") { CorrelationId = "c-123" });

Service Bus: receive mode

ModeBehaviorWhen to use
Peek-lockprocess then settleMost reliable (handles failures)
Receive-and-deletedelete immediatelyOnly when loss is acceptable

Storage Queues: visibility timeout pattern (conceptual)

 1using Azure.Storage.Queues;
 2
 3var queue = new QueueClient(connectionString, "jobs");
 4await queue.CreateIfNotExistsAsync();
 5
 6await queue.SendMessageAsync("do-work");
 7var msg = await queue.ReceiveMessageAsync(visibilityTimeout: TimeSpan.FromMinutes(2));
 8
 9// Do work...
10await queue.DeleteMessageAsync(msg.Value.MessageId, msg.Value.PopReceipt);

Poison message rule: if the same message fails repeatedly, move it to a poison/dead-letter queue and alert.


10) Application Insights — what to do on failures

KQL quick wins

requests
| where success == false
| summarize count() by resultCode, operation_Name
| order by count_ desc
dependencies
| where duration > 2s
| summarize avg(duration), count() by target
| order by avg_duration desc
exceptions
| summarize count() by type, outerMessage
| order by count_ desc

Correlation tip: join on operation_Id to stitch requests → dependencies → exceptions for a single transaction.

Alerting defaults

  • Availability test fails (web test)
  • Error rate spike (failed requests)
  • Latency regression (p95 duration)

Fast troubleshooting checklist

  • Is it auth? 401/403 spikes, token failures, Key Vault denies
  • Is it dependency? DB/HTTP dependency duration spikes
  • Is it scale? throttling, queue backlog, timeouts
  • Is it deployment? slot swap/config drift, missing app settings

11) Common exam failure patterns (quick fixes)

SymptomLikely causeFirst fix to try
401 from APIwrong audience/issuerverify Entra app IDs + aud claim
403 from Key Vaultmissing RBAC/access policygrant least-privilege + verify identity
SAS “authentication failed”expired token / clock skewregenerate SAS; ensure UTC + expiry
Cosmos 429RU throttlingincrease RU/autoscale; optimize partition/query
Service Bus “lock lost”processing too slowrenew lock / shorten processing / increase concurrency
Event Grid delivery failuresendpoint down / auth mismatchfix handler auth; configure dead-letter
App Service works in staging but not prodslot settings swappedmark correct settings as slot settings

Keep going