From 223437cc70519642e547c301e88fdbf816c8f774 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Thu, 8 Jul 2021 12:37:40 -0700 Subject: [PATCH 01/35] Deprecated existing ObjectStorage classes and migrated some to the *.Toolkit package, out of *.Toolkit.Uwp. Replaced Local/BaseObjectStorageHelper classes with ApplicationDataStorageHelper. --- .../ApplicationDataStorageHelper.cs | 242 ++++++++++++++++++ .../ObjectStorage/BaseObjectStorageHelper.cs | 1 + .../ObjectStorage/IObjectSerializer.cs | 3 + .../ObjectStorage/IObjectStorageHelper.cs | 2 + .../ObjectStorage/LocalObjectStorageHelper.cs | 2 + .../Helpers/ObjectStorage/SystemSerializer.cs | 1 + .../ObjectStorage/IFileStorageHelper.cs | 57 +++++ .../ObjectStorage/IObjectSerializer.cs | 28 ++ .../ObjectStorage/ISettingsStorageHelper.cs | 75 ++++++ .../Helpers/ObjectStorage/SystemSerializer.cs | 48 ++++ 10 files changed, 459 insertions(+) create mode 100644 Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs create mode 100644 Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs create mode 100644 Microsoft.Toolkit/Helpers/ObjectStorage/IObjectSerializer.cs create mode 100644 Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs create mode 100644 Microsoft.Toolkit/Helpers/ObjectStorage/SystemSerializer.cs diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs new file mode 100644 index 00000000000..0d646e116e5 --- /dev/null +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs @@ -0,0 +1,242 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Toolkit.Helpers; +using Windows.Storage; +using Windows.System; + +namespace Microsoft.Toolkit.Uwp.Helpers.ObjectStorage +{ + /// + /// Storage helper for files and folders living in Windows.Storage.ApplicationData storage endpoints. + /// + public class ApplicationDataStorageHelper : IFileStorageHelper, ISettingsStorageHelper + { + /// + /// Get a new instance using ApplicationData.Current and the provided serializer. + /// + /// Serializer for converting stored values. + /// A new instance of ApplicationDataStorageHelper. + public static ApplicationDataStorageHelper GetCurrent(Toolkit.Helpers.IObjectSerializer objectSerializer) + { + var appData = ApplicationData.Current; + return new ApplicationDataStorageHelper(appData, objectSerializer); + } + + /// + /// Get a new instance using the ApplicationData for the provided user and serializer. + /// + /// App data user owner. + /// Serializer for converting stored values. + /// A new instance of ApplicationDataStorageHelper. + public static async Task GetForUserAsync(User user, Toolkit.Helpers.IObjectSerializer objectSerializer) + { + var appData = await ApplicationData.GetForUserAsync(user); + return new ApplicationDataStorageHelper(appData, objectSerializer); + } + + /// + /// Gets the settings container. + /// + protected ApplicationData AppData { get; private set; } + + private ApplicationDataContainer DefaultSettings => AppData.LocalSettings; + + private StorageFolder DefaultFolder => AppData.LocalFolder; + + private readonly Toolkit.Helpers.IObjectSerializer _serializer; + + /// + /// Initializes a new instance of the class. + /// + /// The data store to interact with. + /// Serializer for converting stored values. + public ApplicationDataStorageHelper(ApplicationData appData, Toolkit.Helpers.IObjectSerializer objectSerializer) + { + if (appData == null) + { + throw new ArgumentNullException(nameof(appData)); + } + + AppData = appData; + + _serializer = objectSerializer ?? throw new ArgumentNullException(nameof(objectSerializer)); + } + + /// + public bool KeyExists(string key) + { + return DefaultSettings.Values.ContainsKey(key); + } + + /// + public bool KeyExists(string compositeKey, string key) + { + if (KeyExists(compositeKey)) + { + ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)DefaultSettings.Values[compositeKey]; + if (composite != null) + { + return composite.ContainsKey(key); + } + } + + return false; + } + + /// + public T Read(string key, T @default = default) + { + if (!DefaultSettings.Values.TryGetValue(key, out var value) || value == null) + { + return @default; + } + + return _serializer.Deserialize(value); + } + + /// + public T Read(string compositeKey, string key, T @default = default) + { + ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)DefaultSettings.Values[compositeKey]; + if (composite != null) + { + string value = (string)composite[key]; + if (value != null) + { + return _serializer.Deserialize(value); + } + } + + return @default; + } + + /// + public void Save(string key, T value) + { + DefaultSettings.Values[key] = _serializer.Serialize(value); + } + + /// + public void Save(string compositeKey, IDictionary values) + { + if (KeyExists(compositeKey)) + { + ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)DefaultSettings.Values[compositeKey]; + + foreach (KeyValuePair setting in values) + { + if (composite.ContainsKey(setting.Key)) + { + composite[setting.Key] = _serializer.Serialize(setting.Value); + } + else + { + composite.Add(setting.Key, _serializer.Serialize(setting.Value)); + } + } + } + else + { + ApplicationDataCompositeValue composite = new ApplicationDataCompositeValue(); + foreach (KeyValuePair setting in values) + { + composite.Add(setting.Key, _serializer.Serialize(setting.Value)); + } + + DefaultSettings.Values[compositeKey] = composite; + } + } + + /// + public void Delete(string key) + { + DefaultSettings.Values.Remove(key); + } + + /// + public void Delete(string compositeKey, string key) + { + if (KeyExists(compositeKey)) + { + ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)DefaultSettings.Values[compositeKey]; + composite.Remove(key); + } + } + + /// + public Task FileExistsAsync(string filePath) + { + return FileExistsAsync(DefaultFolder, filePath); + } + + /// + public Task ReadFileAsync(string filePath, T @default = default) + { + return ReadFileAsync(DefaultFolder, filePath, @default); + } + + /// + public Task> ReadFolderAsync(string folderPath) + { + return ReadFolderAsync(DefaultFolder, folderPath); + } + + /// + public Task SaveFileAsync(string filePath, T value) + { + return SaveFileAsync(DefaultFolder, filePath, value); + } + + /// + public Task SaveFolderAsync(string folderPath) + { + return SaveFolderAsync(DefaultFolder, folderPath); + } + + /// + public Task DeleteItemAsync(string itemPath) + { + return DeleteItemAsync(DefaultFolder, itemPath); + } + + private Task FileExistsAsync(StorageFolder folder, string filePath) + { + return folder.FileExistsAsync(filePath); + } + + private async Task ReadFileAsync(StorageFolder folder, string filePath, T @default = default) + { + string value = await StorageFileHelper.ReadTextFromFileAsync(folder, filePath); + return (value != null) ? _serializer.Deserialize(value) : @default; + } + + private async Task> ReadFolderAsync(StorageFolder folder, string folderPath) + { + var targetFolder = await folder.GetFolderAsync(folderPath); + var files = await targetFolder.GetFilesAsync(); + return files.Select((f) => f.Path + f.Name).ToList(); + } + + private Task SaveFileAsync(StorageFolder folder, string filePath, T value) + { + return StorageFileHelper.WriteTextToFileAsync(folder, _serializer.Serialize(value)?.ToString(), filePath, CreationCollisionOption.ReplaceExisting); + } + + private async Task SaveFolderAsync(StorageFolder folder, string folderPath) + { + await folder.CreateFolderAsync(folderPath, CreationCollisionOption.OpenIfExists); + } + + private async Task DeleteItemAsync(StorageFolder folder, string itemPath) + { + var item = await folder.GetItemAsync(itemPath); + await item.DeleteAsync(); + } + } +} diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/BaseObjectStorageHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/BaseObjectStorageHelper.cs index 528b2ca1c23..bf111d6aa01 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/BaseObjectStorageHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/BaseObjectStorageHelper.cs @@ -12,6 +12,7 @@ namespace Microsoft.Toolkit.Uwp.Helpers /// /// Shared implementation of ObjectStorageHelper. /// + [Obsolete("BaseObjectStorageHelper is deprecated and has been superceded by ApplicationDataStorageHelper.")] public abstract class BaseObjectStorageHelper : IObjectStorageHelper { private readonly IObjectSerializer serializer; diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/IObjectSerializer.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/IObjectSerializer.cs index ca8aa14ec68..c995d7b6f5b 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/IObjectSerializer.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/IObjectSerializer.cs @@ -2,11 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; + namespace Microsoft.Toolkit.Uwp.Helpers { /// /// A basic serialization service. /// + [Obsolete("IObjectSerializer has been migrated to the *.Toolikit package.")] public interface IObjectSerializer { /// diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/IObjectStorageHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/IObjectStorageHelper.cs index f4e5c861e2c..39339502e4e 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/IObjectStorageHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/IObjectStorageHelper.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Generic; using System.Threading.Tasks; using Windows.Storage; @@ -11,6 +12,7 @@ namespace Microsoft.Toolkit.Uwp.Helpers /// /// Service used to store data. /// + [Obsolete("IObjectStorageHelper is deprecated. Please use IDictionaryStorageHelper and IFileStorageHelper interfaces instead.")] public interface IObjectStorageHelper { /// diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/LocalObjectStorageHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/LocalObjectStorageHelper.cs index fedf4b806f8..d7b5d401f11 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/LocalObjectStorageHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/LocalObjectStorageHelper.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using Windows.Storage; namespace Microsoft.Toolkit.Uwp.Helpers @@ -9,6 +10,7 @@ namespace Microsoft.Toolkit.Uwp.Helpers /// /// Store data in the Local environment (only on the current device). /// + [Obsolete("LocalObjectStorageHelper is deprecated and has been superceded by the ApplicationDataStorageHelper.")] public class LocalObjectStorageHelper : BaseObjectStorageHelper { /// diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/SystemSerializer.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/SystemSerializer.cs index 12369315c6b..0565867bb86 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/SystemSerializer.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/SystemSerializer.cs @@ -12,6 +12,7 @@ namespace Microsoft.Toolkit.Uwp.Helpers /// A bare-bones serializer which knows how to deal with primitive types and strings only. It will store them directly based on the API. /// It is recommended for more complex scenarios to implement your own based on System.Text.Json, Newtonsoft.Json, or DataContractJsonSerializer see https://aka.ms/wct/storagehelper-migration /// + [Obsolete("SystemSerializer has been migrated to the *.Toolikit package.")] public class SystemSerializer : IObjectSerializer { /// diff --git a/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs b/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs new file mode 100644 index 00000000000..9aff19738dd --- /dev/null +++ b/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Microsoft.Toolkit.Helpers +{ + /// + /// Service interface used to store data in files and folders. + /// + public interface IFileStorageHelper + { + /// + /// Determines whether a file already exists. + /// + /// Key of the file (that contains object). + /// True if a value exists. + Task FileExistsAsync(string filePath); + + /// + /// Retrieves an object from a file. + /// + /// Type of object retrieved. + /// Path to the file that contains the object. + /// Default value of the object. + /// Waiting task until completion with the object in the file. + Task ReadFileAsync(string filePath, T @default = default(T)); + + /// + /// Retrieves all file listings for a folder. + /// + /// The path to the target folder. + /// A list of file names in the target folder. + Task> ReadFolderAsync(string folderPath); + + /// + /// Saves an object inside a file. + /// + /// Type of object saved. + /// Path to the file that will contain the object. + /// Object to save. + /// Waiting task until completion. + Task SaveFileAsync(string filePath, T value); + + /// + /// Saves a folder. + /// + /// The path and name of the target folder. + /// Waiting task until completion. + Task SaveFolderAsync(string folderPath); + + /// + /// Deletes a file or folder item. + /// + /// The path to the item for deletion. + /// Waiting task until completion. + Task DeleteItemAsync(string itemPath); + } +} diff --git a/Microsoft.Toolkit/Helpers/ObjectStorage/IObjectSerializer.cs b/Microsoft.Toolkit/Helpers/ObjectStorage/IObjectSerializer.cs new file mode 100644 index 00000000000..23095ee45e0 --- /dev/null +++ b/Microsoft.Toolkit/Helpers/ObjectStorage/IObjectSerializer.cs @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Toolkit.Helpers +{ + /// + /// A basic serialization service. + /// + public interface IObjectSerializer + { + /// + /// Serialize an object into a string. It is recommended to use strings as the final format for objects. + /// + /// The type of the object to serialize. + /// The object to serialize. + /// The serialized object. + object Serialize(T value); + + /// + /// Deserialize a primitive or string into an object of the given type. + /// + /// The type of the deserialized object. + /// The string to deserialize. + /// The deserialized object. + T Deserialize(object value); + } +} \ No newline at end of file diff --git a/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs b/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs new file mode 100644 index 00000000000..511adbfd57e --- /dev/null +++ b/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs @@ -0,0 +1,75 @@ +using System.Collections.Generic; + +namespace Microsoft.Toolkit.Helpers +{ + /// + /// Service interface used to store data using key value pairs. + /// + public interface ISettingsStorageHelper + { + /// + /// Determines whether a setting already exists. + /// + /// Key of the setting (that contains object). + /// True if a value exists. + bool KeyExists(string key); + + /// + /// Determines whether a setting already exists in composite. + /// + /// Key of the composite (that contains settings). + /// Key of the setting (that contains object). + /// True if a value exists. + bool KeyExists(string compositeKey, string key); + + /// + /// Retrieves a single item by its key. + /// + /// Type of object retrieved. + /// Key of the object. + /// Default value of the object. + /// The T object + T Read(string key, T @default = default(T)); + + /// + /// Retrieves a single item by its key in composite. + /// + /// Type of object retrieved. + /// Key of the composite (that contains settings). + /// Key of the object. + /// Default value of the object. + /// The T object. + T Read(string compositeKey, string key, T @default = default(T)); + + /// + /// Saves a single item by its key. + /// + /// Type of object saved. + /// Key of the value saved. + /// Object to save. + void Save(string key, T value); + + /// + /// Saves a group of items by its key in a composite. + /// This method should be considered for objects that do not exceed 8k bytes during the lifetime of the application + /// and for groups of settings which need to be treated in an atomic way. + /// + /// Type of object saved. + /// Key of the composite (that contains settings). + /// Objects to save. + void Save(string compositeKey, IDictionary values); + + /// + /// Deletes a single item by its key. + /// + /// Key of the object. + void Delete(string key); + + /// + /// Deletes a single item by its key in composite. + /// + /// Key of the composite (that contains settings). + /// Key of the object. + void Delete(string compositeKey, string key); + } +} diff --git a/Microsoft.Toolkit/Helpers/ObjectStorage/SystemSerializer.cs b/Microsoft.Toolkit/Helpers/ObjectStorage/SystemSerializer.cs new file mode 100644 index 00000000000..06d5c9d3af2 --- /dev/null +++ b/Microsoft.Toolkit/Helpers/ObjectStorage/SystemSerializer.cs @@ -0,0 +1,48 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Reflection; + +namespace Microsoft.Toolkit.Helpers +{ + /// + /// A bare-bones serializer which knows how to deal with primitive types and strings only. + /// It is recommended for more complex scenarios to implement your own based on System.Text.Json, Newtonsoft.Json, or DataContractJsonSerializer see https://aka.ms/wct/storagehelper-migration + /// + public class SystemSerializer : IObjectSerializer + { + /// + /// Take a primitive value from storage and return it as the requested type using the API. + /// + /// Type to convert value to. + /// Value from storage to convert. + /// Deserialized value or default value. + public T Deserialize(object value) + { + var type = typeof(T); + var typeInfo = type.GetTypeInfo(); + + if (typeInfo.IsPrimitive || type == typeof(string)) + { + return (T)Convert.ChangeType(value, type); + } + + return ThrowNotSupportedException(); + + static T ThrowNotSupportedException() => throw new NotSupportedException("This serializer can only handle primitive types and strings. Please implement your own IObjectSerializer for more complex scenarios."); + } + + /// + /// Returns the value so that it can be serialized directly. + /// + /// Type to serialize from. + /// Value to serialize. + /// String representation of value. + public object Serialize(T value) + { + return value; + } + } +} \ No newline at end of file From 5629f4db9969c9aed10276f6fb2910c239f403c6 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Thu, 8 Jul 2021 12:39:04 -0700 Subject: [PATCH 02/35] Code style tweak --- .../Helpers/ObjectStorage/ApplicationDataStorageHelper.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs index 0d646e116e5..c23a52fa40c 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs @@ -58,13 +58,7 @@ public static async Task GetForUserAsync(User user /// Serializer for converting stored values. public ApplicationDataStorageHelper(ApplicationData appData, Toolkit.Helpers.IObjectSerializer objectSerializer) { - if (appData == null) - { - throw new ArgumentNullException(nameof(appData)); - } - - AppData = appData; - + AppData = appData ?? throw new ArgumentNullException(nameof(appData)); _serializer = objectSerializer ?? throw new ArgumentNullException(nameof(objectSerializer)); } From c26c3f1851e6378cc8eec6d2c66e3ea2ce46ee87 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Thu, 8 Jul 2021 13:21:50 -0700 Subject: [PATCH 03/35] Updated headers and bad namespace --- .../Helpers/ObjectStorage/ApplicationDataStorageHelper.cs | 2 +- Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs | 4 ++++ .../Helpers/ObjectStorage/ISettingsStorageHelper.cs | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs index c23a52fa40c..2bdf8fa29f5 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs @@ -10,7 +10,7 @@ using Windows.Storage; using Windows.System; -namespace Microsoft.Toolkit.Uwp.Helpers.ObjectStorage +namespace Microsoft.Toolkit.Uwp.Helpers { /// /// Storage helper for files and folders living in Windows.Storage.ApplicationData storage endpoints. diff --git a/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs b/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs index 9aff19738dd..c402dc76b3c 100644 --- a/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs +++ b/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs @@ -1,3 +1,7 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + using System.Collections.Generic; using System.Threading.Tasks; diff --git a/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs b/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs index 511adbfd57e..0c54261b2f0 100644 --- a/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs +++ b/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs @@ -1,3 +1,7 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + using System.Collections.Generic; namespace Microsoft.Toolkit.Helpers From 41da215006f1ef211d4e3c8c45b06ae5b99c05e8 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Thu, 8 Jul 2021 13:42:30 -0700 Subject: [PATCH 04/35] Fixed possible null reference warnings --- Microsoft.Toolkit.Uwp/Helpers/SystemInformation.cs | 4 ++-- Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs | 2 +- .../Helpers/ObjectStorage/ISettingsStorageHelper.cs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Microsoft.Toolkit.Uwp/Helpers/SystemInformation.cs b/Microsoft.Toolkit.Uwp/Helpers/SystemInformation.cs index 0fa2dc96223..2b84aa7064e 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/SystemInformation.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/SystemInformation.cs @@ -23,9 +23,9 @@ namespace Microsoft.Toolkit.Uwp.Helpers public sealed class SystemInformation { /// - /// The instance used to save and retrieve application settings. + /// The instance used to save and retrieve application settings. /// - private readonly LocalObjectStorageHelper _localObjectStorageHelper = new(new SystemSerializer()); + private readonly ApplicationDataStorageHelper _localObjectStorageHelper = ApplicationDataStorageHelper.GetCurrent(new Toolkit.Helpers.SystemSerializer()); /// /// The starting time of the current application session (since app launch or last move to foreground). diff --git a/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs b/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs index c402dc76b3c..03dd4b20cc3 100644 --- a/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs +++ b/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs @@ -26,7 +26,7 @@ public interface IFileStorageHelper /// Path to the file that contains the object. /// Default value of the object. /// Waiting task until completion with the object in the file. - Task ReadFileAsync(string filePath, T @default = default(T)); + Task ReadFileAsync(string filePath, T? @default = default); /// /// Retrieves all file listings for a folder. diff --git a/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs b/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs index 0c54261b2f0..af99361206e 100644 --- a/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs +++ b/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs @@ -33,7 +33,7 @@ public interface ISettingsStorageHelper /// Key of the object. /// Default value of the object. /// The T object - T Read(string key, T @default = default(T)); + T Read(string key, T? @default = default(T)); /// /// Retrieves a single item by its key in composite. @@ -43,7 +43,7 @@ public interface ISettingsStorageHelper /// Key of the object. /// Default value of the object. /// The T object. - T Read(string compositeKey, string key, T @default = default(T)); + T Read(string compositeKey, string key, T? @default = default(T)); /// /// Saves a single item by its key. From e809fabcc9fd101f65b7943df3a86481d22449c3 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Thu, 8 Jul 2021 14:00:59 -0700 Subject: [PATCH 05/35] Fixed another potential null --- Microsoft.Toolkit/Helpers/ObjectStorage/IObjectSerializer.cs | 2 +- Microsoft.Toolkit/Helpers/ObjectStorage/SystemSerializer.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Microsoft.Toolkit/Helpers/ObjectStorage/IObjectSerializer.cs b/Microsoft.Toolkit/Helpers/ObjectStorage/IObjectSerializer.cs index 23095ee45e0..d046ead57d1 100644 --- a/Microsoft.Toolkit/Helpers/ObjectStorage/IObjectSerializer.cs +++ b/Microsoft.Toolkit/Helpers/ObjectStorage/IObjectSerializer.cs @@ -15,7 +15,7 @@ public interface IObjectSerializer /// The type of the object to serialize. /// The object to serialize. /// The serialized object. - object Serialize(T value); + object? Serialize(T value); /// /// Deserialize a primitive or string into an object of the given type. diff --git a/Microsoft.Toolkit/Helpers/ObjectStorage/SystemSerializer.cs b/Microsoft.Toolkit/Helpers/ObjectStorage/SystemSerializer.cs index 06d5c9d3af2..fbf5d9c1d4e 100644 --- a/Microsoft.Toolkit/Helpers/ObjectStorage/SystemSerializer.cs +++ b/Microsoft.Toolkit/Helpers/ObjectStorage/SystemSerializer.cs @@ -40,7 +40,7 @@ public T Deserialize(object value) /// Type to serialize from. /// Value to serialize. /// String representation of value. - public object Serialize(T value) + public object? Serialize(T value) { return value; } From 4eaceec5d21eb9949a68eb6b5ea5da25739e048f Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Fri, 9 Jul 2021 11:59:29 -0700 Subject: [PATCH 06/35] Updated storage related unit tests --- UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs | 2 +- .../UnitTests.UWP/Helpers/SystemTextJsonSerializer.cs | 2 +- UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs | 8 ++++---- UnitTests/UnitTests.UWP/Helpers/Test_SystemInformation.cs | 3 ++- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs b/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs index 35551ee7421..c0d492467a0 100644 --- a/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs +++ b/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs @@ -4,7 +4,7 @@ using System; using System.Reflection; -using Microsoft.Toolkit.Uwp.Helpers; +using Microsoft.Toolkit.Helpers; using Newtonsoft.Json; namespace UnitTests.UWP.Helpers diff --git a/UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer.cs b/UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer.cs index 139f16135f8..7871089f0b4 100644 --- a/UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer.cs +++ b/UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer.cs @@ -4,7 +4,7 @@ using System; using System.Text.Json; -using Microsoft.Toolkit.Uwp.Helpers; +using Microsoft.Toolkit.Helpers; namespace UnitTests.UWP.Helpers { diff --git a/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs b/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs index 823753060e8..4c4cede0e3a 100644 --- a/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs +++ b/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using Microsoft.Toolkit.Helpers; using Microsoft.Toolkit.Uwp.Helpers; using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json; @@ -14,10 +15,9 @@ namespace UnitTests.Helpers [TestClass] public class Test_StorageHelper { - private LocalObjectStorageHelper _localStorageHelperSystem = new LocalObjectStorageHelper(new SystemSerializer()); - private LocalObjectStorageHelper _localStorageHelperJsonCompat = new LocalObjectStorageHelper(new JsonObjectSerializer()); - - private LocalObjectStorageHelper _localStorageHelperJsonNew = new LocalObjectStorageHelper(new SystemTextJsonSerializer()); + private ISettingsStorageHelper _localStorageHelperSystem = ApplicationDataStorageHelper.GetCurrent(new Microsoft.Toolkit.Helpers.SystemSerializer()); + private ISettingsStorageHelper _localStorageHelperJsonCompat = ApplicationDataStorageHelper.GetCurrent(new JsonObjectSerializer()); + private ISettingsStorageHelper _localStorageHelperJsonNew = ApplicationDataStorageHelper.GetCurrent(new SystemTextJsonSerializer()); /// /// Checks that we're running 10.0.3 version of Newtonsoft.Json package which we used in 6.1.1. diff --git a/UnitTests/UnitTests.UWP/Helpers/Test_SystemInformation.cs b/UnitTests/UnitTests.UWP/Helpers/Test_SystemInformation.cs index 78f12378913..27488ac1a29 100644 --- a/UnitTests/UnitTests.UWP/Helpers/Test_SystemInformation.cs +++ b/UnitTests/UnitTests.UWP/Helpers/Test_SystemInformation.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using Microsoft.Toolkit.Helpers; using Microsoft.Toolkit.Uwp.Helpers; using Microsoft.VisualStudio.TestTools.UnitTesting; using Windows.ApplicationModel; @@ -57,7 +58,7 @@ public void Test_SystemInformation_ConsistentInfoForStartupWithUpdate() // Simulate a first app startup _ = (SystemInformation)Activator.CreateInstance(typeof(SystemInformation), nonPublic: true); - LocalObjectStorageHelper localObjectStorageHelper = new(new SystemSerializer()); + ISettingsStorageHelper localObjectStorageHelper = ApplicationDataStorageHelper.GetCurrent(new Microsoft.Toolkit.Helpers.SystemSerializer()); PackageVersion previousVersion = new() { Build = 42, Major = 1111, Minor = 2222, Revision = 12345 }; localObjectStorageHelper.Save("currentVersion", previousVersion.ToFormattedString()); From be6555d9df7c3cfe534b9a6d6a9fc47b86a6aaef Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Fri, 9 Jul 2021 12:30:54 -0700 Subject: [PATCH 07/35] Updated ambiguous references in comments --- UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs b/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs index 4c4cede0e3a..09714a263f0 100644 --- a/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs +++ b/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs @@ -50,7 +50,7 @@ public void Test_StorageHelper_LegacyIntTest() } /// - /// If we try and deserialize a complex type with the , we do a check ourselves and will throw our own exception. + /// If we try and deserialize a complex type with the , we do a check ourselves and will throw our own exception. /// [TestCategory("Helpers")] [TestMethod] @@ -68,7 +68,7 @@ public void Test_StorageHelper_LegacyDateTestFailure() } /// - /// The doesn't support complex types, since it just passes through directly. + /// The doesn't support complex types, since it just passes through directly. /// We'll get the argument exception from the API. /// [TestCategory("Helpers")] From d9e43fb4edf5d6d61acdb3dd9d8376053e0265eb Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Mon, 12 Jul 2021 14:01:42 -0700 Subject: [PATCH 08/35] Updated ObjectStorage references in samples --- .../Controls/SampleAppMarkdownRenderer.cs | 2 +- .../Models/Sample.cs | 2 +- .../Models/Samples.cs | 2 +- .../Object Storage/ObjectStorageCode.bind | 19 +++++++++---------- .../Object Storage/ObjectStoragePage.xaml.cs | 3 ++- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Controls/SampleAppMarkdownRenderer.cs b/Microsoft.Toolkit.Uwp.SampleApp/Controls/SampleAppMarkdownRenderer.cs index 715a6668d06..c3edb07a141 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Controls/SampleAppMarkdownRenderer.cs +++ b/Microsoft.Toolkit.Uwp.SampleApp/Controls/SampleAppMarkdownRenderer.cs @@ -417,7 +417,7 @@ public string DesiredLang /// /// The Local Storage Helper. /// - private LocalObjectStorageHelper storage = new LocalObjectStorageHelper(new SystemSerializer()); + private ApplicationDataStorageHelper storage = ApplicationDataStorageHelper.GetCurrent(new Toolkit.Helpers.SystemSerializer()); /// /// DocFX note types and styling info, keyed by identifier. diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Models/Sample.cs b/Microsoft.Toolkit.Uwp.SampleApp/Models/Sample.cs index f57a430d307..ad4587b1125 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Models/Sample.cs +++ b/Microsoft.Toolkit.Uwp.SampleApp/Models/Sample.cs @@ -44,7 +44,7 @@ public class Sample public static async void EnsureCacheLatest() { - var settingsStorage = new LocalObjectStorageHelper(new SystemSerializer()); + var settingsStorage = ApplicationDataStorageHelper.GetCurrent(new Toolkit.Helpers.SystemSerializer()); var onlineDocsSHA = await GetDocsSHA(); var cacheSHA = settingsStorage.Read(_cacheSHAKey); diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Models/Samples.cs b/Microsoft.Toolkit.Uwp.SampleApp/Models/Samples.cs index 8105e859b78..c99bc11b8bf 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Models/Samples.cs +++ b/Microsoft.Toolkit.Uwp.SampleApp/Models/Samples.cs @@ -21,7 +21,7 @@ public static class Samples private static SemaphoreSlim _semaphore = new SemaphoreSlim(1); private static LinkedList _recentSamples; - private static LocalObjectStorageHelper _localObjectStorageHelper = new LocalObjectStorageHelper(new SystemSerializer()); + private static ApplicationDataStorageHelper _localObjectStorageHelper = ApplicationDataStorageHelper.GetCurrent(new Toolkit.Helpers.SystemSerializer()); public static async Task GetCategoryBySample(Sample sample) { diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/Object Storage/ObjectStorageCode.bind b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/Object Storage/ObjectStorageCode.bind index 50d77bc5e3e..0b0c4d9263e 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/Object Storage/ObjectStorageCode.bind +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/Object Storage/ObjectStorageCode.bind @@ -1,25 +1,24 @@ -var localObjectStorageHelper = new LocalObjectStorageHelper(); -var roamingObjectStorageHelper = new RoamingObjectStorageHelper(); +ApplicationDataStorageHelper appDataStorageHelper = ApplicationDataStorageHelper.GetCurrent(new Toolkit.Helpers.SystemSerializer()); // Read and Save with simple objects string keySimpleObject = "simple"; -string result = localObjectStorageHelper.Read(keySimpleObject); -localObjectStorageHelper.Save(keySimpleObject, 47); +string result = appDataStorageHelper.Read(keySimpleObject); +appDataStorageHelper.Save(keySimpleObject, 47); // Read and Save with complex/large objects -string keyLargeObject = "large"; -var result = localObjectStorageHelper.ReadFileAsync(keyLargeObject); +string complexObjectKey = "complexObject"; +var complexObject = await appDataStorageHelper.ReadFileAsync(complexObjectKey); -var o = new MyLargeObject +var myComplexObject = new MyComplexObject() { ... }; -localObjectStorageHelper.SaveFileAsync(keySimpleObject, o); +await appDataStorageHelper.SaveFileAsync(complexObjectKey, myComplexObject); // Complex object -public class MyLargeObject +public class MyComplexObject { public string MyContent { get; set; } public List MyContents { get; set; } - public List MyObjects { get; set; } + public List MyObjects { get; set; } } \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/Object Storage/ObjectStoragePage.xaml.cs b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/Object Storage/ObjectStoragePage.xaml.cs index e2da83f53f1..e1e0e925b92 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/Object Storage/ObjectStoragePage.xaml.cs +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/Object Storage/ObjectStoragePage.xaml.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.Toolkit.Helpers; using Microsoft.Toolkit.Uwp.Helpers; using Windows.UI.Xaml; @@ -9,7 +10,7 @@ namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages { public sealed partial class ObjectStoragePage { - private readonly IObjectStorageHelper localStorageHelper = new LocalObjectStorageHelper(new SystemSerializer()); + private readonly ISettingsStorageHelper localStorageHelper = ApplicationDataStorageHelper.GetCurrent(new Toolkit.Helpers.SystemSerializer()); public ObjectStoragePage() { From c6184edf507d0b162b0659788c6373fdeedc68b8 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Tue, 13 Jul 2021 15:26:54 -0700 Subject: [PATCH 09/35] Update Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/IObjectSerializer.cs Co-authored-by: Michael Hawker MSFT (XAML Llama) <24302614+michael-hawker@users.noreply.github.com> --- .../Helpers/ObjectStorage/IObjectSerializer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/IObjectSerializer.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/IObjectSerializer.cs index c995d7b6f5b..0f1bfa4d5e4 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/IObjectSerializer.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/IObjectSerializer.cs @@ -9,7 +9,7 @@ namespace Microsoft.Toolkit.Uwp.Helpers /// /// A basic serialization service. /// - [Obsolete("IObjectSerializer has been migrated to the *.Toolikit package.")] + [Obsolete("IObjectSerializer has been migrated to the Microsoft.Toolkit (CommunityToolkit.Common) package.")] public interface IObjectSerializer { /// @@ -28,4 +28,4 @@ public interface IObjectSerializer /// The deserialized object. T Deserialize(object value); } -} \ No newline at end of file +} From 870c85f32f703aff050748a94432762b79b8697d Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Tue, 13 Jul 2021 15:27:38 -0700 Subject: [PATCH 10/35] Update Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/SystemSerializer.cs Co-authored-by: Michael Hawker MSFT (XAML Llama) <24302614+michael-hawker@users.noreply.github.com> --- .../Helpers/ObjectStorage/SystemSerializer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/SystemSerializer.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/SystemSerializer.cs index 0565867bb86..7c6ad802cf4 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/SystemSerializer.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/SystemSerializer.cs @@ -12,7 +12,7 @@ namespace Microsoft.Toolkit.Uwp.Helpers /// A bare-bones serializer which knows how to deal with primitive types and strings only. It will store them directly based on the API. /// It is recommended for more complex scenarios to implement your own based on System.Text.Json, Newtonsoft.Json, or DataContractJsonSerializer see https://aka.ms/wct/storagehelper-migration /// - [Obsolete("SystemSerializer has been migrated to the *.Toolikit package.")] + [Obsolete("SystemSerializer has been migrated to the Microsoft.Toolkit (CommunityToolkit.Common) package.")] public class SystemSerializer : IObjectSerializer { /// @@ -47,4 +47,4 @@ public object Serialize(T value) return value; } } -} \ No newline at end of file +} From e36c95523fcfaa75d2d3035c44b7288e8b5cbfb9 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Wed, 14 Jul 2021 16:05:10 -0700 Subject: [PATCH 11/35] PR updates --- .../ApplicationDataStorageHelper.cs | 42 +++++++++++++++---- .../ObjectStorage/LocalObjectStorageHelper.cs | 2 +- .../ObjectStorage/DirectoryItemType.cs | 27 ++++++++++++ .../ObjectStorage/IFileStorageHelper.cs | 24 +++++++---- 4 files changed, 77 insertions(+), 18 deletions(-) create mode 100644 Microsoft.Toolkit/Helpers/ObjectStorage/DirectoryItemType.cs diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs index 2bdf8fa29f5..59a20edcfe8 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs @@ -164,9 +164,9 @@ public void Delete(string compositeKey, string key) } /// - public Task FileExistsAsync(string filePath) + public Task ItemExistsAsync(string itemName) { - return FileExistsAsync(DefaultFolder, filePath); + return ItemExistsAsync(DefaultFolder, itemName); } /// @@ -176,7 +176,7 @@ public Task ReadFileAsync(string filePath, T @default = default) } /// - public Task> ReadFolderAsync(string folderPath) + public Task>> ReadFolderAsync(string folderPath) { return ReadFolderAsync(DefaultFolder, folderPath); } @@ -199,9 +199,27 @@ public Task DeleteItemAsync(string itemPath) return DeleteItemAsync(DefaultFolder, itemPath); } - private Task FileExistsAsync(StorageFolder folder, string filePath) + /// + /// Determine the existance of a file at the specified path. + /// To check for folders, use . + /// + /// The name of the file. + /// Whether the file should be searched for recursively. + /// A task with the result of the file query. + public Task FileExistsAsync(string fileName, bool isRecursive = false) + { + return FileExistsAsync(DefaultFolder, fileName, isRecursive); + } + + private async Task ItemExistsAsync(StorageFolder folder, string itemName) { - return folder.FileExistsAsync(filePath); + var item = await folder.TryGetItemAsync(itemName); + return item != null; + } + + private Task FileExistsAsync(StorageFolder folder, string fileName, bool isRecursive) + { + return folder.FileExistsAsync(fileName, isRecursive); } private async Task ReadFileAsync(StorageFolder folder, string filePath, T @default = default) @@ -210,11 +228,19 @@ private async Task ReadFileAsync(StorageFolder folder, string filePath, T return (value != null) ? _serializer.Deserialize(value) : @default; } - private async Task> ReadFolderAsync(StorageFolder folder, string folderPath) + private async Task>> ReadFolderAsync(StorageFolder folder, string folderPath) { var targetFolder = await folder.GetFolderAsync(folderPath); - var files = await targetFolder.GetFilesAsync(); - return files.Select((f) => f.Path + f.Name).ToList(); + var items = await targetFolder.GetItemsAsync(); + + return items.Select((item) => + { + var itemType = item.IsOfType(StorageItemTypes.File) ? DirectoryItemType.File + : item.IsOfType(StorageItemTypes.Folder) ? DirectoryItemType.Folder + : DirectoryItemType.None; + + return new Tuple(itemType, item.Name); + }).ToList(); } private Task SaveFileAsync(StorageFolder folder, string filePath, T value) diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/LocalObjectStorageHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/LocalObjectStorageHelper.cs index d7b5d401f11..45905f73051 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/LocalObjectStorageHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/LocalObjectStorageHelper.cs @@ -10,7 +10,7 @@ namespace Microsoft.Toolkit.Uwp.Helpers /// /// Store data in the Local environment (only on the current device). /// - [Obsolete("LocalObjectStorageHelper is deprecated and has been superceded by the ApplicationDataStorageHelper.")] + [Obsolete("LocalObjectStorageHelper is deprecated and has been superceded by the ApplicationDataStorageHelper. To upgrade, simply swap any LocalObjectStorageHelper instances with ApplicationDataStorageHelper.GetCurrent(serializer). The underlying interfaces are nearly identical but now with even more features available, such as deletion and access to user specific data stores!")] public class LocalObjectStorageHelper : BaseObjectStorageHelper { /// diff --git a/Microsoft.Toolkit/Helpers/ObjectStorage/DirectoryItemType.cs b/Microsoft.Toolkit/Helpers/ObjectStorage/DirectoryItemType.cs new file mode 100644 index 00000000000..150fa3770ac --- /dev/null +++ b/Microsoft.Toolkit/Helpers/ObjectStorage/DirectoryItemType.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Toolkit.Helpers +{ + /// + /// Represents the types of items available in a directory. + /// + public enum DirectoryItemType + { + /// + /// The item is neither a file or a folder. + /// + None, + + /// + /// Represents a file type item. + /// + File, + + /// + /// Represents a folder type item. + /// + Folder + } +} diff --git a/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs b/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs index 03dd4b20cc3..3835c73aabc 100644 --- a/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs +++ b/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs @@ -2,22 +2,28 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Generic; using System.Threading.Tasks; namespace Microsoft.Toolkit.Helpers { /// - /// Service interface used to store data in files and folders. + /// Service interface used to store data in a directory/file-system via files and folders. + /// + /// This interface is meant to help abstract file storage operations across platforms in a library, + /// but the actual behavior will be up to the implementer. Such as, we don't provide a sense of a current directory, + /// so an implementor should consider using full paths to support any file operations. Otherwise, a "directory aware" + /// implementation could be achieved with a current directory field and traversal functions, in which case relative paths would be applicable. /// public interface IFileStorageHelper { /// - /// Determines whether a file already exists. + /// Determines if a directory item already exists. /// - /// Key of the file (that contains object). - /// True if a value exists. - Task FileExistsAsync(string filePath); + /// Key of the file. + /// True if an item exists. + Task ItemExistsAsync(string itemName); /// /// Retrieves an object from a file. @@ -29,11 +35,11 @@ public interface IFileStorageHelper Task ReadFileAsync(string filePath, T? @default = default); /// - /// Retrieves all file listings for a folder. + /// Retrieves the listings for a folder and the item types. /// /// The path to the target folder. - /// A list of file names in the target folder. - Task> ReadFolderAsync(string folderPath); + /// A list of file types and names in the target folder. + Task>> ReadFolderAsync(string folderPath); /// /// Saves an object inside a file. @@ -45,7 +51,7 @@ public interface IFileStorageHelper Task SaveFileAsync(string filePath, T value); /// - /// Saves a folder. + /// Ensure a folder exists at the folder path specified. /// /// The path and name of the target folder. /// Waiting task until completion. From 7edade152609516a0615d687fd9ce9e0b507caf7 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Wed, 14 Jul 2021 16:23:37 -0700 Subject: [PATCH 12/35] Renamed SaveFile/FolderAsync to CreateFile/FolderAsync --- .../ObjectStorage/ApplicationDataStorageHelper.cs | 12 ++++++------ .../Helpers/ObjectStorage/IFileStorageHelper.cs | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs index 59a20edcfe8..58549983dc5 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs @@ -182,15 +182,15 @@ public Task>> ReadFolderAsync(string fold } /// - public Task SaveFileAsync(string filePath, T value) + public Task CreateFileAsync(string filePath, T value) { - return SaveFileAsync(DefaultFolder, filePath, value); + return CreateFileAsync(DefaultFolder, filePath, value); } /// - public Task SaveFolderAsync(string folderPath) + public Task CreateFolderAsync(string folderPath) { - return SaveFolderAsync(DefaultFolder, folderPath); + return CreateFolderAsync(DefaultFolder, folderPath); } /// @@ -243,12 +243,12 @@ private async Task>> ReadFolderAsync(Stor }).ToList(); } - private Task SaveFileAsync(StorageFolder folder, string filePath, T value) + private Task CreateFileAsync(StorageFolder folder, string filePath, T value) { return StorageFileHelper.WriteTextToFileAsync(folder, _serializer.Serialize(value)?.ToString(), filePath, CreationCollisionOption.ReplaceExisting); } - private async Task SaveFolderAsync(StorageFolder folder, string folderPath) + private async Task CreateFolderAsync(StorageFolder folder, string folderPath) { await folder.CreateFolderAsync(folderPath, CreationCollisionOption.OpenIfExists); } diff --git a/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs b/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs index 3835c73aabc..eae8a3dfbef 100644 --- a/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs +++ b/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs @@ -48,14 +48,14 @@ public interface IFileStorageHelper /// Path to the file that will contain the object. /// Object to save. /// Waiting task until completion. - Task SaveFileAsync(string filePath, T value); + Task CreateFileAsync(string filePath, T value); /// /// Ensure a folder exists at the folder path specified. /// /// The path and name of the target folder. /// Waiting task until completion. - Task SaveFolderAsync(string folderPath); + Task CreateFolderAsync(string folderPath); /// /// Deletes a file or folder item. From bf97b451759591fd1c111a693ca83905cae46a79 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Wed, 14 Jul 2021 16:37:28 -0700 Subject: [PATCH 13/35] Readded SaveFileAsync to match previous implementation --- .../ApplicationDataStorageHelper.cs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs index 58549983dc5..fcd54e9c0d8 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs @@ -184,7 +184,7 @@ public Task>> ReadFolderAsync(string fold /// public Task CreateFileAsync(string filePath, T value) { - return CreateFileAsync(DefaultFolder, filePath, value); + return SaveFileAsync(DefaultFolder, filePath, value); } /// @@ -211,6 +211,18 @@ public Task FileExistsAsync(string fileName, bool isRecursive = false) return FileExistsAsync(DefaultFolder, fileName, isRecursive); } + /// + /// Saves an object inside a file. + /// + /// Type of object saved. + /// Path to the file that will contain the object. + /// Object to save. + /// Waiting task until completion. + public Task SaveFileAsync(string filePath, T value) + { + return SaveFileAsync(DefaultFolder, filePath, value); + } + private async Task ItemExistsAsync(StorageFolder folder, string itemName) { var item = await folder.TryGetItemAsync(itemName); @@ -243,7 +255,7 @@ private async Task>> ReadFolderAsync(Stor }).ToList(); } - private Task CreateFileAsync(StorageFolder folder, string filePath, T value) + private Task SaveFileAsync(StorageFolder folder, string filePath, T value) { return StorageFileHelper.WriteTextToFileAsync(folder, _serializer.Serialize(value)?.ToString(), filePath, CreationCollisionOption.ReplaceExisting); } From 5707c6d6693298f6c1ecad205b0597d9806a8d1c Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Fri, 16 Jul 2021 09:11:20 -0700 Subject: [PATCH 14/35] Fixed typo in IObjectStorageHelper. Updated var name to be more accurate in Samples.cs --- Microsoft.Toolkit.Uwp.SampleApp/Models/Samples.cs | 6 +++--- .../Helpers/ObjectStorage/IObjectStorageHelper.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Models/Samples.cs b/Microsoft.Toolkit.Uwp.SampleApp/Models/Samples.cs index c99bc11b8bf..f7e096772b0 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Models/Samples.cs +++ b/Microsoft.Toolkit.Uwp.SampleApp/Models/Samples.cs @@ -21,7 +21,7 @@ public static class Samples private static SemaphoreSlim _semaphore = new SemaphoreSlim(1); private static LinkedList _recentSamples; - private static ApplicationDataStorageHelper _localObjectStorageHelper = ApplicationDataStorageHelper.GetCurrent(new Toolkit.Helpers.SystemSerializer()); + private static ApplicationDataStorageHelper _appDataStorageHelper = ApplicationDataStorageHelper.GetCurrent(new Toolkit.Helpers.SystemSerializer()); public static async Task GetCategoryBySample(Sample sample) { @@ -98,7 +98,7 @@ public static async Task> GetRecentSamples() if (_recentSamples == null) { _recentSamples = new LinkedList(); - var savedSamples = _localObjectStorageHelper.Read(_recentSamplesStorageKey); + var savedSamples = _appDataStorageHelper.Read(_recentSamplesStorageKey); if (savedSamples != null) { @@ -144,7 +144,7 @@ private static void SaveRecentSamples() } var str = string.Join(";", _recentSamples.Take(10).Select(s => s.Name).ToArray()); - _localObjectStorageHelper.Save(_recentSamplesStorageKey, str); + _appDataStorageHelper.Save(_recentSamplesStorageKey, str); } } } \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/IObjectStorageHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/IObjectStorageHelper.cs index 39339502e4e..e742fe18586 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/IObjectStorageHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/IObjectStorageHelper.cs @@ -12,7 +12,7 @@ namespace Microsoft.Toolkit.Uwp.Helpers /// /// Service used to store data. /// - [Obsolete("IObjectStorageHelper is deprecated. Please use IDictionaryStorageHelper and IFileStorageHelper interfaces instead.")] + [Obsolete("IObjectStorageHelper is deprecated. Please use ISettingsStorageHelper and IFileStorageHelper interfaces instead.")] public interface IObjectStorageHelper { /// From f70e3696bed16887126fd5687a125b5b4cc3758b Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Mon, 19 Jul 2021 09:51:49 -0700 Subject: [PATCH 15/35] Updated storage var names to be consistent across solution --- .../Controls/SampleAppMarkdownRenderer.cs | 9 +-- .../Models/Sample.cs | 3 +- .../Models/Samples.cs | 7 ++- .../Object Storage/ObjectStoragePage.xaml.cs | 8 +-- .../Helpers/SystemInformation.cs | 57 ++++++++++--------- .../Helpers/Test_StorageHelper.cs | 36 ++++++------ .../Helpers/Test_SystemInformation.cs | 4 +- 7 files changed, 64 insertions(+), 60 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Controls/SampleAppMarkdownRenderer.cs b/Microsoft.Toolkit.Uwp.SampleApp/Controls/SampleAppMarkdownRenderer.cs index c3edb07a141..4085cd81575 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Controls/SampleAppMarkdownRenderer.cs +++ b/Microsoft.Toolkit.Uwp.SampleApp/Controls/SampleAppMarkdownRenderer.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Toolkit.Helpers; using Microsoft.Toolkit.Parsers.Markdown; using Microsoft.Toolkit.Parsers.Markdown.Blocks; using Microsoft.Toolkit.Parsers.Markdown.Inlines; @@ -405,19 +406,19 @@ public string DesiredLang { get { - return storage.Read(DesiredLangKey); + return settingsStorage.Read(DesiredLangKey); } set { - storage.Save(DesiredLangKey, value); + settingsStorage.Save(DesiredLangKey, value); } } /// - /// The Local Storage Helper. + /// The local app data storage helper for storing settings. /// - private ApplicationDataStorageHelper storage = ApplicationDataStorageHelper.GetCurrent(new Toolkit.Helpers.SystemSerializer()); + private ISettingsStorageHelper settingsStorage = ApplicationDataStorageHelper.GetCurrent(new Toolkit.Helpers.SystemSerializer()); /// /// DocFX note types and styling info, keyed by identifier. diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Models/Sample.cs b/Microsoft.Toolkit.Uwp.SampleApp/Models/Sample.cs index d15a54ce2f3..e792801959a 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Models/Sample.cs +++ b/Microsoft.Toolkit.Uwp.SampleApp/Models/Sample.cs @@ -20,6 +20,7 @@ // TODO Reintroduce graph controls // using Microsoft.Toolkit.Graph.Converters; // using Microsoft.Toolkit.Graph.Providers; +using Microsoft.Toolkit.Helpers; using Microsoft.Toolkit.Uwp.Helpers; using Microsoft.Toolkit.Uwp.Input.GazeInteraction; using Microsoft.Toolkit.Uwp.SampleApp.Models; @@ -45,7 +46,7 @@ public class Sample public static async void EnsureCacheLatest() { - var settingsStorage = ApplicationDataStorageHelper.GetCurrent(new Toolkit.Helpers.SystemSerializer()); + ISettingsStorageHelper settingsStorage = ApplicationDataStorageHelper.GetCurrent(new Toolkit.Helpers.SystemSerializer()); var onlineDocsSHA = await GetDocsSHA(); var cacheSHA = settingsStorage.Read(_cacheSHAKey); diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Models/Samples.cs b/Microsoft.Toolkit.Uwp.SampleApp/Models/Samples.cs index f7e096772b0..c43cf3aeb33 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Models/Samples.cs +++ b/Microsoft.Toolkit.Uwp.SampleApp/Models/Samples.cs @@ -9,6 +9,7 @@ using System.Text.Json; using System.Threading; using System.Threading.Tasks; +using Microsoft.Toolkit.Helpers; using Microsoft.Toolkit.Uwp.Helpers; namespace Microsoft.Toolkit.Uwp.SampleApp @@ -21,7 +22,7 @@ public static class Samples private static SemaphoreSlim _semaphore = new SemaphoreSlim(1); private static LinkedList _recentSamples; - private static ApplicationDataStorageHelper _appDataStorageHelper = ApplicationDataStorageHelper.GetCurrent(new Toolkit.Helpers.SystemSerializer()); + private static ISettingsStorageHelper _settingsStorage = ApplicationDataStorageHelper.GetCurrent(new Toolkit.Helpers.SystemSerializer()); public static async Task GetCategoryBySample(Sample sample) { @@ -98,7 +99,7 @@ public static async Task> GetRecentSamples() if (_recentSamples == null) { _recentSamples = new LinkedList(); - var savedSamples = _appDataStorageHelper.Read(_recentSamplesStorageKey); + var savedSamples = _settingsStorage.Read(_recentSamplesStorageKey); if (savedSamples != null) { @@ -144,7 +145,7 @@ private static void SaveRecentSamples() } var str = string.Join(";", _recentSamples.Take(10).Select(s => s.Name).ToArray()); - _appDataStorageHelper.Save(_recentSamplesStorageKey, str); + _settingsStorage.Save(_recentSamplesStorageKey, str); } } } \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/Object Storage/ObjectStoragePage.xaml.cs b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/Object Storage/ObjectStoragePage.xaml.cs index e1e0e925b92..96079fb89f6 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/Object Storage/ObjectStoragePage.xaml.cs +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/Object Storage/ObjectStoragePage.xaml.cs @@ -10,7 +10,7 @@ namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages { public sealed partial class ObjectStoragePage { - private readonly ISettingsStorageHelper localStorageHelper = ApplicationDataStorageHelper.GetCurrent(new Toolkit.Helpers.SystemSerializer()); + private readonly ISettingsStorageHelper _settingsStorage = ApplicationDataStorageHelper.GetCurrent(new Toolkit.Helpers.SystemSerializer()); public ObjectStoragePage() { @@ -25,9 +25,9 @@ private void ReadButton_Click(object sender, RoutedEventArgs e) } // Read from local storage - if (localStorageHelper.KeyExists(KeyTextBox.Text)) + if (_settingsStorage.KeyExists(KeyTextBox.Text)) { - ContentTextBox.Text = localStorageHelper.Read(KeyTextBox.Text); + ContentTextBox.Text = _settingsStorage.Read(KeyTextBox.Text); } } @@ -44,7 +44,7 @@ private void SaveButton_Click(object sender, RoutedEventArgs e) } // Save into local storage - localStorageHelper.Save(KeyTextBox.Text, ContentTextBox.Text); + _settingsStorage.Save(KeyTextBox.Text, ContentTextBox.Text); } } } \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp/Helpers/SystemInformation.cs b/Microsoft.Toolkit.Uwp/Helpers/SystemInformation.cs index 2b84aa7064e..81f7a6cac39 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/SystemInformation.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/SystemInformation.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.Linq; using System.Threading.Tasks; +using Microsoft.Toolkit.Helpers; using Windows.ApplicationModel; using Windows.ApplicationModel.Activation; using Windows.Security.ExchangeActiveSyncProvisioning; @@ -25,7 +26,7 @@ public sealed class SystemInformation /// /// The instance used to save and retrieve application settings. /// - private readonly ApplicationDataStorageHelper _localObjectStorageHelper = ApplicationDataStorageHelper.GetCurrent(new Toolkit.Helpers.SystemSerializer()); + private readonly ISettingsStorageHelper _settingsStorage = ApplicationDataStorageHelper.GetCurrent(new Toolkit.Helpers.SystemSerializer()); /// /// The starting time of the current application session (since app launch or last move to foreground). @@ -216,7 +217,7 @@ public TimeSpan AppUptime if (LaunchCount > 0) { var subSessionLength = DateTime.UtcNow.Subtract(_sessionStart).Ticks; - var uptimeSoFar = _localObjectStorageHelper.Read(nameof(AppUptime)); + var uptimeSoFar = _settingsStorage.Read(nameof(AppUptime)); return new(uptimeSoFar + subSessionLength); } @@ -232,9 +233,9 @@ public TimeSpan AppUptime /// The amount to time to add public void AddToAppUptime(TimeSpan duration) { - var uptimeSoFar = _localObjectStorageHelper.Read(nameof(AppUptime)); + var uptimeSoFar = _settingsStorage.Read(nameof(AppUptime)); - _localObjectStorageHelper.Save(nameof(AppUptime), uptimeSoFar + duration.Ticks); + _settingsStorage.Save(nameof(AppUptime), uptimeSoFar + duration.Ticks); } /// @@ -245,8 +246,8 @@ public void ResetLaunchCount() LastResetTime = DateTime.UtcNow; LaunchCount = 0; - _localObjectStorageHelper.Save(nameof(LastResetTime), LastResetTime.ToFileTimeUtc()); - _localObjectStorageHelper.Save(nameof(LaunchCount), LaunchCount); + _settingsStorage.Save(nameof(LastResetTime), LastResetTime.ToFileTimeUtc()); + _settingsStorage.Save(nameof(LaunchCount), LaunchCount); } /// @@ -258,8 +259,8 @@ public void TrackAppUse(IActivatedEventArgs args, XamlRoot xamlRoot = null) { if (args.PreviousExecutionState is ApplicationExecutionState.ClosedByUser or ApplicationExecutionState.NotRunning) { - LaunchCount = _localObjectStorageHelper.Read(nameof(LaunchCount)) + 1; - TotalLaunchCount = _localObjectStorageHelper.Read(nameof(TotalLaunchCount)) + 1; + LaunchCount = _settingsStorage.Read(nameof(LaunchCount)) + 1; + TotalLaunchCount = _settingsStorage.Read(nameof(TotalLaunchCount)) + 1; // In case we upgraded the properties, make TotalLaunchCount is correct if (TotalLaunchCount < LaunchCount) @@ -267,21 +268,21 @@ public void TrackAppUse(IActivatedEventArgs args, XamlRoot xamlRoot = null) TotalLaunchCount = LaunchCount; } - _localObjectStorageHelper.Save(nameof(LaunchCount), LaunchCount); - _localObjectStorageHelper.Save(nameof(TotalLaunchCount), TotalLaunchCount); + _settingsStorage.Save(nameof(LaunchCount), LaunchCount); + _settingsStorage.Save(nameof(TotalLaunchCount), TotalLaunchCount); LaunchTime = DateTime.UtcNow; - var lastLaunch = _localObjectStorageHelper.Read(nameof(LastLaunchTime)); + var lastLaunch = _settingsStorage.Read(nameof(LastLaunchTime)); LastLaunchTime = lastLaunch != 0 ? DateTime.FromFileTimeUtc(lastLaunch) : LaunchTime; - _localObjectStorageHelper.Save(nameof(LastLaunchTime), LaunchTime.ToFileTimeUtc()); - _localObjectStorageHelper.Save(nameof(AppUptime), 0L); + _settingsStorage.Save(nameof(LastLaunchTime), LaunchTime.ToFileTimeUtc()); + _settingsStorage.Save(nameof(AppUptime), 0L); - var lastResetTime = _localObjectStorageHelper.Read(nameof(LastResetTime)); + var lastResetTime = _settingsStorage.Read(nameof(LastResetTime)); LastResetTime = lastResetTime != 0 ? DateTime.FromFileTimeUtc(lastResetTime) @@ -321,20 +322,20 @@ private void UpdateVisibility(bool visible) else { var subSessionLength = DateTime.UtcNow.Subtract(_sessionStart).Ticks; - var uptimeSoFar = _localObjectStorageHelper.Read(nameof(AppUptime)); + var uptimeSoFar = _settingsStorage.Read(nameof(AppUptime)); - _localObjectStorageHelper.Save(nameof(AppUptime), uptimeSoFar + subSessionLength); + _settingsStorage.Save(nameof(AppUptime), uptimeSoFar + subSessionLength); } } private bool DetectIfFirstUse() { - if (_localObjectStorageHelper.KeyExists(nameof(IsFirstRun))) + if (_settingsStorage.KeyExists(nameof(IsFirstRun))) { return false; } - _localObjectStorageHelper.Save(nameof(IsFirstRun), true); + _settingsStorage.Save(nameof(IsFirstRun), true); return true; } @@ -347,13 +348,13 @@ private bool DetectIfFirstUse() // is ever called. That is, this is either the first time the app has been launched, or the first // time a previously existing app has run this method (or has run it after a new update of the app). // In this case, save the current version and report the same version as previous version installed. - if (!_localObjectStorageHelper.KeyExists(nameof(currentVersion))) + if (!_settingsStorage.KeyExists(nameof(currentVersion))) { - _localObjectStorageHelper.Save(nameof(currentVersion), currentVersion); + _settingsStorage.Save(nameof(currentVersion), currentVersion); } else { - var previousVersion = _localObjectStorageHelper.Read(nameof(currentVersion)); + var previousVersion = _settingsStorage.Read(nameof(currentVersion)); // There are two possible cases if the "currentVersion" key exists: // 1) The previous version is different than the current one. This means that the application @@ -363,7 +364,7 @@ private bool DetectIfFirstUse() // In this case we have nothing to do and just return the previous version installed to be the same. if (currentVersion != previousVersion) { - _localObjectStorageHelper.Save(nameof(currentVersion), currentVersion); + _settingsStorage.Save(nameof(currentVersion), currentVersion); return (true, previousVersion.ToPackageVersion()); } @@ -374,28 +375,28 @@ private bool DetectIfFirstUse() private DateTime DetectFirstUseTime() { - if (_localObjectStorageHelper.KeyExists(nameof(FirstUseTime))) + if (_settingsStorage.KeyExists(nameof(FirstUseTime))) { - var firstUse = _localObjectStorageHelper.Read(nameof(FirstUseTime)); + var firstUse = _settingsStorage.Read(nameof(FirstUseTime)); return DateTime.FromFileTimeUtc(firstUse); } DateTime utcNow = DateTime.UtcNow; - _localObjectStorageHelper.Save(nameof(FirstUseTime), utcNow.ToFileTimeUtc()); + _settingsStorage.Save(nameof(FirstUseTime), utcNow.ToFileTimeUtc()); return utcNow; } private PackageVersion DetectFirstVersionInstalled() { - if (_localObjectStorageHelper.KeyExists(nameof(FirstVersionInstalled))) + if (_settingsStorage.KeyExists(nameof(FirstVersionInstalled))) { - return _localObjectStorageHelper.Read(nameof(FirstVersionInstalled)).ToPackageVersion(); + return _settingsStorage.Read(nameof(FirstVersionInstalled)).ToPackageVersion(); } - _localObjectStorageHelper.Save(nameof(FirstVersionInstalled), ApplicationVersion.ToFormattedString()); + _settingsStorage.Save(nameof(FirstVersionInstalled), ApplicationVersion.ToFormattedString()); return ApplicationVersion; } diff --git a/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs b/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs index 09714a263f0..0b27db815db 100644 --- a/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs +++ b/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs @@ -15,9 +15,9 @@ namespace UnitTests.Helpers [TestClass] public class Test_StorageHelper { - private ISettingsStorageHelper _localStorageHelperSystem = ApplicationDataStorageHelper.GetCurrent(new Microsoft.Toolkit.Helpers.SystemSerializer()); - private ISettingsStorageHelper _localStorageHelperJsonCompat = ApplicationDataStorageHelper.GetCurrent(new JsonObjectSerializer()); - private ISettingsStorageHelper _localStorageHelperJsonNew = ApplicationDataStorageHelper.GetCurrent(new SystemTextJsonSerializer()); + private ISettingsStorageHelper _settingsStorage_System = ApplicationDataStorageHelper.GetCurrent(new Microsoft.Toolkit.Helpers.SystemSerializer()); + private ISettingsStorageHelper _settingsStorage_JsonCompat = ApplicationDataStorageHelper.GetCurrent(new JsonObjectSerializer()); + private ISettingsStorageHelper _settingsStorage_JsonNew = ApplicationDataStorageHelper.GetCurrent(new SystemTextJsonSerializer()); /// /// Checks that we're running 10.0.3 version of Newtonsoft.Json package which we used in 6.1.1. @@ -41,10 +41,10 @@ public void Test_StorageHelper_LegacyIntTest() int input = 42; // Use our previous Json layer to store value - _localStorageHelperJsonCompat.Save(key, input); + _settingsStorage_JsonCompat.Save(key, input); // But try and read from our new system to see if it works - int output = _localStorageHelperSystem.Read(key, 0); + int output = _settingsStorage_System.Read(key, 0); Assert.AreEqual(input, output); } @@ -61,10 +61,10 @@ public void Test_StorageHelper_LegacyDateTestFailure() DateTime input = new DateTime(2017, 12, 25); - _localStorageHelperJsonCompat.Save(key, input); + _settingsStorage_JsonCompat.Save(key, input); // now read it as int to valid that the change works - DateTime output = _localStorageHelperSystem.Read(key, DateTime.Today); + DateTime output = _settingsStorage_System.Read(key, DateTime.Today); } /// @@ -81,7 +81,7 @@ public void Test_StorageHelper_DateTestFailure() // as local and online platforms seem to throw different exception types :( try { - _localStorageHelperSystem.Save("Today", DateTime.Today); + _settingsStorage_System.Save("Today", DateTime.Today); } catch (Exception exception) { @@ -100,10 +100,10 @@ public void Test_StorageHelper_LegacyInternalClassTest() UI.Person input = new UI.Person() { Name = "Joe Bloggs", Age = 42 }; // simulate previous version by generating json and manually inserting it as string - _localStorageHelperJsonCompat.Save(key, input); + _settingsStorage_JsonCompat.Save(key, input); // now read it as int to valid that the change works - UI.Person output = _localStorageHelperJsonCompat.Read(key, null); + UI.Person output = _settingsStorage_JsonCompat.Read(key, null); Assert.IsNotNull(output); Assert.AreEqual(input.Name, output.Name); @@ -120,10 +120,10 @@ public void Test_StorageHelper_LegacyPublicClassTest() UI.Person input = new UI.Person() { Name = "Joe Bloggs", Age = 42 }; // simulate previous version by generating json and manually inserting it as string - _localStorageHelperJsonCompat.Save(key, input); + _settingsStorage_JsonCompat.Save(key, input); // now read it as int to valid that the change works - Person output = _localStorageHelperJsonCompat.Read(key, null); + Person output = _settingsStorage_JsonCompat.Read(key, null); Assert.IsNotNull(output); Assert.AreEqual(input.Name, output.Name); @@ -138,10 +138,10 @@ public void Test_StorageHelper_IntTest() int input = 42; - _localStorageHelperSystem.Save(key, input); + _settingsStorage_System.Save(key, input); // now read it as int to valid that the change works - int output = _localStorageHelperSystem.Read(key, 0); + int output = _settingsStorage_System.Read(key, 0); Assert.AreEqual(input, output); } @@ -154,10 +154,10 @@ public void Test_StorageHelper_NewDateTest() DateTime input = new DateTime(2017, 12, 25); - _localStorageHelperJsonNew.Save(key, input); + _settingsStorage_JsonNew.Save(key, input); // now read it as int to valid that the change works - DateTime output = _localStorageHelperJsonNew.Read(key, DateTime.Today); + DateTime output = _settingsStorage_JsonNew.Read(key, DateTime.Today); Assert.AreEqual(input, output); } @@ -170,10 +170,10 @@ public void Test_StorageHelper_NewPersonTest() Person input = new Person() { Name = "Joe Bloggs", Age = 42 }; - _localStorageHelperJsonNew.Save(key, input); + _settingsStorage_JsonNew.Save(key, input); // now read it as int to valid that the change works - Person output = _localStorageHelperJsonNew.Read(key, null); + Person output = _settingsStorage_JsonNew.Read(key, null); Assert.IsNotNull(output); Assert.AreEqual(input.Name, output.Name); diff --git a/UnitTests/UnitTests.UWP/Helpers/Test_SystemInformation.cs b/UnitTests/UnitTests.UWP/Helpers/Test_SystemInformation.cs index 27488ac1a29..7132f500abd 100644 --- a/UnitTests/UnitTests.UWP/Helpers/Test_SystemInformation.cs +++ b/UnitTests/UnitTests.UWP/Helpers/Test_SystemInformation.cs @@ -58,10 +58,10 @@ public void Test_SystemInformation_ConsistentInfoForStartupWithUpdate() // Simulate a first app startup _ = (SystemInformation)Activator.CreateInstance(typeof(SystemInformation), nonPublic: true); - ISettingsStorageHelper localObjectStorageHelper = ApplicationDataStorageHelper.GetCurrent(new Microsoft.Toolkit.Helpers.SystemSerializer()); + ISettingsStorageHelper settingsStorage = ApplicationDataStorageHelper.GetCurrent(new Microsoft.Toolkit.Helpers.SystemSerializer()); PackageVersion previousVersion = new() { Build = 42, Major = 1111, Minor = 2222, Revision = 12345 }; - localObjectStorageHelper.Save("currentVersion", previousVersion.ToFormattedString()); + settingsStorage.Save("currentVersion", previousVersion.ToFormattedString()); var systemInformation = (SystemInformation)Activator.CreateInstance(typeof(SystemInformation), nonPublic: true); var currentAppVersion = Package.Current.Id.Version; From 1f53d9a79eeead70c6c6ba9868e009bb3ad02797 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Mon, 19 Jul 2021 13:09:09 -0700 Subject: [PATCH 16/35] Making serializer optional for ApplicationDataStorageHelper and defaulting to SystemSerializer --- .../ObjectStorage/ApplicationDataStorageHelper.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs index fcd54e9c0d8..97b38035ded 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs @@ -20,9 +20,9 @@ public class ApplicationDataStorageHelper : IFileStorageHelper, ISettingsStorage /// /// Get a new instance using ApplicationData.Current and the provided serializer. /// - /// Serializer for converting stored values. + /// Serializer for converting stored values. Defaults to . /// A new instance of ApplicationDataStorageHelper. - public static ApplicationDataStorageHelper GetCurrent(Toolkit.Helpers.IObjectSerializer objectSerializer) + public static ApplicationDataStorageHelper GetCurrent(Toolkit.Helpers.IObjectSerializer objectSerializer = null) { var appData = ApplicationData.Current; return new ApplicationDataStorageHelper(appData, objectSerializer); @@ -32,9 +32,9 @@ public static ApplicationDataStorageHelper GetCurrent(Toolkit.Helpers.IObjectSer /// Get a new instance using the ApplicationData for the provided user and serializer. /// /// App data user owner. - /// Serializer for converting stored values. + /// Serializer for converting stored values. Defaults to . /// A new instance of ApplicationDataStorageHelper. - public static async Task GetForUserAsync(User user, Toolkit.Helpers.IObjectSerializer objectSerializer) + public static async Task GetForUserAsync(User user, Toolkit.Helpers.IObjectSerializer objectSerializer = null) { var appData = await ApplicationData.GetForUserAsync(user); return new ApplicationDataStorageHelper(appData, objectSerializer); @@ -55,11 +55,11 @@ public static async Task GetForUserAsync(User user /// Initializes a new instance of the class. /// /// The data store to interact with. - /// Serializer for converting stored values. - public ApplicationDataStorageHelper(ApplicationData appData, Toolkit.Helpers.IObjectSerializer objectSerializer) + /// Serializer for converting stored values. Defaults to . + public ApplicationDataStorageHelper(ApplicationData appData, Toolkit.Helpers.IObjectSerializer objectSerializer = null) { AppData = appData ?? throw new ArgumentNullException(nameof(appData)); - _serializer = objectSerializer ?? throw new ArgumentNullException(nameof(objectSerializer)); + _serializer = objectSerializer ?? new Toolkit.Helpers.SystemSerializer(); } /// From 8140bff9b44e0861c2c3406024f60a8eaa6e51fd Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Mon, 19 Jul 2021 13:50:18 -0700 Subject: [PATCH 17/35] Added support for the LocalCacheFolder to validate extensibility of AppDataStorageHelper --- ...pplicationDataStorageHelper.CacheFolder.cs | 84 +++++++++++++++++++ .../ApplicationDataStorageHelper.cs | 48 ++++++----- 2 files changed, 111 insertions(+), 21 deletions(-) create mode 100644 Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.CacheFolder.cs diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.CacheFolder.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.CacheFolder.cs new file mode 100644 index 00000000000..95018f51b7f --- /dev/null +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.CacheFolder.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.Toolkit.Helpers; +using Windows.Storage; + +namespace Microsoft.Toolkit.Uwp.Helpers +{ + /// + /// An extension of ApplicationDataStorageHelper with additional features for interop with the LocalCacheFolder. + /// + public partial class ApplicationDataStorageHelper + { + /// + /// Gets the storage folder. + /// + public StorageFolder CacheFolder => AppData.LocalCacheFolder; + + /// + /// Determines if a directory item already exists in the LocalCacheFolder. + /// + /// Key of the file. + /// True if an item exists. + public Task CacheItemExistsAsync(string itemName) + { + return ItemExistsAsync(CacheFolder, itemName); + } + + /// + /// Retrieves an object from a file in the LocalCacheFolder. + /// + /// Type of object retrieved. + /// Path to the file that contains the object. + /// Default value of the object. + /// Waiting task until completion with the object in the file. + public Task ReadCacheFileAsync(string filePath, T @default = default) + { + return ReadFileAsync(CacheFolder, filePath, @default); + } + + + /// + /// Retrieves the listings for a folder and the item types in the LocalCacheFolder. + /// + /// The path to the target folder. + /// A list of file types and names in the target folder. + public Task>> ReadCacheFolderAsync(string folderPath) + { + return ReadFolderAsync(CacheFolder, folderPath); + } + + /// + /// Saves an object inside a file in the LocalCacheFolder. + /// + /// Type of object saved. + /// Path to the file that will contain the object. + /// Object to save. + /// Waiting task until completion. + public Task CreateCacheFileAsync(string filePath, T value) + { + return SaveFileAsync(CacheFolder, filePath, value); + } + + /// + /// Ensure a folder exists at the folder path specified in the LocalCacheFolder. + /// + /// The path and name of the target folder. + /// Waiting task until completion. + public Task CreateCacheFolderAsync(string folderPath) + { + return CreateFolderAsync(CacheFolder, folderPath); + } + + /// + /// Deletes a file or folder item in the LocalCacheFolder. + /// + /// The path to the item for deletion. + /// Waiting task until completion. + public Task DeleteCacheItemAsync(string itemPath) + { + return DeleteItemAsync(CacheFolder, itemPath); + } + } +} diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs index 97b38035ded..583bbc4a19c 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs @@ -15,7 +15,7 @@ namespace Microsoft.Toolkit.Uwp.Helpers /// /// Storage helper for files and folders living in Windows.Storage.ApplicationData storage endpoints. /// - public class ApplicationDataStorageHelper : IFileStorageHelper, ISettingsStorageHelper + public partial class ApplicationDataStorageHelper : IFileStorageHelper, ISettingsStorageHelper { /// /// Get a new instance using ApplicationData.Current and the provided serializer. @@ -43,11 +43,17 @@ public static async Task GetForUserAsync(User user /// /// Gets the settings container. /// - protected ApplicationData AppData { get; private set; } + public ApplicationDataContainer Settings => AppData.LocalSettings; - private ApplicationDataContainer DefaultSettings => AppData.LocalSettings; + /// + /// Gets the storage folder. + /// + public StorageFolder Folder => AppData.LocalFolder; - private StorageFolder DefaultFolder => AppData.LocalFolder; + /// + /// Gets the storage host. + /// + protected ApplicationData AppData { get; private set; } private readonly Toolkit.Helpers.IObjectSerializer _serializer; @@ -65,7 +71,7 @@ public ApplicationDataStorageHelper(ApplicationData appData, Toolkit.Helpers.IOb /// public bool KeyExists(string key) { - return DefaultSettings.Values.ContainsKey(key); + return Settings.Values.ContainsKey(key); } /// @@ -73,7 +79,7 @@ public bool KeyExists(string compositeKey, string key) { if (KeyExists(compositeKey)) { - ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)DefaultSettings.Values[compositeKey]; + ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)Settings.Values[compositeKey]; if (composite != null) { return composite.ContainsKey(key); @@ -86,7 +92,7 @@ public bool KeyExists(string compositeKey, string key) /// public T Read(string key, T @default = default) { - if (!DefaultSettings.Values.TryGetValue(key, out var value) || value == null) + if (!Settings.Values.TryGetValue(key, out var value) || value == null) { return @default; } @@ -97,7 +103,7 @@ public T Read(string key, T @default = default) /// public T Read(string compositeKey, string key, T @default = default) { - ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)DefaultSettings.Values[compositeKey]; + ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)Settings.Values[compositeKey]; if (composite != null) { string value = (string)composite[key]; @@ -113,7 +119,7 @@ public T Read(string compositeKey, string key, T @default = default) /// public void Save(string key, T value) { - DefaultSettings.Values[key] = _serializer.Serialize(value); + Settings.Values[key] = _serializer.Serialize(value); } /// @@ -121,7 +127,7 @@ public void Save(string compositeKey, IDictionary values) { if (KeyExists(compositeKey)) { - ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)DefaultSettings.Values[compositeKey]; + ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)Settings.Values[compositeKey]; foreach (KeyValuePair setting in values) { @@ -143,14 +149,14 @@ public void Save(string compositeKey, IDictionary values) composite.Add(setting.Key, _serializer.Serialize(setting.Value)); } - DefaultSettings.Values[compositeKey] = composite; + Settings.Values[compositeKey] = composite; } } /// public void Delete(string key) { - DefaultSettings.Values.Remove(key); + Settings.Values.Remove(key); } /// @@ -158,7 +164,7 @@ public void Delete(string compositeKey, string key) { if (KeyExists(compositeKey)) { - ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)DefaultSettings.Values[compositeKey]; + ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)Settings.Values[compositeKey]; composite.Remove(key); } } @@ -166,37 +172,37 @@ public void Delete(string compositeKey, string key) /// public Task ItemExistsAsync(string itemName) { - return ItemExistsAsync(DefaultFolder, itemName); + return ItemExistsAsync(Folder, itemName); } /// public Task ReadFileAsync(string filePath, T @default = default) { - return ReadFileAsync(DefaultFolder, filePath, @default); + return ReadFileAsync(Folder, filePath, @default); } /// public Task>> ReadFolderAsync(string folderPath) { - return ReadFolderAsync(DefaultFolder, folderPath); + return ReadFolderAsync(Folder, folderPath); } /// public Task CreateFileAsync(string filePath, T value) { - return SaveFileAsync(DefaultFolder, filePath, value); + return SaveFileAsync(Folder, filePath, value); } /// public Task CreateFolderAsync(string folderPath) { - return CreateFolderAsync(DefaultFolder, folderPath); + return CreateFolderAsync(Folder, folderPath); } /// public Task DeleteItemAsync(string itemPath) { - return DeleteItemAsync(DefaultFolder, itemPath); + return DeleteItemAsync(Folder, itemPath); } /// @@ -208,7 +214,7 @@ public Task DeleteItemAsync(string itemPath) /// A task with the result of the file query. public Task FileExistsAsync(string fileName, bool isRecursive = false) { - return FileExistsAsync(DefaultFolder, fileName, isRecursive); + return FileExistsAsync(Folder, fileName, isRecursive); } /// @@ -220,7 +226,7 @@ public Task FileExistsAsync(string fileName, bool isRecursive = false) /// Waiting task until completion. public Task SaveFileAsync(string filePath, T value) { - return SaveFileAsync(DefaultFolder, filePath, value); + return SaveFileAsync(Folder, filePath, value); } private async Task ItemExistsAsync(StorageFolder folder, string itemName) From ddcf8c2b7d89620e7d8e12b2b3647950e9bac2c0 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Mon, 19 Jul 2021 14:30:45 -0700 Subject: [PATCH 18/35] Adding license header --- .../ObjectStorage/ApplicationDataStorageHelper.CacheFolder.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.CacheFolder.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.CacheFolder.cs index 95018f51b7f..272afab07aa 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.CacheFolder.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.CacheFolder.cs @@ -1,3 +1,7 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + using System; using System.Collections.Generic; using System.Threading.Tasks; From 655caf655d33b359c8a267879f6bdaa376be45f8 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Mon, 19 Jul 2021 15:08:27 -0700 Subject: [PATCH 19/35] Whitespace fix --- .../ObjectStorage/ApplicationDataStorageHelper.CacheFolder.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.CacheFolder.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.CacheFolder.cs index 272afab07aa..d0f6fd1dff5 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.CacheFolder.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.CacheFolder.cs @@ -42,7 +42,6 @@ public Task ReadCacheFileAsync(string filePath, T @default = default) return ReadFileAsync(CacheFolder, filePath, @default); } - /// /// Retrieves the listings for a folder and the item types in the LocalCacheFolder. /// From 8476f708f2ced7b826b13c49838feb1d29f7cee1 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Wed, 21 Jul 2021 16:36:45 -0700 Subject: [PATCH 20/35] PR updates --- ...pplicationDataStorageHelper.CacheFolder.cs | 14 +- .../ApplicationDataStorageHelper.cs | 145 +++++++++--------- .../ObjectStorage/IFileStorageHelper.cs | 11 +- .../ObjectStorage/IObjectSerializer.cs | 10 +- .../ObjectStorage/ISettingsStorageHelper.cs | 57 ++----- .../Helpers/ObjectStorage/SystemSerializer.cs | 10 +- Microsoft.Toolkit/Microsoft.Toolkit.csproj | 3 + 7 files changed, 105 insertions(+), 145 deletions(-) diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.CacheFolder.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.CacheFolder.cs index d0f6fd1dff5..ee94dd5bf61 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.CacheFolder.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.CacheFolder.cs @@ -16,20 +16,10 @@ namespace Microsoft.Toolkit.Uwp.Helpers public partial class ApplicationDataStorageHelper { /// - /// Gets the storage folder. + /// Gets the local cache folder. /// public StorageFolder CacheFolder => AppData.LocalCacheFolder; - /// - /// Determines if a directory item already exists in the LocalCacheFolder. - /// - /// Key of the file. - /// True if an item exists. - public Task CacheItemExistsAsync(string itemName) - { - return ItemExistsAsync(CacheFolder, itemName); - } - /// /// Retrieves an object from a file in the LocalCacheFolder. /// @@ -47,7 +37,7 @@ public Task ReadCacheFileAsync(string filePath, T @default = default) /// /// The path to the target folder. /// A list of file types and names in the target folder. - public Task>> ReadCacheFolderAsync(string folderPath) + public Task> ReadCacheFolderAsync(string folderPath) { return ReadFolderAsync(CacheFolder, folderPath); } diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs index 583bbc4a19c..4f1ddbb4169 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs @@ -15,7 +15,7 @@ namespace Microsoft.Toolkit.Uwp.Helpers /// /// Storage helper for files and folders living in Windows.Storage.ApplicationData storage endpoints. /// - public partial class ApplicationDataStorageHelper : IFileStorageHelper, ISettingsStorageHelper + public partial class ApplicationDataStorageHelper : IFileStorageHelper, ISettingsStorageHelper { /// /// Get a new instance using ApplicationData.Current and the provided serializer. @@ -53,9 +53,12 @@ public static async Task GetForUserAsync(User user /// /// Gets the storage host. /// - protected ApplicationData AppData { get; private set; } + protected ApplicationData AppData { get; } - private readonly Toolkit.Helpers.IObjectSerializer _serializer; + /// + /// Gets the serializer for converting stored values. + /// + protected Toolkit.Helpers.IObjectSerializer Serializer { get; } /// /// Initializes a new instance of the class. @@ -65,16 +68,54 @@ public static async Task GetForUserAsync(User user public ApplicationDataStorageHelper(ApplicationData appData, Toolkit.Helpers.IObjectSerializer objectSerializer = null) { AppData = appData ?? throw new ArgumentNullException(nameof(appData)); - _serializer = objectSerializer ?? new Toolkit.Helpers.SystemSerializer(); + Serializer = objectSerializer ?? new Toolkit.Helpers.SystemSerializer(); } - /// + /// + /// Determines whether a setting already exists. + /// + /// Key of the setting (that contains object). + /// True if a value exists. public bool KeyExists(string key) { return Settings.Values.ContainsKey(key); } /// + public T Read(string key, T @default = default) + { + if (!Settings.Values.TryGetValue(key, out var valueObj) || valueObj == null) + { + return @default; + } + + return Serializer.Deserialize(valueObj as string); + } + + /// + public void Save(string key, T value) + { + Settings.Values[key] = Serializer.Serialize(value); + } + + /// + public void Delete(string key) + { + Settings.Values.Remove(key); + } + + /// + public void Clear() + { + Settings.Values.Clear(); + } + + /// + /// Determines whether a setting already exists in composite. + /// + /// Key of the composite (that contains settings). + /// Key of the setting (that contains object). + /// True if a value exists. public bool KeyExists(string compositeKey, string key) { if (KeyExists(compositeKey)) @@ -89,18 +130,14 @@ public bool KeyExists(string compositeKey, string key) return false; } - /// - public T Read(string key, T @default = default) - { - if (!Settings.Values.TryGetValue(key, out var value) || value == null) - { - return @default; - } - - return _serializer.Deserialize(value); - } - - /// + /// + /// Retrieves a single item by its key in composite. + /// + /// Type of object retrieved. + /// Key of the composite (that contains settings). + /// Key of the object. + /// Default value of the object. + /// The T object. public T Read(string compositeKey, string key, T @default = default) { ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)Settings.Values[compositeKey]; @@ -109,20 +146,21 @@ public T Read(string compositeKey, string key, T @default = default) string value = (string)composite[key]; if (value != null) { - return _serializer.Deserialize(value); + return Serializer.Deserialize(value); } } return @default; } - /// - public void Save(string key, T value) - { - Settings.Values[key] = _serializer.Serialize(value); - } - - /// + /// + /// Saves a group of items by its key in a composite. + /// This method should be considered for objects that do not exceed 8k bytes during the lifetime of the application + /// and for groups of settings which need to be treated in an atomic way. + /// + /// Type of object saved. + /// Key of the composite (that contains settings). + /// Objects to save. public void Save(string compositeKey, IDictionary values) { if (KeyExists(compositeKey)) @@ -133,11 +171,11 @@ public void Save(string compositeKey, IDictionary values) { if (composite.ContainsKey(setting.Key)) { - composite[setting.Key] = _serializer.Serialize(setting.Value); + composite[setting.Key] = Serializer.Serialize(setting.Value); } else { - composite.Add(setting.Key, _serializer.Serialize(setting.Value)); + composite.Add(setting.Key, Serializer.Serialize(setting.Value)); } } } @@ -146,20 +184,18 @@ public void Save(string compositeKey, IDictionary values) ApplicationDataCompositeValue composite = new ApplicationDataCompositeValue(); foreach (KeyValuePair setting in values) { - composite.Add(setting.Key, _serializer.Serialize(setting.Value)); + composite.Add(setting.Key, Serializer.Serialize(setting.Value)); } Settings.Values[compositeKey] = composite; } } - /// - public void Delete(string key) - { - Settings.Values.Remove(key); - } - - /// + /// + /// Deletes a single item by its key in composite. + /// + /// Key of the composite (that contains settings). + /// Key of the object. public void Delete(string compositeKey, string key) { if (KeyExists(compositeKey)) @@ -169,12 +205,6 @@ public void Delete(string compositeKey, string key) } } - /// - public Task ItemExistsAsync(string itemName) - { - return ItemExistsAsync(Folder, itemName); - } - /// public Task ReadFileAsync(string filePath, T @default = default) { @@ -182,7 +212,7 @@ public Task ReadFileAsync(string filePath, T @default = default) } /// - public Task>> ReadFolderAsync(string folderPath) + public Task> ReadFolderAsync(string folderPath) { return ReadFolderAsync(Folder, folderPath); } @@ -205,18 +235,6 @@ public Task DeleteItemAsync(string itemPath) return DeleteItemAsync(Folder, itemPath); } - /// - /// Determine the existance of a file at the specified path. - /// To check for folders, use . - /// - /// The name of the file. - /// Whether the file should be searched for recursively. - /// A task with the result of the file query. - public Task FileExistsAsync(string fileName, bool isRecursive = false) - { - return FileExistsAsync(Folder, fileName, isRecursive); - } - /// /// Saves an object inside a file. /// @@ -229,24 +247,13 @@ public Task SaveFileAsync(string filePath, T value) return SaveFileAsync(Folder, filePath, value); } - private async Task ItemExistsAsync(StorageFolder folder, string itemName) - { - var item = await folder.TryGetItemAsync(itemName); - return item != null; - } - - private Task FileExistsAsync(StorageFolder folder, string fileName, bool isRecursive) - { - return folder.FileExistsAsync(fileName, isRecursive); - } - private async Task ReadFileAsync(StorageFolder folder, string filePath, T @default = default) { string value = await StorageFileHelper.ReadTextFromFileAsync(folder, filePath); - return (value != null) ? _serializer.Deserialize(value) : @default; + return (value != null) ? Serializer.Deserialize(value) : @default; } - private async Task>> ReadFolderAsync(StorageFolder folder, string folderPath) + private async Task> ReadFolderAsync(StorageFolder folder, string folderPath) { var targetFolder = await folder.GetFolderAsync(folderPath); var items = await targetFolder.GetItemsAsync(); @@ -257,13 +264,13 @@ private async Task>> ReadFolderAsync(Stor : item.IsOfType(StorageItemTypes.Folder) ? DirectoryItemType.Folder : DirectoryItemType.None; - return new Tuple(itemType, item.Name); + return new ValueTuple(itemType, item.Name); }).ToList(); } private Task SaveFileAsync(StorageFolder folder, string filePath, T value) { - return StorageFileHelper.WriteTextToFileAsync(folder, _serializer.Serialize(value)?.ToString(), filePath, CreationCollisionOption.ReplaceExisting); + return StorageFileHelper.WriteTextToFileAsync(folder, Serializer.Serialize(value)?.ToString(), filePath, CreationCollisionOption.ReplaceExisting); } private async Task CreateFolderAsync(StorageFolder folder, string folderPath) diff --git a/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs b/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs index eae8a3dfbef..2ca3397eee8 100644 --- a/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs +++ b/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs @@ -18,13 +18,6 @@ namespace Microsoft.Toolkit.Helpers /// public interface IFileStorageHelper { - /// - /// Determines if a directory item already exists. - /// - /// Key of the file. - /// True if an item exists. - Task ItemExistsAsync(string itemName); - /// /// Retrieves an object from a file. /// @@ -38,8 +31,8 @@ public interface IFileStorageHelper /// Retrieves the listings for a folder and the item types. /// /// The path to the target folder. - /// A list of file types and names in the target folder. - Task>> ReadFolderAsync(string folderPath); + /// A list of item types and names in the target folder. + Task> ReadFolderAsync(string folderPath); /// /// Saves an object inside a file. diff --git a/Microsoft.Toolkit/Helpers/ObjectStorage/IObjectSerializer.cs b/Microsoft.Toolkit/Helpers/ObjectStorage/IObjectSerializer.cs index d046ead57d1..266ec157976 100644 --- a/Microsoft.Toolkit/Helpers/ObjectStorage/IObjectSerializer.cs +++ b/Microsoft.Toolkit/Helpers/ObjectStorage/IObjectSerializer.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; + namespace Microsoft.Toolkit.Helpers { /// @@ -15,14 +17,16 @@ public interface IObjectSerializer /// The type of the object to serialize. /// The object to serialize. /// The serialized object. - object? Serialize(T value); + [return: NotNullIfNotNull("value")] + string? Serialize(T value); /// - /// Deserialize a primitive or string into an object of the given type. + /// Deserialize string into an object of the given type. /// /// The type of the deserialized object. /// The string to deserialize. /// The deserialized object. - T Deserialize(object value); + [return: NotNullIfNotNull("value")] + T Deserialize(string value); } } \ No newline at end of file diff --git a/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs b/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs index af99361206e..43a03a72ada 100644 --- a/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs +++ b/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs @@ -9,71 +9,36 @@ namespace Microsoft.Toolkit.Helpers /// /// Service interface used to store data using key value pairs. /// - public interface ISettingsStorageHelper + /// The type of keys to use for accessing values. + public interface ISettingsStorageHelper + where TKey : notnull { - /// - /// Determines whether a setting already exists. - /// - /// Key of the setting (that contains object). - /// True if a value exists. - bool KeyExists(string key); - - /// - /// Determines whether a setting already exists in composite. - /// - /// Key of the composite (that contains settings). - /// Key of the setting (that contains object). - /// True if a value exists. - bool KeyExists(string compositeKey, string key); - /// /// Retrieves a single item by its key. /// - /// Type of object retrieved. + /// Type of object retrieved. /// Key of the object. /// Default value of the object. - /// The T object - T Read(string key, T? @default = default(T)); - - /// - /// Retrieves a single item by its key in composite. - /// - /// Type of object retrieved. - /// Key of the composite (that contains settings). - /// Key of the object. - /// Default value of the object. - /// The T object. - T Read(string compositeKey, string key, T? @default = default(T)); + /// The TValue object + TValue? Read(TKey key, TValue? @default = default); /// /// Saves a single item by its key. /// - /// Type of object saved. + /// Type of object saved. /// Key of the value saved. /// Object to save. - void Save(string key, T value); - - /// - /// Saves a group of items by its key in a composite. - /// This method should be considered for objects that do not exceed 8k bytes during the lifetime of the application - /// and for groups of settings which need to be treated in an atomic way. - /// - /// Type of object saved. - /// Key of the composite (that contains settings). - /// Objects to save. - void Save(string compositeKey, IDictionary values); + void Save(TKey key, TValue value); /// /// Deletes a single item by its key. /// /// Key of the object. - void Delete(string key); + void Delete(TKey key); /// - /// Deletes a single item by its key in composite. + /// Clear all keys and values from the settings store. /// - /// Key of the composite (that contains settings). - /// Key of the object. - void Delete(string compositeKey, string key); + void Clear(); } } diff --git a/Microsoft.Toolkit/Helpers/ObjectStorage/SystemSerializer.cs b/Microsoft.Toolkit/Helpers/ObjectStorage/SystemSerializer.cs index fbf5d9c1d4e..62d1b681c06 100644 --- a/Microsoft.Toolkit/Helpers/ObjectStorage/SystemSerializer.cs +++ b/Microsoft.Toolkit/Helpers/ObjectStorage/SystemSerializer.cs @@ -19,7 +19,7 @@ public class SystemSerializer : IObjectSerializer /// Type to convert value to. /// Value from storage to convert. /// Deserialized value or default value. - public T Deserialize(object value) + public T Deserialize(string value) { var type = typeof(T); var typeInfo = type.GetTypeInfo(); @@ -29,9 +29,7 @@ public T Deserialize(object value) return (T)Convert.ChangeType(value, type); } - return ThrowNotSupportedException(); - - static T ThrowNotSupportedException() => throw new NotSupportedException("This serializer can only handle primitive types and strings. Please implement your own IObjectSerializer for more complex scenarios."); + throw new NotSupportedException("This serializer can only handle primitive types and strings. Please implement your own IObjectSerializer for more complex scenarios."); } /// @@ -40,9 +38,9 @@ public T Deserialize(object value) /// Type to serialize from. /// Value to serialize. /// String representation of value. - public object? Serialize(T value) + public string? Serialize(T value) { - return value; + return value?.ToString(); } } } \ No newline at end of file diff --git a/Microsoft.Toolkit/Microsoft.Toolkit.csproj b/Microsoft.Toolkit/Microsoft.Toolkit.csproj index 8b428ac2652..49f3c5e5576 100644 --- a/Microsoft.Toolkit/Microsoft.Toolkit.csproj +++ b/Microsoft.Toolkit/Microsoft.Toolkit.csproj @@ -23,5 +23,8 @@ + + + \ No newline at end of file From e921d894821d7735fd9cac66bcf7c6087299583c Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Thu, 22 Jul 2021 12:15:58 -0700 Subject: [PATCH 21/35] Updated ISettingsStorageHelper references --- .../Controls/SampleAppMarkdownRenderer.cs | 2 +- Microsoft.Toolkit.Uwp.SampleApp/Models/Sample.cs | 2 +- Microsoft.Toolkit.Uwp.SampleApp/Models/Samples.cs | 2 +- .../SamplePages/Object Storage/ObjectStoragePage.xaml.cs | 2 +- Microsoft.Toolkit.Uwp/Helpers/SystemInformation.cs | 2 +- UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs | 6 +++--- UnitTests/UnitTests.UWP/Helpers/Test_SystemInformation.cs | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Controls/SampleAppMarkdownRenderer.cs b/Microsoft.Toolkit.Uwp.SampleApp/Controls/SampleAppMarkdownRenderer.cs index 4085cd81575..e30989e9b4c 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Controls/SampleAppMarkdownRenderer.cs +++ b/Microsoft.Toolkit.Uwp.SampleApp/Controls/SampleAppMarkdownRenderer.cs @@ -418,7 +418,7 @@ public string DesiredLang /// /// The local app data storage helper for storing settings. /// - private ISettingsStorageHelper settingsStorage = ApplicationDataStorageHelper.GetCurrent(new Toolkit.Helpers.SystemSerializer()); + private readonly ApplicationDataStorageHelper settingsStorage = ApplicationDataStorageHelper.GetCurrent(); /// /// DocFX note types and styling info, keyed by identifier. diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Models/Sample.cs b/Microsoft.Toolkit.Uwp.SampleApp/Models/Sample.cs index ce625ec03e9..6e512819c70 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Models/Sample.cs +++ b/Microsoft.Toolkit.Uwp.SampleApp/Models/Sample.cs @@ -46,7 +46,7 @@ public class Sample public static async void EnsureCacheLatest() { - ISettingsStorageHelper settingsStorage = ApplicationDataStorageHelper.GetCurrent(new Toolkit.Helpers.SystemSerializer()); + var settingsStorage = ApplicationDataStorageHelper.GetCurrent(); var onlineDocsSHA = await GetDocsSHA(); var cacheSHA = settingsStorage.Read(_cacheSHAKey); diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Models/Samples.cs b/Microsoft.Toolkit.Uwp.SampleApp/Models/Samples.cs index c43cf3aeb33..a05c2c19f22 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Models/Samples.cs +++ b/Microsoft.Toolkit.Uwp.SampleApp/Models/Samples.cs @@ -22,7 +22,7 @@ public static class Samples private static SemaphoreSlim _semaphore = new SemaphoreSlim(1); private static LinkedList _recentSamples; - private static ISettingsStorageHelper _settingsStorage = ApplicationDataStorageHelper.GetCurrent(new Toolkit.Helpers.SystemSerializer()); + private static ApplicationDataStorageHelper _settingsStorage = ApplicationDataStorageHelper.GetCurrent(); public static async Task GetCategoryBySample(Sample sample) { diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/Object Storage/ObjectStoragePage.xaml.cs b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/Object Storage/ObjectStoragePage.xaml.cs index 96079fb89f6..9bc0b00df04 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/Object Storage/ObjectStoragePage.xaml.cs +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/Object Storage/ObjectStoragePage.xaml.cs @@ -10,7 +10,7 @@ namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages { public sealed partial class ObjectStoragePage { - private readonly ISettingsStorageHelper _settingsStorage = ApplicationDataStorageHelper.GetCurrent(new Toolkit.Helpers.SystemSerializer()); + private readonly ApplicationDataStorageHelper _settingsStorage = ApplicationDataStorageHelper.GetCurrent(); public ObjectStoragePage() { diff --git a/Microsoft.Toolkit.Uwp/Helpers/SystemInformation.cs b/Microsoft.Toolkit.Uwp/Helpers/SystemInformation.cs index 81f7a6cac39..d55ccddccdc 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/SystemInformation.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/SystemInformation.cs @@ -26,7 +26,7 @@ public sealed class SystemInformation /// /// The instance used to save and retrieve application settings. /// - private readonly ISettingsStorageHelper _settingsStorage = ApplicationDataStorageHelper.GetCurrent(new Toolkit.Helpers.SystemSerializer()); + private readonly ApplicationDataStorageHelper _settingsStorage = ApplicationDataStorageHelper.GetCurrent(); /// /// The starting time of the current application session (since app launch or last move to foreground). diff --git a/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs b/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs index 0b27db815db..e5922304f0e 100644 --- a/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs +++ b/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs @@ -15,9 +15,9 @@ namespace UnitTests.Helpers [TestClass] public class Test_StorageHelper { - private ISettingsStorageHelper _settingsStorage_System = ApplicationDataStorageHelper.GetCurrent(new Microsoft.Toolkit.Helpers.SystemSerializer()); - private ISettingsStorageHelper _settingsStorage_JsonCompat = ApplicationDataStorageHelper.GetCurrent(new JsonObjectSerializer()); - private ISettingsStorageHelper _settingsStorage_JsonNew = ApplicationDataStorageHelper.GetCurrent(new SystemTextJsonSerializer()); + private readonly ISettingsStorageHelper _settingsStorage_System = ApplicationDataStorageHelper.GetCurrent(); + private readonly ISettingsStorageHelper _settingsStorage_JsonCompat = ApplicationDataStorageHelper.GetCurrent(new JsonObjectSerializer()); + private readonly ISettingsStorageHelper _settingsStorage_JsonNew = ApplicationDataStorageHelper.GetCurrent(new SystemTextJsonSerializer()); /// /// Checks that we're running 10.0.3 version of Newtonsoft.Json package which we used in 6.1.1. diff --git a/UnitTests/UnitTests.UWP/Helpers/Test_SystemInformation.cs b/UnitTests/UnitTests.UWP/Helpers/Test_SystemInformation.cs index 7132f500abd..466398d6809 100644 --- a/UnitTests/UnitTests.UWP/Helpers/Test_SystemInformation.cs +++ b/UnitTests/UnitTests.UWP/Helpers/Test_SystemInformation.cs @@ -58,7 +58,7 @@ public void Test_SystemInformation_ConsistentInfoForStartupWithUpdate() // Simulate a first app startup _ = (SystemInformation)Activator.CreateInstance(typeof(SystemInformation), nonPublic: true); - ISettingsStorageHelper settingsStorage = ApplicationDataStorageHelper.GetCurrent(new Microsoft.Toolkit.Helpers.SystemSerializer()); + var settingsStorage = ApplicationDataStorageHelper.GetCurrent(); PackageVersion previousVersion = new() { Build = 42, Major = 1111, Minor = 2222, Revision = 12345 }; settingsStorage.Save("currentVersion", previousVersion.ToFormattedString()); From e61c0cdd044916ad9eb1e89972c874e8c523c732 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Thu, 22 Jul 2021 12:26:08 -0700 Subject: [PATCH 22/35] Update Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs Co-authored-by: Sergio Pedri --- Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs b/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs index 2ca3397eee8..df3b1600c39 100644 --- a/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs +++ b/Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs @@ -25,7 +25,7 @@ public interface IFileStorageHelper /// Path to the file that contains the object. /// Default value of the object. /// Waiting task until completion with the object in the file. - Task ReadFileAsync(string filePath, T? @default = default); + Task ReadFileAsync(string filePath, T? @default = default); /// /// Retrieves the listings for a folder and the item types. From 0e414ec54d98059deb50fd2c72ede34c23502f2b Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Thu, 22 Jul 2021 12:57:41 -0700 Subject: [PATCH 23/35] Removed default param from ISettingsStorageHelper.Read method and updated exception handling in ApplicationDataStorageHelper for missing keys --- .../ApplicationDataStorageHelper.cs | 38 ++++++++++++++++--- .../ObjectStorage/ISettingsStorageHelper.cs | 5 ++- .../Helpers/Test_StorageHelper.cs | 6 +-- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs index 4f1ddbb4169..75c8d2d7e45 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs @@ -81,7 +81,13 @@ public bool KeyExists(string key) return Settings.Values.ContainsKey(key); } - /// + /// + /// Retrieves a single item by its key. + /// + /// Type of object retrieved. + /// Key of the object. + /// Default value of the object. + /// The TValue object public T Read(string key, T @default = default) { if (!Settings.Values.TryGetValue(key, out var valueObj) || valueObj == null) @@ -92,6 +98,17 @@ public T Read(string key, T @default = default) return Serializer.Deserialize(valueObj as string); } + /// + public T Read(string key) + { + if (Settings.Values.TryGetValue(key, out var valueObj) && valueObj != null) + { + return Serializer.Deserialize(valueObj as string); + } + + throw new KeyNotFoundException(key); + } + /// public void Save(string key, T value) { @@ -101,7 +118,11 @@ public void Save(string key, T value) /// public void Delete(string key) { - Settings.Values.Remove(key); + var removed = Settings.Values.Remove(key); + if (!removed) + { + throw new KeyNotFoundException(key); + } } /// @@ -196,12 +217,19 @@ public void Save(string compositeKey, IDictionary values) /// /// Key of the composite (that contains settings). /// Key of the object. + /// Throws when the specified composite/settings key is not found. public void Delete(string compositeKey, string key) { - if (KeyExists(compositeKey)) + if (!KeyExists(compositeKey)) { - ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)Settings.Values[compositeKey]; - composite.Remove(key); + throw new KeyNotFoundException($"Composite key not found: {compositeKey}"); + } + + ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)Settings.Values[compositeKey]; + + if (!composite.Remove(key)) + { + throw new KeyNotFoundException($"Settings key not found: {key}"); } } diff --git a/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs b/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs index 43a03a72ada..f1ea8827635 100644 --- a/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs +++ b/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs @@ -18,9 +18,9 @@ public interface ISettingsStorageHelper /// /// Type of object retrieved. /// Key of the object. - /// Default value of the object. + /// Throws when the specified key is not found. /// The TValue object - TValue? Read(TKey key, TValue? @default = default); + TValue? Read(TKey key); /// /// Saves a single item by its key. @@ -34,6 +34,7 @@ public interface ISettingsStorageHelper /// Deletes a single item by its key. /// /// Key of the object. + /// Throws when the specified key is not found. void Delete(TKey key); /// diff --git a/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs b/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs index e5922304f0e..be0b192e6df 100644 --- a/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs +++ b/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs @@ -15,9 +15,9 @@ namespace UnitTests.Helpers [TestClass] public class Test_StorageHelper { - private readonly ISettingsStorageHelper _settingsStorage_System = ApplicationDataStorageHelper.GetCurrent(); - private readonly ISettingsStorageHelper _settingsStorage_JsonCompat = ApplicationDataStorageHelper.GetCurrent(new JsonObjectSerializer()); - private readonly ISettingsStorageHelper _settingsStorage_JsonNew = ApplicationDataStorageHelper.GetCurrent(new SystemTextJsonSerializer()); + private readonly ApplicationDataStorageHelper _settingsStorage_System = ApplicationDataStorageHelper.GetCurrent(); + private readonly ApplicationDataStorageHelper _settingsStorage_JsonCompat = ApplicationDataStorageHelper.GetCurrent(new JsonObjectSerializer()); + private readonly ApplicationDataStorageHelper _settingsStorage_JsonNew = ApplicationDataStorageHelper.GetCurrent(new SystemTextJsonSerializer()); /// /// Checks that we're running 10.0.3 version of Newtonsoft.Json package which we used in 6.1.1. From 51d58cd014ec1f1b04f9b56d3d6ba68b4a3832da Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Thu, 22 Jul 2021 13:23:51 -0700 Subject: [PATCH 24/35] Updated JsonObjectSerializer and SystemTextJsonSerializer in Uwp test app --- UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs | 6 +++--- UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer.cs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs b/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs index c0d492467a0..160c52aecb3 100644 --- a/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs +++ b/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs @@ -14,7 +14,7 @@ namespace UnitTests.UWP.Helpers /// internal class JsonObjectSerializer : IObjectSerializer { - public T Deserialize(object value) + public T Deserialize(string value) { var type = typeof(T); var typeInfo = type.GetTypeInfo(); @@ -29,7 +29,7 @@ public T Deserialize(object value) return JsonConvert.DeserializeObject((string)value); } - public object Serialize(T value) + public string Serialize(T value) { var type = typeof(T); var typeInfo = type.GetTypeInfo(); @@ -38,7 +38,7 @@ public object Serialize(T value) // This if/return combo is to maintain compatibility with 6.1.1 if (typeInfo.IsPrimitive || type == typeof(string)) { - return value; + return value.ToString(); } return JsonConvert.SerializeObject(value); diff --git a/UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer.cs b/UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer.cs index 7871089f0b4..6204426a15b 100644 --- a/UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer.cs +++ b/UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer.cs @@ -13,8 +13,8 @@ namespace UnitTests.UWP.Helpers /// internal class SystemTextJsonSerializer : IObjectSerializer { - public T Deserialize(object value) => JsonSerializer.Deserialize(value as string); + public T Deserialize(string value) => JsonSerializer.Deserialize(value); - public object Serialize(T value) => JsonSerializer.Serialize(value); + public string Serialize(T value) => JsonSerializer.Serialize(value); } } \ No newline at end of file From 27cae2eec777fcee25dfde1523d1013e1f0a06e8 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Thu, 22 Jul 2021 16:13:07 -0700 Subject: [PATCH 25/35] Added extension methods for ISettingsStorageHelper --- .../ISettingsStorageHelperExtensions.cs | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 Microsoft.Toolkit/Extensions/ISettingsStorageHelperExtensions.cs diff --git a/Microsoft.Toolkit/Extensions/ISettingsStorageHelperExtensions.cs b/Microsoft.Toolkit/Extensions/ISettingsStorageHelperExtensions.cs new file mode 100644 index 00000000000..fa0664a1bd7 --- /dev/null +++ b/Microsoft.Toolkit/Extensions/ISettingsStorageHelperExtensions.cs @@ -0,0 +1,88 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Toolkit.Helpers; + +namespace Microsoft.Toolkit.Extensions +{ + /// + /// Helpers methods for working with implementations. + /// + public static class ISettingsStorageHelperExtensions + { + /// + /// Attempts to read the provided key and return the value. + /// If the key is not found, the fallback value will be used instead. + /// + /// The type of key used to lookup the object. + /// The type of object value expected. + /// The storage helper instance fo read from. + /// The key of the target object. + /// An alternative value returned if the read fails. + /// The value of the target object, or the fallback value. + public static TValue? GetValueOrDefault(this ISettingsStorageHelper storageHelper, TKey key, TValue? fallback = default) + where TKey : notnull + { + try + { + return storageHelper.Read(key); + } + catch (KeyNotFoundException) + { + return fallback; + } + } + + /// + /// Attempts to perform read the provided key and returns a boolean indicator of success. + /// If the key is not found, the fallback value will be used instead. + /// + /// The type of key used to lookup the object. + /// The type of object value expected. + /// The storage helper instance to read from. + /// The key of the target object. + /// The value of the target object, or the fallback value. + /// An alternate value returned if the read fails. + /// A boolean indicator of success. + public static bool TryRead(this ISettingsStorageHelper storageHelper, TKey key, out TValue? value, TValue? fallback = default) + where TKey : notnull + { + try + { + value = storageHelper.Read(key); + return true; + } + catch (KeyNotFoundException) + { + value = fallback; + return false; + } + } + + /// + /// Attempts to remove an object by key and returns a boolean indicator of success. + /// If the key is not found, the method will return false. + /// + /// The type of key used to lookup the object. + /// The storage helper instance to delete from. + /// The key of the target object. + /// A boolean indicator of success. + public static bool TryDelete(this ISettingsStorageHelper storageHelper, TKey key) + where TKey : notnull + { + try + { + storageHelper.Delete(key); + return true; + } + catch (KeyNotFoundException) + { + return false; + } + } + } +} From 13c3e2f4918b81124d80254de3ec8a1e5c8f3375 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Mon, 26 Jul 2021 11:50:08 -0700 Subject: [PATCH 26/35] Update Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs Co-authored-by: Sergio Pedri --- .../Helpers/ObjectStorage/ISettingsStorageHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs b/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs index f1ea8827635..6bc4063d290 100644 --- a/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs +++ b/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs @@ -10,7 +10,7 @@ namespace Microsoft.Toolkit.Helpers /// Service interface used to store data using key value pairs. /// /// The type of keys to use for accessing values. - public interface ISettingsStorageHelper + public interface ISettingsStorageHelper where TKey : notnull { /// From b472cc849679d5d811725851399cad10eb3b7799 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Mon, 26 Jul 2021 12:15:46 -0700 Subject: [PATCH 27/35] PR updates --- Microsoft.Toolkit/Helpers/ObjectStorage/IObjectSerializer.cs | 4 ---- .../Helpers/ObjectStorage/ISettingsStorageHelper.cs | 2 +- Microsoft.Toolkit/Microsoft.Toolkit.csproj | 4 +--- UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs | 2 +- 4 files changed, 3 insertions(+), 9 deletions(-) diff --git a/Microsoft.Toolkit/Helpers/ObjectStorage/IObjectSerializer.cs b/Microsoft.Toolkit/Helpers/ObjectStorage/IObjectSerializer.cs index 266ec157976..5a8177b4f78 100644 --- a/Microsoft.Toolkit/Helpers/ObjectStorage/IObjectSerializer.cs +++ b/Microsoft.Toolkit/Helpers/ObjectStorage/IObjectSerializer.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.Toolkit.Helpers { /// @@ -17,7 +15,6 @@ public interface IObjectSerializer /// The type of the object to serialize. /// The object to serialize. /// The serialized object. - [return: NotNullIfNotNull("value")] string? Serialize(T value); /// @@ -26,7 +23,6 @@ public interface IObjectSerializer /// The type of the deserialized object. /// The string to deserialize. /// The deserialized object. - [return: NotNullIfNotNull("value")] T Deserialize(string value); } } \ No newline at end of file diff --git a/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs b/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs index f1ea8827635..d8dba333caa 100644 --- a/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs +++ b/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs @@ -19,7 +19,7 @@ public interface ISettingsStorageHelper /// Type of object retrieved. /// Key of the object. /// Throws when the specified key is not found. - /// The TValue object + /// The object for key. TValue? Read(TKey key); /// diff --git a/Microsoft.Toolkit/Microsoft.Toolkit.csproj b/Microsoft.Toolkit/Microsoft.Toolkit.csproj index 31afd868c1f..6efb4c97210 100644 --- a/Microsoft.Toolkit/Microsoft.Toolkit.csproj +++ b/Microsoft.Toolkit/Microsoft.Toolkit.csproj @@ -21,11 +21,9 @@ NETSTANDARD2_1_OR_GREATER - + - - diff --git a/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs b/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs index 160c52aecb3..c9b4aeaa302 100644 --- a/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs +++ b/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs @@ -26,7 +26,7 @@ public T Deserialize(string value) return (T)Convert.ChangeType(value, type); } - return JsonConvert.DeserializeObject((string)value); + return JsonConvert.DeserializeObject(value); } public string Serialize(T value) From 82c2ba31d3fcc803587e98707e0f32ab9355f96a Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Mon, 26 Jul 2021 15:09:18 -0700 Subject: [PATCH 28/35] PR updates --- .../ApplicationDataStorageHelper.cs | 16 +- .../ISettingsStorageHelperExtensions.cs | 53 +++--- .../ObjectStorage/ISettingsStorageHelper.cs | 10 +- .../Helpers/JsonObjectSerializer.cs | 13 +- .../Helpers/JsonObjectSerializer2.cs | 48 +++++ .../Helpers/SystemTextJsonSerializer.cs | 9 +- .../Helpers/SystemTextJsonSerializer2.cs | 20 ++ .../Test_ApplicationDataStorageHelper.cs | 177 ++++++++++++++++++ .../Helpers/Test_StorageHelper.cs | 43 +++-- UnitTests/UnitTests.UWP/UnitTests.UWP.csproj | 5 +- 10 files changed, 317 insertions(+), 77 deletions(-) create mode 100644 UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer2.cs create mode 100644 UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer2.cs create mode 100644 UnitTests/UnitTests.UWP/Helpers/Test_ApplicationDataStorageHelper.cs diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs index 75c8d2d7e45..7231254604b 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs @@ -99,14 +99,16 @@ public T Read(string key, T @default = default) } /// - public T Read(string key) + public bool TryRead(string key, out T value) { if (Settings.Values.TryGetValue(key, out var valueObj) && valueObj != null) { - return Serializer.Deserialize(valueObj as string); + value = Serializer.Deserialize(valueObj as string); + return true; } - throw new KeyNotFoundException(key); + value = default; + return false; } /// @@ -116,13 +118,9 @@ public void Save(string key, T value) } /// - public void Delete(string key) + public bool TryDelete(string key) { - var removed = Settings.Values.Remove(key); - if (!removed) - { - throw new KeyNotFoundException(key); - } + return Settings.Values.Remove(key); } /// diff --git a/Microsoft.Toolkit/Extensions/ISettingsStorageHelperExtensions.cs b/Microsoft.Toolkit/Extensions/ISettingsStorageHelperExtensions.cs index fa0664a1bd7..b8b11a7b9db 100644 --- a/Microsoft.Toolkit/Extensions/ISettingsStorageHelperExtensions.cs +++ b/Microsoft.Toolkit/Extensions/ISettingsStorageHelperExtensions.cs @@ -22,66 +22,59 @@ public static class ISettingsStorageHelperExtensions /// The type of object value expected. /// The storage helper instance fo read from. /// The key of the target object. + /// The value of the target object, or the fallback value. /// An alternative value returned if the read fails. - /// The value of the target object, or the fallback value. - public static TValue? GetValueOrDefault(this ISettingsStorageHelper storageHelper, TKey key, TValue? fallback = default) + /// A boolean indicator of success. + public static bool TryGetValueOrDefault(this ISettingsStorageHelper storageHelper, TKey key, out TValue? value, TValue? fallback = default) where TKey : notnull { - try + if (storageHelper.TryRead(key, out TValue? storedValue)) { - return storageHelper.Read(key); + value = storedValue; + return true; } - catch (KeyNotFoundException) + else { - return fallback; + value = fallback; + return false; } } /// - /// Attempts to perform read the provided key and returns a boolean indicator of success. - /// If the key is not found, the fallback value will be used instead. + /// Read the key in the storage helper instance and get the value. /// /// The type of key used to lookup the object. /// The type of object value expected. - /// The storage helper instance to read from. + /// The storage helper instance fo read from. /// The key of the target object. - /// The value of the target object, or the fallback value. - /// An alternate value returned if the read fails. - /// A boolean indicator of success. - public static bool TryRead(this ISettingsStorageHelper storageHelper, TKey key, out TValue? value, TValue? fallback = default) + /// The value of the target object + /// Throws when the key is not found in storage. + public static TValue? Read(this ISettingsStorageHelper storageHelper, TKey key) where TKey : notnull { - try + if (storageHelper.TryRead(key, out TValue? value)) { - value = storageHelper.Read(key); - return true; + return value; } - catch (KeyNotFoundException) + else { - value = fallback; - return false; + throw new KeyNotFoundException(); } } /// - /// Attempts to remove an object by key and returns a boolean indicator of success. - /// If the key is not found, the method will return false. + /// Deletes a key from storage. /// /// The type of key used to lookup the object. /// The storage helper instance to delete from. /// The key of the target object. - /// A boolean indicator of success. - public static bool TryDelete(this ISettingsStorageHelper storageHelper, TKey key) + /// Throws when the key is not found in storage. + public static void Delete(this ISettingsStorageHelper storageHelper, TKey key) where TKey : notnull { - try + if (!storageHelper.TryDelete(key)) { - storageHelper.Delete(key); - return true; - } - catch (KeyNotFoundException) - { - return false; + throw new KeyNotFoundException(); } } } diff --git a/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs b/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs index 90068d1cee5..c8f9713b5d8 100644 --- a/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs +++ b/Microsoft.Toolkit/Helpers/ObjectStorage/ISettingsStorageHelper.cs @@ -18,9 +18,9 @@ public interface ISettingsStorageHelper /// /// Type of object retrieved. /// Key of the object. - /// Throws when the specified key is not found. - /// The object for key. - TValue? Read(TKey key); + /// The object for key. + /// A boolean indicator of success. + bool TryRead(TKey key, out TValue? value); /// /// Saves a single item by its key. @@ -34,8 +34,8 @@ public interface ISettingsStorageHelper /// Deletes a single item by its key. /// /// Key of the object. - /// Throws when the specified key is not found. - void Delete(TKey key); + /// A boolean indicator of success. + bool TryDelete(TKey key); /// /// Clear all keys and values from the settings store. diff --git a/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs b/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs index c9b4aeaa302..e14a612cf6b 100644 --- a/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs +++ b/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs @@ -4,17 +4,18 @@ using System; using System.Reflection; -using Microsoft.Toolkit.Helpers; +using Microsoft.Toolkit.Uwp.Helpers; using Newtonsoft.Json; -namespace UnitTests.UWP.Helpers +namespace UnitTests.Helpers { /// /// This is a Serializer which should mimic the previous functionality of 6.1.1 release of the Toolkit with Newtonsoft.Json. + /// Based on . /// internal class JsonObjectSerializer : IObjectSerializer { - public T Deserialize(string value) + public T Deserialize(object value) { var type = typeof(T); var typeInfo = type.GetTypeInfo(); @@ -26,10 +27,10 @@ public T Deserialize(string value) return (T)Convert.ChangeType(value, type); } - return JsonConvert.DeserializeObject(value); + return JsonConvert.DeserializeObject((string)value); } - public string Serialize(T value) + public object Serialize(T value) { var type = typeof(T); var typeInfo = type.GetTypeInfo(); @@ -38,7 +39,7 @@ public string Serialize(T value) // This if/return combo is to maintain compatibility with 6.1.1 if (typeInfo.IsPrimitive || type == typeof(string)) { - return value.ToString(); + return value; } return JsonConvert.SerializeObject(value); diff --git a/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer2.cs b/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer2.cs new file mode 100644 index 00000000000..8721acc6920 --- /dev/null +++ b/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer2.cs @@ -0,0 +1,48 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Reflection; +using Microsoft.Toolkit.Helpers; +using Newtonsoft.Json; + +namespace UnitTests.Helpers +{ + /// + /// This is a Serializer which should mimic the previous functionality of 6.1.1 release of the Toolkit with Newtonsoft.Json. + /// Based on . + /// + internal class JsonObjectSerializer2 : IObjectSerializer + { + public T Deserialize(string value) + { + var type = typeof(T); + var typeInfo = type.GetTypeInfo(); + + // Note: If you're creating a new app, you could just use the serializer directly. + // This if/return combo is to maintain compatibility with 6.1.1 + if (typeInfo.IsPrimitive || type == typeof(string)) + { + return (T)Convert.ChangeType(value, type); + } + + return JsonConvert.DeserializeObject(value); + } + + public string Serialize(T value) + { + var type = typeof(T); + var typeInfo = type.GetTypeInfo(); + + // Note: If you're creating a new app, you could just use the serializer directly. + // This if/return combo is to maintain compatibility with 6.1.1 + if (typeInfo.IsPrimitive || type == typeof(string)) + { + return value.ToString(); + } + + return JsonConvert.SerializeObject(value); + } + } +} \ No newline at end of file diff --git a/UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer.cs b/UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer.cs index 6204426a15b..3598d2deb24 100644 --- a/UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer.cs +++ b/UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer.cs @@ -4,17 +4,18 @@ using System; using System.Text.Json; -using Microsoft.Toolkit.Helpers; +using Microsoft.Toolkit.Uwp.Helpers; -namespace UnitTests.UWP.Helpers +namespace UnitTests.Helpers { /// /// Example class of writing a new that uses System.Text.Json. + /// Based on . /// internal class SystemTextJsonSerializer : IObjectSerializer { - public T Deserialize(string value) => JsonSerializer.Deserialize(value); + public T Deserialize(object value) => JsonSerializer.Deserialize(value as string); - public string Serialize(T value) => JsonSerializer.Serialize(value); + public object Serialize(T value) => JsonSerializer.Serialize(value); } } \ No newline at end of file diff --git a/UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer2.cs b/UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer2.cs new file mode 100644 index 00000000000..caae64f288c --- /dev/null +++ b/UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer2.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json; +using Microsoft.Toolkit.Helpers; + +namespace UnitTests.Helpers +{ + /// + /// Example class of writing a new that uses System.Text.Json. + /// Based on . + /// + internal class SystemTextJsonSerializer2 : IObjectSerializer + { + public T Deserialize(string value) => JsonSerializer.Deserialize(value); + + public string Serialize(T value) => JsonSerializer.Serialize(value); + } +} \ No newline at end of file diff --git a/UnitTests/UnitTests.UWP/Helpers/Test_ApplicationDataStorageHelper.cs b/UnitTests/UnitTests.UWP/Helpers/Test_ApplicationDataStorageHelper.cs new file mode 100644 index 00000000000..f6c5e184a9f --- /dev/null +++ b/UnitTests/UnitTests.UWP/Helpers/Test_ApplicationDataStorageHelper.cs @@ -0,0 +1,177 @@ +using Microsoft.Toolkit.Uwp.Helpers; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace UnitTests.Helpers +{ + [TestClass] + public class Test_ApplicationDataStorageHelper + { + private readonly ApplicationDataStorageHelper _settingsStorage_System = ApplicationDataStorageHelper.GetCurrent(); + private readonly ApplicationDataStorageHelper _settingsStorage_JsonCompat = ApplicationDataStorageHelper.GetCurrent(new JsonObjectSerializer2()); + private readonly ApplicationDataStorageHelper _settingsStorage_JsonNew = ApplicationDataStorageHelper.GetCurrent(new SystemTextJsonSerializer2()); + + /// + /// Checks that we're running 10.0.3 version of Newtonsoft.Json package which we used in 6.1.1. + /// + [TestCategory("Helpers")] + [TestMethod] + public void Test_StorageHelper_CheckNewtonsoftVersion() + { + var version = typeof(Newtonsoft.Json.JsonSerializer).Assembly.GetName().Version; + Assert.AreEqual(10, version.Major); + Assert.AreEqual(0, version.Minor); + Assert.AreEqual(0, version.Revision); // Apparently the file revision was not updated for the updated package + } + + [TestCategory("Helpers")] + [TestMethod] + public void Test_StorageHelper_LegacyIntTest() + { + string key = "LifeUniverseAndEverything"; + + int input = 42; + + // Use our previous Json layer to store value + _settingsStorage_JsonCompat.Save(key, input); + + // But try and read from our new system to see if it works + int output = _settingsStorage_System.Read(key, 0); + + Assert.AreEqual(input, output); + } + + /// + /// If we try and deserialize a complex type with the , we do a check ourselves and will throw our own exception. + /// + [TestCategory("Helpers")] + [TestMethod] + [ExpectedException(typeof(NotSupportedException))] + public void Test_StorageHelper_LegacyDateTestFailure() + { + string key = "ChristmasDay"; + + DateTime input = new DateTime(2017, 12, 25); + + _settingsStorage_JsonCompat.Save(key, input); + + // now read it as int to valid that the change works + _ = _settingsStorage_System.Read(key, DateTime.Today); + } + + /// + /// The doesn't support complex types, since it just passes through directly. + /// We'll get the argument exception from the API. + /// + [TestCategory("Helpers")] + [TestMethod] + [ExpectedException(typeof(NotSupportedException))] + public void Test_StorageHelper_DateTestFailure() + { + string key = "Today"; + + _settingsStorage_System.Save(key, DateTime.Today); + _settingsStorage_System.TryRead(key, out _); + } + + [TestCategory("Helpers")] + [TestMethod] + public void Test_StorageHelper_LegacyInternalClassTest() + { + string key = "Contact"; + + UI.Person input = new UI.Person() { Name = "Joe Bloggs", Age = 42 }; + + // simulate previous version by generating json and manually inserting it as string + _settingsStorage_JsonCompat.Save(key, input); + + // now read it as int to valid that the change works + UI.Person output = _settingsStorage_JsonCompat.Read(key, null); + + Assert.IsNotNull(output); + Assert.AreEqual(input.Name, output.Name); + Assert.AreEqual(input.Age, output.Age); + } + + [TestCategory("Helpers")] + [TestMethod] + public void Test_StorageHelper_LegacyPublicClassTest() + { + string key = "Contact"; + + // Here's we're serializing a different class which has the same properties as our other class below. + UI.Person input = new UI.Person() { Name = "Joe Bloggs", Age = 42 }; + + // simulate previous version by generating json and manually inserting it as string + _settingsStorage_JsonCompat.Save(key, input); + + // now read it as int to valid that the change works + Person output = _settingsStorage_JsonCompat.Read(key, null); + + Assert.IsNotNull(output); + Assert.AreEqual(input.Name, output.Name); + Assert.AreEqual(input.Age, output.Age); + } + + [TestCategory("Helpers")] + [TestMethod] + public void Test_StorageHelper_IntTest() + { + string key = "NewLifeUniverseAndEverything"; + + int input = 42; + + _settingsStorage_System.Save(key, input); + + // now read it as int to valid that the change works + int output = _settingsStorage_System.Read(key, 0); + + Assert.AreEqual(input, output); + } + + [TestCategory("Helpers")] + [TestMethod] + public void Test_StorageHelper_NewDateTest() + { + string key = "NewChristmasDay"; + + DateTime input = new DateTime(2017, 12, 25); + + _settingsStorage_JsonNew.Save(key, input); + + // now read it as int to valid that the change works + DateTime output = _settingsStorage_JsonNew.Read(key, DateTime.Today); + + Assert.AreEqual(input, output); + } + + [TestCategory("Helpers")] + [TestMethod] + public void Test_StorageHelper_NewPersonTest() + { + string key = "Contact"; + + Person input = new Person() { Name = "Joe Bloggs", Age = 42 }; + + _settingsStorage_JsonNew.Save(key, input); + + // now read it as int to valid that the change works + Person output = _settingsStorage_JsonNew.Read(key, null); + + Assert.IsNotNull(output); + Assert.AreEqual(input.Name, output.Name); + Assert.AreEqual(input.Age, output.Age); + } + + public class Person + { + public string Name { get; set; } + + public int Age { get; set; } + } + } +} diff --git a/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs b/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs index be0b192e6df..a70abd9b53f 100644 --- a/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs +++ b/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs @@ -3,11 +3,10 @@ // See the LICENSE file in the project root for more information. using System; -using Microsoft.Toolkit.Helpers; using Microsoft.Toolkit.Uwp.Helpers; using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json; -using UnitTests.UWP.Helpers; +using UnitTests.Helpers; using Windows.Storage; namespace UnitTests.Helpers @@ -15,9 +14,9 @@ namespace UnitTests.Helpers [TestClass] public class Test_StorageHelper { - private readonly ApplicationDataStorageHelper _settingsStorage_System = ApplicationDataStorageHelper.GetCurrent(); - private readonly ApplicationDataStorageHelper _settingsStorage_JsonCompat = ApplicationDataStorageHelper.GetCurrent(new JsonObjectSerializer()); - private readonly ApplicationDataStorageHelper _settingsStorage_JsonNew = ApplicationDataStorageHelper.GetCurrent(new SystemTextJsonSerializer()); + private readonly LocalObjectStorageHelper _localStorageHelperSystem = new LocalObjectStorageHelper(new SystemSerializer()); + private readonly LocalObjectStorageHelper _localStorageHelperJsonCompat = new LocalObjectStorageHelper(new JsonObjectSerializer()); + private readonly LocalObjectStorageHelper _localStorageHelperJsonNew = new LocalObjectStorageHelper(new SystemTextJsonSerializer()); /// /// Checks that we're running 10.0.3 version of Newtonsoft.Json package which we used in 6.1.1. @@ -41,16 +40,16 @@ public void Test_StorageHelper_LegacyIntTest() int input = 42; // Use our previous Json layer to store value - _settingsStorage_JsonCompat.Save(key, input); + _localStorageHelperJsonCompat.Save(key, input); // But try and read from our new system to see if it works - int output = _settingsStorage_System.Read(key, 0); + int output = _localStorageHelperSystem.Read(key, 0); Assert.AreEqual(input, output); } /// - /// If we try and deserialize a complex type with the , we do a check ourselves and will throw our own exception. + /// If we try and deserialize a complex type with the , we do a check ourselves and will throw our own exception. /// [TestCategory("Helpers")] [TestMethod] @@ -61,14 +60,14 @@ public void Test_StorageHelper_LegacyDateTestFailure() DateTime input = new DateTime(2017, 12, 25); - _settingsStorage_JsonCompat.Save(key, input); + _localStorageHelperJsonCompat.Save(key, input); // now read it as int to valid that the change works - DateTime output = _settingsStorage_System.Read(key, DateTime.Today); + DateTime output = _localStorageHelperSystem.Read(key, DateTime.Today); } /// - /// The doesn't support complex types, since it just passes through directly. + /// The doesn't support complex types, since it just passes through directly. /// We'll get the argument exception from the API. /// [TestCategory("Helpers")] @@ -81,7 +80,7 @@ public void Test_StorageHelper_DateTestFailure() // as local and online platforms seem to throw different exception types :( try { - _settingsStorage_System.Save("Today", DateTime.Today); + _localStorageHelperSystem.Save("Today", DateTime.Today); } catch (Exception exception) { @@ -100,10 +99,10 @@ public void Test_StorageHelper_LegacyInternalClassTest() UI.Person input = new UI.Person() { Name = "Joe Bloggs", Age = 42 }; // simulate previous version by generating json and manually inserting it as string - _settingsStorage_JsonCompat.Save(key, input); + _localStorageHelperJsonCompat.Save(key, input); // now read it as int to valid that the change works - UI.Person output = _settingsStorage_JsonCompat.Read(key, null); + UI.Person output = _localStorageHelperJsonCompat.Read(key, null); Assert.IsNotNull(output); Assert.AreEqual(input.Name, output.Name); @@ -120,10 +119,10 @@ public void Test_StorageHelper_LegacyPublicClassTest() UI.Person input = new UI.Person() { Name = "Joe Bloggs", Age = 42 }; // simulate previous version by generating json and manually inserting it as string - _settingsStorage_JsonCompat.Save(key, input); + _localStorageHelperJsonCompat.Save(key, input); // now read it as int to valid that the change works - Person output = _settingsStorage_JsonCompat.Read(key, null); + Person output = _localStorageHelperJsonCompat.Read(key, null); Assert.IsNotNull(output); Assert.AreEqual(input.Name, output.Name); @@ -138,10 +137,10 @@ public void Test_StorageHelper_IntTest() int input = 42; - _settingsStorage_System.Save(key, input); + _localStorageHelperSystem.Save(key, input); // now read it as int to valid that the change works - int output = _settingsStorage_System.Read(key, 0); + int output = _localStorageHelperSystem.Read(key, 0); Assert.AreEqual(input, output); } @@ -154,10 +153,10 @@ public void Test_StorageHelper_NewDateTest() DateTime input = new DateTime(2017, 12, 25); - _settingsStorage_JsonNew.Save(key, input); + _localStorageHelperJsonNew.Save(key, input); // now read it as int to valid that the change works - DateTime output = _settingsStorage_JsonNew.Read(key, DateTime.Today); + DateTime output = _localStorageHelperJsonNew.Read(key, DateTime.Today); Assert.AreEqual(input, output); } @@ -170,10 +169,10 @@ public void Test_StorageHelper_NewPersonTest() Person input = new Person() { Name = "Joe Bloggs", Age = 42 }; - _settingsStorage_JsonNew.Save(key, input); + _localStorageHelperJsonNew.Save(key, input); // now read it as int to valid that the change works - Person output = _settingsStorage_JsonNew.Read(key, null); + Person output = _localStorageHelperJsonNew.Read(key, null); Assert.IsNotNull(output); Assert.AreEqual(input.Name, output.Name); diff --git a/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj b/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj index 0323d553a9a..215c4582b40 100644 --- a/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj +++ b/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj @@ -1,4 +1,4 @@ - + Debug @@ -175,10 +175,13 @@ + + + From dc218aa0bb7930f4583f5dcb11e1925a7d5ae2b6 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Mon, 26 Jul 2021 15:23:33 -0700 Subject: [PATCH 29/35] The ever important file header! --- .../Helpers/Test_ApplicationDataStorageHelper.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/UnitTests/UnitTests.UWP/Helpers/Test_ApplicationDataStorageHelper.cs b/UnitTests/UnitTests.UWP/Helpers/Test_ApplicationDataStorageHelper.cs index f6c5e184a9f..94d44b77093 100644 --- a/UnitTests/UnitTests.UWP/Helpers/Test_ApplicationDataStorageHelper.cs +++ b/UnitTests/UnitTests.UWP/Helpers/Test_ApplicationDataStorageHelper.cs @@ -1,3 +1,7 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + using Microsoft.Toolkit.Uwp.Helpers; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; From f4207eaa02904598a61feac813f72cdb6baff9e4 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Mon, 26 Jul 2021 17:18:20 -0700 Subject: [PATCH 30/35] Added Obsolete attributes to old storage helper tests --- .../UnitTests.UWP/Helpers/JsonObjectSerializer.cs | 1 + .../UnitTests.UWP/Helpers/SystemTextJsonSerializer.cs | 1 + UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs | 11 +++++++++++ 3 files changed, 13 insertions(+) diff --git a/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs b/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs index e14a612cf6b..27b775155ef 100644 --- a/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs +++ b/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs @@ -13,6 +13,7 @@ namespace UnitTests.Helpers /// This is a Serializer which should mimic the previous functionality of 6.1.1 release of the Toolkit with Newtonsoft.Json. /// Based on . /// + [Obsolete] internal class JsonObjectSerializer : IObjectSerializer { public T Deserialize(object value) diff --git a/UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer.cs b/UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer.cs index 3598d2deb24..9bdb208f08f 100644 --- a/UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer.cs +++ b/UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer.cs @@ -12,6 +12,7 @@ namespace UnitTests.Helpers /// Example class of writing a new that uses System.Text.Json. /// Based on . /// + [Obsolete] internal class SystemTextJsonSerializer : IObjectSerializer { public T Deserialize(object value) => JsonSerializer.Deserialize(value as string); diff --git a/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs b/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs index a70abd9b53f..c7d66e3dda5 100644 --- a/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs +++ b/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs @@ -14,8 +14,11 @@ namespace UnitTests.Helpers [TestClass] public class Test_StorageHelper { + [Obsolete] private readonly LocalObjectStorageHelper _localStorageHelperSystem = new LocalObjectStorageHelper(new SystemSerializer()); + [Obsolete] private readonly LocalObjectStorageHelper _localStorageHelperJsonCompat = new LocalObjectStorageHelper(new JsonObjectSerializer()); + [Obsolete] private readonly LocalObjectStorageHelper _localStorageHelperJsonNew = new LocalObjectStorageHelper(new SystemTextJsonSerializer()); /// @@ -33,6 +36,7 @@ public void Test_StorageHelper_CheckNewtonsoftVersion() [TestCategory("Helpers")] [TestMethod] + [Obsolete] public void Test_StorageHelper_LegacyIntTest() { string key = "LifeUniverseAndEverything"; @@ -53,6 +57,7 @@ public void Test_StorageHelper_LegacyIntTest() /// [TestCategory("Helpers")] [TestMethod] + [Obsolete] [ExpectedException(typeof(NotSupportedException))] public void Test_StorageHelper_LegacyDateTestFailure() { @@ -72,6 +77,7 @@ public void Test_StorageHelper_LegacyDateTestFailure() /// [TestCategory("Helpers")] [TestMethod] + [Obsolete] public void Test_StorageHelper_DateTestFailure() { Exception expectedException = null; @@ -92,6 +98,7 @@ public void Test_StorageHelper_DateTestFailure() [TestCategory("Helpers")] [TestMethod] + [Obsolete] public void Test_StorageHelper_LegacyInternalClassTest() { string key = "Contact"; @@ -111,6 +118,7 @@ public void Test_StorageHelper_LegacyInternalClassTest() [TestCategory("Helpers")] [TestMethod] + [Obsolete] public void Test_StorageHelper_LegacyPublicClassTest() { string key = "Contact"; @@ -131,6 +139,7 @@ public void Test_StorageHelper_LegacyPublicClassTest() [TestCategory("Helpers")] [TestMethod] + [Obsolete] public void Test_StorageHelper_IntTest() { string key = "NewLifeUniverseAndEverything"; @@ -147,6 +156,7 @@ public void Test_StorageHelper_IntTest() [TestCategory("Helpers")] [TestMethod] + [Obsolete] public void Test_StorageHelper_NewDateTest() { string key = "NewChristmasDay"; @@ -163,6 +173,7 @@ public void Test_StorageHelper_NewDateTest() [TestCategory("Helpers")] [TestMethod] + [Obsolete] public void Test_StorageHelper_NewPersonTest() { string key = "Contact"; From 331f7ddc3d617b6c3b960167c779a125df7a187e Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Tue, 27 Jul 2021 10:18:31 -0700 Subject: [PATCH 31/35] Comment cref updates in test app --- UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs | 2 +- UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer.cs | 2 +- .../UnitTests.UWP/Helpers/Test_ApplicationDataStorageHelper.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs b/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs index 27b775155ef..0cfcb64d0ec 100644 --- a/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs +++ b/UnitTests/UnitTests.UWP/Helpers/JsonObjectSerializer.cs @@ -11,7 +11,7 @@ namespace UnitTests.Helpers { /// /// This is a Serializer which should mimic the previous functionality of 6.1.1 release of the Toolkit with Newtonsoft.Json. - /// Based on . + /// Based on . /// [Obsolete] internal class JsonObjectSerializer : IObjectSerializer diff --git a/UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer.cs b/UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer.cs index 9bdb208f08f..b4b47f73f78 100644 --- a/UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer.cs +++ b/UnitTests/UnitTests.UWP/Helpers/SystemTextJsonSerializer.cs @@ -10,7 +10,7 @@ namespace UnitTests.Helpers { /// /// Example class of writing a new that uses System.Text.Json. - /// Based on . + /// Based on . /// [Obsolete] internal class SystemTextJsonSerializer : IObjectSerializer diff --git a/UnitTests/UnitTests.UWP/Helpers/Test_ApplicationDataStorageHelper.cs b/UnitTests/UnitTests.UWP/Helpers/Test_ApplicationDataStorageHelper.cs index 94d44b77093..3181736f824 100644 --- a/UnitTests/UnitTests.UWP/Helpers/Test_ApplicationDataStorageHelper.cs +++ b/UnitTests/UnitTests.UWP/Helpers/Test_ApplicationDataStorageHelper.cs @@ -69,7 +69,7 @@ public void Test_StorageHelper_LegacyDateTestFailure() /// /// The doesn't support complex types, since it just passes through directly. - /// We'll get the argument exception from the API. + /// We'll get the argument exception from the API. /// [TestCategory("Helpers")] [TestMethod] From 11d1a5e6ca29dbfc85786c0cc3d7c7ce5c8bafb2 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Tue, 27 Jul 2021 17:34:38 -0700 Subject: [PATCH 32/35] PR updates --- ...pplicationDataStorageHelper.CacheFolder.cs | 2 +- .../ApplicationDataStorageHelper.cs | 67 +++++++++++-------- .../ISettingsStorageHelperExtensions.cs | 21 +++--- 3 files changed, 52 insertions(+), 38 deletions(-) diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.CacheFolder.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.CacheFolder.cs index ee94dd5bf61..78a73a566a9 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.CacheFolder.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.CacheFolder.cs @@ -37,7 +37,7 @@ public Task ReadCacheFileAsync(string filePath, T @default = default) /// /// The path to the target folder. /// A list of file types and names in the target folder. - public Task> ReadCacheFolderAsync(string folderPath) + public Task> ReadCacheFolderAsync(string folderPath) { return ReadFolderAsync(CacheFolder, folderPath); } diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs index 7231254604b..0b16553e91b 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs @@ -22,7 +22,7 @@ public partial class ApplicationDataStorageHelper : IFileStorageHelper, ISetting /// /// Serializer for converting stored values. Defaults to . /// A new instance of ApplicationDataStorageHelper. - public static ApplicationDataStorageHelper GetCurrent(Toolkit.Helpers.IObjectSerializer objectSerializer = null) + public static ApplicationDataStorageHelper GetCurrent(Toolkit.Helpers.IObjectSerializer? objectSerializer = null) { var appData = ApplicationData.Current; return new ApplicationDataStorageHelper(appData, objectSerializer); @@ -34,7 +34,7 @@ public static ApplicationDataStorageHelper GetCurrent(Toolkit.Helpers.IObjectSer /// App data user owner. /// Serializer for converting stored values. Defaults to . /// A new instance of ApplicationDataStorageHelper. - public static async Task GetForUserAsync(User user, Toolkit.Helpers.IObjectSerializer objectSerializer = null) + public static async Task GetForUserAsync(User user, Toolkit.Helpers.IObjectSerializer? objectSerializer = null) { var appData = await ApplicationData.GetForUserAsync(user); return new ApplicationDataStorageHelper(appData, objectSerializer); @@ -65,7 +65,7 @@ public static async Task GetForUserAsync(User user /// /// The data store to interact with. /// Serializer for converting stored values. Defaults to . - public ApplicationDataStorageHelper(ApplicationData appData, Toolkit.Helpers.IObjectSerializer objectSerializer = null) + public ApplicationDataStorageHelper(ApplicationData appData, Toolkit.Helpers.IObjectSerializer? objectSerializer = null) { AppData = appData ?? throw new ArgumentNullException(nameof(appData)); Serializer = objectSerializer ?? new Toolkit.Helpers.SystemSerializer(); @@ -137,15 +137,35 @@ public void Clear() /// True if a value exists. public bool KeyExists(string compositeKey, string key) { - if (KeyExists(compositeKey)) + if (TryRead(compositeKey, out ApplicationDataCompositeValue composite)) { - ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)Settings.Values[compositeKey]; - if (composite != null) + return composite.ContainsKey(key); + } + + return false; + } + + /// + /// Attempts to retrieve a single item by its key in composite. + /// + /// Type of object retrieved. + /// Key of the composite (that contains settings). + /// Key of the object. + /// The value of the object retrieved. + /// The T object. + public bool TryRead(string compositeKey, string key, out T value) + { + if (TryRead(compositeKey, out ApplicationDataCompositeValue composite)) + { + string compositeValue = (string)composite[key]; + if (compositeValue != null) { - return composite.ContainsKey(key); + value = Serializer.Deserialize(compositeValue); + return true; } } + value = default; return false; } @@ -159,11 +179,9 @@ public bool KeyExists(string compositeKey, string key) /// The T object. public T Read(string compositeKey, string key, T @default = default) { - ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)Settings.Values[compositeKey]; - if (composite != null) + if (TryRead(compositeKey, out ApplicationDataCompositeValue composite)) { - string value = (string)composite[key]; - if (value != null) + if (composite.TryGetValue(key, out object valueObj) && valueObj is string value) { return Serializer.Deserialize(value); } @@ -182,10 +200,8 @@ public T Read(string compositeKey, string key, T @default = default) /// Objects to save. public void Save(string compositeKey, IDictionary values) { - if (KeyExists(compositeKey)) + if (TryRead(compositeKey, out ApplicationDataCompositeValue composite)) { - ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)Settings.Values[compositeKey]; - foreach (KeyValuePair setting in values) { if (composite.ContainsKey(setting.Key)) @@ -200,7 +216,7 @@ public void Save(string compositeKey, IDictionary values) } else { - ApplicationDataCompositeValue composite = new ApplicationDataCompositeValue(); + composite = new ApplicationDataCompositeValue(); foreach (KeyValuePair setting in values) { composite.Add(setting.Key, Serializer.Serialize(setting.Value)); @@ -215,20 +231,15 @@ public void Save(string compositeKey, IDictionary values) /// /// Key of the composite (that contains settings). /// Key of the object. - /// Throws when the specified composite/settings key is not found. - public void Delete(string compositeKey, string key) + /// A boolean indicator of success. + public bool TryDelete(string compositeKey, string key) { - if (!KeyExists(compositeKey)) + if (TryRead(compositeKey, out ApplicationDataCompositeValue composite)) { - throw new KeyNotFoundException($"Composite key not found: {compositeKey}"); + return composite.Remove(key); } - ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)Settings.Values[compositeKey]; - - if (!composite.Remove(key)) - { - throw new KeyNotFoundException($"Settings key not found: {key}"); - } + return false; } /// @@ -238,7 +249,7 @@ public Task ReadFileAsync(string filePath, T @default = default) } /// - public Task> ReadFolderAsync(string folderPath) + public Task> ReadFolderAsync(string folderPath) { return ReadFolderAsync(Folder, folderPath); } @@ -290,8 +301,8 @@ private async Task ReadFileAsync(StorageFolder folder, string filePath, T : item.IsOfType(StorageItemTypes.Folder) ? DirectoryItemType.Folder : DirectoryItemType.None; - return new ValueTuple(itemType, item.Name); - }).ToList(); + return (itemType, item.Name); + }); } private Task SaveFileAsync(StorageFolder folder, string filePath, T value) diff --git a/Microsoft.Toolkit/Extensions/ISettingsStorageHelperExtensions.cs b/Microsoft.Toolkit/Extensions/ISettingsStorageHelperExtensions.cs index b8b11a7b9db..b5e56ce1aba 100644 --- a/Microsoft.Toolkit/Extensions/ISettingsStorageHelperExtensions.cs +++ b/Microsoft.Toolkit/Extensions/ISettingsStorageHelperExtensions.cs @@ -22,21 +22,18 @@ public static class ISettingsStorageHelperExtensions /// The type of object value expected. /// The storage helper instance fo read from. /// The key of the target object. - /// The value of the target object, or the fallback value. /// An alternative value returned if the read fails. - /// A boolean indicator of success. - public static bool TryGetValueOrDefault(this ISettingsStorageHelper storageHelper, TKey key, out TValue? value, TValue? fallback = default) + /// The value of the target object, or the fallback value. + public static TValue GetValueOrDefault(this ISettingsStorageHelper storageHelper, TKey key, TValue? fallback = default) where TKey : notnull { if (storageHelper.TryRead(key, out TValue? storedValue)) { - value = storedValue; - return true; + return storedValue; } else { - value = fallback; - return false; + return fallback; } } @@ -58,7 +55,8 @@ public static bool TryGetValueOrDefault(this ISettingsStorageHelpe } else { - throw new KeyNotFoundException(); + ThrowKeyNotFoundException(key); + return default; } } @@ -74,8 +72,13 @@ public static void Delete(this ISettingsStorageHelper storageHelper, { if (!storageHelper.TryDelete(key)) { - throw new KeyNotFoundException(); + ThrowKeyNotFoundException(key); } } + + private static void ThrowKeyNotFoundException(TKey key) + { + throw new KeyNotFoundException($"The given key '{key}' was not present"); + } } } From b551d431036fd3920312e7d6227565dba616bdd5 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Wed, 28 Jul 2021 10:55:26 -0700 Subject: [PATCH 33/35] Update Microsoft.Toolkit/Extensions/ISettingsStorageHelperExtensions.cs Co-authored-by: Sergio Pedri --- .../Extensions/ISettingsStorageHelperExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Microsoft.Toolkit/Extensions/ISettingsStorageHelperExtensions.cs b/Microsoft.Toolkit/Extensions/ISettingsStorageHelperExtensions.cs index b5e56ce1aba..765408d92ff 100644 --- a/Microsoft.Toolkit/Extensions/ISettingsStorageHelperExtensions.cs +++ b/Microsoft.Toolkit/Extensions/ISettingsStorageHelperExtensions.cs @@ -24,7 +24,7 @@ public static class ISettingsStorageHelperExtensions /// The key of the target object. /// An alternative value returned if the read fails. /// The value of the target object, or the fallback value. - public static TValue GetValueOrDefault(this ISettingsStorageHelper storageHelper, TKey key, TValue? fallback = default) + public static TValue? GetValueOrDefault(this ISettingsStorageHelper storageHelper, TKey key, TValue? fallback = default) where TKey : notnull { if (storageHelper.TryRead(key, out TValue? storedValue)) From 76aa847b31d85f32926fa44abc3a905741450719 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Thu, 29 Jul 2021 10:18:26 -0700 Subject: [PATCH 34/35] Update Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs Co-authored-by: Sergio Pedri --- .../Helpers/ObjectStorage/ApplicationDataStorageHelper.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs index 0b16553e91b..ed487ec2cae 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs @@ -10,6 +10,8 @@ using Windows.Storage; using Windows.System; +#nullable enable + namespace Microsoft.Toolkit.Uwp.Helpers { /// From b0a33c559b498fb595cf2c742d64d1ceacd7550c Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Thu, 29 Jul 2021 11:10:17 -0700 Subject: [PATCH 35/35] Fixed warnings in ObjectStorage classes --- .../ApplicationDataStorageHelper.cs | 118 +++++++++--------- .../ObjectStorage/IObjectStorageHelper.cs | 66 +++++----- .../ObjectStorage/LocalObjectStorageHelper.cs | 6 +- 3 files changed, 95 insertions(+), 95 deletions(-) diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs index ed487ec2cae..2cf1c568f54 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs @@ -20,37 +20,25 @@ namespace Microsoft.Toolkit.Uwp.Helpers public partial class ApplicationDataStorageHelper : IFileStorageHelper, ISettingsStorageHelper { /// - /// Get a new instance using ApplicationData.Current and the provided serializer. - /// - /// Serializer for converting stored values. Defaults to . - /// A new instance of ApplicationDataStorageHelper. - public static ApplicationDataStorageHelper GetCurrent(Toolkit.Helpers.IObjectSerializer? objectSerializer = null) - { - var appData = ApplicationData.Current; - return new ApplicationDataStorageHelper(appData, objectSerializer); - } - - /// - /// Get a new instance using the ApplicationData for the provided user and serializer. + /// Initializes a new instance of the class. /// - /// App data user owner. + /// The data store to interact with. /// Serializer for converting stored values. Defaults to . - /// A new instance of ApplicationDataStorageHelper. - public static async Task GetForUserAsync(User user, Toolkit.Helpers.IObjectSerializer? objectSerializer = null) + public ApplicationDataStorageHelper(ApplicationData appData, Toolkit.Helpers.IObjectSerializer? objectSerializer = null) { - var appData = await ApplicationData.GetForUserAsync(user); - return new ApplicationDataStorageHelper(appData, objectSerializer); + this.AppData = appData ?? throw new ArgumentNullException(nameof(appData)); + this.Serializer = objectSerializer ?? new Toolkit.Helpers.SystemSerializer(); } /// /// Gets the settings container. /// - public ApplicationDataContainer Settings => AppData.LocalSettings; + public ApplicationDataContainer Settings => this.AppData.LocalSettings; /// /// Gets the storage folder. /// - public StorageFolder Folder => AppData.LocalFolder; + public StorageFolder Folder => this.AppData.LocalFolder; /// /// Gets the storage host. @@ -63,14 +51,26 @@ public static async Task GetForUserAsync(User user protected Toolkit.Helpers.IObjectSerializer Serializer { get; } /// - /// Initializes a new instance of the class. + /// Get a new instance using ApplicationData.Current and the provided serializer. /// - /// The data store to interact with. /// Serializer for converting stored values. Defaults to . - public ApplicationDataStorageHelper(ApplicationData appData, Toolkit.Helpers.IObjectSerializer? objectSerializer = null) + /// A new instance of ApplicationDataStorageHelper. + public static ApplicationDataStorageHelper GetCurrent(Toolkit.Helpers.IObjectSerializer? objectSerializer = null) + { + var appData = ApplicationData.Current; + return new ApplicationDataStorageHelper(appData, objectSerializer); + } + + /// + /// Get a new instance using the ApplicationData for the provided user and serializer. + /// + /// App data user owner. + /// Serializer for converting stored values. Defaults to . + /// A new instance of ApplicationDataStorageHelper. + public static async Task GetForUserAsync(User user, Toolkit.Helpers.IObjectSerializer? objectSerializer = null) { - AppData = appData ?? throw new ArgumentNullException(nameof(appData)); - Serializer = objectSerializer ?? new Toolkit.Helpers.SystemSerializer(); + var appData = await ApplicationData.GetForUserAsync(user); + return new ApplicationDataStorageHelper(appData, objectSerializer); } /// @@ -80,7 +80,7 @@ public ApplicationDataStorageHelper(ApplicationData appData, Toolkit.Helpers.IOb /// True if a value exists. public bool KeyExists(string key) { - return Settings.Values.ContainsKey(key); + return this.Settings.Values.ContainsKey(key); } /// @@ -89,23 +89,23 @@ public bool KeyExists(string key) /// Type of object retrieved. /// Key of the object. /// Default value of the object. - /// The TValue object - public T Read(string key, T @default = default) + /// The TValue object. + public T? Read(string key, T? @default = default) { - if (!Settings.Values.TryGetValue(key, out var valueObj) || valueObj == null) + if (this.Settings.Values.TryGetValue(key, out var valueObj) && valueObj is string valueString) { - return @default; + return this.Serializer.Deserialize(valueString); } - return Serializer.Deserialize(valueObj as string); + return @default; } /// - public bool TryRead(string key, out T value) + public bool TryRead(string key, out T? value) { - if (Settings.Values.TryGetValue(key, out var valueObj) && valueObj != null) + if (this.Settings.Values.TryGetValue(key, out var valueObj) && valueObj is string valueString) { - value = Serializer.Deserialize(valueObj as string); + value = this.Serializer.Deserialize(valueString); return true; } @@ -116,19 +116,19 @@ public bool TryRead(string key, out T value) /// public void Save(string key, T value) { - Settings.Values[key] = Serializer.Serialize(value); + this.Settings.Values[key] = this.Serializer.Serialize(value); } /// public bool TryDelete(string key) { - return Settings.Values.Remove(key); + return this.Settings.Values.Remove(key); } /// public void Clear() { - Settings.Values.Clear(); + this.Settings.Values.Clear(); } /// @@ -139,7 +139,7 @@ public void Clear() /// True if a value exists. public bool KeyExists(string compositeKey, string key) { - if (TryRead(compositeKey, out ApplicationDataCompositeValue composite)) + if (this.TryRead(compositeKey, out ApplicationDataCompositeValue? composite) && composite != null) { return composite.ContainsKey(key); } @@ -155,14 +155,14 @@ public bool KeyExists(string compositeKey, string key) /// Key of the object. /// The value of the object retrieved. /// The T object. - public bool TryRead(string compositeKey, string key, out T value) + public bool TryRead(string compositeKey, string key, out T? value) { - if (TryRead(compositeKey, out ApplicationDataCompositeValue composite)) + if (this.TryRead(compositeKey, out ApplicationDataCompositeValue? composite) && composite != null) { string compositeValue = (string)composite[key]; if (compositeValue != null) { - value = Serializer.Deserialize(compositeValue); + value = this.Serializer.Deserialize(compositeValue); return true; } } @@ -179,13 +179,13 @@ public bool TryRead(string compositeKey, string key, out T value) /// Key of the object. /// Default value of the object. /// The T object. - public T Read(string compositeKey, string key, T @default = default) + public T? Read(string compositeKey, string key, T? @default = default) { - if (TryRead(compositeKey, out ApplicationDataCompositeValue composite)) + if (this.TryRead(compositeKey, out ApplicationDataCompositeValue? composite) && composite != null) { if (composite.TryGetValue(key, out object valueObj) && valueObj is string value) { - return Serializer.Deserialize(value); + return this.Serializer.Deserialize(value); } } @@ -202,17 +202,17 @@ public T Read(string compositeKey, string key, T @default = default) /// Objects to save. public void Save(string compositeKey, IDictionary values) { - if (TryRead(compositeKey, out ApplicationDataCompositeValue composite)) + if (this.TryRead(compositeKey, out ApplicationDataCompositeValue? composite) && composite != null) { foreach (KeyValuePair setting in values) { if (composite.ContainsKey(setting.Key)) { - composite[setting.Key] = Serializer.Serialize(setting.Value); + composite[setting.Key] = this.Serializer.Serialize(setting.Value); } else { - composite.Add(setting.Key, Serializer.Serialize(setting.Value)); + composite.Add(setting.Key, this.Serializer.Serialize(setting.Value)); } } } @@ -221,10 +221,10 @@ public void Save(string compositeKey, IDictionary values) composite = new ApplicationDataCompositeValue(); foreach (KeyValuePair setting in values) { - composite.Add(setting.Key, Serializer.Serialize(setting.Value)); + composite.Add(setting.Key, this.Serializer.Serialize(setting.Value)); } - Settings.Values[compositeKey] = composite; + this.Settings.Values[compositeKey] = composite; } } @@ -236,7 +236,7 @@ public void Save(string compositeKey, IDictionary values) /// A boolean indicator of success. public bool TryDelete(string compositeKey, string key) { - if (TryRead(compositeKey, out ApplicationDataCompositeValue composite)) + if (this.TryRead(compositeKey, out ApplicationDataCompositeValue? composite) && composite != null) { return composite.Remove(key); } @@ -245,33 +245,33 @@ public bool TryDelete(string compositeKey, string key) } /// - public Task ReadFileAsync(string filePath, T @default = default) + public Task ReadFileAsync(string filePath, T? @default = default) { - return ReadFileAsync(Folder, filePath, @default); + return this.ReadFileAsync(this.Folder, filePath, @default); } /// public Task> ReadFolderAsync(string folderPath) { - return ReadFolderAsync(Folder, folderPath); + return this.ReadFolderAsync(this.Folder, folderPath); } /// public Task CreateFileAsync(string filePath, T value) { - return SaveFileAsync(Folder, filePath, value); + return this.SaveFileAsync(this.Folder, filePath, value); } /// public Task CreateFolderAsync(string folderPath) { - return CreateFolderAsync(Folder, folderPath); + return this.CreateFolderAsync(this.Folder, folderPath); } /// public Task DeleteItemAsync(string itemPath) { - return DeleteItemAsync(Folder, itemPath); + return this.DeleteItemAsync(this.Folder, itemPath); } /// @@ -283,13 +283,13 @@ public Task DeleteItemAsync(string itemPath) /// Waiting task until completion. public Task SaveFileAsync(string filePath, T value) { - return SaveFileAsync(Folder, filePath, value); + return this.SaveFileAsync(this.Folder, filePath, value); } - private async Task ReadFileAsync(StorageFolder folder, string filePath, T @default = default) + private async Task ReadFileAsync(StorageFolder folder, string filePath, T? @default = default) { string value = await StorageFileHelper.ReadTextFromFileAsync(folder, filePath); - return (value != null) ? Serializer.Deserialize(value) : @default; + return (value != null) ? this.Serializer.Deserialize(value) : @default; } private async Task> ReadFolderAsync(StorageFolder folder, string folderPath) @@ -309,7 +309,7 @@ private async Task ReadFileAsync(StorageFolder folder, string filePath, T private Task SaveFileAsync(StorageFolder folder, string filePath, T value) { - return StorageFileHelper.WriteTextToFileAsync(folder, Serializer.Serialize(value)?.ToString(), filePath, CreationCollisionOption.ReplaceExisting); + return StorageFileHelper.WriteTextToFileAsync(folder, this.Serializer.Serialize(value)?.ToString(), filePath, CreationCollisionOption.ReplaceExisting); } private async Task CreateFolderAsync(StorageFolder folder, string folderPath) diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/IObjectStorageHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/IObjectStorageHelper.cs index e742fe18586..ecdb7e8bcc1 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/IObjectStorageHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/IObjectStorageHelper.cs @@ -18,43 +18,43 @@ public interface IObjectStorageHelper /// /// Determines whether a setting already exists. /// - /// Key of the setting (that contains object) - /// True if a value exists + /// Key of the setting (that contains object). + /// True if a value exists. bool KeyExists(string key); /// /// Determines whether a setting already exists in composite. /// - /// Key of the composite (that contains settings) - /// Key of the setting (that contains object) - /// True if a value exists + /// Key of the composite (that contains settings). + /// Key of the setting (that contains object). + /// True if a value exists. bool KeyExists(string compositeKey, string key); /// /// Retrieves a single item by its key. /// - /// Type of object retrieved - /// Key of the object - /// Default value of the object - /// The T object - T Read(string key, T @default = default(T)); + /// Type of object retrieved. + /// Key of the object. + /// Default value of the object. + /// The T object. + T Read(string key, T @default = default); /// /// Retrieves a single item by its key in composite. /// - /// Type of object retrieved - /// Key of the composite (that contains settings) - /// Key of the object - /// Default value of the object - /// The T object - T Read(string compositeKey, string key, T @default = default(T)); + /// Type of object retrieved. + /// Key of the composite (that contains settings). + /// Key of the object. + /// Default value of the object. + /// The T object. + T Read(string compositeKey, string key, T @default = default); /// /// Saves a single item by its key. /// - /// Type of object saved - /// Key of the value saved - /// Object to save + /// Type of object saved. + /// Key of the value saved. + /// Object to save. void Save(string key, T value); /// @@ -63,34 +63,34 @@ public interface IObjectStorageHelper /// (refers to for complex/large objects) and for groups of settings which /// need to be treated in an atomic way. /// - /// Type of object saved - /// Key of the composite (that contains settings) - /// Objects to save + /// Type of object saved. + /// Key of the composite (that contains settings). + /// Objects to save. void Save(string compositeKey, IDictionary values); /// /// Determines whether a file already exists. /// - /// Key of the file (that contains object) - /// True if a value exists + /// Key of the file (that contains object). + /// True if a value exists. Task FileExistsAsync(string filePath); /// /// Retrieves an object from a file. /// - /// Type of object retrieved - /// Path to the file that contains the object - /// Default value of the object - /// Waiting task until completion with the object in the file - Task ReadFileAsync(string filePath, T @default = default(T)); + /// Type of object retrieved. + /// Path to the file that contains the object. + /// Default value of the object. + /// Waiting task until completion with the object in the file. + Task ReadFileAsync(string filePath, T @default = default); /// /// Saves an object inside a file. /// - /// Type of object saved - /// Path to the file that will contain the object - /// Object to save - /// Waiting task until completion + /// Type of object saved. + /// Path to the file that will contain the object. + /// Object to save. + /// Waiting task until completion. Task SaveFileAsync(string filePath, T value); } } \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/LocalObjectStorageHelper.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/LocalObjectStorageHelper.cs index 45905f73051..30df84933e3 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/LocalObjectStorageHelper.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/LocalObjectStorageHelper.cs @@ -17,14 +17,14 @@ public class LocalObjectStorageHelper : BaseObjectStorageHelper /// Initializes a new instance of the class, /// which can read and write data using the provided ; /// In 6.1 and older the default Serializer was based on Newtonsoft.Json. - /// To implement an based on System.Text.Json, Newtonsoft.Json, or DataContractJsonSerializer see https://aka.ms/wct/storagehelper-migration + /// To implement an based on System.Text.Json, Newtonsoft.Json, or DataContractJsonSerializer see https://aka.ms/wct/storagehelper-migration. /// /// The serializer to use. public LocalObjectStorageHelper(IObjectSerializer objectSerializer) : base(objectSerializer) { - Settings = ApplicationData.Current.LocalSettings; - Folder = ApplicationData.Current.LocalFolder; + this.Settings = ApplicationData.Current.LocalSettings; + this.Folder = ApplicationData.Current.LocalFolder; } } } \ No newline at end of file