System.Text.Json
Use System.Text.Json for JSON serialization of [JsonBlob] properties. This is the recommended serializer for new projects, especially those targeting AOT compilation.
Installation
dotnet add package Oproto.FluentDynamoDb.SystemTextJson
Configuration
Configure System.Text.Json at runtime using FluentDynamoDbOptions:
using Oproto.FluentDynamoDb;
using Oproto.FluentDynamoDb.SystemTextJson;
// Default options
var options = new FluentDynamoDbOptions()
.WithSystemTextJson();
var table = new DocumentTable(dynamoDbClient, "documents", options);
Custom JsonSerializerOptions
Pass custom JsonSerializerOptions to control serialization behavior:
var jsonOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = false,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
var options = new FluentDynamoDbOptions()
.WithSystemTextJson(jsonOptions);
var table = new DocumentTable(dynamoDbClient, "documents", options);
AOT-Compatible Configuration
For Native AOT scenarios, use a JsonSerializerContext to enable source-generated serialization:
// 1. Define your JSON context with types that need serialization
[JsonSerializable(typeof(DocumentContent))]
[JsonSerializable(typeof(List<string>))]
public partial class DocumentJsonContext : JsonSerializerContext
{
}
// 2. Configure FluentDynamoDbOptions with the context
var options = new FluentDynamoDbOptions()
.WithSystemTextJson(DocumentJsonContext.Default);
var table = new DocumentTable(dynamoDbClient, "documents", options);
Entity Definition
Use the [JsonBlob] attribute on properties that should be serialized as JSON strings in DynamoDB:
[DynamoDbTable("documents")]
public partial class Document
{
[PartitionKey]
[DynamoDbAttribute("pk")]
public string Pk { get; set; } = string.Empty;
[SortKey]
[DynamoDbAttribute("sk")]
public string Sk { get; set; } = string.Empty;
[DynamoDbAttribute("title")]
public string Title { get; set; } = string.Empty;
// This property will be serialized as a JSON string
[JsonBlob]
[DynamoDbAttribute("content")]
public DocumentContent Content { get; set; } = new();
}
public class DocumentContent
{
public string Body { get; set; } = string.Empty;
public List<string> Tags { get; set; } = new();
public Dictionary<string, object> Metadata { get; set; } = new();
}
Usage Example
// Configure options
var options = new FluentDynamoDbOptions()
.WithSystemTextJson();
var table = new DocumentTable(dynamoDbClient, "documents", options);
// Create a document with complex content
var document = new Document
{
Pk = Document.Keys.Pk("doc123"),
Sk = Document.Keys.Sk(),
Title = "My Document",
Content = new DocumentContent
{
Body = "Document body text",
Tags = new List<string> { "important", "draft" },
Metadata = new Dictionary<string, object>
{
{ "author", "John Doe" },
{ "version", 1 }
}
}
};
// Save - Content is automatically serialized to JSON
await table.Documents.PutAsync(document);
// Retrieve - Content is automatically deserialized from JSON
var retrieved = await table.Documents.GetAsync("doc123");
Console.WriteLine(retrieved?.Content.Body); // "Document body text"
Custom Converters
Register custom JsonConverter implementations for specialized serialization:
var jsonOptions = new JsonSerializerOptions();
jsonOptions.Converters.Add(new CustomDateTimeConverter());
jsonOptions.Converters.Add(new CustomEnumConverter());
var options = new FluentDynamoDbOptions()
.WithSystemTextJson(jsonOptions);
Example: Custom DateTime Converter
public class CustomDateTimeConverter : JsonConverter<DateTime>
{
private const string Format = "yyyy-MM-dd'T'HH:mm:ss.fffZ";
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return DateTime.ParseExact(reader.GetString()!, Format, CultureInfo.InvariantCulture);
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToUniversalTime().ToString(Format, CultureInfo.InvariantCulture));
}
}
Error Handling
If you use [JsonBlob] without configuring a JSON serializer, you'll get a runtime exception:
// This will throw at runtime
var options = new FluentDynamoDbOptions(); // No JSON serializer configured!
var table = new DocumentTable(dynamoDbClient, "documents", options);
await table.Documents.PutAsync(document);
// InvalidOperationException: Property 'Content' has [JsonBlob] attribute but no JSON serializer is configured.
// Call .WithSystemTextJson() or .WithNewtonsoftJson() on FluentDynamoDbOptions.
Best Practices
- Use AOT configuration for production - Source-generated serialization is faster and supports Native AOT
- Configure once, reuse - Create
FluentDynamoDbOptionsonce and reuse across table instances - Match serialization settings - Use consistent
JsonSerializerOptionsacross your application - Handle nulls explicitly - Configure
DefaultIgnoreConditionbased on your requirements