Skip to content

Integration BlobStorage Extension

aryehcitron@gmail.com edited this page May 24, 2026 · 12 revisions

The Kronikol.Extensions.BlobStorage package adds Azure Blob Storage operation tracking to your test diagrams. Instead of showing raw HTTP requests like PUT /mycontainer/myblob.txt?comp=blocklist, your sequence diagrams show classified operations like Upload: /mycontainer/myblob.txt or ListBlobs: /mycontainer.

Using a shared library or abstraction layer? If your code doesn't use the Blob Storage SDK directly — e.g. it goes through a shared storage library, wrapper, or custom abstraction — this extension won't be able to intercept the underlying calls. See Tracking Custom Dependencies for alternative approaches including RequestResponseLogger.LogPair(), TrackingProxy<T>, and MessageTracker.


How It Works

The Azure Blob Storage SDK translates all operations into HTTP requests to the Azure Storage REST API. BlobTrackingMessageHandler is a DelegatingHandler that intercepts these HTTP requests, classifies each one into a Blob operation (Upload, Download, Delete, ListBlobs, etc.) using the HTTP method, URL path, and query parameters, then logs it to RequestResponseLogger with a human-readable label.

Because it logs to the same RequestResponseLogger as the standard TestTrackingMessageHandler, Blob Storage operations appear alongside your HTTP API calls in the same sequence diagram — showing the complete flow from test → API → Blob Storage.


Install

dotnet add package Kronikol.Extensions.BlobStorage

Verbosity Levels

The extension supports three verbosity levels that control how much detail appears in the diagrams:

Level Method shown URI shown Headers Request body Response body
Raw HTTP method (PUT, GET, etc.) Full URI with query parameters All except excluded set Full content Full content
Detailed Classified operation (Upload) Clean path without query params (/mycontainer/myblob.txt) Filtered (noisy Storage headers excluded) Full content Full content
Summarised Classified operation (Upload) Clean path (/mycontainer/myblob.txt) None None None

The default is Detailed.

Diagram Label Examples

Operation Raw Detailed Summarised
Upload blob PUT: /mycontainer/myblob.txt Upload: /mycontainer/myblob.txt Upload: /mycontainer/myblob.txt
Download blob GET: /mycontainer/myblob.txt Download: /mycontainer/myblob.txt Download: /mycontainer/myblob.txt
Delete blob DELETE: /mycontainer/myblob.txt Delete: /mycontainer/myblob.txt Delete: /mycontainer/myblob.txt
Get blob properties HEAD: /mycontainer/myblob.txt GetProperties: /mycontainer/myblob.txt GetProperties: /mycontainer/myblob.txt
List blobs GET: /mycontainer?restype=container&comp=list ListBlobs: /mycontainer ListBlobs: /mycontainer
Create container PUT: /mycontainer?restype=container CreateContainer: /mycontainer CreateContainer: /mycontainer
Set metadata PUT: /mycontainer/myblob.txt?comp=metadata SetMetadata: /mycontainer/myblob.txt SetMetadata: /mycontainer/myblob.txt
Put block list PUT: /mycontainer/myblob.txt?comp=blocklist PutBlockList: /mycontainer/myblob.txt PutBlockList: /mycontainer/myblob.txt
SDK metadata GET: /mycontainer?restype=container Other: /mycontainer (skipped)

Classified Operations

The classifier recognises these Blob Storage operations from the SDK's HTTP traffic:

Operation HTTP Pattern
Upload PUT /{container}/{blob} (no comp parameter)
Download GET /{container}/{blob} (no comp parameter)
Delete DELETE /{container}/{blob}
GetProperties HEAD /{container}/{blob}
SetMetadata PUT /{container}/{blob}?comp=metadata
GetMetadata GET /{container}/{blob}?comp=metadata
Copy PUT /{container}/{blob}?comp=copy
PutBlock PUT /{container}/{blob}?comp=block
PutBlockList PUT /{container}/{blob}?comp=blocklist
Lease PUT /{container}/{blob}?comp=lease
CreateContainer PUT /{container}?restype=container
DeleteContainer DELETE /{container}?restype=container
ListBlobs GET /{container}?restype=container&comp=list
Other Unrecognised or SDK metadata requests

In Summarised mode, Other operations are silently skipped.


Setup

Option A: With BlobClientOptions Extension (Recommended)

var trackingOptions = new BlobTrackingMessageHandlerOptions
{
    ServiceName = "BlobStorage",
    CallerName = "My API",
    Verbosity = BlobTrackingVerbosity.Detailed,
    CurrentTestInfoFetcher = CurrentTestInfo.Fetcher
};

var clientOptions = new BlobClientOptions();
clientOptions.WithTestTracking(trackingOptions);

var client = new BlobServiceClient(connectionString, clientOptions);

WithTestTracking sets the Transport property on BlobClientOptions to route all HTTP requests through the tracking handler.

Option B: Manual HttpClient Construction

If you need more control over the HTTP pipeline:

var trackingOptions = new BlobTrackingMessageHandlerOptions
{
    ServiceName = "BlobStorage",
    CallerName = "My API",
    Verbosity = BlobTrackingVerbosity.Detailed,
    CurrentTestInfoFetcher = CurrentTestInfo.Fetcher
};

var trackingHandler = new BlobTrackingMessageHandler(trackingOptions);
var httpClient = new HttpClient(trackingHandler);
var transport = new Azure.Core.Pipeline.HttpClientTransport(httpClient);

var clientOptions = new BlobClientOptions
{
    Transport = transport
};

var client = new BlobServiceClient(connectionString, clientOptions);

Option C: In DI-based Tests (WebApplicationFactory)

builder.ConfigureTestServices(services =>
{
    // Replace BlobServiceClient with one that uses the tracking transport
    services.AddSingleton(sp =>
    {
        var trackingOptions = new BlobTrackingMessageHandlerOptions
        {
            ServiceName = "BlobStorage",
            CallerName = "My API",
            Verbosity = BlobTrackingVerbosity.Detailed,
            CurrentTestInfoFetcher = CurrentTestInfo.Fetcher
        };

        var clientOptions = new BlobClientOptions();
        clientOptions.WithTestTracking(trackingOptions);

        return new BlobServiceClient("UseDevelopmentStorage=true", clientOptions);
    });
});

Configuration Reference

BlobTrackingMessageHandlerOptions

Property Type Default Description
ServiceName string "BlobStorage" The participant name shown in the diagram for the Blob Storage service
CallerName string "Caller" The participant name shown for the service making Blob Storage calls
Verbosity BlobTrackingVerbosity Detailed Controls how much detail appears in the diagram (Raw, Detailed, Summarised)
CurrentTestInfoFetcher Func<(string Name, string Id)>? null Returns the current test's name and ID. Required — if null, requests are forwarded but not logged
CurrentStepTypeFetcher Func<string?>? null Optional — returns the current BDD step type (Given/When/Then)
HttpContextAccessor IHttpContextAccessor? null Optional — enables dual-resolution of test identity from HTTP headers. Auto-resolved by DI extensions (v2.26.3+). See HTTP Tracking Setup#Dual-Resolution Test Identity (v2.23.0+)
ExcludedHeaders HashSet<string> See below Headers to exclude from diagrams in Raw/Detailed mode
SetupVerbosity BlobTrackingVerbosity? null Verbosity override for the Setup phase. See Phase-Aware Tracking
ActionVerbosity BlobTrackingVerbosity? null Verbosity override for the Action phase. See Phase-Aware Tracking
TrackDuringSetup bool true When false, tracking is suppressed during Setup. See Phase-Aware Tracking
TrackDuringAction bool true When false, tracking is suppressed during Action. See Phase-Aware Tracking

v2.23.0+ Dual-Resolution: BlobTrackingMessageHandler accepts an optional IHttpContextAccessor? httpContextAccessor constructor parameter for resolving test identity from HTTP request headers when running inside the SUT's request pipeline. v2.26.3+: Set HttpContextAccessor on BlobTrackingMessageHandlerOptions instead — the tracker reads it automatically. See HTTP Tracking Setup#Dual-Resolution Test Identity (v2.23.0+) for details.

Default Excluded Headers

The following Azure Storage headers are excluded by default (they add noise without diagnostic value):

  • Authorization
  • x-ms-date
  • x-ms-version
  • x-ms-client-request-id
  • x-ms-return-client-request-id
  • User-Agent
  • Cache-Control

Override ExcludedHeaders to customise:

new BlobTrackingMessageHandlerOptions
{
    ExcludedHeaders = ["Authorization", "x-ms-date"] // Only exclude these two
}

CurrentTestInfoFetcher by Framework

Every framework package provides a CurrentTestInfo static class with a Fetcher property. The syntax is identical regardless of framework - just ensure you have the correct using directive:

CurrentTestInfoFetcher = CurrentTestInfo.Fetcher
Framework using directive
xUnit v3 using Kronikol.xUnit3;
xUnit v2 using Kronikol.xUnit2;
NUnit 4 using Kronikol.NUnit4;
MSTest using Kronikol.MSTest;
TUnit using Kronikol.TUnit;
LightBDD using Kronikol.LightBDD;
ReqNRoll using Kronikol.ReqNRoll;
BDDfy using Kronikol.BDDfy.xUnit3;

Extension Methods

BlobClientOptions.WithTestTracking()

public static BlobClientOptions WithTestTracking(
    this BlobClientOptions options,
    BlobTrackingMessageHandlerOptions trackingOptions,
    HttpMessageHandler? innerHandler = null)

Configures BlobClientOptions to use BlobTrackingMessageHandler. Sets options.Transport to an HttpClientTransport backed by an HttpClient wrapping the tracking handler. The optional innerHandler parameter sets the inner handler (defaults to HttpClientHandler).


Invocation Validation

BlobTrackingMessageHandler implements ITrackingComponent and auto-registers with TrackingComponentRegistry on construction. At report generation time, unused components are automatically detected and surfaced as console warnings and in the diagnostic report (when DiagnosticMode=true). This never throws or fails tests.

See Diagnostics and Debugging for full details on the TrackingComponentRegistry API.

Home


Demo


Getting Started

Common Tasks

Integration Guides

Extensions

Configuration

Features

Reference

Clone this wiki locally