Skip to content

docs(csharp): document the .NET FileSystem serializer (#2540) - #280

Open
GarrettBeatty wants to merge 4 commits into
aws:mainfrom
GarrettBeatty:filesystem-serializer-docs
Open

GarrettBeatty wants to merge 4 commits into
aws:mainfrom
GarrettBeatty:filesystem-serializer-docs

Conversation

@GarrettBeatty

Copy link
Copy Markdown
Contributor

Summary

Fills in the C# tabs of the existing FileSystem serdes section of the serialization reference, documenting the new .NET FileSystemSerializer. Companion to the SDK PR aws/aws-lambda-dotnet#2558.

Stacked on #279. This branch is cut from #279's branch (per-operation-serializer-docs), so until #279 merges to main this PR's diff also shows #279's two commits. Review/merge #279 first; the only commit unique to this PR is docs(csharp): document the FileSystem serializer.

What changed

C# tabs (previously "Not available") now covered in docs/sdk-reference/state/serialization.md:

  • Walkthrough — FileSystemSerializer wrapping an inner ILambdaSerializer, passed via StepConfig.Serializer (and Child/WaitForCondition/Map/Parallel).
  • Constructor signature — inner, basePath, storageMode, pathEncoding.
  • Inner serializer / compression — the .NET-specific angle: the inner serializer controls the on-the-wire format; a gzip wrapper compresses before writing to disk.
  • Storage modes — Always vs Overflow.
  • Path encoding — Uri vs Hash.

New C# example snippets under examples/csharp/sdk-reference/serialization/ (FileSystemSerdesWalkthrough / Signature / Compression / Overflow / PathEncoding).

Noted as follow-ups (not yet in the .NET SDK)

  • Preview & PII masking — not supported yet in the .NET serializer.
  • Execution-wide default serializer — .NET is per-operation only for now (mirrors the deferred hook in #2558).

The .NET SDK now supports an optional per-operation `Serializer` (an ILambdaSerializer)
on StepConfig, CallbackConfig, InvokeConfig, WaitForConditionConfig<TState>, and
ChildContextConfig; when null the globally-registered serializer is used.

Update the C# tabs on the serialization page (Default serialization, SerDes interface,
StepConfig, CallbackConfig) and the StepConfigExample/CallbackConfigExample examples.
Map/Parallel C# tabs left as-is pending two-level (item + whole-result) support.
MapConfig<TItem> and ParallelConfig now expose ItemSerializer for each item/branch result;
the aggregated batch envelope is SDK-internal and not user-serialized (no whole-result
serializer). Update the Map/Parallel C# tab and MapConfigExample.
Fill in the C# tabs of the FileSystem serdes section: walkthrough, constructor signature,
inner-serializer/compression, storage modes (Always/Overflow), and path encoding (Uri/Hash),
with matching csharp example snippets. Note preview/masking and an execution-wide default
serializer as planned follow-ups. Documents aws/aws-lambda-dotnet#2558.
Document the new FileSystemSerializer(basePath, storageMode?, pathEncoding?)
constructor that reuses the host-boundary ILambdaSerializer as the inner
(bound by the durable runtime when used through a per-operation slot), and
note that an explicit inner wins and that using it with no bound inner throws.
@GarrettBeatty
GarrettBeatty marked this pull request as ready for review September 8, 2026 18:46
@GarrettBeatty
GarrettBeatty temporarily deployed to ai-pr-review-runtime September 8, 2026 18:46 — with GitHub Actions Inactive
zhongkechen added a commit that referenced this pull request Oct 28, 2026
Document missing operation config signatures, incremental parallel
branches, custom subtype rules, terminal serializer failures, and local
checkpoint-token omission for Core 2.2.0 and Testing 1.1.0.

Leave the serialization guide and its examples to PRs #279 and #280.
Keep shared prose and other language updates in PR #300. All remaining
Markdown changes are inside C# tabs; no file overlaps #279 or #280.

Validate formatting, spelling, snippets, vendored assets, rendered links,
and a clean Zensical build. Retained examples match the previously
compiled and runtime-checked versions.

@zhongkechen zhongkechen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Carrying over 11 outstanding .NET serialization review comments from #300 to #280. Each inline thread links to the original feedback and the follow-up confirming it remains unaddressed here. These corrections remain open in #280; resolving their source threads in #300 records the transfer, not a completed fix.

Comment on lines +520 to +523
A `FileSystemSerializer` built without an inner serializer only resolves the global
serializer when it is used through a per-operation slot (for example
`StepConfig.Serializer`). Using it as a plain `ILambdaSerializer` with no bound inner —
for instance as the host-boundary serializer — throws `InvalidOperationException`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Carried over from the original review comment on #300 by SilanHe, with the follow-up confirming it remains unaddressed in #280. Please track the correction here.

Original feedback (line references refer to the version reviewed in #300):

C# failure mode is half right. NotSupportedException is thrown when used as a plain ILambdaSerializer. InvalidOperationException is thrown only when the inner serializer is missing.

Comment on lines +6 to +7
// The inner serializer controls the on-the-wire format. Wrap one to compress results before
// they are written to the filesystem — FileSystemSerializer just handles storage.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Carried over from the original review comment on #300 by SilanHe, with the follow-up confirming it remains unaddressed in #280. Please track the correction here.

Original feedback (line references refer to the version reviewed in #300):

Four em-dashes, plus long comments that repeat the page prose. Both break the authoring guide.

The current version still has an em dash and a prose-style explanatory comment at lines 6–7; the count in the original feedback describes the version reviewed in #300.

Comment on lines +102 to +108
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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Carried over from the original review comment on #300 by yaythomas, with the follow-up confirming it remains unaddressed in #280. Please track the correction here.

Original feedback (line references refer to the version reviewed in #300):

The C# tabs on this page state one fact five times: the registered serializer is the default, and a per-operation serializer overrides it. The statements are at lines 91-94, 132-138, 231-234, 247-248, and 331-334. Could the page state it once, here, and keep the later tabs to what each section adds? This list also leaves out ItemSerializer on MapConfig<TItem> and ParallelConfig, and the per-branch serializer on IDurableParallel.Branch.

Comment on lines +171 to +174
.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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Carried over from the original review comment on #300 by yaythomas, with the follow-up confirming it remains unaddressed in #280. Please track the correction here.

Original feedback (line references refer to the version reviewed in #300):

Core 2.0.0 added IDurableResultSerializer, an optional interface for per-operation serializers. Its Serialize<T> and Deserialize<T> overloads receive a DurableSerializationContext, which has EntityId and DurableExecutionArn properties. The runtime calls these overloads when the configured serializer implements the interface. FileSystemSerializer implements it. So "no separate per-operation SerDes interface" is not accurate for 2.x. Could this tab document IDurableResultSerializer, the way the Java tab now documents SerDesContext?

[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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Carried over from the original review comment on #300 by yaythomas, with the follow-up confirming it remains unaddressed in #280. Please track the correction here.

Original feedback (line references refer to the version reviewed in #300):

This tab now says a per-operation override affects only the selected operation. The C# tab of "Custom SerDes example" (lines 284-285) still says "The custom serializer applies to every durable operation result, not a single operation." With StepConfig.Serializer and the other per-operation properties, that sentence is no longer true. Could that tab change in this PR too, so the page gives one answer?

In this PR, the conflicting "Custom SerDes example" wording is at lines 215–216 of this file; this thread is anchored to the changed per-operation guidance.

Comment on lines +287 to +290
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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Carried over from the original review comment on #300 by yaythomas, with the follow-up confirming it remains unaddressed in #280. Please track the correction here.

Original feedback (line references refer to the version reviewed in #300):

This also uses passive voice. How about this?

Set CallbackConfig.Serializer to deserialize the callback payload with a specific ILambdaSerializer. When it is null, the SDK deserializes the payload with the ILambdaSerializer registered at the host boundary. The SDK never serializes a callback result, so it calls only Deserialize.

Comment on lines +332 to +337
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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Carried over from the original review comment on #300 by yaythomas, with the follow-up confirming it remains unaddressed in #280. Please track the correction here.

Original feedback (line references refer to the version reviewed in #300):

The last sentence here chains two colons, uses passive voice, and names an implementation detail ("source-generated"). How about this?

Set MapConfig<TItem>.ItemSerializer or ParallelConfig.ItemSerializer to serialize each item or branch result with a specific ILambdaSerializer. When it is null, item results use the serializer registered at the host boundary. The SDK writes the batch envelope (item statuses and the completion reason) itself, so there is no whole-result serializer.

Comment on lines +607 to +609
`FileSystemStorageMode.Always` (default) writes every result to a file; the checkpoint
holds only the pointer. `FileSystemStorageMode.Overflow` keeps the result inline until it
would exceed the durable execution checkpoint size limit, then spills to a file.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Carried over from the original review comment on #300 by yaythomas, with the follow-up confirming it remains unaddressed in #280. Please track the correction here.

Original feedback (line references refer to the version reviewed in #300):

In Overflow mode, the .NET serializer base64-encodes the serialized bytes into a {"data": ...} envelope. It then compares the envelope's size with 255 KiB. Base64 adds a third to the size. I tested 2.2.0: a 190 KiB string stayed inline, and a 192 KiB string went to a file. So inline storage ends near 191 KiB of serialized bytes, not at the checkpoint limit. The comment in FileSystemSerdesOverflow.cs (lines 12-13) also says "~256 KB". Could both state the 255 KiB envelope rule, the way the Java tab states its own?

Comment on lines +763 to +766
Not yet supported in the .NET SDK. Set `FileSystemSerializer` per operation via
`StepConfig.Serializer` (or `ItemSerializer` for Map/Parallel). An execution-wide default
serializer hook is planned as a follow-up; until then, the single `ILambdaSerializer` you
register at the host boundary applies to any operation that does not set its own.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Carried over from the original review comment on #300 by yaythomas, with the follow-up confirming it remains unaddressed in #280. Please track the correction here.

Original feedback (line references refer to the version reviewed in #300):

"Not yet supported" and "is not supported" say the same thing, and "yet" promises future work. The Java tab gives the reason, and the same reason applies here: FileSystemSerializer throws NotSupportedException at the host boundary. How about this?

The FileSystem serializer cannot be the handler-wide default, because the host-boundary serializer also handles Lambda input and output, which have no operation identity. Set it per operation through StepConfig.Serializer or ItemSerializer.

var config = new CallbackConfig
{
Timeout = TimeSpan.FromHours(1),
Serializer = new DefaultLambdaJsonSerializer(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Carried over from the original review comment on #300 by yaythomas, with the follow-up confirming it remains unaddressed in #280. Please track the correction here.

Original feedback (line references refer to the version reviewed in #300):

DefaultLambdaJsonSerializer is also the usual host-boundary serializer, so this override looks the same as the default. The Step and Map examples use CamelCaseLambdaJsonSerializer. Could this one use it too?

This branch had an error being deployed

1 failed and 1 inactive deployments
ai-pr-review-runtime — 36646684 Deployed Sep 8, 2026 by GarrettBeatty via ai-pr-review / Codex review / Generate Codex review #108
ai-pr-review — 36646684 Deployed Sep 8, 2026 by GarrettBeatty via ai-pr-review / Approve AI PR review #108
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants