/// <summary> /// Perform event to message encoding /// </summary> /// <param name="message"></param> /// <returns></returns> public IEnumerable <NetworkMessageModel> Encode(DataSetMessageModel message) { foreach (var notification in message.Notifications) { var value = new MonitoredItemMessage { MessageContentMask = (message.Writer?.MessageSettings? .DataSetMessageContentMask).ToMonitoredItemMessageMask( message.Writer?.DataSetFieldContentMask), ApplicationUri = message.ApplicationUri, EndpointUrl = message.EndpointUrl, ExtensionFields = message.Writer?.DataSet?.ExtensionFields, NodeId = notification.NodeId, Value = notification.Value, DisplayName = notification.DisplayName }; using (var writer = new StringWriter()) { using (var encoder = new JsonEncoderEx(writer, message.ServiceMessageContext) { // TODO: Configure encoding further UseUriEncoding = true }) { value.Encode(encoder); } var encoded = new NetworkMessageModel { Body = Encoding.UTF8.GetBytes(writer.ToString()), ContentEncoding = "utf-8", Timestamp = DateTime.UtcNow, ContentType = ContentMimeType.Json, MessageId = message.SequenceNumber.ToString(), MessageSchema = MessageSchemaTypes.MonitoredItemMessageJson }; yield return(encoded); } } }
/// <inheritdoc/> public JToken Encode(Variant value, out BuiltInType builtinType, ServiceMessageContext context) { if (value == Variant.Null) { builtinType = BuiltInType.Null; return(JValue.CreateNull()); } using (var stream = new MemoryStream()) { using (var encoder = new JsonEncoderEx(stream, context ?? Context) { UseAdvancedEncoding = true }) { encoder.WriteVariant(nameof(value), value); } var json = Encoding.UTF8.GetString(stream.ToArray()); try { var token = JToken.Parse(json); Enum.TryParse((string)token.SelectToken("value.Type"), true, out builtinType); return(token.SelectToken("value.Body")); } catch (JsonReaderException jre) { throw new FormatException($"Failed to parse '{json}'. " + "See inner exception for more details.", jre); } } }
/// <summary> /// Perform event to message Json encoding /// </summary> /// <param name="messages"></param> /// <returns></returns> private IEnumerable <NetworkMessageModel> EncodeAsJson( IEnumerable <DataSetMessageModel> messages) { var notifications = GetMonitoredItemMessages(messages, MessageEncoding.Json); if (notifications.Count() == 0) { yield break; } var encodingContext = messages.First().ServiceMessageContext; foreach (var networkMessage in notifications) { var writer = new StringWriter(); var encoder = new JsonEncoderEx(writer, encodingContext) { UseAdvancedEncoding = true, UseUriEncoding = true, UseReversibleEncoding = false }; networkMessage.Encode(encoder); encoder.Close(); var encoded = new NetworkMessageModel { Body = Encoding.UTF8.GetBytes(writer.ToString()), ContentEncoding = "utf-8", Timestamp = DateTime.UtcNow, ContentType = ContentMimeType.UaLegacyPublisher, MessageSchema = MessageSchemaTypes.MonitoredItemMessageJson }; yield return(encoded); } }
/// <summary> /// Perform json encoding /// </summary> /// <param name="message"></param> /// <returns></returns> public IEnumerable <NetworkMessageModel> EncodeAsJson(DataSetMessageModel message) { foreach (var networkMessage in GetNetworkMessages(message.YieldReturn())) { using (var writer = new StringWriter()) { using (var encoder = new JsonEncoderEx(writer, message.ServiceMessageContext) { UseAdvancedEncoding = true, UseUriEncoding = true, UseReversibleEncoding = false }) { networkMessage.Encode(encoder); } var json = writer.ToString(); var encoded = new NetworkMessageModel { Body = Encoding.UTF8.GetBytes(json), ContentEncoding = "utf-8", Timestamp = DateTime.UtcNow, ContentType = ContentMimeType.Json, MessageId = message.SequenceNumber.ToString(), MessageSchema = MessageSchemaTypes.NetworkMessageJson }; yield return(encoded); } } }
public void EncodeDecodeNetworkMessage() { var payload = new Dictionary <string, DataValue> { { "1", new DataValue(new Variant(5), StatusCodes.Good, DateTime.Now) }, { "2", new DataValue(new Variant(0.5), StatusCodes.Good, DateTime.Now) }, { "3", new DataValue("abcd") } }; var message = new DataSetMessage { DataSetWriterId = "WriterId", MetaDataVersion = new ConfigurationVersionDataType { MajorVersion = 1, MinorVersion = 1 }, SequenceNumber = ++_currentSequenceNumber, Status = StatusCodes.Good, Timestamp = DateTime.UtcNow, MessageContentMask = (uint)( JsonDataSetMessageContentMask.DataSetWriterId | JsonDataSetMessageContentMask.SequenceNumber | JsonDataSetMessageContentMask.MetaDataVersion | JsonDataSetMessageContentMask.Timestamp | JsonDataSetMessageContentMask.Status), Payload = new DataSet(payload) { FieldContentMask = (uint)(DataSetFieldContentMask.StatusCode | DataSetFieldContentMask.SourceTimestamp) } }; var networkMessage = new NetworkMessage { MessageId = Guid.NewGuid().ToString(), // TODO MessageType = "ua-data", Messages = new List <DataSetMessage>(), PublisherId = "PublisherId" }; networkMessage.Messages.Add(message); networkMessage.MessageContentMask = (uint)( JsonNetworkMessageContentMask.PublisherId | JsonNetworkMessageContentMask.NetworkMessageHeader | JsonNetworkMessageContentMask.SingleDataSetMessage); byte[] buffer; string json; var context = new ServiceMessageContext(); using (var stream = new MemoryStream()) { using (var encoder = new JsonEncoderEx(stream, context)) { networkMessage.Encode(encoder); } buffer = stream.ToArray(); json = buffer.ToBase16String(); } using (var stream = new MemoryStream(buffer)) { using (var decoder = new JsonDecoderEx(stream, context)) { var result = decoder.ReadEncodeable(null, typeof(NetworkMessage)) as NetworkMessage; Assert.Equal(networkMessage, result); } } }
/// <summary> /// Convert operation results to json /// </summary> /// <param name="results"></param> /// <param name="config"></param> /// <param name="context"></param> /// <returns></returns> private static JToken ToJson(this List <OperationResultModel> results, DiagnosticsModel config, ServiceMessageContext context) { var level = config?.Level ?? Twin.Models.DiagnosticsLevel.Status; if (level == Twin.Models.DiagnosticsLevel.None) { return(null); } using (var stream = new MemoryStream()) { var root = kDiagnosticsProperty; using (var encoder = new JsonEncoderEx(stream, context) { UseAdvancedEncoding = true, IgnoreDefaultValues = true }) { switch (level) { case Twin.Models.DiagnosticsLevel.Diagnostics: case Twin.Models.DiagnosticsLevel.Verbose: encoder.WriteEncodeableArray(root, results); break; case Twin.Models.DiagnosticsLevel.Operations: var codes = results .GroupBy(d => d.StatusCode.CodeBits); root = null; foreach (var code in codes) { encoder.WriteStringArray(StatusCode.LookupSymbolicId(code.Key), code.Select(c => c.Operation).ToArray()); } break; case Twin.Models.DiagnosticsLevel.Status: var statusCodes = results .Select(d => StatusCode.LookupSymbolicId(d.StatusCode.CodeBits)) .Where(s => !string.IsNullOrEmpty(s)) .Distinct(); if (!statusCodes.Any()) { return(null); } encoder.WriteStringArray(root, statusCodes.ToArray()); break; } } var o = JObject.Parse(Encoding.UTF8.GetString(stream.ToArray())); return(root != null?o.Property(root).Value : o); } }
/// <summary> /// Perform json encoding /// </summary> /// <param name="messages"></param> /// <param name="maxMessageSize"></param> /// <returns></returns> private IEnumerable <NetworkMessageModel> EncodeAsJson( IEnumerable <DataSetMessageModel> messages, int maxMessageSize) { // by design all messages are generated in the same session context, // therefore it is safe to get the first message's context var encodingContext = messages.FirstOrDefault(m => m.ServiceMessageContext != null) ?.ServiceMessageContext; var notifications = GetNetworkMessages(messages, MessageEncoding.Json, encodingContext); if (!notifications.Any()) { yield break; } var routingInfo = messages.FirstOrDefault(m => m?.WriterGroup != null)?.WriterGroup.WriterGroupId; foreach (var networkMessage in notifications) { int notificationsPerMessage = networkMessage.Messages.Sum(m => m.Payload.Count); var writer = new StringWriter(); var encoder = new JsonEncoderEx(writer, encodingContext) { UseAdvancedEncoding = true, UseUriEncoding = true, UseReversibleEncoding = false }; networkMessage.Encode(encoder); encoder.Close(); var encoded = new NetworkMessageModel { Body = Encoding.UTF8.GetBytes(writer.ToString()), ContentEncoding = "utf-8", Timestamp = DateTime.UtcNow, ContentType = ContentMimeType.Json, MessageSchema = MessageSchemaTypes.NetworkMessageJson, RoutingInfo = _enableRoutingInfo ? routingInfo : null, }; if (encoded.Body.Length > maxMessageSize) { // Message too large, drop it. NotificationsDroppedCount += (uint)notificationsPerMessage; _logger.Warning("Message too large, dropped {notificationsPerMessage} values", notificationsPerMessage); continue; } NotificationsProcessedCount += (uint)notificationsPerMessage; AvgMessageSize = (AvgMessageSize * MessagesProcessedCount + encoded.Body.Length) / (MessagesProcessedCount + 1); AvgNotificationsPerMessage = (AvgNotificationsPerMessage * MessagesProcessedCount + notificationsPerMessage) / (MessagesProcessedCount + 1); MessagesProcessedCount++; yield return(encoded); } }
/// <summary> /// Perform json encoding /// </summary> /// <param name="messages"></param> /// <param name="maxMessageSize"></param> /// <returns></returns> private IEnumerable <NetworkMessageModel> EncodeAsJson( IEnumerable <DataSetMessageModel> messages, int maxMessageSize) { // by design all messages are generated in the same session context, // therefore it is safe to get the first message's context var encodingContext = messages.FirstOrDefault(m => m.ServiceMessageContext != null) ?.ServiceMessageContext; var notifications = GetNetworkMessages(messages, MessageEncoding.Json, encodingContext); if (notifications.Count() == 0) { yield break; } foreach (var networkMessage in notifications) { ulong notificationsPerMessage = (ulong)networkMessage.Messages.Sum(m => m.Payload.Count); var writer = new StringWriter(); var encoder = new JsonEncoderEx(writer, encodingContext) { UseAdvancedEncoding = true, UseUriEncoding = true, UseReversibleEncoding = false }; networkMessage.Encode(encoder); encoder.Close(); var encoded = new NetworkMessageModel { Body = Encoding.UTF8.GetBytes(writer.ToString()), ContentEncoding = "utf-8", Timestamp = DateTime.UtcNow, ContentType = ContentMimeType.Json, MessageSchema = MessageSchemaTypes.NetworkMessageJson }; if (encoded.Body.Length > maxMessageSize) { // this message is too large to be processed. Drop it // TODO Trace NotificationsDroppedCount++; yield break; } NotificationsProcessedCount++; AvgMessageSize = (AvgMessageSize * MessagesProcessedCount + encoded.Body.Length) / (MessagesProcessedCount + 1); AvgNotificationsPerMessage = (AvgNotificationsPerMessage * MessagesProcessedCount + notificationsPerMessage) / (MessagesProcessedCount + 1); MessagesProcessedCount++; yield return(encoded); } }
/// <summary> /// Writes collection as json /// </summary> /// <param name="collection"></param> /// <param name="context"></param> /// <param name="formatting"></param> /// <param name="ostrm"></param> public static void SaveAsJson(this NodeStateCollection collection, Stream ostrm, Newtonsoft.Json.Formatting formatting, ISystemContext context) { using (var encoder = new JsonEncoderEx(ostrm, context.ToMessageContext(), JsonEncoderEx.JsonEncoding.Array, formatting) { UseAdvancedEncoding = true, IgnoreDefaultValues = true }) { foreach (var node in collection.ToNodeModels(context)) { if (node != null) { encoder.WriteEncodeable(null, new EncodeableNodeModel(node)); } } } }
/// <inheritdoc/> public VariantValue Encode(Variant?value, out BuiltInType builtinType) { if (value == null || value == Variant.Null) { builtinType = BuiltInType.Null; return(VariantValue.Null); } using (var stream = new MemoryStream()) { using (var encoder = new JsonEncoderEx(stream, Context) { UseAdvancedEncoding = true }) { encoder.WriteVariant(nameof(value), value.Value); } var token = Serializer.Parse(stream.ToArray()); Enum.TryParse((string)token.GetByPath("value.Type"), true, out builtinType); return(token.GetByPath("value.Body")); } }
/// <summary> /// Perform event to message encoding /// </summary> /// <param name="message"></param> /// <returns></returns> public IEnumerable <NetworkMessageModel> EncodeAsJson(DataSetMessageModel message) { foreach (var notification in message.Notifications) { using (var writer = new StringWriter()) { var value = new MonitoredItemMessage { MessageContentMask = (message.Writer?.MessageSettings? .DataSetMessageContentMask).ToMonitoredItemMessageMask( message.Writer?.DataSetFieldContentMask), ApplicationUri = message.ApplicationUri, EndpointUrl = message.EndpointUrl, ExtensionFields = message.Writer?.DataSet?.ExtensionFields, NodeId = notification.NodeId.ToExpandedNodeId(message.ServiceMessageContext.NamespaceUris), Timestamp = message.TimeStamp ?? DateTime.UtcNow, Value = notification.Value, DisplayName = notification.DisplayName }; using (var encoder = new JsonEncoderEx(writer, message.ServiceMessageContext) { UseAdvancedEncoding = true, UseUriEncoding = true, UseReversibleEncoding = false }){ value.Encode(encoder); } var encoded = new NetworkMessageModel { Body = Encoding.UTF8.GetBytes(writer.ToString()), ContentEncoding = "utf-8", Timestamp = DateTime.UtcNow, ContentType = ContentMimeType.UaLegacyPublisher, MessageId = message.SequenceNumber.ToString(), MessageSchema = MessageSchemaTypes.MonitoredItemMessageJson }; yield return(encoded); } } }
/// <summary> /// Test model browse encoder /// </summary> private static async Task TestOpcUaModelExportServiceAsync(EndpointModel endpoint) { using (var logger = StackLogger.Create(ConsoleLogger.Create())) using (var client = new ClientServices(logger.Logger, new TestClientServicesConfig())) using (var server = new ServerWrapper(endpoint, logger)) using (var stream = Console.OpenStandardOutput()) using (var writer = new StreamWriter(stream)) using (var json = new JsonTextWriter(writer) { AutoCompleteOnClose = true, Formatting = Formatting.Indented, DateFormatHandling = DateFormatHandling.IsoDateFormat }) using (var encoder = new JsonEncoderEx(json, null, JsonEncoderEx.JsonEncoding.Array) { IgnoreDefaultValues = true, UseAdvancedEncoding = true }) using (var browser = new BrowseStreamEncoder(client, endpoint, encoder, null, logger.Logger, null)) { await browser.EncodeAsync(CancellationToken.None); } }
/// <inheritdoc/> public async Task SendEventAsync(byte[] data, string contentType, string eventSchema, string contentEncoding) { var ev = JsonConvert.DeserializeObject <DiscoveryEventModel>( Encoding.UTF8.GetString(data)); var endpoint = ev.Registration?.Endpoint; if (endpoint == null) { return; } try { var id = endpoint.Url.ToSha1Hash(); _logger.Information("Writing {id}.json for {@ev}", id, ev); using (var writer = File.CreateText($"iop_{id}.json")) using (var json = new JsonTextWriter(writer) { AutoCompleteOnClose = true, Formatting = Formatting.Indented, DateFormatHandling = DateFormatHandling.IsoDateFormat }) using (var encoder = new JsonEncoderEx(json, null, JsonEncoderEx.JsonEncoding.Array) { IgnoreDefaultValues = true, UseAdvancedEncoding = true }) using (var browser = new BrowseStreamEncoder(_client, endpoint, encoder, null, _logger, null)) { await browser.EncodeAsync(CancellationToken.None); } } catch (Exception ex) { _logger.Error(ex, "Failed to browse"); } }
/// <summary> /// DataSetMessage to NetworkMessage Json batched encoding /// </summary> /// <param name="messages"></param> /// <param name="maxMessageSize"></param> /// <returns></returns> private IEnumerable <NetworkMessageModel> EncodeBatchAsJson( IEnumerable <DataSetMessageModel> messages, int maxMessageSize) { var notifications = GetNetworkMessages(messages, MessageEncoding.Json); if (notifications.Count() == 0) { yield break; } // by design all messages are generated in the same session context, // therefore it is safe to get the first message's context var encodingContext = messages.First().ServiceMessageContext; var current = notifications.GetEnumerator(); var processing = current.MoveNext(); var messageSize = 2; // array brackets maxMessageSize -= 2048; // reserve 2k for header var chunk = new Collection <NetworkMessage>(); while (processing) { var notification = current.Current; var messageCompleted = false; if (notification != null) { var helperWriter = new StringWriter(); var helperEncoder = new JsonEncoderEx(helperWriter, encodingContext) { UseAdvancedEncoding = true, UseUriEncoding = true, UseReversibleEncoding = false }; notification.Encode(helperEncoder); helperEncoder.Close(); var notificationSize = Encoding.UTF8.GetByteCount(helperWriter.ToString()); if (notificationSize > maxMessageSize) { // we cannot handle this notification. Drop it. // TODO Trace NotificationsDroppedCount++; processing = current.MoveNext(); } else { messageCompleted = maxMessageSize < (messageSize + notificationSize); if (!messageCompleted) { NotificationsProcessedCount++; chunk.Add(notification); processing = current.MoveNext(); messageSize += notificationSize + (processing ? 1 : 0); } } } if (!processing || messageCompleted) { var writer = new StringWriter(); var encoder = new JsonEncoderEx(writer, encodingContext, JsonEncoderEx.JsonEncoding.Array) { UseAdvancedEncoding = true, UseUriEncoding = true, UseReversibleEncoding = false }; foreach (var element in chunk) { encoder.WriteEncodeable(null, element); } encoder.Close(); var encoded = new NetworkMessageModel { Body = Encoding.UTF8.GetBytes(writer.ToString()), ContentEncoding = "utf-8", Timestamp = DateTime.UtcNow, ContentType = ContentMimeType.UaJson, MessageSchema = MessageSchemaTypes.NetworkMessageJson }; AvgMessageSize = (AvgMessageSize * MessagesProcessedCount + encoded.Body.Length) / (MessagesProcessedCount + 1); AvgNotificationsPerMessage = (AvgNotificationsPerMessage * MessagesProcessedCount + chunk.Count) / (MessagesProcessedCount + 1); MessagesProcessedCount++; chunk.Clear(); messageSize = 2; yield return(encoded); } } }
/// <summary> /// DataSetMessage to NetworkMessage Json batched encoding /// </summary> /// <param name="messages"></param> /// <param name="maxMessageSize"></param> /// <returns></returns> private IEnumerable <NetworkMessageModel> EncodeBatchAsJson( IEnumerable <DataSetMessageModel> messages, int maxMessageSize) { // by design all messages are generated in the same session context, // therefore it is safe to get the first message's context var encodingContext = messages.FirstOrDefault(m => m.ServiceMessageContext != null) ?.ServiceMessageContext; var notifications = GetNetworkMessages(messages, MessageEncoding.Json, encodingContext); if (!notifications.Any()) { yield break; } var routingInfo = messages.FirstOrDefault(m => m?.WriterGroup != null)?.WriterGroup.WriterGroupId; var current = notifications.GetEnumerator(); var processing = current.MoveNext(); var messageSize = 2; // array brackets var chunk = new Collection <NetworkMessage>(); int notificationsPerMessage = 0; while (processing) { var notification = current.Current; var messageCompleted = false; if (notification != null) { var helperWriter = new StringWriter(); var helperEncoder = new JsonEncoderEx(helperWriter, encodingContext) { UseAdvancedEncoding = true, UseUriEncoding = true, UseReversibleEncoding = false }; notification.Encode(helperEncoder); helperEncoder.Close(); var notificationSize = Encoding.UTF8.GetByteCount(helperWriter.ToString()); var notificationsInBatch = notification.Messages.Sum(m => m.Payload.Count); if (notificationSize > maxMessageSize) { // Message too large, drop it. NotificationsDroppedCount += (uint)notificationsInBatch; _logger.Warning("Message too large, dropped {notificationsInBatch} values", notificationsInBatch); processing = current.MoveNext(); } else { messageCompleted = maxMessageSize < (messageSize + notificationSize); if (!messageCompleted) { chunk.Add(notification); NotificationsProcessedCount += (uint)notificationsInBatch; notificationsPerMessage += notificationsInBatch; processing = current.MoveNext(); messageSize += notificationSize + (processing ? 1 : 0); } } } if (messageCompleted || (!processing && chunk.Count > 0)) { var writer = new StringWriter(); var encoder = new JsonEncoderEx(writer, encodingContext, JsonEncoderEx.JsonEncoding.Array) { UseAdvancedEncoding = true, UseUriEncoding = true, UseReversibleEncoding = false }; foreach (var element in chunk) { encoder.WriteEncodeable(null, element); } encoder.Close(); var encoded = new NetworkMessageModel { Body = Encoding.UTF8.GetBytes(writer.ToString()), ContentEncoding = "utf-8", Timestamp = DateTime.UtcNow, ContentType = ContentMimeType.Json, MessageSchema = MessageSchemaTypes.NetworkMessageJson, RoutingInfo = _enableRoutingInfo ? routingInfo : null, }; AvgMessageSize = (AvgMessageSize * MessagesProcessedCount + encoded.Body.Length) / (MessagesProcessedCount + 1); AvgNotificationsPerMessage = (AvgNotificationsPerMessage * MessagesProcessedCount + notificationsPerMessage) / (MessagesProcessedCount + 1); MessagesProcessedCount++; chunk.Clear(); messageSize = 2; notificationsPerMessage = 0; yield return(encoded); } } }
/// <summary> /// Perform DataSetMessageModel to NetworkMessageModel batch using Json encoding /// </summary> /// <param name="messages"></param> /// <param name="maxMessageSize"></param> /// <returns></returns> private IEnumerable <NetworkMessageModel> EncodeBatchAsJson( IEnumerable <DataSetMessageModel> messages, int maxMessageSize) { var notifications = GetMonitoredItemMessages(messages, MessageEncoding.Json); if (notifications.Count() == 0) { yield break; } var encodingContext = messages.First().ServiceMessageContext; var current = notifications.GetEnumerator(); var processing = current.MoveNext(); var messageSize = 2; // array brackets maxMessageSize -= 2048; // reserve 2k for header var chunk = new Collection <MonitoredItemMessage>(); while (processing) { var notification = current.Current; var messageCompleted = false; if (notification != null) { var helperWriter = new StringWriter(); var helperEncoder = new JsonEncoderEx(helperWriter, encodingContext) { UseAdvancedEncoding = true, UseUriEncoding = true, UseReversibleEncoding = false }; notification.Encode(helperEncoder); helperEncoder.Close(); var notificationSize = Encoding.UTF8.GetByteCount(helperWriter.ToString()); messageCompleted = maxMessageSize < (messageSize + notificationSize); if (!messageCompleted) { chunk.Add(notification); processing = current.MoveNext(); messageSize += notificationSize + (processing ? 1 : 0); } } if (!processing || messageCompleted) { var writer = new StringWriter(); var encoder = new JsonEncoderEx(writer, encodingContext, JsonEncoderEx.JsonEncoding.Array) { UseAdvancedEncoding = true, UseUriEncoding = true, UseReversibleEncoding = false }; foreach (var element in chunk) { encoder.WriteEncodeable(null, element); } encoder.Close(); chunk.Clear(); messageSize = 2; // array brackets var encoded = new NetworkMessageModel { Body = Encoding.UTF8.GetBytes(writer.ToString()), ContentEncoding = "utf-8", Timestamp = DateTime.UtcNow, ContentType = ContentMimeType.UaJson, MessageSchema = MessageSchemaTypes.MonitoredItemMessageJson }; yield return(encoded); } } }
public void EncodeDecodeNetworkMessageFull() { var payload = new Dictionary <string, DataValue> { ["abcd"] = new DataValue(new Variant(1234), StatusCodes.Good, DateTime.Now, DateTime.UtcNow), ["http://microsoft.com"] = new DataValue(new Variant(-222222222), StatusCodes.Bad, DateTime.MinValue, DateTime.Now), ["1111111111111111111111111"] = new DataValue(new Variant(false), StatusCodes.Bad, DateTime.UtcNow, DateTime.MinValue), ["@#$%^&*()_+~!@#$%^*(){}"] = new DataValue(new Variant(new byte[] { 0, 2, 4, 6 }), StatusCodes.Good), ["1245"] = new DataValue(new Variant("hello"), StatusCodes.Bad, DateTime.Now, DateTime.MinValue), ["..."] = new DataValue(new Variant(new Variant("imbricated"))) }; var message = new DataSetMessage { DataSetWriterId = "WriterId", MetaDataVersion = new ConfigurationVersionDataType { MajorVersion = 1, MinorVersion = 1 }, SequenceNumber = ++_currentSequenceNumber, Status = StatusCodes.Good, Timestamp = DateTime.UtcNow, Picoseconds = 1234, MessageContentMask = (uint)( JsonDataSetMessageContentMask.DataSetWriterId | JsonDataSetMessageContentMask.SequenceNumber | JsonDataSetMessageContentMask.MetaDataVersion | JsonDataSetMessageContentMask.Timestamp | JsonDataSetMessageContentMask.Status), Payload = new DataSet(payload, (uint)( DataSetFieldContentMask.StatusCode | DataSetFieldContentMask.SourceTimestamp | DataSetFieldContentMask.ServerTimestamp | DataSetFieldContentMask.SourcePicoSeconds | DataSetFieldContentMask.ServerPicoSeconds)) }; var networkMessage = new NetworkMessage { MessageId = Guid.NewGuid().ToString(), // TODO MessageType = "ua-data", Messages = new List <DataSetMessage>(), PublisherId = "PublisherId", DataSetClassId = "1234" }; networkMessage.Messages.Add(message); networkMessage.MessageContentMask = (uint)( JsonNetworkMessageContentMask.PublisherId | JsonNetworkMessageContentMask.NetworkMessageHeader | JsonNetworkMessageContentMask.SingleDataSetMessage | JsonNetworkMessageContentMask.DataSetClassId); byte[] buffer; var context = new ServiceMessageContext(); using (var stream = new MemoryStream()) { using (var encoder = new JsonEncoderEx(stream, context)) { networkMessage.Encode(encoder); } buffer = stream.ToArray(); } ConvertToOpcUaUniversalTime(networkMessage); using (var stream = new MemoryStream(buffer)) { using (var decoder = new JsonDecoderEx(stream, context)) { var result = decoder.ReadEncodeable(null, typeof(NetworkMessage)) as NetworkMessage; Assert.Equal(networkMessage, result); } } }