Skip to content
Tutorial2/5

2. The model and the Deserializer

Define the order message and implement the Deserializer.

The send pipeline receives bytes, then works on a typed message. Replace In and the placeholder comment in Line.cs:

src/Model/In.cs
namespace OrderSync.Model;
public record In(
string OrderId,
string CustomerId,
DateTimeOffset OrderDate,
IReadOnlyList<Line> Lines);
src/Model/Line.cs
namespace OrderSync.Model;
public record Line(
string Sku,
int Quantity,
decimal UnitPrice);

Leave Out empty until chapter 3.

Keep the existing ExecuteAsync signature. Replace only its body, from the opening { to the closing }:

src/Send/Deserializer.cs: ExecuteAsync body
{
var order = JsonSerializer.Deserialize<In>(input.Span,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true })!;
context.Metadata[Constants.ContextKeyOrderId] = order.OrderId;
context.Metadata[Constants.ContextKeyProcessedAt] = DateTimeOffset.UtcNow.ToString("O");
return Task.FromResult<(BusinessStepResult<In>, Context)>(
(new BusinessStepResult<In>.Success(order), context));
}

Store two context values:

  • ProcessedAt, read from the clock once.
  • OrderId, so later steps can name the order without re-parsing.

The metadata keys live in src/Configuration/Constants.cs.

Replace the skipped placeholder in test/OrderSync.Test.Unit/Send/DeserializerTests.cs:

test/OrderSync.Test.Unit/Send/DeserializerTests.cs
[Fact]
public async Task ExecuteAsync_WithValidJson_ReturnsSuccess()
{
var deserializer = new Deserializer();
var context = new Context(new Dictionary<string, string>());
var json = """{"orderId":"ORD-1001","customerId":"CUST-42","orderDate":"2026-01-15T09:30:00+00:00","lines":[{"sku":"SKU-1","quantity":2,"unitPrice":10.0}]}""";
var (result, _) = await deserializer.ExecuteAsync(
Encoding.UTF8.GetBytes(json), context, CancellationToken.None);
var success = Assert.IsType<BusinessStepResult<In>.Success>(result);
Assert.Equal("ORD-1001", success.Value.OrderId);
Assert.Single(success.Value.Lines);
}
[Fact]
public async Task ExecuteAsync_WithValidJson_StoresOrderIdAndProcessedAtInContext()
{
var deserializer = new Deserializer();
var context = new Context(new Dictionary<string, string>());
var json = """{"orderId":"ORD-1001","customerId":"CUST-42","orderDate":"2026-01-15T09:30:00+00:00","lines":[]}""";
var (_, resultContext) = await deserializer.ExecuteAsync(
Encoding.UTF8.GetBytes(json), context, CancellationToken.None);
Assert.Equal("ORD-1001", resultContext.Metadata[Constants.ContextKeyOrderId]);
Assert.True(resultContext.Metadata.ContainsKey(Constants.ContextKeyProcessedAt));
}

Run the unit suite:

Terminal window
dotnet test ./test/OrderSync.Test.Unit
Passed! - Failed: 0, Passed: 2, Skipped: 0, Total: 2 - OrderSync.Test.Unit.dll (net10.0)

Both Deserializer tests should pass.