Table of Contents

Class DynamoDbClient

Namespace
DynaSharp
Assembly
DynaSharp.dll

The client for Amazon DynamoDB: it owns the resolved configuration, the credentials and the HTTP connections that every request of the library runs on. The way in is Table<T>() for an entity that declares its table, Table<T>(string) to name it, and Table(string, string, string?) for a table without a model.

public sealed class DynamoDbClient : IDisposable
Inheritance
DynamoDbClient
Implements
Inherited Members
Extension Methods

Remarks

A table is the primary API: client.Table("Shop", "pk", "sk") gives a Table<T>, whose methods are the DynamoDB operations on items. The request API, with one method per DynamoDB operation that takes and returns the request and response records, is in the DynaSharp.Requests namespace: add using DynaSharp.Requests; and see DynamoDbRequests, which also describes how errors, retries and telemetry behave.

Create one client per application (or per region and credentials) and keep it for the lifetime of the process: it holds the HTTP connections. Instances are thread-safe, and every operation can run concurrently with others.

The client is configured through DynamoDbClientOptions. Whatever the options leave unset is read from the environment the way the AWS SDKs do (AWS_REGION, AWS_ENDPOINT_URL_DYNAMODB, AWS_ACCESS_KEY_ID and so on). Configuration problems surface when the client is created, not on the first request. Requests are signed with AWS Signature Version 4.

Dispose the client to release its connections. A client created with an HttpHandler does not dispose that handler.

Constructors

DynamoDbClient()

Initializes a new instance of the DynamoDbClient class that takes all settings from the environment: the region from AWS_REGION (or AWS_DEFAULT_REGION, or the selected profile in the shared AWS config file), the endpoint from AWS_ENDPOINT_URL_DYNAMODB (or AWS_ENDPOINT_URL, otherwise the public endpoint of the region) and the credentials from the default chain of the AWS SDKs, see DefaultCredentialsProvider.

public DynamoDbClient()

Exceptions

InvalidOperationException

No region is configured, or a region or endpoint environment variable is invalid.

DynamoDbClient(DynamoDbClientOptions)

Initializes a new instance of the DynamoDbClient class.

public DynamoDbClient(DynamoDbClientOptions options)

Parameters

options DynamoDbClientOptions

The settings. Options that are not set fall back to the environment, see DynamoDbClientOptions. The client reads the options once; changing the options object later has no effect.

Remarks

Credentials are not looked up here, but with the first request. A client without credentials is created successfully and fails its first request with a CredentialsUnavailableException. When Credentials is not set, the client uses a DefaultCredentialsProvider: environment variables, then a web identity token file (IRSA on EKS), then the shared AWS files, then the container credentials endpoint (ECS, EKS Pod Identity), then the instance metadata service (EC2). It logs the source it chose and failed refreshes to LoggerFactory. The only file read when the client is created is the shared AWS config file, and only when no region is set in the options or the environment.

Exceptions

ArgumentNullException

options or its TimeProvider is null.

ArgumentOutOfRangeException

AttemptTimeout is neither positive nor InfiniteTimeSpan, or exceeds about 49.7 days; or MaxAttempts is below 1.

ArgumentException

ServiceUrl is not an absolute http or https URL without user info, path, query and fragment.

InvalidOperationException

No region is configured, or a region or endpoint environment variable is invalid.

Properties

Options

Gets the options as the client resolved them when it was created: the region, the endpoint and the credentials provider it really uses, also those that came from the environment.

public DynamoDbClientOptions Options { get; }

Property Value

DynamoDbClientOptions

Remarks

Resolved once. A region from the environment or a profile and an endpoint from AWS_ENDPOINT_URL are here and not null, and Credentials is the provider in use, also the default chain that the client made itself. Nothing is read again, so the environment of today can say something else.

A second client. It is new DynamoDbClient(client.Options with { MaxAttempts = 1 }). It shares the provider and with it the cached credentials, and a handler the first client was given. A handler the first client made stays its own, so HttpHandler is null there and the second client makes one too, and each outlives the other.

The endpoint of the service stays out. ServiceUrl holds an endpoint that came from the options or from AWS_ENDPOINT_URL, which a copy keeps. The public endpoint that the client derived from its region, and one from AWS_ENDPOINT_URL_DYNAMODB (or AWS_ENDPOINT_URL_DYNAMODB_STREAMS for a streams client), are in use and still stay null here, on purpose: they belong to the service and the region of this client, not to a copy. So client.Options with { Region = other } goes to the endpoint of the new region, and new DynamoDbStreamsClient(client.Options) gets its own endpoint, also when AWS_ENDPOINT_URL_DYNAMODB is set.

The options hold a provider and not credentials, and ToString() prints only its type.

Methods

DescribeTableAsync(string, CancellationToken)

Reads the definition and state of a table by its name (DescribeTable): status, key schema, indexes and approximate counts, which DynamoDB updates about every six hours.

public Task<DescribeTableResponse> DescribeTableAsync(string tableName, CancellationToken cancellationToken = default)

Parameters

tableName string

The table name, or its ARN.

cancellationToken CancellationToken

Cancels the request.

Returns

Task<DescribeTableResponse>

The response. Table holds the description, and is null only if the response omits it.

Remarks

It is DescribeTableAsync(DynamoDbClient, DescribeTableRequest, CancellationToken) without a request to build and without using DynaSharp.Requests;, and it returns what that returns. A Table<T> at hand has DescribeTableAsync(CancellationToken).

The result is eventually consistent: right after creating a table it may still be reported as missing, which WaitUntilActiveAsync(CancellationToken) bears with.

Exceptions

ArgumentException

tableName is null or empty.

ObjectDisposedException

The client is disposed.

ResourceNotFoundException

The table does not exist.

ValidationException

DynamoDB rejects the request, for example because the table name is malformed.

AccessDeniedException

The credentials lack permission for dynamodb:DescribeTable on the table.

DynamoDbException

DynamoDB returns any other error, or a response that is not a DynamoDB response. A throttling or server error surfaces only when the last attempt failed with it too.

CredentialsUnavailableException

No credentials can be found.

HttpRequestException

The request could not be sent or the response could not be read, on every attempt.

TimeoutException

The last attempt did not complete within AttemptTimeout.

OperationCanceledException

cancellationToken was cancelled.

Dispose()

Releases the HTTP connections. Requests still running may fail. Calling it again has no effect.

public void Dispose()

Remarks

The handler given in HttpHandler is not disposed; its owner does that.

SendRawAsync(string, ReadOnlyMemory<byte>, CancellationToken)

Sends a DynamoDB operation by name, with a request body that you write as JSON, and returns the response body as JSON. It is for the operations and parameters that DynaSharp does not model: an operation without a request type, such as DescribeLimits or DescribeEndpoints, or a parameter that a modeled operation does not have yet.

public Task<byte[]> SendRawAsync(string operation, ReadOnlyMemory<byte> requestJson, CancellationToken cancellationToken = default)

Parameters

operation string

The operation name as DynamoDB knows it, for example DescribeLimits. It consists of ASCII letters and digits; it is sent as the X-Amz-Target header and is the operation of the span and the metrics of the call.

requestJson ReadOnlyMemory<byte>

The request body as UTF-8 bytes, such as """{}"""u8.ToArray(): a JSON object in the format of the DynamoDB API (AWS JSON 1.0), with attribute values in their typed form, for example {"TableName":"Users","Key":{"pk":{"S":"user-1"}}}, or {} for an operation without parameters. The bytes are copied; they are not read or checked, so DynamoDB reports a request it cannot parse. The memory can be reused as soon as the returned task has completed.

cancellationToken CancellationToken

Cancels the request.

Returns

Task<byte[]>

The body of the response as UTF-8 JSON, exactly as DynamoDB sent it. It is not parsed, so a success response that is not JSON is returned too.

Remarks

The call runs through the same pipeline as the operations of DynaSharp.Requests: it is signed, sent to the endpoint of the client, repeated as MaxAttempts says, bounded by AttemptTimeout, and an error response surfaces as the same DynamoDbException types, which name the operation. The retries send the same bytes again. As for every call, a retry can apply a write twice when the first attempt reached DynamoDB and its response was lost: guard such requests with a condition or an idempotency token of the operation, or set MaxAttempts to 1.

Telemetry is that of the other calls, minus what the library cannot read from JSON it does not parse: the span is named DynamoDB.<operation> and the duration, retry and throttle measurements carry the operation, but there is no table tag and no consumed capacity. The request and the response never appear in telemetry or logs.

Exceptions

ArgumentNullException

operation is null.

ArgumentException

operation is empty or contains a character other than an ASCII letter or digit.

ObjectDisposedException

The client is disposed.

ValidationException

DynamoDB rejects the request, for example because it is not valid JSON or has a parameter the operation does not know.

AccessDeniedException

The credentials lack permission for the operation.

DynamoDbException

DynamoDB returns any other error, an operation it does not know, or a response that is not a DynamoDB response. A throttling or server error surfaces only when the last attempt failed with it too.

CredentialsUnavailableException

No credentials can be found.

HttpRequestException

The request could not be sent or the response could not be read, on every attempt.

TimeoutException

The last attempt did not complete within AttemptTimeout.

OperationCanceledException

cancellationToken was cancelled.

Table(string, string, string?)

Opens a table without a schema, which reads and writes Item. It makes no request, so a table that does not exist shows up with the first command. Hold the result in a field: it is immutable and thread-safe.

public Table<Item> Table(string name, string partitionKey, string? sortKey = null)

Parameters

name string

The table name, or its ARN.

partitionKey string

The attribute name of the partition key.

sortKey string

The attribute name of the sort key, or null if the table has none.

Returns

Table<Item>

The table.

Exceptions

ArgumentException

name or partitionKey is null or empty, or sortKey is empty.

Table<T>()

Opens the table an entity declares, through Table or Table, as TableNaming names it. It makes no request, so a table that does not exist shows up with the first command.

public Table<T> Table<T>() where T : IDynamoDbEntity<T>

Returns

Table<T>

The table.

Type Parameters

T

The entity, which declares its table.

Examples

// Order declares [DynamoDbEntity(Table = "Shop")], or the assembly [assembly: DynamoDbDefaults(Table = "Shop")].
using var client = new DynamoDbClient(new DynamoDbClientOptions { TableNaming = name => $"dev-{name}" });
var orders = client.Table<Order>();        // "dev-Shop"
var scratch = client.Table<Order>("test-1"); // "test-1", as given

Remarks

Declared, then named. The declaration of the entity wins over the default of its assembly, and TableNaming, if set, turns the result into the name the client opens, such as dev-orders for orders. Table<T>(string) skips both and opens the name it is given.

Hold the result. The table is immutable and thread-safe, so a field or a singleton keeps it. Every call runs TableNaming again.

No declaration. An entity of the compilation that declares no table is DYNA238 at the call, and an entity from elsewhere throws here.

Exceptions

InvalidOperationException

T declares no table, or TableNaming returned null or an empty name.

Table<T>(string)

Opens a table as an entity type sees it: key names, indexes and discriminator come from the entity. It makes no request, so a table that does not exist shows up with the first command. Hold the result in a field: it is immutable and thread-safe.

public Table<T> Table<T>(string name) where T : IDynamoDbEntity<T>

Parameters

name string

The table name, or its ARN.

Returns

Table<T>

The table.

Type Parameters

T

The entity. A nested document has no key, so it does not fit here, which the constraint enforces, and neither does Item: a table without a schema is opened with Table(string, string, string?).

Exceptions

ArgumentException

name is null or empty.

TransactGet()

Starts a transaction of reads (TransactGetItems): up to 100 gets on any tables, which see one snapshot. See TransactGetCommand.

public TransactGetCommand TransactGet()

Returns

TransactGetCommand

The command.

TransactWrite()

Starts a transaction of writes (TransactWriteItems): up to 100 puts, updates, deletes and condition checks on any tables, which take effect together or not at all. See TransactWriteCommand.

public TransactWriteCommand TransactWrite()

Returns

TransactWriteCommand

The command, which needs an action before it can be sent.