Updated Graph usage pattern in RoamingSettings helpers and updated descriptions to csproj files. (#139)
This commit is contained in:
Родитель
6fdcc7dbe2
Коммит
1daaf4ee3b
|
@ -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
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче