Tutorial2/5
2. The model and the Deserializer
Define the order message and implement the Deserializer.
Define the message
Section titled “Define the message”The send pipeline receives bytes, then works on a typed message. Replace In and the placeholder comment in Line.cs:
namespace OrderSync.Model;
public record In( string OrderId, string CustomerId, DateTimeOffset OrderDate, IReadOnlyList<Line> Lines);namespace OrderSync.Model;
public record Line( string Sku, int Quantity, decimal UnitPrice);Leave Out empty until chapter 3.
Implement the Deserializer
Section titled “Implement the Deserializer”Keep the existing ExecuteAsync signature. Replace only its body, from the opening { to the closing }:
{ 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.
Check it
Section titled “Check it”Replace the skipped placeholder in 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:
dotnet test ./test/OrderSync.Test.UnitPassed! - Failed: 0, Passed: 2, Skipped: 0, Total: 2 - OrderSync.Test.Unit.dll (net10.0)Both Deserializer tests should pass.