Updated Graph usage pattern in RoamingSettings helpers and updated descriptions to csproj files. (#139)

This commit is contained in:
Shane Weaver 2021-08-03 13:29:43 -07:00 коммит произвёл GitHub
Родитель 6fdcc7dbe2
Коммит 1daaf4ee3b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
13 изменённых файлов: 161 добавлений и 173 удалений

Просмотреть файл

@ -4,8 +4,10 @@
<Title>Windows Community Toolkit .NET Standard Auth Services</Title>
<Description>
This package includes .NET Standard authentication helpers such as:
- MsalProvider:
This library provides an authentication provider based on the native Windows dialogues. It is part of the Windows Community Toolkit.
Classes:
- MsalProvider: An authentication provider based on MSAL for .NET.
</Description>
<PackageTags>Community Toolkit Provider Authentication Auth Msal</PackageTags>
</PropertyGroup>
@ -18,7 +20,4 @@
<ProjectReference Include="..\CommunityToolkit.Authentication\CommunityToolkit.Authentication.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="Nerdbank.GitVersioning" Version="3.4.194" />
</ItemGroup>
</Project>

Просмотреть файл

@ -4,12 +4,12 @@
<TargetFramework>uap10.0.17134</TargetFramework>
<Title>Windows Community Toolkit Graph Uwp Authentication Provider</Title>
<Description>
This library provides an authentication provider based on the native Windows dialogues. It is part of the Windows Community Toolkit.
This library provides an authentication provider based on the native Windows dialogues.
Classes:
- WindowsProvider:
- WindowsProvider: An authentication provider based on the native AccountsSettingsPane in Windows.
</Description>
<PackageTags>UWP Toolkit Windows Microsoft Graph AadLogin Authentication Login</PackageTags>
<PackageTags>UWP Community Toolkit Provider Authentication Auth Windows</PackageTags>
<LangVersion>9.0</LangVersion>
</PropertyGroup>

Просмотреть файл

@ -5,12 +5,11 @@
<Title>Windows Community Toolkit .NET Standard Auth Services</Title>
<Description>
This package includes .NET Standard authentication helpers such as:
- BaseProvider:
- IProvider:
- MockProvider:
- ProviderManager:
- ProviderState:
- ProviderStateChangedEventArgs:
- BaseProvider: A base construct for building Graph Providers on top of.
- IProvider: Authentication provider interface to expose more states around the authentication process for Graph controls and helpers.
- ProviderManager: Shared provider manager used by controls and helpers to authenticate and call the Microsoft Graph.
- ProviderState: Represents the current authentication state of the session for a given IProvider.
</Description>
<PackageTags>Community Toolkit Provider Authentication Auth</PackageTags>
</PropertyGroup>

Просмотреть файл

@ -6,13 +6,19 @@
<Description>
This library provides Microsoft Graph UWP XAML controls. It is part of the Windows Community Toolkit.
Classes:
- GraphPresenter:
- LoginButton: The Login Control leverages MSAL libraries to support the sign-in processes for Microsoft Graph and beyond.
Controls:
- GraphPresenter: A specialized ContentPresenter for fetching and displaying data from Microsoft Graph.
- LoginButton: The Login Control leverages the global authentication provider to support the sign-in processes for Microsoft Graph and beyond.
- PersonView: The PersonView control displays a user photo and can display their name and e-mail.
- PeoplePicker: The PeoplePicker Control is a simple control that allows for selection of one or more users.
- PeoplePicker: The PeoplePicker Control is a simple control that allows for selection users.
Extensions:
- FrameworkElement.IsVisibleWhen(ProviderState): Extension on FrameworkElement for toggling visibility in response to changes in the global authentcation provider.
Triggers:
- ProviderStateTrigger: StateTrigger for reacting to changes in the global authentcation provider.
</Description>
<PackageTags>UWP Toolkit Windows Controls MSAL Microsoft Graph AadLogin ProfileCard Person PeoplePicker Login</PackageTags>
<PackageTags>UWP Community Toolkit Windows Controls Microsoft Graph Login Person PeoplePicker Presenter</PackageTags>
<LangVersion>9.0</LangVersion>
</PropertyGroup>
@ -22,8 +28,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
<PackageReference Include="Microsoft.Graph" Version="4.0.0" />
<PackageReference Include="Microsoft.Toolkit.Uwp.UI" Version="7.0.1" />
<PackageReference Include="Microsoft.Toolkit.Uwp.UI.Controls.Input" Version="7.0.1" />
</ItemGroup>
@ -35,14 +41,6 @@
<None Include="VisualStudioToolsManifest.xml" Pack="true" PackagePath="tools" />
<None Include="$(OutDir)\Design\$(MSBuildProjectName).Design*.dll;$(OutDir)\Design\$(MSBuildProjectName).Design*.pdb" Pack="true" PackagePath="lib\$(TargetFramework)\Design" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
</ItemGroup>
<ItemGroup>
<Folder Include="Triggers\" />
</ItemGroup>
<!-- https://weblogs.asp.net/rweigelt/disable-warnings-in-generated-c-files-of-uwp-app -->
<Target Name="PragmaWarningDisablePrefixer" AfterTargets="MarkupCompilePass2">

Просмотреть файл

@ -74,11 +74,11 @@ namespace CommunityToolkit.Graph.Uwp.Controls
// Note: some interfaces from the Graph SDK don't implement IBaseRequestBuilder properly, see https://github.com/microsoftgraph/msgraph-sdk-dotnet/issues/722
if (RequestBuilder != null)
{
var request = new BaseRequest(
RequestBuilder.RequestUrl,
RequestBuilder.Client); // TODO: Do we need separate Options here?
request.Method = HttpMethods.GET;
request.QueryOptions = QueryOptions?.Select(option => (Microsoft.Graph.QueryOption)option)?.ToList() ?? new List<Microsoft.Graph.QueryOption>();
var request = new BaseRequest(RequestBuilder.RequestUrl, RequestBuilder.Client) // TODO: Do we need separate Options here?
{
Method = HttpMethods.GET,
QueryOptions = QueryOptions?.Select(option => (Microsoft.Graph.QueryOption)option)?.ToList() ?? new List<Microsoft.Graph.QueryOption>(),
};
// Handle Special QueryOptions
if (!string.IsNullOrWhiteSpace(OrderBy))

Просмотреть файл

@ -22,7 +22,7 @@ namespace CommunityToolkit.Graph.Uwp.Controls
/// </summary>
public partial class PeoplePicker : TokenizingTextBox
{
private DispatcherQueueTimer _typeTimer = null;
private readonly DispatcherQueueTimer _typeTimer = null;
/// <summary>
/// Initializes a new instance of the <see cref="PeoplePicker"/> class.

Просмотреть файл

@ -5,11 +5,17 @@
<Title>Windows Community Toolkit .NET Standard Graph Services</Title>
<Description>
This package includes .NET Standard code helpers such as:
- GraphExtensions: Helpers for common tasks related to the Microsoft Graph used by the Microsoft.Toolkit.Graph.Controls.
- ProviderExtensions: Extension on IProvider for accessing a pre-configured GraphServiceClient instance.
This package includes .NET Standard code helpers such as:
Extensions:
- GraphExtensions: Helpers for common tasks related to the Microsoft Graph in context of the available controls and helpers.
- ProviderExtensions: Extension on IProvider for accessing a pre-configured GraphServiceClient instance.
Helpers:
- OneDriveStorageHelper: A helper for interacting with data stored via files and folders in OneDrive.
- UserExtensionStorageHelper: A helper for interacting with open extensions on the Graph User to store data in key/value pairs.
</Description>
<PackageTags>Windows Community Toolkit Graph Provider Extensions</PackageTags>
<PackageTags>Windows Community Toolkit Microsoft Graph Provider Extensions Helpers Roaming Settings</PackageTags>
<LangVersion>9.0</LangVersion>
</PropertyGroup>

Просмотреть файл

@ -7,31 +7,27 @@ using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using CommunityToolkit.Authentication;
using CommunityToolkit.Graph.Extensions;
using Microsoft.Graph;
using Microsoft.Toolkit.Helpers;
namespace CommunityToolkit.Graph.Helpers.RoamingSettings
namespace CommunityToolkit.Graph.Extensions
{
/// <summary>
/// Helpers for interacting with files in the special OneDrive AppRoot folder.
/// OneDrive focused extension methods to the Graph SDK used by the controls and helpers.
/// </summary>
internal static class OneDriveDataSource
public static partial class GraphExtensions
{
private static GraphServiceClient Graph => ProviderManager.Instance.GlobalProvider?.GetClient();
/// <summary>
/// Updates or create a new file on the remote with the provided content.
/// </summary>
/// <typeparam name="T">The type of object to save.</typeparam>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static async Task<DriveItem> SetFileAsync<T>(string userId, string itemPath, T fileContents, IObjectSerializer serializer)
public static async Task<DriveItem> SetFileAsync<T>(this GraphServiceClient graph, string userId, string itemPath, T fileContents, IObjectSerializer serializer)
{
var json = serializer.Serialize(fileContents) as string;
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json));
return await Graph.Users[userId].Drive.Special.AppRoot.ItemWithPath(itemPath).Content.Request().PutAsync<DriveItem>(stream);
return await graph.Users[userId].Drive.Special.AppRoot.ItemWithPath(itemPath).Content.Request().PutAsync<DriveItem>(stream);
}
/// <summary>
@ -39,9 +35,9 @@ namespace CommunityToolkit.Graph.Helpers.RoamingSettings
/// </summary>
/// <typeparam name="T">The type of object to return.</typeparam>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static async Task<T> GetFileAsync<T>(string userId, string itemPath, IObjectSerializer serializer)
public static async Task<T> GetFileAsync<T>(this GraphServiceClient graph, string userId, string itemPath, IObjectSerializer serializer)
{
Stream stream = await Graph.Users[userId].Drive.Special.AppRoot.ItemWithPath(itemPath).Content.Request().GetAsync();
Stream stream = await graph.Users[userId].Drive.Special.AppRoot.ItemWithPath(itemPath).Content.Request().GetAsync();
string streamContents = new StreamReader(stream).ReadToEnd();
@ -52,12 +48,20 @@ namespace CommunityToolkit.Graph.Helpers.RoamingSettings
/// Delete the file from the remote.
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static async Task DeleteItemAsync(string userId, string itemPath)
public static async Task DeleteItemAsync(this GraphServiceClient graph, string userId, string itemPath)
{
await Graph.Users[userId].Drive.Special.AppRoot.ItemWithPath(itemPath).Request().DeleteAsync();
await graph.Users[userId].Drive.Special.AppRoot.ItemWithPath(itemPath).Request().DeleteAsync();
}
public static async Task CreateFolderAsync(string userId, string folderName, string path = null)
/// <summary>
/// Ensure a folder exists by name.
/// </summary>
/// <param name="graph">Instance of the <see cref="GraphServiceClient"/>.</param>
/// <param name="userId">The id of the target Graph user.</param>
/// <param name="folderName">The name of the new folder.</param>
/// <param name="path">The path to create the new folder in.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static async Task CreateFolderAsync(this GraphServiceClient graph, string userId, string folderName, string path = null)
{
var folderDriveItem = new DriveItem()
{
@ -67,17 +71,24 @@ namespace CommunityToolkit.Graph.Helpers.RoamingSettings
if (path != null)
{
await Graph.Users[userId].Drive.Special.AppRoot.ItemWithPath(path).Children.Request().AddAsync(folderDriveItem);
await graph.Users[userId].Drive.Special.AppRoot.ItemWithPath(path).Children.Request().AddAsync(folderDriveItem);
}
else
{
await Graph.Users[userId].Drive.Special.AppRoot.Children.Request().AddAsync(folderDriveItem);
await graph.Users[userId].Drive.Special.AppRoot.Children.Request().AddAsync(folderDriveItem);
}
}
public static async Task<IEnumerable<(DirectoryItemType, string)>> ReadFolderAsync(string userId, string folderPath)
/// <summary>
/// Retrieve a list of directory items with names and types.
/// </summary>
/// <param name="graph">Instance of the <see cref="GraphServiceClient"/>.</param>
/// <param name="userId">The id of the target Graph user.</param>
/// <param name="folderPath">The path to create the new folder in.</param>
/// <returns>A <see cref="Task"/> with the directory listings.</returns>
public static async Task<IEnumerable<(DirectoryItemType, string)>> ReadFolderAsync(this GraphServiceClient graph, string userId, string folderPath)
{
IDriveItemChildrenCollectionPage folderContents = await Graph.Users[userId].Drive.Special.AppRoot.ItemWithPath(folderPath).Children.Request().GetAsync();
IDriveItemChildrenCollectionPage folderContents = await graph.Users[userId].Drive.Special.AppRoot.ItemWithPath(folderPath).Children.Request().GetAsync();
var results = new List<(DirectoryItemType, string)>();
foreach (var item in folderContents)

Просмотреть файл

@ -4,28 +4,28 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using CommunityToolkit.Authentication;
using CommunityToolkit.Graph.Extensions;
using Microsoft.Graph;
using Microsoft.Toolkit.Helpers;
namespace CommunityToolkit.Graph.Helpers.RoamingSettings
namespace CommunityToolkit.Graph.Extensions
{
/// <summary>
/// Manages Graph interaction with open extensions on the user.
/// UserExtensions focused extension methods to the Graph SDK used by the controls and helpers.
/// </summary>
internal static class UserExtensionDataSource
public static partial class GraphExtensions
{
private static GraphServiceClient Graph => ProviderManager.Instance.GlobalProvider?.GetClient();
/// <summary>
/// Retrieve an extension object for a user.
/// </summary>
/// <param name="graph">Instance of the <see cref="GraphServiceClient"/>.</param>
/// <param name="userId">The user to access.</param>
/// <param name="extensionId">The extension to retrieve.</param>
/// <returns>The extension result.</returns>
public static async Task<Extension> GetExtension(string userId, string extensionId)
public static async Task<Extension> GetExtension(this GraphServiceClient graph, string userId, string extensionId)
{
if (string.IsNullOrWhiteSpace(extensionId))
{
@ -37,33 +37,35 @@ namespace CommunityToolkit.Graph.Helpers.RoamingSettings
throw new ArgumentNullException(nameof(userId));
}
var extension = await Graph.Users[userId].Extensions[extensionId].Request().GetAsync();
var extension = await graph.Users[userId].Extensions[extensionId].Request().GetAsync();
return extension;
}
/// <summary>
/// Get all extension objects for a user.
/// </summary>
/// <param name="graph">Instance of the <see cref="GraphServiceClient"/>.</param>
/// <param name="userId">The user to access.</param>
/// <returns>All extension results.</returns>
public static async Task<IList<Extension>> GetAllExtensions(string userId)
public static async Task<IList<Extension>> GetAllExtensions(this GraphServiceClient graph, string userId)
{
if (string.IsNullOrWhiteSpace(userId))
{
throw new ArgumentNullException(nameof(userId));
}
var extensions = await Graph.Users[userId].Extensions.Request().GetAsync();
var extensions = await graph.Users[userId].Extensions.Request().GetAsync();
return extensions;
}
/// <summary>
/// Create a new extension object on a user.
/// </summary>
/// <param name="graph">Instance of the <see cref="GraphServiceClient"/>.</param>
/// <param name="userId">The user to access.</param>
/// <param name="extensionId">The id of the new extension.</param>
/// <returns>The newly created extension.</returns>
public static async Task<Extension> CreateExtension(string userId, string extensionId)
public static async Task<Extension> CreateExtension(this GraphServiceClient graph, string userId, string extensionId)
{
if (string.IsNullOrWhiteSpace(extensionId))
{
@ -78,13 +80,13 @@ namespace CommunityToolkit.Graph.Helpers.RoamingSettings
try
{
// Try to see if the extension already exists.
return await GetExtension(userId, extensionId);
return await graph.GetExtension(userId, extensionId);
}
catch
{
}
string requestUrl = Graph.Users[userId].Extensions.Request().RequestUrl;
string requestUrl = graph.Users[userId].Extensions.Request().RequestUrl;
string json = "{" +
"\"@odata.type\": \"microsoft.graph.openTypeExtension\"," +
@ -93,13 +95,13 @@ namespace CommunityToolkit.Graph.Helpers.RoamingSettings
HttpRequestMessage hrm = new (HttpMethod.Post, requestUrl);
hrm.Content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");
await Graph.AuthenticationProvider.AuthenticateRequestAsync(hrm);
HttpResponseMessage response = await Graph.HttpProvider.SendAsync(hrm);
await graph.AuthenticationProvider.AuthenticateRequestAsync(hrm);
HttpResponseMessage response = await graph.HttpProvider.SendAsync(hrm);
if (response.IsSuccessStatusCode)
{
// Deserialize into Extension object.
var content = await response.Content.ReadAsStringAsync();
var extension = Graph.HttpProvider.Serializer.DeserializeObject<Extension>(content);
var extension = graph.HttpProvider.Serializer.DeserializeObject<Extension>(content);
return extension;
}
@ -109,10 +111,11 @@ namespace CommunityToolkit.Graph.Helpers.RoamingSettings
/// <summary>
/// Delete a user extension by id.
/// </summary>
/// <param name="graph">Instance of the <see cref="GraphServiceClient"/>.</param>
/// <param name="userId">The user to access.</param>
/// <param name="extensionId">The id of the extension to delete.</param>
/// <returns>A task.</returns>
public static async Task DeleteExtension(string userId, string extensionId)
public static async Task DeleteExtension(this GraphServiceClient graph, string userId, string extensionId)
{
if (string.IsNullOrWhiteSpace(extensionId))
{
@ -126,7 +129,7 @@ namespace CommunityToolkit.Graph.Helpers.RoamingSettings
try
{
await GetExtension(userId, extensionId);
await graph.GetExtension(userId, extensionId);
}
catch
{
@ -134,51 +137,19 @@ namespace CommunityToolkit.Graph.Helpers.RoamingSettings
return;
}
await Graph.Users[userId].Extensions[extensionId].Request().DeleteAsync();
}
/// <summary>
/// Get a value from an extension by key.
/// </summary>
/// <typeparam name="T">The type of object to return.</typeparam>
/// <param name="extension">The target extension.</param>
/// <param name="key">The key for the desired value.</param>
/// <returns>The value for the provided key.</returns>
public static T GetValue<T>(this Extension extension, string key)
{
return (T)GetValue(extension, key);
}
/// <summary>
/// Get a value from a user extension by key.
/// </summary>
/// <param name="extension">The target extension.</param>
/// <param name="key">The key for the desired value.</param>
/// <returns>The value for the provided key.</returns>
public static object GetValue(this Extension extension, string key)
{
if (string.IsNullOrWhiteSpace(key))
{
throw new ArgumentNullException(nameof(key));
}
if (extension.AdditionalData.ContainsKey(key))
{
return extension.AdditionalData[key];
}
return null;
await graph.Users[userId].Extensions[extensionId].Request().DeleteAsync();
}
/// <summary>
/// Sets a user extension value at the specified key.
/// </summary>
/// <param name="graph">Instance of the <see cref="GraphServiceClient"/>.</param>
/// <param name="userId">The user to access.</param>
/// <param name="extensionId">The id of the target extension.</param>
/// <param name="key">The key.</param>
/// <param name="value">The value to set.</param>
/// <returns>A task.</returns>
public static async Task SetValue(string userId, string extensionId, string key, object value)
public static async Task SetValue(this GraphServiceClient graph, string userId, string extensionId, string key, object value)
{
if (string.IsNullOrWhiteSpace(userId))
{
@ -198,7 +169,7 @@ namespace CommunityToolkit.Graph.Helpers.RoamingSettings
var extensionToUpdate = (Extension)Activator.CreateInstance(typeof(Extension), true);
extensionToUpdate.AdditionalData = new Dictionary<string, object>() { { key, value } };
await Graph.Users[userId].Extensions[extensionId].Request().UpdateAsync(extensionToUpdate);
await graph.Users[userId].Extensions[extensionId].Request().UpdateAsync(extensionToUpdate);
}
}
}
}

Просмотреть файл

@ -20,7 +20,11 @@ namespace CommunityToolkit.Graph.Extensions
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static async Task<User> GetMeAsync(this GraphServiceClient graph)
{
return await graph.Me.Request().GetAsync();
return await graph
.Me
.Request()
.WithScopes(new string[] { "user.read" })
.GetAsync();
}
/// <summary>
@ -31,7 +35,11 @@ namespace CommunityToolkit.Graph.Extensions
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static async Task<User> GetUserAsync(this GraphServiceClient graph, string userId)
{
return await graph.Users[userId].Request().GetAsync();
return await graph
.Users[userId]
.Request()
.WithScopes(new string[] { "user.read" })
.GetAsync();
}
/// <summary>
@ -46,7 +54,7 @@ namespace CommunityToolkit.Graph.Extensions
.Users
.Request()
.Filter($"startswith(displayName, '{query}') or startswith(givenName, '{query}') or startswith(surname, '{query}') or startswith(mail, '{query}') or startswith(userPrincipalName, '{query}')")
////.WithScopes(new string[] { "user.readbasic.all" })
.WithScopes(new string[] { "user.readbasic.all" })
.GetAsync();
}
@ -63,7 +71,7 @@ namespace CommunityToolkit.Graph.Extensions
.Photo
.Content
.Request()
////.WithScopes(new string[] { "user.readbasic.all" })
.WithScopes(new string[] { "user.readbasic.all" })
.GetAsync();
}
@ -79,7 +87,7 @@ namespace CommunityToolkit.Graph.Extensions
.Photo
.Content
.Request()
////.WithScopes(new string[] { "user.read" })
.WithScopes(new string[] { "user.read" })
.GetAsync();
}
}

Просмотреть файл

@ -1,35 +0,0 @@
// 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 System.Threading.Tasks;
using Microsoft.Toolkit.Helpers;
namespace CommunityToolkit.Graph.Helpers.RoamingSettings
{
/// <summary>
/// Describes a remote settings storage location with basic sync support.
/// </summary>
/// <typeparam name="TKey">The type of keys to use for accessing values.</typeparam>
public interface IRemoteSettingsStorageHelper<TKey> : ISettingsStorageHelper<TKey>
{
/// <summary>
/// Gets or sets an event that fires whenever a sync request has completed.
/// </summary>
EventHandler SyncCompleted { get; set; }
/// <summary>
/// Gets or sets a value an event that fires whenever a remote sync request has failed.
/// </summary>
EventHandler SyncFailed { get; set; }
/// <summary>
/// Update the remote extension to match the local cache and retrieve any new keys. Any existing remote values are replaced.
/// </summary>
/// <returns>The freshly synced user extension.</returns>
Task Sync();
}
}

Просмотреть файл

@ -9,12 +9,13 @@ using System.Reflection;
using System.Threading.Tasks;
using CommunityToolkit.Authentication;
using CommunityToolkit.Graph.Extensions;
using Microsoft.Graph;
using Microsoft.Toolkit.Helpers;
namespace CommunityToolkit.Graph.Helpers.RoamingSettings
{
/// <summary>
/// A base class for easily building roaming settings helper implementations.
/// An IFileStorageHelper implementation for interacting with data stored via files and folders in OneDrive.
/// </summary>
public class OneDriveStorageHelper : IFileStorageHelper
{
@ -35,13 +36,8 @@ namespace CommunityToolkit.Graph.Helpers.RoamingSettings
/// <returns>A new instance of the <see cref="OneDriveStorageHelper"/> configured for the current Graph user.</returns>
public static async Task<OneDriveStorageHelper> CreateForCurrentUserAsync(IObjectSerializer objectSerializer = null)
{
var provider = ProviderManager.Instance.GlobalProvider;
if (provider == null || provider.State != ProviderState.SignedIn)
{
throw new InvalidOperationException($"The {nameof(ProviderManager.GlobalProvider)} must be set and signed in to create a new {nameof(OneDriveStorageHelper)} for the current user.");
}
var me = await provider.GetClient().Me.Request().GetAsync();
var graph = GetGraphClient();
var me = await graph.GetMeAsync();
var userId = me.Id;
return new OneDriveStorageHelper(userId, objectSerializer);
@ -61,25 +57,29 @@ namespace CommunityToolkit.Graph.Helpers.RoamingSettings
/// <inheritdoc />
public async Task<T> ReadFileAsync<T>(string filePath, T @default = default)
{
return await OneDriveDataSource.GetFileAsync<T>(UserId, filePath, Serializer) ?? @default;
var graph = ProviderManager.Instance.GlobalProvider.GetClient();
return await graph.GetFileAsync<T>(UserId, filePath, Serializer) ?? @default;
}
/// <inheritdoc />
public Task<IEnumerable<(DirectoryItemType ItemType, string Name)>> ReadFolderAsync(string folderPath)
{
return OneDriveDataSource.ReadFolderAsync(UserId, folderPath);
var graph = GetGraphClient();
return graph.ReadFolderAsync(UserId, folderPath);
}
/// <inheritdoc />
public async Task CreateFileAsync<T>(string filePath, T value)
{
await OneDriveDataSource.SetFileAsync<T>(UserId, filePath, value, Serializer);
var graph = GetGraphClient();
await graph.SetFileAsync<T>(UserId, filePath, value, Serializer);
}
/// <inheritdoc />
public Task CreateFolderAsync(string folderName)
{
return OneDriveDataSource.CreateFolderAsync(UserId, folderName);
var graph = GetGraphClient();
return graph.CreateFolderAsync(UserId, folderName);
}
/// <summary>
@ -90,13 +90,26 @@ namespace CommunityToolkit.Graph.Helpers.RoamingSettings
/// <returns>A task.</returns>
public Task CreateFolderAsync(string folderName, string folderPath)
{
return OneDriveDataSource.CreateFolderAsync(UserId, folderName, folderPath);
var graph = GetGraphClient();
return graph.CreateFolderAsync(UserId, folderName, folderPath);
}
/// <inheritdoc />
public Task DeleteItemAsync(string itemPath)
{
return OneDriveDataSource.DeleteItemAsync(UserId, itemPath);
var graph = GetGraphClient();
return graph.DeleteItemAsync(UserId, itemPath);
}
private static GraphServiceClient GetGraphClient()
{
var provider = ProviderManager.Instance.GlobalProvider;
if (provider == null || provider.State != ProviderState.SignedIn)
{
throw new InvalidOperationException($"The {nameof(ProviderManager.GlobalProvider)} must be set and signed in to perform this action.");
}
return provider.GetClient();
}
}
}

Просмотреть файл

@ -17,9 +17,9 @@ using Microsoft.Toolkit.Helpers;
namespace CommunityToolkit.Graph.Helpers.RoamingSettings
{
/// <summary>
/// An IObjectStorageHelper implementation using open extensions on the Graph User for storing key/value pairs.
/// An ISettingsStorageHelper implementation using open extensions on the Graph User for storing key/value pairs.
/// </summary>
public class UserExtensionStorageHelper : IRemoteSettingsStorageHelper<string>
public class UserExtensionStorageHelper : ISettingsStorageHelper<string>
{
private static readonly IList<string> ReservedKeys = new List<string> { "responseHeaders", "statusCode", "@odata.context" };
private static readonly SemaphoreSlim SyncLock = new (1);
@ -30,7 +30,7 @@ namespace CommunityToolkit.Graph.Helpers.RoamingSettings
public EventHandler SyncCompleted { get; set; }
/// <summary>
/// gets or sets an event that fires whenever a remote sync request has failed.
/// Gets or sets an event that fires whenever a remote sync request has failed.
/// </summary>
public EventHandler SyncFailed { get; set; }
@ -82,6 +82,21 @@ namespace CommunityToolkit.Graph.Helpers.RoamingSettings
return new UserExtensionStorageHelper(extensionId, userId, objectSerializer);
}
/// <summary>
/// Retrieve an instance of the GraphServiceClient, or throws an exception if not signed in.
/// </summary>
/// <returns>A <see cref="GraphServiceClient"/> instance.</returns>
protected static GraphServiceClient GetGraphClient()
{
var provider = ProviderManager.Instance.GlobalProvider;
if (provider == null || provider.State != ProviderState.SignedIn)
{
throw new InvalidOperationException($"The {nameof(ProviderManager.GlobalProvider)} must be set and signed in to perform this action.");
}
return provider.GetClient();
}
/// <summary>
/// An indexer for easily accessing key values.
/// </summary>
@ -156,14 +171,16 @@ namespace CommunityToolkit.Graph.Helpers.RoamingSettings
try
{
var graph = GetGraphClient();
IDictionary<string, object> remoteData = null;
// Check if the extension should be cleared.
if (_cleared)
{
// Delete and re-create the remote extension.
await UserExtensionDataSource.DeleteExtension(UserId, ExtensionId);
Extension extension = await UserExtensionDataSource.CreateExtension(UserId, ExtensionId);
await graph.DeleteExtension(UserId, ExtensionId);
Extension extension = await graph.CreateExtension(UserId, ExtensionId);
remoteData = extension.AdditionalData;
_cleared = false;
@ -171,7 +188,7 @@ namespace CommunityToolkit.Graph.Helpers.RoamingSettings
else
{
// Get the remote extension.
Extension extension = await UserExtensionDataSource.GetExtension(UserId, ExtensionId);
Extension extension = await graph.GetExtension(UserId, ExtensionId);
remoteData = extension.AdditionalData;
}
@ -208,9 +225,10 @@ namespace CommunityToolkit.Graph.Helpers.RoamingSettings
SyncCompleted?.Invoke(this, new EventArgs());
}
catch
catch (Exception e)
{
SyncFailed?.Invoke(this, new EventArgs());
throw e;
}
finally
{