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