Updated Implementation Using System.Text.Json
#
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
public abstract class MessageEnvelope<T>
{
// Properties remain immutable
public string EventType { get; private init; }
public string SourceService { get; private init; }
public DateTime Timestamp { get; private init; }
public Guid TraceId { get; private init; }
public T Payload { get; private init; }
// Private constructor for builder use only
private MessageEnvelope() { }
public static Builder CreateBuilder() => new Builder();
// Serialization to JSON
public string ToJson()
{
var options = new JsonSerializerOptions
{
WriteIndented = true // Makes the output JSON easier to read
};
return JsonSerializer.Serialize(this, options);
}
// Deserialization from JSON
public static MessageEnvelope<T> FromJson(string json)
{
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true // Handles case differences in JSON properties
};
return JsonSerializer.Deserialize<ConcreteMessageEnvelope>(json, options);
}
// Concrete implementation example for proper deserialization
private class ConcreteMessageEnvelope : MessageEnvelope<T> { }
public class Builder
{
private readonly MessageEnvelope<T> _envelope = new ConcreteMessageEnvelope();
public Builder WithEventType(string eventType)
{
_envelope.EventType = eventType;
return this;
}
public Builder WithSourceService(string sourceService)
{
_envelope.SourceService = sourceService;
return this;
}
public Builder WithPayload(T payload)
{
_envelope.Payload = payload;
return this;
}
public Builder WithTimestamp(DateTime timestamp)
{
_envelope.Timestamp = timestamp;
return this;
}
public Builder WithTraceId(Guid traceId)
{
_envelope.TraceId = traceId;
return this;
}
public MessageEnvelope<T> Build()
{
_envelope.Timestamp = _envelope.Timestamp == default ? DateTime.UtcNow : _envelope.Timestamp;
_envelope.TraceId = _envelope.TraceId == default ? Guid.NewGuid() : _envelope.TraceId;
return _envelope;
}
}
}
Example Usage#
1. Serialize a MessageEnvelope to JSON#
var envelope = MessageEnvelope<Reservation>
.CreateBuilder()
.WithEventType("ReservationExpiry")
.WithSourceService("ReservationService")
.WithPayload(new Reservation
{
ReservationId = "res-001",
SlotId = "slot-123",
ExpiryTime = DateTime.UtcNow
})
.Build();
string serialized = envelope.ToJson();
Console.WriteLine($"Serialized Envelope:\n{serialized}");
2. Deserialize a JSON String to MessageEnvelope#
string json = "{\"EventType\":\"ReservationExpiry\",\"SourceService\":\"ReservationService\",\"Timestamp\":\"2025-03-25T17:00:00Z\",\"TraceId\":\"8a1db2c2-ec3e-45f7-a3eb-bd9dfb351245\",\"Payload\":{\"ReservationId\":\"res-001\",\"SlotId\":\"slot-123\",\"ExpiryTime\":\"2025-03-25T17:00:00Z\"}}";
var deserializedEnvelope = MessageEnvelope<Reservation>.FromJson(json);
Console.WriteLine($"Deserialized EventType: {deserializedEnvelope.EventType}");
Console.WriteLine($"Deserialized Reservation ID: {deserializedEnvelope.Payload.ReservationId}");
Benefits of Serialization#
- Portability: You can transmit envelopes as JSON over APIs, message brokers, or store them in databases.
- Interoperability: Many systems can parse JSON, making serialized envelopes easy to integrate across platforms.
- Flexibility: Deserialization lets you reconstruct envelopes when receiving messages.
Advantages of System.Text.Json
#
- Performance: Faster than
Newtonsoft.Json
, especially for large-scale applications. - Built-in Support: No need for external dependencies; it’s natively part of .NET Core and .NET 5+.
- Configuration Options: Flexible JSON options like camel casing, case insensitivity, and indented formatting.
Related Posts