Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 25 additions & 13 deletions docs/sdk-reference/state/serialization.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,13 @@ Each SDK uses a default SerDes when you do not provide one.

=== "C#"

There is no per-operation default SerDes. Register a single `ILambdaSerializer` at the
host boundary and the SDK uses it for every durable operation result.
The default is the single `ILambdaSerializer` registered at the host boundary — the SDK
uses it for every durable operation result and for the handler's return value. An
optional per-operation override is available (see
[Custom SerDes on durable operations](#custom-serdes-on-durable-operations)): set
`Serializer` on `StepConfig`, `CallbackConfig`, `InvokeConfig`,
`WaitForConditionConfig<TState>`, or `ChildContextConfig` to use a different
`ILambdaSerializer` for that one operation.

Use `DefaultLambdaJsonSerializer` (from `Amazon.Lambda.Serialization.SystemTextJson`)
for reflection-based serialization. For AOT or trim-friendly functions, use
Expand Down Expand Up @@ -163,8 +168,10 @@ Each SDK uses a default SerDes when you do not provide one.

=== "C#"

.NET has no per-operation SerDes interface. Serialization is controlled by the single
`ILambdaSerializer` registered on `ILambdaContext.Serializer`.
.NET has no separate per-operation SerDes interface — it reuses the standard
`ILambdaSerializer` contract. Serialization defaults to the single `ILambdaSerializer`
registered on `ILambdaContext.Serializer`, and an individual operation can override it
by setting `Serializer` (an `ILambdaSerializer`) on that operation's config.

```csharp
--8<-- "examples/csharp/sdk-reference/serialization/SerdesInterface.cs"
Expand Down Expand Up @@ -240,9 +247,10 @@ same handler continue to use the default.

=== "C#"

`StepConfig` does not expose a serializer. The step result is serialized with the
`ILambdaSerializer` registered at the host boundary. Register a custom
`ILambdaSerializer` there to change how step results are serialized.
Set `StepConfig.Serializer` to serialize this step's result with a specific
`ILambdaSerializer`. When it is `null` (default), the step result is serialized with the
`ILambdaSerializer` registered at the host boundary. Only this step is affected; other
operations and the handler's return value continue to use the registered serializer.

```csharp
--8<-- "examples/csharp/sdk-reference/serialization/StepConfigExample.cs"
Expand Down Expand Up @@ -276,9 +284,10 @@ system sends when it completes the callback.

=== "C#"

`CallbackConfig` does not expose a serializer. The payload the external system delivers
is deserialized with the `ILambdaSerializer` registered at the host boundary. Register a
custom `ILambdaSerializer` there to change how the callback payload is deserialized.
Set `CallbackConfig.Serializer` to deserialize the callback payload with a specific
`ILambdaSerializer`. When it is `null` (default), the payload the external system
delivers is deserialized with the `ILambdaSerializer` registered at the host boundary.
Only the deserialize path is used for callbacks.

```csharp
--8<-- "examples/csharp/sdk-reference/serialization/CallbackConfigExample.cs"
Expand Down Expand Up @@ -320,9 +329,12 @@ Map and parallel perations support two SerDes fields that apply at different lev

=== "C#"

`MapConfig` does not expose a serializer, and there is no separate item-level
serializer. Each item result is serialized with the `ILambdaSerializer` registered at
the host boundary. `ParallelConfig` likewise has no serializer field.
Set `MapConfig<TItem>.ItemSerializer` (and `ParallelConfig.ItemSerializer`) to serialize
each item / branch **result** with a specific `ILambdaSerializer`. When `null` (default),
item results use the `ILambdaSerializer` registered at the host boundary. There is no
separate whole-result serializer: the aggregated batch envelope (per-item statuses and
completion reason) is an SDK-internal, source-generated structure and is not
user-serialized — only the per-item results are.

```csharp
--8<-- "examples/csharp/sdk-reference/serialization/MapConfigExample.cs"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Amazon.Lambda.Core;
using Amazon.Lambda.DurableExecution;
using Amazon.Lambda.Serialization.SystemTextJson;

public class CallbackConfigExample
{
Expand All @@ -9,13 +10,14 @@ public Task<DurableExecutionInvocationOutput> Handler(

private async Task<ApprovalResult> Workflow(object input, IDurableContext ctx)
{
// CallbackConfig has no serializer slot. The callback payload delivered by
// the external system is deserialized with the ILambdaSerializer registered
// on ILambdaContext.Serializer. To customize deserialization, register a
// custom ILambdaSerializer at the host boundary.
// Set CallbackConfig.Serializer to deserialize the callback payload with a specific
// ILambdaSerializer. When null (default), the payload the external system delivers is
// deserialized with the ILambdaSerializer registered on ILambdaContext.Serializer.
// Only the deserialize path is used for callbacks.
var config = new CallbackConfig
{
Timeout = TimeSpan.FromHours(1),
Serializer = new DefaultLambdaJsonSerializer(),
};

ICallback<ApprovalResult> callback =
Expand Down
10 changes: 7 additions & 3 deletions examples/csharp/sdk-reference/serialization/MapConfigExample.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Amazon.Lambda.Core;
using Amazon.Lambda.DurableExecution;
using Amazon.Lambda.Serialization.SystemTextJson;

public class MapConfigExample
{
Expand All @@ -9,12 +10,15 @@ public Task<DurableExecutionInvocationOutput> Handler(

private async Task<IReadOnlyList<ProcessedItem>> Workflow(object input, IDurableContext ctx)
{
// MapConfig has no serializer slot. Each item result is serialized with the
// ILambdaSerializer registered on ILambdaContext.Serializer. To customize
// serialization, register a custom ILambdaSerializer at the host boundary.
// Set MapConfig.ItemSerializer to serialize each item's RESULT with a specific
// ILambdaSerializer. When null (default), item results are serialized with the
// ILambdaSerializer registered on ILambdaContext.Serializer. This controls only the
// per-item result — not the aggregated batch envelope (statuses / completion
// reason), which is SDK-internal. ParallelConfig has the same ItemSerializer field.
var config = new MapConfig<string>
{
MaxConcurrency = 3,
ItemSerializer = new CamelCaseLambdaJsonSerializer(),
};

var items = new[] { "a", "b", "c" };
Expand Down
10 changes: 6 additions & 4 deletions examples/csharp/sdk-reference/serialization/StepConfigExample.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Amazon.Lambda.Core;
using Amazon.Lambda.DurableExecution;
using Amazon.Lambda.Serialization.SystemTextJson;

public class StepConfigExample
{
Expand All @@ -9,13 +10,14 @@ public Task<DurableExecutionInvocationOutput> Handler(

private async Task<Order> Workflow(object input, IDurableContext ctx)
{
// StepConfig has no serializer slot. The step result is serialized with
// the ILambdaSerializer registered on ILambdaContext.Serializer. To
// customize serialization, register a custom ILambdaSerializer at the
// host boundary instead of setting a per-step SerDes.
// Set StepConfig.Serializer to serialize THIS step's result with a specific
// ILambdaSerializer. When null (default), the step result is serialized with the
// ILambdaSerializer registered on ILambdaContext.Serializer. Only this step is
// affected — other operations and the handler's return value are unchanged.
var config = new StepConfig
{
RetryStrategy = RetryStrategy.Exponential(maxAttempts: 3),
Serializer = new CamelCaseLambdaJsonSerializer(),
};

Order order = await ctx.StepAsync(
Expand Down
Loading