Complete Implementation of a Message Envelope Using Newtonsoft.Json

Complete Implementation using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; // For serialization and deserialization public abstract class MessageEnvelope<T> { // Immutable properties 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 to enforce the use of the builder private MessageEnvelope() { } // Static method to start building the envelope public static Builder CreateBuilder() => new Builder(); // Nested Builder class public class Builder { private readonly MessageEnvelope<T> _envelope = new ConcreteMessageEnvelope(); public Builder WithEventType(string eventType) { if (string.IsNullOrWhiteSpace(eventType)) throw new ArgumentException("EventType cannot be null or empty"); _envelope.EventType = eventType; return this; } public Builder WithSourceService(string sourceService) { if (string.IsNullOrWhiteSpace(sourceService)) throw new ArgumentException("SourceService cannot be null or empty"); _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 Builder WithoutPayload() { _envelope.Payload = default; return this; } public MessageEnvelope<T> Build() { // Set defaults if not already set _envelope.EventType ??= "Unknown"; _envelope.Timestamp = _envelope.Timestamp == default ? DateTime.UtcNow : _envelope.Timestamp; _envelope.TraceId = _envelope.TraceId == default ? Guid.NewGuid() : _envelope.TraceId; return _envelope; } } // Clone method to replicate an envelope with modifications public MessageEnvelope<T> Clone() { return CreateBuilder() .WithEventType(this.EventType) .WithSourceService(this.SourceService) .WithPayload(this.Payload) .WithTimestamp(this.Timestamp) .WithTraceId(this.TraceId) .Build(); } // Serialization to JSON public string ToJson() { return JsonConvert.SerializeObject(this); } // Deserialization from JSON public static MessageEnvelope<T> FromJson(string json) { return JsonConvert.DeserializeObject<ConcreteMessageEnvelope>(json); } // Batch creation for multiple payloads public static IEnumerable<MessageEnvelope<T>> CreateBatch(IEnumerable<T> payloads, string eventType, string sourceService) { return payloads.Select(payload => CreateBuilder() .WithEventType(eventType) .WithSourceService(sourceService) .WithPayload(payload) .Build()); } // Example of a concrete implementation private class ConcreteMessageEnvelope : MessageEnvelope<T> { } } Examples 1. Basic Envelope Creation var envelope = MessageEnvelope<Reservation> .CreateBuilder() .WithEventType("ReservationExpiry") .WithSourceService("ReservationService") .WithPayload(new Reservation { ReservationId = "res-001", SlotId = "slot-123", ExpiryTime = DateTime.UtcNow }) .Build(); Console.WriteLine(envelope.ToJson()); 2. Creating an Envelope Without Payload var metadataOnlyEnvelope = MessageEnvelope<object> .CreateBuilder() .WithEventType("SystemEvent") .WithSourceService("MonitoringService") .WithoutPayload() .Build(); 3. Cloning an Envelope var clonedEnvelope = envelope.Clone(); Console.WriteLine(clonedEnvelope.ToJson()); 4. Batch Creation var reservations = new List<Reservation> { new Reservation { ReservationId = "res-001", SlotId = "slot-123", ExpiryTime = DateTime.UtcNow }, new Reservation { ReservationId = "res-002", SlotId = "slot-456", ExpiryTime = DateTime.UtcNow.AddHours(1) } }; var envelopes = MessageEnvelope<Reservation>.CreateBatch(reservations, "ReservationExpiry", "ReservationService"); foreach (var env in envelopes) { Console.WriteLine(env.ToJson()); } 5. Serialization and Deserialization string serialized = envelope.ToJson(); var deserialized = MessageEnvelope<Reservation>.FromJson(serialized); Console.WriteLine($"Deserialized TraceId: {deserialized.TraceId}"); Conclusion This implementation leverages Newtonsoft.Json to serialize and deserialize objects efficiently. The inclusion of batch creation, cloning, and flexibility makes this envelope a robust solution for designing reliable messaging systems in distributed architectures. ...

March 15, 2025 · 3 min · Taner

Message Envelopes in Message-Based Software Development

Message Envelopes in Message-Based Software Development In message-based software development, message envelopes are a design pattern used to wrap the core message with additional metadata. This metadata helps the messaging system process, route, or interpret the message without needing to understand its actual content. Key Features of Message Envelopes Header and Body Separation: The header contains metadata like routing information, encryption details, or timestamps. The body holds the actual message payload. Flexibility: ...

March 15, 2025 · 2 min · Taner

Updated Implementation Using `System.Text.Json`

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.

March 15, 2025 · 2 min · Taner