Feature: Azure Blob Storage Provider (ManagedCode.Storage.Azure)

Purpose

Implement IStorage on top of Azure Blob Storage using the Azure SDK, including streaming and metadata operations.

Main Flows

flowchart LR
  App --> AzureStorage[AzureStorage : IAzureStorage]
  AzureStorage --> BlobClient[Azure SDK BlobContainerClient/BlobClient]
  BlobClient --> Azure[(Azure Blob Storage)]

Components

DI Wiring

dotnet add package ManagedCode.Storage.Azure
using ManagedCode.Storage.Azure.Extensions;

builder.Services.AddAzureStorageAsDefault(options =>
{
    options.Container = "my-container";
    options.ConnectionString = configuration["Azure:ConnectionString"];
});

Current Behavior

Metadata transport

Ordinary metadata with native Azure identifier keys and printable ASCII values is stored directly. A dictionary requiring encoding is stored as one reserved managedcode_storage_metadata_v1 value: utf8-json-base64: followed by the base64 of the complete UTF-8 JSON string dictionary. Reads restore the logical dictionary once. A caller-supplied reserved key is itself wrapped, so its value cannot be confused with provider metadata. Invalid recognized envelopes fail instead of returning opaque transport values. Invalid UTF-16 input is rejected before writing; the provider never substitutes characters.

flowchart LR
  Caller["Logical string dictionary"] --> Transport["AzureMetadataTransport"]
  Transport --> Native["Native printable ASCII metadata"]
  Transport --> Envelope["Versioned ASCII envelope"]
  Native --> Azure["Azure metadata headers"]
  Envelope --> Azure
  Azure --> Decode["Decode once on metadata reads"]
  Decode --> Result["Original logical metadata"]

Azure’s physical metadata-size limits still apply, including envelope overhead. Content bytes, content type, conditional ETags and exact immutable retry matching are unchanged. Objects written directly with ordinary native ASCII metadata remain readable without reinterpretation of percent escapes or value prefixes.

Tests

References

Result failure status

The IStorage result APIs preserve an Azure service failure’s HTTP status and native error code. Missing blob stream/metadata/download reads return a failed result with status 404 and BlobNotFound; authentication failures retain their actual 403 status and Azure code. A normal missing stream is returned without an exception-level log. Successful streaming, idempotent deletion and the optional object-capability throwing contracts keep their existing semantics. Unexpected non-service failures retain the standard problem classification.