Develop Solutions that Use Azure Blob Storage
This guide covers the AZ-204 exam topics for developing solutions with Azure Blob Storage:
- Set and retrieve properties and metadata
- Perform operations on data by using the appropriate SDK
- Implement storage policies and data lifecycle management
Prerequisites
- .NET SDK 8.0 (Install via winget: `winget install Microsoft.DotNet.SDK.8))
- Azure CLI (Install)
- Azure Functions Core Tools (Install)
- Azure Subscription (Free tier or $200 credit recommended)
- Existing Resource Group (
az204exam
)
Set Up Blob Storage
Note: We set up taskmanagerstoreyourname
in Functions for task JSONs (tasks
container). Here, we’ll add attachments
for files to keep them separate.
Follow these steps to set up Blob Storage:
-
Verify the Storage Account.
-
Create an
attachments
container. -
Confirm the connection string in the Function App.
Step 1: Verify Storage Account
In the Azure Portal, go to Storage accounts. Find taskmanagerstoreyourname
. If missing, create:
- Name:
taskmanagerstoreyourname
. - Resource group:
az204
. - Region:
West US3
. - Primary Service:
Azure Blob Storage or Azure Data Lake Storage Gen 2
. - Redundancy:
LRS
.
Step 2: Create Attachments Container
In taskmanagerstoreyourname
, go to Containers > + Container. Name: attachments
. Click Create.
Step 3: Confirm Connection String
Go to Access keys > Copy Connection string for key1
.
In your Function App (taskmanagerfunc-yourname
), go to Configuration > Application settings. Verify StorageConnection
(from Functions). If missing, add:
- Name:
StorageConnection
, Value:[your-connection-string]
. - Save and restart.
Perform Operations with the SDK
Note: We’ll add Functions to upload and download files to attachments
using the Blob SDK, prepping for web app file uploads.
Follow these steps to perform operations with the Blob Storage SDK:
-
Add the Blob Storage SDK.
-
Create an Upload Function.
-
Test locally (optional).
-
Deploy and test in Azure.
Step 1: Add Blob SDK
In TaskManagerFunctions
, run (if not added):
dotnet add package Azure.Storage.Blobs
Step 2: Create Upload Function
Create a new HTTP-triggered Function.
cd TaskManagerFunctions
func new --template "HttpTrigger" --name UploadAttachment
Edit UploadAttachment.cs
:
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Functions.Worker;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
namespace TaskManagerFunctions
{
public class UploadAttachment
{
private readonly ILogger<UploadAttachment> _logger;
public UploadAttachment(ILogger<UploadAttachment> logger)
{
_logger = logger;
}
[Function("UploadAttachment")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequest req)
{
try
{
_logger.LogInformation("Uploading file to attachments.");
// Validate content type
if (!req.HasFormContentType)
{
_logger.LogWarning("Invalid content type: {ContentType}", req.ContentType);
return new BadRequestObjectResult("Please send a multipart form.");
}
// Parse form
var form = await req.ReadFormAsync();
var file = form.Files.FirstOrDefault();
var taskId = form["taskId"];
_logger.LogInformation("Form parsed. File: {FileName}, TaskId: {TaskId}", file?.FileName, taskId);
// Validate form data
if (file == null || string.IsNullOrEmpty(taskId))
{
_logger.LogWarning("Missing file or taskId.");
return new BadRequestObjectResult("Please provide a file and taskId.");
}
// Get storage connection
var connectionString = Environment.GetEnvironmentVariable("StorageConnection");
if (string.IsNullOrEmpty(connectionString))
{
_logger.LogError("StorageConnection environment variable is missing or empty.");
return new StatusCodeResult(500);
}
// Initialize blob client
_logger.LogInformation("Initializing BlobServiceClient.");
var blobServiceClient = new BlobServiceClient(connectionString);
var containerClient = blobServiceClient.GetBlobContainerClient("attachments");
// Create container if it doesn't exist
_logger.LogInformation("Ensuring attachments container exists.");
await containerClient.CreateIfNotExistsAsync();
// Upload blob
var blobName = $"{taskId}/{file.FileName}";
var blobClient = containerClient.GetBlobClient(blobName);
_logger.LogInformation("Uploading file to blob: {BlobName}", blobName);
using (var stream = file.OpenReadStream())
{
await blobClient.UploadAsync(stream, new BlobUploadOptions
{
HttpHeaders = new BlobHttpHeaders { ContentType = file.ContentType },
Metadata = new Dictionary<string, string> { { "TaskId", taskId } }
});
}
_logger.LogInformation("Uploaded: {BlobName}", blobName);
return new OkObjectResult($"File uploaded: {blobName}");
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to upload file. Exception: {Message}, StackTrace: {StackTrace}", ex.Message, ex.StackTrace);
return new ObjectResult($"Error uploading file: {ex.Message}") { StatusCode = 500 };
}
}
}
}
Step 3: Test Locally (Optional)
Update local.settings.json
:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
"StorageConnection": "[your-connection-string]"
}
}
Run the Function locally:
func start
POST (use Postman or curl, with a file like test.txt
):
curl -X POST http://localhost:7071/api/UploadAttachment -F "taskId=test123" -F "file=@test.txt"
Check the attachments
container (Azurite or Azure Portal) for test123/test.txt
.
Step 4: Deploy and Test
Deploy the Function to Azure:
func azure functionapp publish taskmanagerfunc-yourname
Retrieve the Function key:
az functionapp function keys list --name taskmanagerfunc-yourname --resource-group az204 --function-name UploadAttachment
Test:
curl -X POST https://taskmanagerfunc-yourname.azurewebsites.net/api/uploadattachment?code=[your-key] -F "taskId=test123" -F "file=@test.txt"
Verify in Azure Portal > taskmanagerstoreyourname
> attachments
.
Why
Uploads files with the SDK, showing create operations for the exam.
Set and Retrieve Properties and Metadata
Note: We’ll get the file’s content type and metadata (task ID) to show exam skills.
Follow these steps to set and retrieve properties and metadata:
-
Create a Download Function.
-
Test locally (optional).
-
Deploy and test in Azure.
Step 1: Create Download Function
Create a new HTTP-triggered Function.
cd TaskManagerFunctions
func new --template "HttpTrigger" --name GetAttachment
Edit GetAttachment.cs
:
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Functions.Worker;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Azure.Storage.Blobs;
using Azure;
namespace TaskManagerFunctions
{
public class GetAttachment
{
private readonly ILogger<GetAttachment> _logger;
public GetAttachment(ILogger<GetAttachment> logger)
{
_logger = logger;
}
[Function("GetAttachment")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get")] HttpRequest req)
{
try
{
_logger.LogInformation("Retrieving file metadata.");
// Validate query parameters
string? taskId = req.Query["taskId"];
string? fileName = req.Query["fileName"];
_logger.LogInformation("Query parameters: taskId={TaskId}, fileName={FileName}", taskId, fileName);
if (string.IsNullOrEmpty(taskId) || string.IsNullOrEmpty(fileName))
{
_logger.LogWarning("Missing taskId or fileName in query parameters.");
return new BadRequestObjectResult("Please provide taskId and fileName.");
}
// Get storage connection
var connectionString = Environment.GetEnvironmentVariable("StorageConnection");
if (string.IsNullOrEmpty(connectionString))
{
_logger.LogError("StorageConnection environment variable is missing or empty.");
return new StatusCodeResult(500);
}
// Initialize blob client
_logger.LogInformation("Initializing BlobServiceClient.");
var blobServiceClient = new BlobServiceClient(connectionString);
var containerClient = blobServiceClient.GetBlobContainerClient("attachments");
var blobName = $"{taskId}/{fileName}";
var blobClient = containerClient.GetBlobClient(blobName);
_logger.LogInformation("Accessing blob: {BlobName}", blobName);
// Get blob properties
var properties = await blobClient.GetPropertiesAsync();
var metadata = properties.Value.Metadata;
var contentType = properties.Value.ContentType;
// Safely access metadata
string? metadataTaskId = metadata.ContainsKey("TaskId") ? metadata["TaskId"] : null;
_logger.LogInformation("Blob properties retrieved. TaskId={TaskId}, ContentType={ContentType}, Uri={Uri}",
metadataTaskId, contentType, blobClient.Uri);
return new OkObjectResult(new
{
TaskId = metadataTaskId,
ContentType = contentType,
Uri = blobClient.Uri
});
}
catch (RequestFailedException ex) when (ex.Status == 404)
{
_logger.LogWarning("Blob not found: {ErrorMessage}", ex.Message);
return new NotFoundResult();
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to retrieve file metadata. Exception: {Message}, StackTrace: {StackTrace}",
ex.Message, ex.StackTrace);
return new ObjectResult($"Error retrieving file metadata: {ex.Message}") { StatusCode = 500 };
}
}
}
}
Step 2: Test Locally (Optional)
Run the Function locally:
func start
GET:
curl http://localhost:7071/api/GetAttachment?taskId=test123&fileName=test.txt
Expect JSON: {"TaskId":"test123","ContentType":"text/plain","Uri":"..."}
.
Step 3: Deploy and Test
Deploy the Function to Azure:
func azure functionapp publish taskmanagerfunc-yourname
Retrieve the Function key:
az functionapp function keys list --name taskmanagerfunc-yourname --resource-group az204 --function-name GetAttachment
Test:
curl https://taskmanagerfunc-yourname.azurewebsites.net/api/getattachment?code=[your-key]&taskId=test123&fileName=test.txt
Verify metadata and properties.
Why
Shows setting and getting metadata/properties, a key exam topic.
Implement Storage Policies and Data Lifecycle Management
Note: We’ll delete old files in attachments
to manage costs.
Follow these steps to implement storage policies and data lifecycle management:
-
Create a lifecycle rule.
-
Verify the lifecycle rule.
Step 1: Create Lifecycle Rule
In the Azure Portal, go to taskmanagerstoreyourname
> Data Management > Lifecycle management > Add rule.
- Rule name:
ArchiveOldFiles
. - Scope: Filter to
attachments/
(typeattachments/
in Blob prefix). - Conditions:
- Blob type: Block blobs.
- Not modified for 1 days.
- Actions:
- Delete Blob.
- Feel free to set up your own rules here.
- Click Add.
Step 2: Verify
- Upload a file via
UploadAttachment
. - Wait 1 day (or use a test account to simulate).
- Check
attachments
> Confirm old files are deleted.
Why
Lifecycle rules reduce storage costs, an exam must-know.