-
Notifications
You must be signed in to change notification settings - Fork 37
RoamingSettingsHelper with initial support for UserExtensionsDataStore #77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 25 commits
8f63e24
a425f1c
838bff7
5e2d469
d290ffe
728a30f
c60d10c
51a3c03
2224716
9f3829c
36158cb
482fc69
e885706
a44ef0d
431716d
d61ffa5
2713dd3
421b65c
d1194eb
092b779
c6eb117
e041661
d1b4436
1a35447
538c6af
d00e965
4b9a5f3
b1d1b01
17e46d4
43be9f1
da57b77
a5d6737
b2d16bd
8dea981
36a21b5
3bd8b5c
4da9e28
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| // 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.Uwp.Helpers; | ||
|
|
||
| namespace CommunityToolkit.Uwp.Graph.Common | ||
| { | ||
| internal class JsonObjectSerializer : IObjectSerializer | ||
| { | ||
| public string Serialize<T>(T value) => JsonSerializer.Serialize(value); | ||
|
|
||
| public T Deserialize<T>(string value) => JsonSerializer.Deserialize<T>(value); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| // 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; | ||
| using Microsoft.Toolkit.Uwp.Helpers; | ||
|
|
||
| namespace CommunityToolkit.Uwp.Graph.Helpers.RoamingSettings | ||
| { | ||
| /// <summary> | ||
| /// Defines the contract for creating storage containers used for roaming data. | ||
| /// </summary> | ||
| public interface IRoamingSettingsDataStore : IObjectStorageHelper | ||
| { | ||
| /// <summary> | ||
| /// Gets access to the key/value pairs cache directly. | ||
| /// </summary> | ||
| IDictionary<string, object> Settings { get; } | ||
|
|
||
| /// <summary> | ||
| /// Create a new storage container. | ||
| /// </summary> | ||
| /// <returns>A Task.</returns> | ||
| Task Create(); | ||
|
|
||
| /// <summary> | ||
| /// Delete the existing storage container. | ||
| /// </summary> | ||
| /// <returns>A Task.</returns> | ||
| Task Delete(); | ||
|
|
||
| /// <summary> | ||
| /// Syncronize the internal cache with the remote storage endpoint. | ||
| /// </summary> | ||
| /// <returns>A Task.</returns> | ||
| Task Sync(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,161 @@ | ||
| // 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; | ||
| using CommunityToolkit.Net.Authentication; | ||
| using CommunityToolkit.Net.Graph.Extensions; | ||
| using CommunityToolkit.Uwp.Graph.Common; | ||
| using Microsoft.Toolkit.Uwp.Helpers; | ||
| using Windows.Storage; | ||
|
|
||
| namespace CommunityToolkit.Uwp.Graph.Helpers.RoamingSettings | ||
| { | ||
| /// <summary> | ||
| /// An enumeration of the available data storage methods for roaming data. | ||
| /// </summary> | ||
| public enum RoamingDataStore | ||
| { | ||
| /// <summary> | ||
| /// Store data using open extensions on the Graph User. | ||
| /// </summary> | ||
| UserExtensions, | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// A helper class for syncing data to roaming data store. | ||
| /// </summary> | ||
| public class RoamingSettingsHelper : IRoamingSettingsDataStore | ||
| { | ||
| /// <summary> | ||
| /// Gets the internal data storage helper instance. | ||
| /// </summary> | ||
| public IRoamingSettingsDataStore DataStore { get; private set; } | ||
|
|
||
| /// <inheritdoc /> | ||
| public IDictionary<string, object> Settings => DataStore?.Settings; | ||
|
|
||
| /// <summary> | ||
| /// Creates a new RoamingSettingsHelper instance for the currently signed in user. | ||
| /// </summary> | ||
| /// <param name="dataStore">Which specific data store is being used.</param> | ||
| /// <param name="autoSync">Whether the values should immediately sync or not.</param> | ||
| /// <param name="serializer">An object serializer for serialization of objects in the data store.</param> | ||
| /// <returns>A new instance of the RoamingSettingsHelper configured for the current user.</returns> | ||
| public static async Task<RoamingSettingsHelper> CreateForCurrentUser(RoamingDataStore dataStore = RoamingDataStore.UserExtensions, bool autoSync = true, IObjectSerializer serializer = null) | ||
| { | ||
| var provider = ProviderManager.Instance.GlobalProvider; | ||
| if (provider == null || provider.State != ProviderState.SignedIn) | ||
| { | ||
| throw new InvalidOperationException("The GlobalProvider must be set and signed in to create a new RoamingSettingsHelper for the current user."); | ||
| } | ||
|
|
||
| var me = await provider.Graph().Me.Request().GetAsync(); | ||
| return new RoamingSettingsHelper(me.Id, dataStore, autoSync, serializer); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Initializes a new instance of the <see cref="RoamingSettingsHelper"/> class. | ||
| /// </summary> | ||
| /// <param name="userId">The id of the target Graph User.</param> | ||
| /// <param name="dataStore">Which specific data store is being used.</param> | ||
| /// <param name="autoSync">Whether the values should immediately sync or not.</param> | ||
| /// <param name="serializer">An object serializer for serialization of objects in the data store.</param> | ||
| public RoamingSettingsHelper(string userId, RoamingDataStore dataStore = RoamingDataStore.UserExtensions, bool autoSync = true, IObjectSerializer serializer = null) | ||
| { | ||
| // TODO: Infuse unique identifier from Graph registration into the storage name. | ||
| string dataStoreName = "communityToolkit.roamingSettings"; | ||
|
|
||
| if (serializer == null) | ||
| { | ||
| serializer = new JsonObjectSerializer(); | ||
| } | ||
|
|
||
| switch (dataStore) | ||
| { | ||
| case RoamingDataStore.UserExtensions: | ||
| DataStore = new UserExtensionDataStore(dataStoreName, userId, serializer); | ||
| break; | ||
|
|
||
| default: | ||
| throw new ArgumentOutOfRangeException(nameof(dataStore)); | ||
| } | ||
|
|
||
| if (autoSync) | ||
| { | ||
| try | ||
| { | ||
| DataStore.Sync(); | ||
| } | ||
| catch | ||
| { | ||
| // Sync may fail if the storage container does not yet exist. | ||
|
shweaver-MSFT marked this conversation as resolved.
Outdated
|
||
| } | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// An indexer for easily accessing key values. | ||
| /// </summary> | ||
| /// <param name="key">The key for the desired value.</param> | ||
| /// <returns>The value found for the provided key.</returns> | ||
| public object this[string key] | ||
| { | ||
| get => DataStore.Read<object>(key); | ||
| set | ||
| { | ||
| if (DataStore.KeyExists(key)) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if it doesn't exist, shouldn't it create the key?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ya, good point. I think it should.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree - will you do that in this PR?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done :) |
||
| { | ||
| DataStore.Save(key, value); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| public Task<bool> FileExistsAsync(string filePath) => DataStore.FileExistsAsync(filePath); | ||
|
|
||
| /// <inheritdoc /> | ||
| public bool KeyExists(string key) => DataStore.KeyExists(key); | ||
|
|
||
| /// <inheritdoc /> | ||
| public bool KeyExists(string compositeKey, string key) => DataStore.KeyExists(compositeKey, key); | ||
|
|
||
| /// <inheritdoc /> | ||
| public T Read<T>(string key, T @default = default) => DataStore.Read<T>(key, @default); | ||
|
|
||
| /// <inheritdoc /> | ||
| public T Read<T>(string compositeKey, string key, T @default = default) => DataStore.Read(compositeKey, key, @default); | ||
|
|
||
| /// <inheritdoc /> | ||
| public Task<T> ReadFileAsync<T>(string filePath, T @default = default) => DataStore.ReadFileAsync(filePath, @default); | ||
|
|
||
| /// <inheritdoc /> | ||
| public void Save<T>(string key, T value) => DataStore.Save<T>(key, value); | ||
|
|
||
| /// <inheritdoc /> | ||
| public void Save<T>(string compositeKey, IDictionary<string, T> values) => DataStore.Save<T>(compositeKey, values); | ||
|
|
||
| /// <inheritdoc /> | ||
| public Task<StorageFile> SaveFileAsync<T>(string filePath, T value) => DataStore.SaveFileAsync<T>(filePath, value); | ||
|
|
||
| /// <summary> | ||
| /// Create a new storage container. | ||
| /// </summary> | ||
| /// <returns>A Task.</returns> | ||
| public Task Create() => DataStore.Create(); | ||
|
|
||
| /// <summary> | ||
| /// Delete the existing storage container. | ||
| /// </summary> | ||
| /// <returns>A Task.</returns> | ||
| public Task Delete() => DataStore.Delete(); | ||
|
|
||
| /// <summary> | ||
| /// Syncronize the internal cache with the remote storage endpoint. | ||
| /// </summary> | ||
| /// <returns>A Task.</returns> | ||
| public Task Sync() => DataStore.Sync(); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.