Skip to content

Integration DynamoDB Extension

Aryeh Citron edited this page Apr 26, 2026 · 10 revisions

The TestTrackingDiagrams.Extensions.DynamoDB package adds Amazon DynamoDB operation tracking to your test diagrams. Instead of showing raw HTTP requests like POST https://dynamodb.us-east-1.amazonaws.com/, your sequence diagrams show classified operations like PutItem with a clean dynamodb:///Users URI.

Using a shared library or abstraction layer? If your code doesn't use the DynamoDB SDK directly — e.g. it goes through a shared data-access 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 AWS SDK for .NET translates all DynamoDB operations into HTTP POST requests to a single endpoint. The operation type is encoded in the X-Amz-Target header (e.g. DynamoDB_20120810.PutItem) and the table name is in the JSON request body's TableName field. DynamoDbTrackingMessageHandler is a DelegatingHandler that:

  1. Reads the request body to extract the table name (since it's in the JSON, not the URL)
  2. Classifies the operation from the X-Amz-Target header
  3. Reconstructs the request content so the inner handler can still read it
  4. Logs the request/response to RequestResponseLogger

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


Install

dotnet add package TestTrackingDiagrams.Extensions.DynamoDB

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 (POST) Full original URI All except excluded set Full content Full content
Detailed Classified operation (PutItem) dynamodb:///TableName Filtered (noisy AWS headers excluded) Full content Full content
Summarised Classified operation (PutItem) dynamodb:///TableName None None None

The default is Detailed.

Diagram Label Examples

Operation Raw Detailed Summarised
Put item POST: https://dynamodb.us-east-1.amazonaws.com/ PutItem: dynamodb:///Users PutItem: dynamodb:///Users
Get item POST: https://dynamodb.us-east-1.amazonaws.com/ GetItem: dynamodb:///Users GetItem: dynamodb:///Users
Query POST: https://dynamodb.us-east-1.amazonaws.com/ Query: dynamodb:///Orders Query: dynamodb:///Orders
Batch write POST: https://dynamodb.us-east-1.amazonaws.com/ BatchWriteItem: dynamodb:///Users, Orders BatchWriteItem: dynamodb:///Users, Orders
PartiQL POST: https://dynamodb.us-east-1.amazonaws.com/ ExecuteStatement: dynamodb:/// ExecuteStatement: dynamodb:///
Unrecognised POST: https://dynamodb.us-east-1.amazonaws.com/ Other: dynamodb:/// (skipped)

Classified Operations

The classifier recognises these DynamoDB operations from the X-Amz-Target header:

Category Operations
CRUD PutItem, GetItem, UpdateItem, DeleteItem
Queries Query, Scan
Batch BatchWriteItem, BatchGetItem
Transactions TransactWriteItems, TransactGetItems
Table management CreateTable, DeleteTable, DescribeTable, ListTables, UpdateTable
PartiQL ExecuteStatement, BatchExecuteStatement, ExecuteTransaction
Fallback Other (unrecognised target header)

Table Name Extraction

  • Single-table operations (PutItem, GetItem, Query, etc.): Extracted from the "TableName" field in the JSON body
  • Batch operations (BatchWriteItem, BatchGetItem): Extracted from the keys of the "RequestItems" object, producing a comma-separated list like Users, Orders
  • PartiQL operations: The "Statement" field is extracted for potential use in detailed logging
  • Table management: Extracted from the "TableName" field

In Summarised mode, Other operations are silently skipped.


Setup

Option A: With AmazonDynamoDBConfig Extension (Recommended)

var trackingOptions = new DynamoDbTrackingMessageHandlerOptions
{
    ServiceName = "DynamoDB",
    CallingServiceName = "My API",
    Verbosity = DynamoDbTrackingVerbosity.Detailed,
    CurrentTestInfoFetcher = () =>
    {
        var test = TestContext.Current.Test;
        return test is not null
            ? (test.TestDisplayName, test.UniqueID)
            : ("Unknown", "unknown");
    }
};

var config = new AmazonDynamoDBConfig
{
    RegionEndpoint = RegionEndpoint.USEast1
};
config.WithTestTracking(trackingOptions);

var client = new AmazonDynamoDBClient(credentials, config);

WithTestTracking sets the HttpClientFactory property on AmazonDynamoDBConfig to route all HTTP requests through the tracking handler. This requires no production code changes.

Option B: Manual HttpClient Construction

If you need more control over the HTTP pipeline:

var trackingOptions = new DynamoDbTrackingMessageHandlerOptions
{
    ServiceName = "DynamoDB",
    CallingServiceName = "My API",
    Verbosity = DynamoDbTrackingVerbosity.Detailed,
    CurrentTestInfoFetcher = () =>
    {
        var test = TestContext.Current.Test;
        return test is not null
            ? (test.TestDisplayName, test.UniqueID)
            : ("Unknown", "unknown");
    }
};

var trackingHandler = new DynamoDbTrackingMessageHandler(trackingOptions);
// Use trackingHandler with your own HttpClient / AWS pipeline customization

Option C: In DI-based Tests (WebApplicationFactory)

builder.ConfigureTestServices(services =>
{
    services.AddSingleton<IAmazonDynamoDB>(sp =>
    {
        var trackingOptions = new DynamoDbTrackingMessageHandlerOptions
        {
            ServiceName = "DynamoDB",
            CallingServiceName = "My API",
            Verbosity = DynamoDbTrackingVerbosity.Detailed,
            CurrentTestInfoFetcher = () =>
            {
                var test = TestContext.Current.Test;
                return test is not null
                    ? (test.TestDisplayName, test.UniqueID)
                    : ("Unknown", "unknown");
            }
        };

        var config = new AmazonDynamoDBConfig
        {
            RegionEndpoint = RegionEndpoint.USEast1,
            ServiceURL = "http://localhost:8000" // e.g. DynamoDB Local
        };
        config.WithTestTracking(trackingOptions);

        return new AmazonDynamoDBClient(new BasicAWSCredentials("test", "test"), config);
    });
});

Configuration Reference

DynamoDbTrackingMessageHandlerOptions

Property Type Default Description
ServiceName string "DynamoDB" The participant name shown in the diagram for the DynamoDB service
CallingServiceName string "Caller" The participant name shown for the service making DynamoDB calls
Verbosity DynamoDbTrackingVerbosity 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)

v2.23.0+ Dual-Resolution: DynamoDbTrackingMessageHandler accepts an optional IHttpContextAccessor? httpContextAccessor constructor parameter for resolving test identity from HTTP request headers when running inside the SUT's request pipeline. See HTTP Tracking Setup#Dual-Resolution Test Identity (v2.23.0+) for details.

v2.23.0+ Dual-Resolution: DynamoDbTrackingMessageHandler accepts an optional IHttpContextAccessor? httpContextAccessor constructor parameter for resolving test identity from HTTP request headers when running inside the SUT's request pipeline. See HTTP Tracking Setup#Dual-Resolution Test Identity (v2.23.0+) for details. | ExcludedHeaders | HashSet<string> | See below | Headers to exclude from diagrams in Raw/Detailed mode | | SetupVerbosity | DynamoDbTrackingVerbosity? | null | Verbosity override for the Setup phase. See Phase-Aware Tracking | | ActionVerbosity | DynamoDbTrackingVerbosity? | 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 |

Default Excluded Headers

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

  • Authorization
  • x-amz-date
  • x-amz-security-token
  • x-amz-content-sha256
  • User-Agent
  • amz-sdk-invocation-id
  • amz-sdk-request

Override ExcludedHeaders to customise:

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

Body Reconstruction

Unlike most HTTP tracking handlers, DynamoDB tracking needs special handling: because DynamoDB encodes the operation type in the request body (not just the URL), the handler must read the request body before forwarding. After reading and classifying, it reconstructs the request content with the original body and Content-Type header so the inner handler (the AWS SDK) can still consume it.

This is transparent — your production code and the AWS SDK continue to work normally.


ITrackingComponent

DynamoDbTrackingMessageHandler implements ITrackingComponent and auto-registers with TrackingComponentRegistry. You can use this to assert that DynamoDB was (or wasn't) invoked during a test:

var handler = new DynamoDbTrackingMessageHandler(options);

// ... run test ...

Assert.True(handler.WasInvoked);
Assert.Equal(3, handler.InvocationCount);

Or use TrackingComponentRegistry.GetUnusedComponents() at the end of each test to find services that were wired up but never called.

Home


Demo


Getting Started

Common Tasks

Integration Guides

Extensions

Configuration

Features

Reference

Clone this wiki locally