diff --git a/src/Settings.Json.Net/CustomJsonConverters/FileSystemInfoConverter.cs b/src/Settings.Json.Net/CustomJsonConverters/FileSystemInfoConverter.cs index 238a2d2..699aa2b 100644 --- a/src/Settings.Json.Net/CustomJsonConverters/FileSystemInfoConverter.cs +++ b/src/Settings.Json.Net/CustomJsonConverters/FileSystemInfoConverter.cs @@ -52,13 +52,15 @@ public class FileInfoConverter : JsonConverter /// public override FileInfo Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { + var value = reader.GetString(); try { - return new FileInfo(reader.GetString()); + if (value is null) throw new NotSupportedException(); + return new FileInfo(value); } catch (Exception) { - throw new JsonException($"Cannot convert the value '{(reader.GetString() ?? "[NULL]")}' of type {reader.TokenType} into a {nameof(FileInfo)}."); + throw new JsonException($"Cannot convert the value '{value ?? "[NULL]"}' of type {reader.TokenType} into a {nameof(FileInfo)}."); } } @@ -79,13 +81,15 @@ public class DirectoryInfoConverter : JsonConverter /// public override DirectoryInfo Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { + var value = reader.GetString(); try { - return new DirectoryInfo(reader.GetString()); + if (value is null) throw new NotSupportedException(); + return new DirectoryInfo(value); } catch (Exception) { - throw new JsonException($"Cannot convert the value '{(reader.GetString() ?? "[NULL]")}' of type {reader.TokenType} into a {nameof(DirectoryInfo)}."); + throw new JsonException($"Cannot convert the value '{value ?? "[NULL]"}' of type {reader.TokenType} into a {nameof(DirectoryInfo)}."); } } diff --git a/src/Settings.Json.Net/CustomJsonConverters/RegexConverter.cs b/src/Settings.Json.Net/CustomJsonConverters/RegexConverter.cs index c33e27c..71b1cfa 100644 --- a/src/Settings.Json.Net/CustomJsonConverters/RegexConverter.cs +++ b/src/Settings.Json.Net/CustomJsonConverters/RegexConverter.cs @@ -18,7 +18,8 @@ public class RegexConverter : JsonConverter /// public override Regex Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - return new Regex(reader.GetString(), RegexOptions.IgnoreCase | RegexOptions.Compiled); + var value = reader.GetString() ?? ".*"; + return new Regex(value, RegexOptions.IgnoreCase | RegexOptions.Compiled); } /// diff --git a/src/Settings.Json.Net/JsonSettingsManager.cs b/src/Settings.Json.Net/JsonSettingsManager.cs index 127c236..6b75ea7 100644 --- a/src/Settings.Json.Net/JsonSettingsManager.cs +++ b/src/Settings.Json.Net/JsonSettingsManager.cs @@ -4,17 +4,9 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Dynamic; using System.IO; using System.Linq; -using System.Net.Http.Headers; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Text; using System.Text.Json; -using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using Phoenix.Functionality.Settings.Cache; @@ -87,7 +79,7 @@ public JsonSettingsManager(ISettingsCache cache) : this(null, cache) { } /// /// The directory where all setting files reside. /// An used for caching all loaded settings instances. If this is Null then will be used. - public JsonSettingsManager(DirectoryInfo baseDirectory, ISettingsCache cache) + public JsonSettingsManager(DirectoryInfo? baseDirectory, ISettingsCache? cache) { // Save parameters. _baseDirectory = baseDirectory ?? new DirectoryInfo(Path.Combine(Directory.GetCurrentDirectory(), ".settings")); @@ -167,7 +159,16 @@ public static IDirectoryJsonSettingsManagerBuilder Construct() { // YES: Deserialize it. origin = SettingsOrigin.File; - settings = JsonSettingsManager.Deserialize(settingsFile); + var deserializedSettings = JsonSettingsManager.Deserialize(settingsFile); + if (deserializedSettings is null) + { + origin = SettingsOrigin.Default; + settings = JsonSettingsManager.GetDefaultInstance(); + } + else + { + settings = deserializedSettings; + } } // Update the cache if needed. @@ -182,17 +183,15 @@ public static IDirectoryJsonSettingsManagerBuilder Construct() /// /// The settings file to deserialize. /// The deserialized settings object. - private static TSettings Deserialize(FileInfo settingsFile) where TSettings : class, ISettings, new() + private static TSettings? Deserialize(FileInfo settingsFile) where TSettings : class, ISettings, new() { if (settingsFile == null) throw new ArgumentNullException(nameof(settingsFile)); if (!settingsFile.Exists) throw new ArgumentException($"The settings file '{settingsFile.FullName}' does not exist.", nameof(settingsFile)); - - using (var stream = settingsFile.Open(FileMode.Open, FileAccess.Read)) - { - // Directly deserialize the file into an instance of TSettings. - //? What about error handling for (partially) invalid json? - return JsonSerializer.DeserializeAsync(stream, JsonOptions.Instance, CancellationToken.None).Result; - } + + // Directly deserialize the file into an instance of TSettings. + //? What about error handling for (partially) invalid json? + using var stream = settingsFile.Open(FileMode.Open, FileAccess.Read); + return JsonSerializer.DeserializeAsync(stream, JsonOptions.Instance, CancellationToken.None).Result; } /// @@ -203,15 +202,15 @@ public static IDirectoryJsonSettingsManagerBuilder Construct() /// True if they match, otherwise False. public static async Task ShouldSettingsFileBeUpdatedAsync(FileInfo settingsFile, object settings) { - var targetJsonDocument = JsonDocument.Parse(await JsonSettingsManager.SerializeAsync(settings)); - var targetData = await JsonSettingsManager.ConvertJsonDocumentToData(targetJsonDocument); + var targetJsonDocument = JsonDocument.Parse(await JsonSettingsManager.SerializeAsync(settings).ConfigureAwait(false)); + var targetData = await JsonSettingsManager.ConvertJsonDocumentToData(targetJsonDocument).ConfigureAwait(false); #if NETSTANDARD2_0 || NETSTANDARD1_6 || NETSTANDARD1_5 || NETSTANDARD1_4 || NETSTANDARD1_3 || NETSTANDARD1_2 || NETSTANDARD1_1 || NETSTANDARD1_0 var actualJsonDocument = JsonDocument.Parse(File.ReadAllText(settingsFile.FullName)); #else - var actualJsonDocument = JsonDocument.Parse(await File.ReadAllTextAsync(settingsFile.FullName)); + var actualJsonDocument = JsonDocument.Parse(await File.ReadAllTextAsync(settingsFile.FullName).ConfigureAwait(false)); #endif - var actualData = await JsonSettingsManager.ConvertJsonDocumentToData(actualJsonDocument); + var actualData = await JsonSettingsManager.ConvertJsonDocumentToData(actualJsonDocument).ConfigureAwait(false); var areEqual = targetData.SequenceEqual(actualData); return !areEqual; @@ -219,23 +218,25 @@ public static async Task ShouldSettingsFileBeUpdatedAsync(FileInfo setting private static async Task ConvertJsonDocumentToData(JsonDocument document) { - using (var stream = new MemoryStream()) +#if NETSTANDARD2_0 || NETSTANDARD1_6 || NETSTANDARD1_5 || NETSTANDARD1_4 || NETSTANDARD1_3 || NETSTANDARD1_2 || NETSTANDARD1_1 || NETSTANDARD1_0 + using var stream = new MemoryStream(); +#else + await using var stream = new MemoryStream(); +#endif + await using (var writer = new Utf8JsonWriter(stream)) { - using (var writer = new Utf8JsonWriter(stream)) - { - document.RootElement.WriteTo(writer); - //document.RootElement.WriteValue(writer); //.Net Core 3.0 - await writer.FlushAsync(); - } - - stream.Seek(0, SeekOrigin.Begin); - return stream.ToArray(); + document.RootElement.WriteTo(writer); + //document.RootElement.WriteValue(writer); //.Net Core 3.0 + await writer.FlushAsync().ConfigureAwait(false); } + + stream.Seek(0, SeekOrigin.Begin); + return stream.ToArray(); } - #endregion +#endregion - #region Save +#region Save /// public void Save(TSettings settings, bool createBackup = default) where TSettings : ISettings @@ -273,13 +274,11 @@ private static void Save(string jsonString, FileInfo settingsFile) } // Check if the directory of the file exists. Trying to create a file, whose directory is also not existing, will throw an exception. - if (!settingsFile.Directory.Exists) settingsFile.Directory.Create(); + if (!settingsFile.Directory!.Exists) settingsFile.Directory.Create(); - using (var fileStream = settingsFile.Open(FileMode.Create)) - { - var jsonData = System.Text.Encoding.UTF8.GetBytes(jsonString); - fileStream.Write(jsonData, offset: 0, count: jsonData.Length); - } + using var fileStream = settingsFile.Open(FileMode.Create); + var jsonData = System.Text.Encoding.UTF8.GetBytes(jsonString); + fileStream.Write(jsonData, offset: 0, count: jsonData.Length); } /// @@ -303,7 +302,7 @@ private static void CreateBackup(FileInfo settingsFile) if (settingsFile.Exists) { // Create a backup of the current file. - var backupFolder = Path.Combine(settingsFile.DirectoryName, ".backup"); + var backupFolder = Path.Combine(settingsFile.DirectoryName!, ".backup"); var backupFile = $"{Path.GetFileNameWithoutExtension(settingsFile.Name)}_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}{settingsFile.Extension}"; Directory.CreateDirectory(backupFolder); @@ -311,9 +310,9 @@ private static void CreateBackup(FileInfo settingsFile) } } - #endregion +#endregion - #region Helper +#region Helper /// /// Creates a default settings instance. @@ -346,8 +345,8 @@ private static FileInfo GetSettingsFile(string settingsName, DirectoryInfo setti return new FileInfo(Path.Combine(settingsDirectory.FullName, fileName)); } - #endregion +#endregion - #endregion +#endregion } } \ No newline at end of file diff --git a/src/Settings.Json.Net/JsonSettingsManagerBuilder.cs b/src/Settings.Json.Net/JsonSettingsManagerBuilder.cs index ad3a4fd..fd2899f 100644 --- a/src/Settings.Json.Net/JsonSettingsManagerBuilder.cs +++ b/src/Settings.Json.Net/JsonSettingsManagerBuilder.cs @@ -81,9 +81,9 @@ public class JsonSettingsManagerBuilder #region Fields - private DirectoryInfo _settingsDirectory; + private DirectoryInfo? _settingsDirectory; - private ISettingsCache _cache; + private ISettingsCache? _cache; #endregion diff --git a/src/Settings.Json.Net/Settings.Json.Net.csproj b/src/Settings.Json.Net/Settings.Json.Net.csproj index 99a4df6..580a77c 100644 --- a/src/Settings.Json.Net/Settings.Json.Net.csproj +++ b/src/Settings.Json.Net/Settings.Json.Net.csproj @@ -6,7 +6,7 @@ enable Phoenix.Functionality.Settings.Json.Net Phoenix.Functionality.Settings.Json.Net - 2.0.0 + 2.1.0 Felix Leistner Little Phoenix 2021 diff --git "a/src/Settings.Json.Net/\342\254\231/CHANGELOG.md" "b/src/Settings.Json.Net/\342\254\231/CHANGELOG.md" index 1ed8c83..9bbe7e0 100644 --- "a/src/Settings.Json.Net/\342\254\231/CHANGELOG.md" +++ "b/src/Settings.Json.Net/\342\254\231/CHANGELOG.md" @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ___ +## 2.1.0 (2021-23-11) + +### Changed + +- If the value of a **RegEx** setting property is **null**, then the pattern **.\*** (anything) will be used. +- The project now fully uses [nullable reference types](https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references). + +### Fixed + +- A possible deadlock scenario when updating a settings file based on a changed class layout has been addressed. +___ + ## 2.0.0 (2021-11-01) ### Added @@ -19,7 +31,6 @@ ___ :large_blue_circle: Phoenix.Functionality.Settings ~~1.1.0~~ → **2.0.0** :large_blue_circle: System.Text.Json ~~4.7.0~~ → **5.0.2** - ___ ## 1.1.0 (2020-02-09)