#pragma warning disable CS1591 // Deserialize. public void Deserialize(Stream stream, out IDictionary <SettingKey, object> values, out SettingsMetadata metadata) { // build JSON document using var jsonDocument = JsonDocument.Parse(stream); // read metadata var rootJsonElement = jsonDocument.RootElement; if (rootJsonElement.ValueKind != JsonValueKind.Object) { throw new ArgumentException("Invalid root JSON element."); } var version = rootJsonElement.GetProperty("Version").Let((it) => { if (it.ValueKind == JsonValueKind.Undefined) { return(0); } return(it.GetInt32()); }); var lastModifiedTime = rootJsonElement.GetProperty("LastModifiedTime").Let((it) => { if (it.ValueKind == JsonValueKind.Undefined) { return(DateTime.Now); } return(DateTime.FromBinary(it.GetInt64())); }); // read keys and values var keyValues = new Dictionary <SettingKey, object>(); rootJsonElement.GetProperty("Values").Let((jsonValuesArray) => { if (jsonValuesArray.ValueKind == JsonValueKind.Undefined) { return; } foreach (var jsonValueEntry in jsonValuesArray.EnumerateArray()) { var name = jsonValueEntry.GetProperty("Name").GetString().AsNonNull(); var typeName = jsonValueEntry.GetProperty("Type").GetString().AsNonNull(); var defaultValue = this.ReadJsonValue(jsonValueEntry.GetProperty("Default"), typeName); var value = this.ReadJsonValue(jsonValueEntry.GetProperty("Value"), typeName); keyValues[new SettingKey(name, defaultValue.GetType(), defaultValue)] = value; } }); // complete values = keyValues; metadata = new SettingsMetadata(version, lastModifiedTime); }
#pragma warning disable CS1591 // Deserialize. public void Deserialize(Stream stream, out IDictionary <SettingKey, object> values, out SettingsMetadata metadata) { // parse document var xmlDocument = new XmlDocument(); xmlDocument.Load(stream); // find root element var settingsElement = xmlDocument.FirstChild.Let((node) => { while (node != null) { if (node.NodeType == XmlNodeType.Element && node.Name == "Settings") { return(node); } node = node.NextSibling; } return(null); }) ?? throw new XmlException("No 'Settings' element."); // get metadata and values var version = (int?)null; var lastModifiedTime = (DateTime?)null; var keyValues = new Dictionary <SettingKey, object>(); var node = settingsElement.FirstChild; while (node != null) { try { if (node.NodeType != XmlNodeType.Element) { continue; } switch (node.Name) { case "Version": if (version != null) { throw new XmlException("Duplicate 'Version' specified."); } version = node.Let((_) => { if (!node.HasChildNodes) { return(null); } return(node.FirstChild?.Let((it) => { if (it.NodeType == XmlNodeType.Text && int.TryParse(it.Value, out var intValue)) { return (int?)intValue; } return null; })); }); break; case "LastModifiedTime": if (lastModifiedTime != null) { throw new XmlException("Duplicate 'LastModifiedTime' specified."); } lastModifiedTime = node.Let((_) => { if (!node.HasChildNodes) { return(null); } return(node.FirstChild?.Let((it) => { if (it.NodeType == XmlNodeType.Text && long.TryParse(it.Value, out var longValue)) { return (DateTime?)DateTime.FromBinary(longValue); } return null; })); }); break; case "Values": if (node.HasChildNodes) { var keyValueNode = node.FirstChild; while (keyValueNode != null) { try { if (keyValueNode.NodeType != XmlNodeType.Element || keyValueNode.Name != "Value" || !keyValueNode.HasChildNodes) { continue; } var name = (string?)null; var typeName = (string?)null; var defaultValue = (object?)null; var value = (object?)null; var childNode = keyValueNode.FirstChild; while (childNode != null) { try { if (childNode.NodeType != XmlNodeType.Element || !childNode.HasChildNodes) { continue; } switch (childNode.Name) { case "Name": name = childNode.FirstChild?.Value; break; case "Type": typeName = childNode.FirstChild?.Value; break; case "Default": if (typeName == null) { throw new XmlException($"No type of setting value specified for '{name}'."); } defaultValue = this.ReadXmlValue(childNode.FirstChild.AsNonNull(), typeName); break; case "Value": if (typeName == null) { throw new XmlException($"No type of setting value specified for '{name}'."); } value = this.ReadXmlValue(childNode.FirstChild.AsNonNull(), typeName); break; } } finally { childNode = childNode.NextSibling; } } if (name == null) { throw new XmlException("No name of setting key specified."); } if (defaultValue == null) { throw new XmlException($"No default setting value specified for '{name}'."); } if (value == null) { throw new XmlException($"No value specified for '{name}'."); } keyValues[new SettingKey(name, defaultValue.GetType(), defaultValue)] = value; } finally { keyValueNode = keyValueNode.NextSibling; } } } break; } } finally { node = node.NextSibling; } } // complete if (version == null) { throw new XmlException("No 'Version' specified."); } if (lastModifiedTime == null) { throw new XmlException("No 'LastModifiedTime' specified."); } metadata = new SettingsMetadata(version.GetValueOrDefault(), lastModifiedTime.GetValueOrDefault()); values = keyValues; }
#pragma warning disable CS1591 // Serialize. public void Serialize(Stream stream, IDictionary <SettingKey, object> values, SettingsMetadata metadata) { // prepare using var writer = XmlWriter.Create(stream, new XmlWriterSettings() { Encoding = Encoding.UTF8, Indent = true, }); // start document writer.WriteStartDocument(); writer.WriteStartElement("Settings"); // versin writer.WriteStartElement("Version"); writer.WriteValue(metadata.Version); writer.WriteEndElement(); // last modified time writer.WriteStartElement("LastModifiedTime"); writer.WriteValue(metadata.LastModifiedTime.ToBinary()); writer.WriteEndElement(); // key-values writer.WriteStartElement("Values"); foreach (var keyValue in values) { var key = keyValue.Key; var value = keyValue.Value; var typeName = this.GetTypeName(key.DefaultValue.GetType()); writer.WriteStartElement("Value"); writer.WriteStartElement("Name"); writer.WriteValue(key.Name); writer.WriteEndElement(); writer.WriteStartElement("Type"); writer.WriteValue(typeName); writer.WriteEndElement(); writer.WriteStartElement("Default"); this.WriteXmlValue(writer, key.DefaultValue); writer.WriteEndElement(); writer.WriteStartElement("Value"); this.WriteXmlValue(writer, value); writer.WriteEndElement(); writer.WriteEndElement(); } writer.WriteEndElement(); // complete writer.WriteEndElement(); writer.WriteEndDocument(); }