Skip to main content

Binary Assets in Blob Storage

Table Storage held the metadata; the actual bytes — camera images, panoramas, videos, map tiles, location boundary files — live in Blob Storage. Most of this layer is exactly as dull as you'd hope: upload, download, delete. The one thing worth stopping on is a small dependency-injection trick that looks like three separate stores but is one.

The one idea to hold on to​

ISingleImageStorageRepository, IPanoImageStorageRepository, and IPreStitchImageStorageRepository are three marker interfaces over a single ImageStorageRepository — all pointing at the same container. The class implements all three, and every registration hands back the identical thing:

public class ImageStorageRepository : AzureStorageRepository<byte[]>,
ISingleImageStorageRepository, IPanoImageStorageRepository, IPreStitchImageStorageRepository

// all three DI registrations:
new ImageStorageRepository(blobServiceClient, blobStorageOptions.ContainerName);

So why three names? So a service that only handles panoramas injects IPanoImageStorageRepository and reads as if panoramas were their own store — the interface documents intent at the call site. But single, pano, and pre-stitch images share one physical container; they're told apart by blob name, not by container.

Gotcha: the three image types are not isolated

Because all three interfaces resolve to the same container, there's no storage-level boundary between single, pano, and pre-stitch images. A naming collision across the "three stores" is a real collision on one container. If you need them physically separated, that's a config and registration change — the interfaces alone won't do it.

The base class​

Every blob repository inherits AzureStorageRepository<T>, which is the whole upload/download surface: DoesBlobExists, GetFileBlobAsync (bytes plus metadata as a BlobEntity), UploadFileBlobAsync (with or without a metadata dictionary), UploadZipBlobAsync (builds a ZIP at a chosen CompressionLevel), and DeleteFromBlob.

ImageStorageRepository adds the image-shaped conveniences on top — UploadImageAsync (the metadata overload carries PTZ position and timestamps), UploadImageAsZipAsync (used to archive pre-stitch frames), and DownloadImagesAsync (parallel bulk download).

Wrapping up​

Blob Storage is the byte store, and it's mostly plain CRUD over per-purpose containers. The one thing to carry forward: the three image interfaces are ergonomic aliases over a single ImageStorageRepository and a single shared container — convenient for injection, but not a real boundary between image types.

Next, the asynchronous side of storage — one service class wearing nine queue identities: One Service, Nine Queues.