Newtonsoft.Json
Use Newtonsoft.Json (Json.NET) for JSON serialization of [JsonBlob] properties. This serializer is useful when you need advanced features like polymorphic serialization or have existing Newtonsoft.Json infrastructure.
Installation
dotnet add package Oproto.FluentDynamoDb.NewtonsoftJson
Configuration
Configure Newtonsoft.Json at runtime using FluentDynamoDbOptions:
using Oproto.FluentDynamoDb;
using Oproto.FluentDynamoDb.NewtonsoftJson;
// Default settings
var options = new FluentDynamoDbOptions()
.WithNewtonsoftJson();
var table = new DocumentTable(dynamoDbClient, "documents", options);
Custom JsonSerializerSettings
Pass custom JsonSerializerSettings to control serialization behavior:
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
var jsonSettings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
DateFormatHandling = DateFormatHandling.IsoDateFormat,
Formatting = Formatting.None
};
var options = new FluentDynamoDbOptions()
.WithNewtonsoftJson(jsonSettings);
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()
.WithNewtonsoftJson();
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 jsonSettings = new JsonSerializerSettings();
jsonSettings.Converters.Add(new CustomDateTimeConverter());
jsonSettings.Converters.Add(new StringEnumConverter());
var options = new FluentDynamoDbOptions()
.WithNewtonsoftJson(jsonSettings);
Example: Polymorphic Serialization
Newtonsoft.Json excels at polymorphic serialization with type handling:
var jsonSettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto,
SerializationBinder = new KnownTypesBinder
{
KnownTypes = new List<Type> { typeof(TextContent), typeof(ImageContent) }
}
};
var options = new FluentDynamoDbOptions()
.WithNewtonsoftJson(jsonSettings);
// Base class
public abstract class ContentBase
{
public string Type { get; set; } = string.Empty;
}
// Derived types
public class TextContent : ContentBase
{
public string Text { get; set; } = string.Empty;
}
public class ImageContent : ContentBase
{
public string Url { get; set; } = string.Empty;
public int Width { get; set; }
public int Height { get; set; }
}
// Entity with polymorphic content
[DynamoDbTable("posts")]
public partial class Post
{
[PartitionKey]
[DynamoDbAttribute("pk")]
public string Pk { get; set; } = string.Empty;
[JsonBlob]
[DynamoDbAttribute("content")]
public ContentBase Content { get; set; } = null!;
}
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.
When to Use Newtonsoft.Json
Consider Newtonsoft.Json when you need:
- Polymorphic serialization with
TypeNameHandling - Custom contract resolvers for complex mapping scenarios
- Reference handling for circular references
- Compatibility with existing Newtonsoft.Json infrastructure
For new projects without these requirements, consider using System.Text.Json for better performance and AOT support.
Best Practices
- Configure once, reuse - Create
FluentDynamoDbOptionsonce and reuse across table instances - Match serialization settings - Use consistent
JsonSerializerSettingsacross your application - Avoid TypeNameHandling.All - Use
TypeNameHandling.AutoorTypeNameHandling.Objectswith a custom binder for security - Handle nulls explicitly - Configure
NullValueHandlingbased on your requirements