using System; using System.IO; using System.Runtime.Serialization.Json; namespace AppDiagnostic.Logging { public static class DiagnosticMessageSerializer { private static readonly DataContractJsonSerializer Serializer = new DataContractJsonSerializer(typeof(DiagnosticLogEntry)); private static readonly object SerializerLock = new object(); public static byte[] Serialize(DiagnosticLogEntry entry) { if (entry == null) { throw new ArgumentNullException(nameof(entry)); } using (var stream = new MemoryStream()) { lock (SerializerLock) { Serializer.WriteObject(stream, entry); } return stream.ToArray(); } } public static DiagnosticLogEntry Deserialize(byte[] payload) { if (payload == null) { throw new ArgumentNullException(nameof(payload)); } if (payload.Length == 0 || payload.Length > DiagnosticProtocol.MaximumMessageSize) { throw new InvalidDataException("Invalid diagnostic message size."); } using (var stream = new MemoryStream(payload, false)) { lock (SerializerLock) { return (DiagnosticLogEntry)Serializer.ReadObject(stream); } } } public static void WriteFramed(Stream stream, DiagnosticLogEntry entry) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } byte[] payload = Serialize(entry); if (payload.Length > DiagnosticProtocol.MaximumMessageSize) { throw new InvalidDataException("Diagnostic message is too large."); } byte[] length = BitConverter.GetBytes(payload.Length); stream.Write(length, 0, length.Length); stream.Write(payload, 0, payload.Length); stream.Flush(); } public static DiagnosticLogEntry ReadFramed(Stream stream) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } byte[] lengthBuffer = ReadExactly(stream, sizeof(int)); int payloadLength = BitConverter.ToInt32(lengthBuffer, 0); if (payloadLength <= 0 || payloadLength > DiagnosticProtocol.MaximumMessageSize) { throw new InvalidDataException("Invalid diagnostic message size."); } return Deserialize(ReadExactly(stream, payloadLength)); } private static byte[] ReadExactly(Stream stream, int count) { byte[] buffer = new byte[count]; int offset = 0; while (offset < count) { int bytesRead = stream.Read(buffer, offset, count - offset); if (bytesRead == 0) { throw new EndOfStreamException(); } offset += bytesRead; } return buffer; } } }