diff --git a/Microsoft.Toolkit.Graph.Controls/Controls/LoginButton/LoginButton.cs b/Microsoft.Toolkit.Graph.Controls/Controls/LoginButton/LoginButton.cs
index bb7c505..37d6362 100644
--- a/Microsoft.Toolkit.Graph.Controls/Controls/LoginButton/LoginButton.cs
+++ b/Microsoft.Toolkit.Graph.Controls/Controls/LoginButton/LoginButton.cs
@@ -110,6 +110,8 @@ private async void LoadData()
}
else if (provider.State == ProviderState.SignedIn)
{
+ IsLoading = true;
+
try
{
// https://github.com/microsoftgraph/microsoft-graph-toolkit/blob/master/src/components/mgt-login/mgt-login.ts#L139
diff --git a/Microsoft.Toolkit.Graph.Controls/Providers/CommonProviderBehaviorBase.Properties.cs b/Microsoft.Toolkit.Graph.Controls/Providers/CommonProviderBehaviorBase.Properties.cs
deleted file mode 100644
index e957366..0000000
--- a/Microsoft.Toolkit.Graph.Controls/Providers/CommonProviderBehaviorBase.Properties.cs
+++ /dev/null
@@ -1,74 +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.
-
-#if DOTNET
-using System.Windows;
-#else
-using Windows.UI.Xaml;
-#endif
-
-#if DOTNET
-namespace Microsoft.Toolkit.Wpf.Graph.Providers
-#else
-namespace Microsoft.Toolkit.Graph.Providers
-#endif
-{
- ///
- /// Properties for .
- ///
- public partial class CommonProviderBehaviorBase
- {
- ///
- /// Gets or sets the Client ID (the unique application (client) ID assigned to your app by Azure AD when the app was registered).
- ///
- ///
- /// For details about how to register an app and get a client ID,
- /// see the Register an app quick start.
- ///
- public string ClientId
- {
- get { return (string)GetValue(ClientIdProperty); }
- set { SetValue(ClientIdProperty, value); }
- }
-
- ///
- /// Identifies the dependency property.
- ///
- ///
- /// The identifier for the dependency property.
- ///
- public static readonly DependencyProperty ClientIdProperty =
- DependencyProperty.Register(nameof(ClientId), typeof(string), typeof(CommonProviderBehaviorBase), new PropertyMetadata(string.Empty));
-
- ///
- /// Gets or sets the redirect URI (the URI the identity provider will send the security tokens back to).
- ///
- public string RedirectUri
- {
- get { return (string)GetValue(RedirectUriProperty); }
- set { SetValue(RedirectUriProperty, value); }
- }
-
- ///
- /// Identifies the dependency property.
- ///
- ///
- /// The identifier for the dependency property.
- ///
- public static readonly DependencyProperty RedirectUriProperty =
-#if DOTNET
- DependencyProperty.Register(nameof(RedirectUri), typeof(string), typeof(CommonProviderBehaviorBase), new PropertyMetadata("http://localhost")); //// https://aka.ms/msal-net-os-browser
-#else
- DependencyProperty.Register(nameof(RedirectUri), typeof(string), typeof(CommonProviderBehaviorBase), new PropertyMetadata("https://login.microsoftonline.com/common/oauth2/nativeclient"));
-#endif
-
- ///
- /// Gets or sets the list of Scopes (permissions) to request on initial login.
- ///
- ///
- /// This list can be modified by controls which require specific scopes to function. This will aid in requesting all scopes required by controls used before login is initiated, if using the LoginButton.
- ///
- public ScopeSet Scopes { get; set; } = new ScopeSet { "User.Read", "User.ReadBasic.All" };
- }
-}
diff --git a/Microsoft.Toolkit.Graph.Controls/Providers/CommonProviderBehaviorBase.cs b/Microsoft.Toolkit.Graph.Controls/Providers/CommonProviderBehaviorBase.cs
deleted file mode 100644
index bf8bd86..0000000
--- a/Microsoft.Toolkit.Graph.Controls/Providers/CommonProviderBehaviorBase.cs
+++ /dev/null
@@ -1,25 +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.
-
-#if DOTNET
-using System.Windows;
-using Microsoft.Toolkit.Wpf.UI.Behaviors;
-#else
-using Microsoft.Toolkit.Uwp.UI.Behaviors;
-using Windows.UI.Xaml;
-#endif
-
-#if DOTNET
-namespace Microsoft.Toolkit.Wpf.Graph.Providers
-#else
-namespace Microsoft.Toolkit.Graph.Providers
-#endif
-{
- ///
- /// Provides a common base class for UWP XAML based provider wrappers to the Microsoft.Graph.Auth SDK.
- ///
- public abstract partial class CommonProviderBehaviorBase : BehaviorBase
- {
- }
-}
diff --git a/Microsoft.Toolkit.Graph.Controls/Providers/InteractiveProviderBehavior.cs b/Microsoft.Toolkit.Graph.Controls/Providers/InteractiveProviderBehavior.cs
deleted file mode 100644
index 99de148..0000000
--- a/Microsoft.Toolkit.Graph.Controls/Providers/InteractiveProviderBehavior.cs
+++ /dev/null
@@ -1,63 +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.
-
-#if DOTNET
-using System;
-using System.Linq;
-using System.Windows;
-using Microsoft.Toolkit.Graph.Providers;
-#else
-using System.Linq;
-using Windows.System;
-#endif
-
-#if DOTNET
-namespace Microsoft.Toolkit.Wpf.Graph.Providers
-#else
-namespace Microsoft.Toolkit.Graph.Providers
-#endif
-{
- ///
- /// Put in a xaml page with ClientId
- /// https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/Acquiring-tokens-interactively.
- ///
- ///
- ///
- /// <Interactivity:Interaction.Behaviors>
- /// <providers:InteractiveProviderBehavior ClientId = "MyClientIdGuid"/>
- /// </Interactivity:Interaction.Behaviors>
- ///
- ///
- public class InteractiveProviderBehavior : CommonProviderBehaviorBase
- {
- private object lock_sync = new object();
- private bool initialized = false;
-
- ///
- protected override bool Initialize()
- {
- lock (lock_sync)
- {
- if (!initialized)
- {
-#if DOTNET
- _ = Dispatcher.BeginInvoke(new Action(async () =>
- {
- ProviderManager.Instance.GlobalProvider =
- await QuickCreate.CreateMsalProviderAsync(ClientId, RedirectUri, Scopes.ToArray());
- }), System.Windows.Threading.DispatcherPriority.Normal);
-#else
- _ = DispatcherQueue.GetForCurrentThread().TryEnqueue(DispatcherQueuePriority.Normal, async () =>
- {
- ProviderManager.Instance.GlobalProvider =
- await QuickCreate.CreateMsalProviderAsync(ClientId, RedirectUri, Scopes.ToArray());
- });
-#endif
- }
- }
-
- return base.Initialize();
- }
- }
-}
diff --git a/Microsoft.Toolkit.Graph.Controls/Providers/MockProviderBehavior.cs b/Microsoft.Toolkit.Graph.Controls/Providers/MockProviderBehavior.cs
deleted file mode 100644
index 03a7ba7..0000000
--- a/Microsoft.Toolkit.Graph.Controls/Providers/MockProviderBehavior.cs
+++ /dev/null
@@ -1,69 +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.
-
-#if DOTNET
-using System;
-using System.Linq;
-using System.Windows;
-using Microsoft.Toolkit.Graph.Providers;
-#else
-using System.Linq;
-using Windows.UI.Xaml;
-#endif
-
-#if DOTNET
-namespace Microsoft.Toolkit.Wpf.Graph.Providers
-#else
-namespace Microsoft.Toolkit.Graph.Providers
-#endif
-{
- ///
- /// Put in a xaml page with ClientId
- /// https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/Acquiring-tokens-interactively.
- ///
- ///
- ///
- /// <Interactivity:Interaction.Behaviors>
- /// <providers:InteractiveProviderBehavior ClientId = "MyClientIdGuid"/>
- /// </Interactivity:Interaction.Behaviors>
- ///
- ///
- public class MockProviderBehavior : CommonProviderBehaviorBase
- {
- private object lock_sync = new object();
- private bool initialized = false;
-
- ///
- /// Gets or sets a value indicating whether the mock provider is signed-in upon initialization.
- ///
- public bool SignedIn
- {
- get { return (bool)GetValue(SignedInProperty); }
- set { SetValue(SignedInProperty, value); }
- }
-
- ///
- /// Identifies the dependency property.
- ///
- ///
- /// The identifier for the dependency property.
- ///
- public static readonly DependencyProperty SignedInProperty =
- DependencyProperty.Register(nameof(SignedIn), typeof(bool), typeof(MockProviderBehavior), new PropertyMetadata(true));
-
- ///
- protected override bool Initialize()
- {
- lock (lock_sync)
- {
- if (!initialized)
- {
- ProviderManager.Instance.GlobalProvider = new MockProvider(SignedIn);
- }
- }
-
- return base.Initialize();
- }
- }
-}
diff --git a/Microsoft.Toolkit.Graph.Controls/Providers/QuickCreate.cs b/Microsoft.Toolkit.Graph.Controls/Providers/QuickCreate.cs
deleted file mode 100644
index b9fdfe7..0000000
--- a/Microsoft.Toolkit.Graph.Controls/Providers/QuickCreate.cs
+++ /dev/null
@@ -1,56 +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.Reflection;
-using System.Threading.Tasks;
-using Microsoft.Graph.Auth;
-using Microsoft.Identity.Client;
-using Microsoft.Toolkit.Graph.Providers;
-
-#if DOTNET
-namespace Microsoft.Toolkit.Wpf.Graph.Providers
-#else
-namespace Microsoft.Toolkit.Graph.Providers
-#endif
-{
- //// TODO: This should probably live in .NET Standard lib; however, Uno one needs to be at UI layer for Parent Window?
- //// TODO: Need to set up XAML Islands sample to test in the new repo and make sure this works from this context.
-
- ///
- /// Helper class to easily initialize provider from just ClientId.
- ///
- public static class QuickCreate
- {
- ///
- /// Easily creates a from a ClientId.
- ///
- ///
- ///
- /// ProviderManager.Instance.GlobalProvider = await QuickCreate.CreateMsalProviderAsync("MyClientId");
- ///
- ///
- /// Registered ClientId.
- /// RedirectUri for auth response.
- /// List of Scopes to initially request.
- /// New reference.
- public static async Task CreateMsalProviderAsync(string clientid, string redirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient", string[] scopes = null)
- {
- var client = PublicClientApplicationBuilder.Create(clientid)
- .WithAuthority(AzureCloudInstance.AzurePublic, AadAuthorityAudience.AzureAdAndPersonalMicrosoftAccount)
- .WithRedirectUri(redirectUri)
- .WithClientName(ProviderManager.ClientName)
- .WithClientVersion(Assembly.GetExecutingAssembly().GetName().Version.ToString())
- .Build();
-
- if (scopes == null)
- {
- scopes = new string[] { string.Empty };
- }
-
- var provider = new InteractiveAuthenticationProvider(client, scopes);
-
- return await MsalProvider.CreateAsync(client, provider);
- }
- }
-}
diff --git a/Microsoft.Toolkit.Graph.Providers.Msal/Microsoft.Toolkit.Graph.Providers.Msal.csproj b/Microsoft.Toolkit.Graph.Providers.Msal/Microsoft.Toolkit.Graph.Providers.Msal.csproj
new file mode 100644
index 0000000..7a997ca
--- /dev/null
+++ b/Microsoft.Toolkit.Graph.Providers.Msal/Microsoft.Toolkit.Graph.Providers.Msal.csproj
@@ -0,0 +1,41 @@
+
+
+
+ uap10.0.17763
+ Windows Community Toolkit Msal Graph Provider
+ Microsoft.Toolkit.Graph.Providers.Msal
+
+ This library provides... It is part of the Windows Community Toolkit.
+
+ Classes:
+ - MsalProvider:
+ - MsalConfig:
+
+ UWP Toolkit Windows Controls MSAL Microsoft Graph AadLogin Login
+ false
+ true
+ 8.0
+ Debug;Release;CI
+ AnyCPU;ARM;ARM64;x64;x86
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Microsoft.Toolkit.Graph.Providers.Msal/MsalConfig.cs b/Microsoft.Toolkit.Graph.Providers.Msal/MsalConfig.cs
new file mode 100644
index 0000000..cd763a9
--- /dev/null
+++ b/Microsoft.Toolkit.Graph.Providers.Msal/MsalConfig.cs
@@ -0,0 +1,40 @@
+// 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.Graph.Providers.Msal
+{
+ ///
+ /// Configuration values for initializing the MsalProvider.
+ ///
+ public class MsalConfig : IGraphConfig
+ {
+ static MsalConfig()
+ {
+ Graph.RegisterConfig(typeof(MsalConfig), (c) => MsalProvider.Create(c as MsalConfig));
+ }
+
+ ///
+ /// Gets or sets the Client ID (the unique application (client) ID assigned to your app by Azure AD when the app was registered).
+ ///
+ ///
+ /// For details about how to register an app and get a client ID,
+ /// see the Register an app quick start.
+ ///
+ public string ClientId { get; set; }
+
+ ///
+ /// Gets or sets the redirect URI (the URI the identity provider will send the security tokens back to).
+ ///
+ public string RedirectUri { get; set; }
+
+ ///
+ /// Gets or sets the list of Scopes (permissions) to request on initial login.
+ ///
+ ///
+ /// This list can be modified by controls which require specific scopes to function.
+ /// This will aid in requesting all scopes required by controls used before login is initiated, if using the LoginButton.
+ ///
+ public ScopeSet Scopes { get; set; }
+ }
+}
diff --git a/Microsoft.Toolkit.Graph/Providers/MsalProvider.cs b/Microsoft.Toolkit.Graph.Providers.Msal/MsalProvider.cs
similarity index 65%
rename from Microsoft.Toolkit.Graph/Providers/MsalProvider.cs
rename to Microsoft.Toolkit.Graph.Providers.Msal/MsalProvider.cs
index 42c00bc..2987e98 100644
--- a/Microsoft.Toolkit.Graph/Providers/MsalProvider.cs
+++ b/Microsoft.Toolkit.Graph.Providers.Msal/MsalProvider.cs
@@ -3,23 +3,20 @@
// See the LICENSE file in the project root for more information.
using System;
-using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.Graph;
+using Microsoft.Graph.Auth;
using Microsoft.Identity.Client;
-using Microsoft.Toolkit.Graph.Extensions;
-namespace Microsoft.Toolkit.Graph.Providers
+namespace Microsoft.Toolkit.Graph.Providers.Msal
{
- //// TODO: Move some of this to a simple base-class for non-MSAL parts related to Provider only and properties?
-
///
/// MSAL.NET provider helper for tracking authentication state using an class.
///
- public class MsalProvider : IProvider
+ public class MsalProvider : BaseProvider
{
///
/// Gets or sets the MSAL.NET Client used to authenticate the user.
@@ -31,65 +28,71 @@ public class MsalProvider : IProvider
///
protected IAuthenticationProvider Provider { get; set; }
- private ProviderState _state = ProviderState.Loading;
-
- ///
- public ProviderState State
+ ///
+ /// Initializes a new instance of the class. .
+ ///
+ private MsalProvider()
{
- get
- {
- return _state;
- }
-
- private set
- {
- var current = _state;
- _state = value;
-
- StateChanged?.Invoke(this, new StateChangedEventArgs(current, _state));
- }
}
- ///
- public GraphServiceClient Graph { get; private set; }
-
- ///
- public event EventHandler StateChanged;
-
///
- /// Initializes a new instance of the class. .
+ /// Easily creates a from a config object.
///
- private MsalProvider()
+ ///
+ /// The configuration object used to initialize the provider.
+ ///
+ ///
+ /// A new instance of the MsalProvider.
+ ///
+ public static MsalProvider Create(MsalConfig config)
{
+ return Create(config.ClientId, config.RedirectUri, config.Scopes.ToArray());
}
///
- /// Initializes a new instance of the class.
+ /// Easily creates a from a ClientId.
///
- /// Existing instance.
- /// Existing instance.
- /// A returning a instance.
- public static async Task CreateAsync(IPublicClientApplication client, IAuthenticationProvider provider)
+ ///
+ ///
+ /// ProviderManager.Instance.GlobalProvider = await QuickCreate.CreateMsalProviderAsync("MyClientId");
+ ///
+ ///
+ /// Registered ClientId.
+ /// RedirectUri for auth response.
+ /// List of Scopes to initially request.
+ /// New reference.
+ public static MsalProvider Create(string clientid, string redirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient", string[] scopes = null)
{
//// TODO: Check all config provided
+ var client = PublicClientApplicationBuilder.Create(clientid)
+ .WithAuthority(AzureCloudInstance.AzurePublic, AadAuthorityAudience.AzureAdAndPersonalMicrosoftAccount)
+ .WithRedirectUri(redirectUri)
+ .WithClientName(ProviderManager.ClientName)
+ .WithClientVersion(Assembly.GetExecutingAssembly().GetName().Version.ToString())
+ .Build();
+
+ if (scopes == null)
+ {
+ scopes = new string[] { string.Empty };
+ }
+
var msal = new MsalProvider
{
Client = client,
- Provider = provider,
+ Provider = new InteractiveAuthenticationProvider(client, scopes),
};
-
msal.Graph = new GraphServiceClient(msal);
- await msal.TrySilentSignInAsync();
+ _ = msal.TrySilentSignInAsync();
return msal;
}
///
- public async Task AuthenticateRequestAsync(HttpRequestMessage request)
+ public override async Task AuthenticateRequestAsync(HttpRequestMessage request)
{
- request.AddSdkVersion();
+ AddSdkVersion(request);
try
{
@@ -159,14 +162,14 @@ public async Task TrySilentSignInAsync()
}
///
- public async Task LoginAsync()
+ public override async Task LoginAsync()
{
// Force fake request to start auth process
await AuthenticateRequestAsync(new System.Net.Http.HttpRequestMessage());
}
///
- public async Task LogoutAsync()
+ public override async Task LogoutAsync()
{
// Forcibly remove each user.
foreach (var user in await Client.GetAccountsAsync())
diff --git a/Microsoft.Toolkit.Graph.Providers.Msal/Properties/AssemblyInfo.cs b/Microsoft.Toolkit.Graph.Providers.Msal/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..c244792
--- /dev/null
+++ b/Microsoft.Toolkit.Graph.Providers.Msal/Properties/AssemblyInfo.cs
@@ -0,0 +1,11 @@
+// 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.Resources;
+using System.Runtime.CompilerServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: NeutralResourcesLanguage("en-US")]
\ No newline at end of file
diff --git a/Microsoft.Toolkit.Graph.Providers.Msal/Properties/Microsoft.Toolkit.Graph.Providers.Msal.rd.xml b/Microsoft.Toolkit.Graph.Providers.Msal/Properties/Microsoft.Toolkit.Graph.Providers.Msal.rd.xml
new file mode 100644
index 0000000..195d8f6
--- /dev/null
+++ b/Microsoft.Toolkit.Graph.Providers.Msal/Properties/Microsoft.Toolkit.Graph.Providers.Msal.rd.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/Microsoft.Toolkit.Graph.Providers.Uwp/Microsoft.Toolkit.Graph.Providers.Uwp.csproj b/Microsoft.Toolkit.Graph.Providers.Uwp/Microsoft.Toolkit.Graph.Providers.Uwp.csproj
new file mode 100644
index 0000000..8a71155
--- /dev/null
+++ b/Microsoft.Toolkit.Graph.Providers.Uwp/Microsoft.Toolkit.Graph.Providers.Uwp.csproj
@@ -0,0 +1,41 @@
+
+
+
+ uap10.0.17763
+ Windows Community Toolkit Uwp Graph Provider
+ Microsoft.Toolkit.Graph.Providers.Uwp
+
+ This library provides an IProvider implenetation that authenticates using the native Windows dialoges. It is part of the Windows Community Toolkit.
+
+ Classes:
+ - UwpProvider:
+ - UwpConfig:
+
+ UWP Toolkit Windows Controls MSAL Microsoft Graph AadLogin Login
+ false
+ true
+ 8.0
+ Debug;Release;CI
+ AnyCPU;ARM;ARM64;x64;x86
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Microsoft.Toolkit.Graph.Providers.Uwp/Properties/AssemblyInfo.cs b/Microsoft.Toolkit.Graph.Providers.Uwp/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..c244792
--- /dev/null
+++ b/Microsoft.Toolkit.Graph.Providers.Uwp/Properties/AssemblyInfo.cs
@@ -0,0 +1,11 @@
+// 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.Resources;
+using System.Runtime.CompilerServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: NeutralResourcesLanguage("en-US")]
\ No newline at end of file
diff --git a/Microsoft.Toolkit.Graph.Providers.Uwp/Properties/Microsoft.Toolkit.Graph.Providers.Uwp.rd.xml b/Microsoft.Toolkit.Graph.Providers.Uwp/Properties/Microsoft.Toolkit.Graph.Providers.Uwp.rd.xml
new file mode 100644
index 0000000..db84211
--- /dev/null
+++ b/Microsoft.Toolkit.Graph.Providers.Uwp/Properties/Microsoft.Toolkit.Graph.Providers.Uwp.rd.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/Microsoft.Toolkit.Graph.Providers.Uwp/WindowsConfig.cs b/Microsoft.Toolkit.Graph.Providers.Uwp/WindowsConfig.cs
new file mode 100644
index 0000000..1c8b01b
--- /dev/null
+++ b/Microsoft.Toolkit.Graph.Providers.Uwp/WindowsConfig.cs
@@ -0,0 +1,35 @@
+// 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.Graph.Providers.Uwp
+{
+ ///
+ /// Basic configuration for talking to the Graph.
+ ///
+ public class WindowsConfig : IGraphConfig
+ {
+ static WindowsConfig()
+ {
+ Graph.RegisterConfig(typeof(WindowsConfig), (c) => WindowsProvider.Create(c as WindowsConfig));
+ }
+
+ ///
+ /// Gets or sets the Client ID (the unique application (client) ID assigned to your app by Azure AD when the app was registered).
+ ///
+ ///
+ /// For details about how to register an app and get a client ID,
+ /// see the Register an app quick start.
+ ///
+ public string ClientId { get; set; }
+
+ ///
+ /// Gets or sets the list of Scopes (permissions) to request on initial login.
+ ///
+ ///
+ /// This list can be modified by controls which require specific scopes to function.
+ /// This will aid in requesting all scopes required by controls used before login is initiated, if using the LoginButton.
+ ///
+ public ScopeSet Scopes { get; set; } = new ScopeSet { "User.Read", "User.ReadBasic.All" };
+ }
+}
diff --git a/Microsoft.Toolkit.Graph.Providers.Uwp/WindowsProvider.cs b/Microsoft.Toolkit.Graph.Providers.Uwp/WindowsProvider.cs
new file mode 100644
index 0000000..c480679
--- /dev/null
+++ b/Microsoft.Toolkit.Graph.Providers.Uwp/WindowsProvider.cs
@@ -0,0 +1,304 @@
+// 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.Diagnostics;
+using System.Linq;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Threading.Tasks;
+using Microsoft.Graph;
+using Windows.Security.Authentication.Web;
+using Windows.Security.Authentication.Web.Core;
+using Windows.UI.ApplicationSettings;
+
+namespace Microsoft.Toolkit.Graph.Providers.Uwp
+{
+ ///
+ /// A provider for leveraging Windows system authentication.
+ ///
+ public class WindowsProvider : BaseProvider
+ {
+ private struct AuthenticatedUser
+ {
+ public Windows.Security.Credentials.PasswordCredential TokenCredential { get; private set; }
+
+ public string GetUserName()
+ {
+ return TokenCredential?.UserName;
+ }
+
+ public string GetToken()
+ {
+ return TokenCredential?.Password;
+ }
+
+ public AuthenticatedUser(Windows.Security.Credentials.PasswordCredential tokenCredential)
+ {
+ TokenCredential = tokenCredential;
+ }
+ }
+
+ private const string TokenCredentialResourceName = "WindowsProviderToken";
+ private const string WebAccountProviderId = "https://login.microsoft.com";
+ private static readonly string[] DefaultScopes = new string[] { "user.read" };
+ private static readonly string GraphResourceProperty = "https://graph.microsoft.com";
+
+ ///
+ /// Gets the redirect uri value based on the current app callback uri.
+ ///
+ public static string RedirectUri => string.Format("ms-appx-web://Microsoft.AAD.BrokerPlugIn/{0}", WebAuthenticationBroker.GetCurrentApplicationCallbackUri().Host.ToUpper());
+
+ private AccountsSettingsPane _currentPane;
+ private AuthenticatedUser? _currentUser;
+ private string[] _scopes;
+ private string _clientId;
+
+ ///
+ /// Creates a new instance of the WindowsProvider with a WindowsConfig object.
+ ///
+ ///
+ /// The configuration object used to initialize the provider.
+ ///
+ ///
+ /// A new instance of the WindowsProvider.
+ ///
+ public static WindowsProvider Create(WindowsConfig config)
+ {
+ return Create(config.ClientId, config.Scopes.ToArray());
+ }
+
+ ///
+ /// Creates a new instance of the WindowsProvider and attempts to sign in silently.
+ ///
+ ///
+ /// The clientId value used to initialize the provider.
+ ///
+ ///
+ /// The scope values used to initialize the provider.
+ ///
+ /// A new instance of a WindowsProvider.
+ public static WindowsProvider Create(string clientId, string[] scopes)
+ {
+ var provider = new WindowsProvider(clientId, scopes);
+
+ provider.Graph = new GraphServiceClient(provider);
+
+ _ = provider.TrySilentSignInAsync();
+
+ return provider;
+ }
+
+ private WindowsProvider(string clientId, string[] scopes = null)
+ {
+ _clientId = clientId ?? throw new ArgumentNullException(nameof(clientId));
+ _currentPane = null;
+ _currentUser = null;
+ _scopes = scopes ?? DefaultScopes;
+
+ Graph = new GraphServiceClient(new DelegateAuthenticationProvider(AuthenticateRequestAsync));
+
+ State = ProviderState.SignedOut;
+ }
+
+ ///
+ /// Attempts to sign in the logged in user automatically.
+ ///
+ /// Success boolean.
+ public async Task TrySilentSignInAsync()
+ {
+ if (State == ProviderState.SignedIn)
+ {
+ return false;
+ }
+
+ State = ProviderState.Loading;
+
+ var tokenCredential = GetCredentialFromLocker();
+ if (tokenCredential == null)
+ {
+ // There is no credential stored in the locker.
+ State = ProviderState.SignedOut;
+ return false;
+ }
+
+ // Populate the password (aka token).
+ tokenCredential.RetrievePassword();
+
+ // Log the user in by storing the credential in memory.
+ _currentUser = new AuthenticatedUser(tokenCredential);
+
+ try
+ {
+ var me = await Graph.Me.Request().GetAsync();
+
+ // Update the state to be signed in.
+ State = ProviderState.SignedIn;
+ return true;
+ }
+ catch
+ {
+ // Update the state to be signed in.
+ State = ProviderState.SignedOut;
+ return false;
+ }
+ }
+
+ ///
+ public override Task LoginAsync()
+ {
+ if (State == ProviderState.SignedIn)
+ {
+ return Task.CompletedTask;
+ }
+
+ State = ProviderState.Loading;
+
+ if (_currentPane != null)
+ {
+ _currentPane.AccountCommandsRequested -= BuildPaneAsync;
+ }
+
+ _currentPane = AccountsSettingsPane.GetForCurrentView();
+ _currentPane.AccountCommandsRequested += BuildPaneAsync;
+
+ AccountsSettingsPane.Show();
+ return Task.CompletedTask;
+ }
+
+ ///
+ public override Task LogoutAsync()
+ {
+ if (State == ProviderState.SignedOut)
+ {
+ return Task.CompletedTask;
+ }
+
+ State = ProviderState.Loading;
+
+ if (_currentPane != null)
+ {
+ _currentPane.AccountCommandsRequested -= BuildPaneAsync;
+ _currentPane = null;
+ }
+
+ if (_currentUser != null)
+ {
+ // Remove the user info from the PaasswordVault
+ var vault = new Windows.Security.Credentials.PasswordVault();
+ vault.Remove(_currentUser?.TokenCredential);
+
+ _currentUser = null;
+ }
+
+ State = ProviderState.SignedOut;
+ return Task.CompletedTask;
+ }
+
+ ///
+ public override Task AuthenticateRequestAsync(HttpRequestMessage request)
+ {
+ // Append the token to the authorization header of any outgoing Graph requests.
+ var token = _currentUser?.GetToken();
+ request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
+ return Task.CompletedTask;
+ }
+
+ ///
+ /// https://docs.microsoft.com/en-us/windows/uwp/security/web-account-manager#build-the-account-settings-pane.
+ ///
+ private async void BuildPaneAsync(AccountsSettingsPane sender, AccountsSettingsPaneCommandsRequestedEventArgs args)
+ {
+ var deferral = args.GetDeferral();
+
+ try
+ {
+ // Providing nothing shows all accounts, providing authority shows only aad
+ var msaProvider = await WebAuthenticationCoreManager.FindAccountProviderAsync(WebAccountProviderId);
+
+ if (msaProvider == null)
+ {
+ State = ProviderState.SignedOut;
+ return;
+ }
+
+ var command = new WebAccountProviderCommand(msaProvider, GetTokenAsync);
+ args.WebAccountProviderCommands.Add(command);
+ }
+ catch
+ {
+ State = ProviderState.SignedOut;
+ }
+ finally
+ {
+ deferral.Complete();
+ }
+ }
+
+ private async void GetTokenAsync(WebAccountProviderCommand command)
+ {
+ // Build the token request
+ WebTokenRequest request = new WebTokenRequest(command.WebAccountProvider, string.Join(',', _scopes), _clientId);
+ request.Properties.Add("resource", GraphResourceProperty);
+
+ // Get the results
+ WebTokenRequestResult result = await WebAuthenticationCoreManager.RequestTokenAsync(request);
+
+ // Handle user cancellation
+ if (result.ResponseStatus == WebTokenRequestStatus.UserCancel)
+ {
+ State = ProviderState.SignedOut;
+ return;
+ }
+
+ // Handle any errors
+ if (result.ResponseStatus != WebTokenRequestStatus.Success)
+ {
+ Debug.WriteLine(result.ResponseError.ErrorMessage);
+ State = ProviderState.SignedOut;
+ return;
+ }
+
+ // Extract values from the results
+ var token = result.ResponseData[0].Token;
+ var account = result.ResponseData[0].WebAccount;
+
+ // The UserName value may be null, but the Id is always present.
+ var userName = account.Id;
+
+ // Save the user info to the PaasswordVault
+ var vault = new Windows.Security.Credentials.PasswordVault();
+ var tokenCredential = new Windows.Security.Credentials.PasswordCredential(TokenCredentialResourceName, userName, token);
+ vault.Add(tokenCredential);
+
+ // Set the current user object
+ _currentUser = new AuthenticatedUser(tokenCredential);
+
+ // Update the state to be signed in.
+ State = ProviderState.SignedIn;
+ }
+
+ private Windows.Security.Credentials.PasswordCredential GetCredentialFromLocker()
+ {
+ Windows.Security.Credentials.PasswordCredential credential = null;
+
+ try
+ {
+ var vault = new Windows.Security.Credentials.PasswordVault();
+ var credentialList = vault.FindAllByResource(TokenCredentialResourceName);
+ if (credentialList.Count > 0)
+ {
+ // We delete the credential upon logout, so only one user can be stored in the vault at a time.
+ credential = credentialList.First();
+ }
+ }
+ catch
+ {
+ // FindAllByResource will throw an exception if the resource isn't found.
+ }
+
+ return credential;
+ }
+ }
+}
diff --git a/Microsoft.Toolkit.Graph.Providers/BaseProvider.cs b/Microsoft.Toolkit.Graph.Providers/BaseProvider.cs
new file mode 100644
index 0000000..4c5d7f7
--- /dev/null
+++ b/Microsoft.Toolkit.Graph.Providers/BaseProvider.cs
@@ -0,0 +1,74 @@
+// 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.Net.Http;
+using System.Threading.Tasks;
+using Microsoft.Graph;
+using Microsoft.Toolkit.Graph.Providers.Extensions;
+
+namespace Microsoft.Toolkit.Graph.Providers
+{
+ ///
+ /// A base construct for building Graph Providers on top of.
+ ///
+ public abstract class BaseProvider : IProvider
+ {
+ private ProviderState _state;
+
+ ///
+ /// Gets or sets the current state of the provider.
+ ///
+ public ProviderState State
+ {
+ get => _state;
+ protected set
+ {
+ var oldState = _state;
+ var newState = value;
+ if (oldState != newState)
+ {
+ _state = newState;
+ StateChanged?.Invoke(this, new ProviderStateChangedEventArgs(oldState, newState));
+ }
+ }
+ }
+
+ ///
+ public event EventHandler StateChanged;
+
+ ///
+ /// Gets or sets the service client instance for making Graph calls.
+ ///
+ public virtual GraphServiceClient Graph { get; protected set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public BaseProvider()
+ {
+ _state = ProviderState.Loading;
+ }
+
+ ///
+ public abstract Task LoginAsync();
+
+ ///
+ public abstract Task LogoutAsync();
+
+ ///
+ public abstract Task AuthenticateRequestAsync(HttpRequestMessage request);
+
+ ///
+ /// Append the Sdk version to the request headers.
+ ///
+ ///
+ /// The request to append the header to.
+ ///
+ protected void AddSdkVersion(HttpRequestMessage request)
+ {
+ request.AddSdkVersion();
+ }
+ }
+}
diff --git a/Microsoft.Toolkit.Graph/Extensions/HttpRequestMessageExtensions.cs b/Microsoft.Toolkit.Graph.Providers/Extensions/HttpRequestMessageExtensions.cs
similarity index 84%
rename from Microsoft.Toolkit.Graph/Extensions/HttpRequestMessageExtensions.cs
rename to Microsoft.Toolkit.Graph.Providers/Extensions/HttpRequestMessageExtensions.cs
index 9d75abf..597d838 100644
--- a/Microsoft.Toolkit.Graph/Extensions/HttpRequestMessageExtensions.cs
+++ b/Microsoft.Toolkit.Graph.Providers/Extensions/HttpRequestMessageExtensions.cs
@@ -11,19 +11,19 @@
using System.Text;
using System.Threading.Tasks;
-namespace Microsoft.Toolkit.Graph.Extensions
+namespace Microsoft.Toolkit.Graph.Providers.Extensions
{
///
/// Helpers for Graph related HTTP Headers.
///
- internal static class HttpRequestMessageExtensions
+ public static class HttpRequestMessageExtensions
{
private const string SdkVersion = "SdkVersion";
private const string LibraryName = "wct";
private const string Bearer = "Bearer";
private const string MockGraphToken = "{token:https://graph.microsoft.com/}";
- public static void AddSdkVersion(this HttpRequestMessage request)
+ internal static void AddSdkVersion(this HttpRequestMessage request)
{
if (request == null || request.Headers == null)
{
@@ -39,7 +39,7 @@ public static void AddSdkVersion(this HttpRequestMessage request)
}
}
- public static void AddMockProviderToken(this HttpRequestMessage request)
+ internal static void AddMockProviderToken(this HttpRequestMessage request)
{
request
.Headers
diff --git a/Microsoft.Toolkit.Graph.Providers/Graph.cs b/Microsoft.Toolkit.Graph.Providers/Graph.cs
new file mode 100644
index 0000000..6976608
--- /dev/null
+++ b/Microsoft.Toolkit.Graph.Providers/Graph.cs
@@ -0,0 +1,102 @@
+// 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 Windows.UI.Xaml;
+
+namespace Microsoft.Toolkit.Graph.Providers
+{
+ ///
+ /// Creates a new provider instance for the provided configuration and sets the GlobalProvider.
+ ///
+ public static class Graph
+ {
+ ///
+ /// Gets the Graph Config property value.
+ ///
+ ///
+ /// The target object to retrieve the property value from.
+ ///
+ ///
+ /// The value of the property on the target.
+ ///
+ public static IGraphConfig GetConfig(ResourceDictionary target)
+ {
+ return (IGraphConfig)target.GetValue(ConfigProperty);
+ }
+
+ ///
+ /// Sets the GraphConfig property value.
+ ///
+ ///
+ /// The target object to set the value on.
+ ///
+ ///
+ /// The value to apply to the target property.
+ ///
+ public static void SetConfig(ResourceDictionary target, IGraphConfig value)
+ {
+ target.SetValue(ConfigProperty, value);
+ }
+
+ ///
+ /// Identifies the Config dependency property.
+ ///
+ ///
+ /// The identifier for the Config dependency property.
+ ///
+ public static readonly DependencyProperty ConfigProperty =
+ DependencyProperty.RegisterAttached("Config", typeof(IGraphConfig), typeof(Graph), new PropertyMetadata(null, OnConfigChanged));
+
+ private static void OnConfigChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
+ {
+ if (sender is ResourceDictionary rd)
+ {
+ IGraphConfig config = GetConfig(rd);
+
+ Type configType = config.GetType();
+ if (_providers.ContainsKey(configType))
+ {
+ var providerFactory = _providers[configType];
+ ProviderManager.Instance.GlobalProvider = providerFactory.Invoke(config);
+ }
+ else if (config is MockConfig mockConfig)
+ {
+ ProviderManager.Instance.GlobalProvider = new MockProvider(mockConfig);
+ }
+ }
+ else
+ {
+ ProviderManager.Instance.GlobalProvider = null;
+ }
+ }
+
+ private static Dictionary> _providers = new Dictionary>();
+
+ ///
+ /// Register a provider to be available for declaration in XAML using the ConfigProperty.
+ /// Use in the static constructor of an IGraphConfig implementation.
+ ///
+ ///
+ /// static MsalConfig()
+ /// {
+ /// Graph.RegisterConfig(typeof(MsalConfig), (c) => MsalProvider.Create(c as MsalConfig));
+ /// }.
+ ///
+ ///
+ /// The Type of the IGraphConfig implementation associated with provider.
+ ///
+ ///
+ /// A factory function for creating a new instance of the IProvider implementation.
+ ///
+ public static void RegisterConfig(Type configType, Func providerFactory)
+ {
+ if (!_providers.ContainsKey(configType))
+ {
+ _providers.Add(configType, providerFactory);
+ }
+ }
+ }
+}
diff --git a/Microsoft.Toolkit.Graph.Providers/IGraphConfig.cs b/Microsoft.Toolkit.Graph.Providers/IGraphConfig.cs
new file mode 100644
index 0000000..37886da
--- /dev/null
+++ b/Microsoft.Toolkit.Graph.Providers/IGraphConfig.cs
@@ -0,0 +1,13 @@
+// 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.Graph.Providers
+{
+ ///
+ /// An interface to base Graph configuration implementations on.
+ ///
+ public interface IGraphConfig
+ {
+ }
+}
diff --git a/Microsoft.Toolkit.Graph.Providers/Microsoft.Toolkit.Graph.Providers.csproj b/Microsoft.Toolkit.Graph.Providers/Microsoft.Toolkit.Graph.Providers.csproj
new file mode 100644
index 0000000..b30053d
--- /dev/null
+++ b/Microsoft.Toolkit.Graph.Providers/Microsoft.Toolkit.Graph.Providers.csproj
@@ -0,0 +1,44 @@
+
+
+
+ uap10.0.17763
+ Windows Community Toolkit Graph Providers
+ Microsoft.Toolkit.Graph.Providers
+
+ This library provides base constructs for building Microsoft Graph XAML providers. It is part of the Windows Community Toolkit.
+
+ Classes:
+ - BaseProvider:
+ - MockProvider:
+ - MockConfig:
+ - ScopeSet:
+
+ UWP Toolkit Windows Providers MSAL Microsoft Graph AadLogin Login
+ false
+ true
+ 8.0
+ Debug;Release;CI
+ AnyCPU;ARM;ARM64;x64;x86
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Microsoft.Toolkit.Graph.Providers/MockConfig.cs b/Microsoft.Toolkit.Graph.Providers/MockConfig.cs
new file mode 100644
index 0000000..c857a47
--- /dev/null
+++ b/Microsoft.Toolkit.Graph.Providers/MockConfig.cs
@@ -0,0 +1,17 @@
+// 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.Graph.Providers
+{
+ ///
+ /// The configuration for the MockProvider.
+ ///
+ public class MockConfig : IGraphConfig
+ {
+ ///
+ /// Gets or sets a value indicating whether the provider should automatically sign in or not.
+ ///
+ public bool SignedIn { get; set; } = true;
+ }
+}
diff --git a/Microsoft.Toolkit.Graph/Providers/MockProvider.cs b/Microsoft.Toolkit.Graph.Providers/MockProvider.cs
similarity index 62%
rename from Microsoft.Toolkit.Graph/Providers/MockProvider.cs
rename to Microsoft.Toolkit.Graph.Providers/MockProvider.cs
index a0d54ec..beec22e 100644
--- a/Microsoft.Toolkit.Graph/Providers/MockProvider.cs
+++ b/Microsoft.Toolkit.Graph.Providers/MockProvider.cs
@@ -3,47 +3,22 @@
// See the LICENSE file in the project root for more information.
using System;
-using System.Collections.Generic;
-using System.Linq;
using System.Net.Http;
-using System.Net.Http.Headers;
-using System.Reflection;
-using System.Text;
using System.Threading.Tasks;
-using System.Web;
using Microsoft.Graph;
-using Microsoft.Toolkit.Graph.Extensions;
+using Microsoft.Toolkit.Graph.Providers.Extensions;
namespace Microsoft.Toolkit.Graph.Providers
{
///
/// Provider to connect to the example data set for Microsoft Graph. Useful for prototyping and samples.
///
- public class MockProvider : IProvider
+ public class MockProvider : BaseProvider
{
private const string GRAPH_PROXY_URL = "https://proxy.apisandbox.msdn.microsoft.com/svc?url=";
- private ProviderState _state = ProviderState.Loading;
-
///
- public ProviderState State
- {
- get
- {
- return _state;
- }
-
- private set
- {
- var current = _state;
- _state = value;
-
- StateChanged?.Invoke(this, new StateChangedEventArgs(current, _state));
- }
- }
-
- ///
- public GraphServiceClient Graph => new GraphServiceClient(
+ public override GraphServiceClient Graph => new GraphServiceClient(
new DelegateAuthenticationProvider((requestMessage) =>
{
var requestUri = requestMessage.RequestUri.ToString();
@@ -54,16 +29,13 @@ private set
return this.AuthenticateRequestAsync(requestMessage);
}));
- ///
- public event EventHandler StateChanged;
-
///
/// Initializes a new instance of the class.
///
- /// Whether the default state should be signedIn, defaults to true.
- public MockProvider(bool signedIn = true)
+ /// Configuration for the MockProvider.
+ public MockProvider(MockConfig config = null)
{
- if (signedIn)
+ if (config == null || config.SignedIn)
{
State = ProviderState.SignedIn;
}
@@ -74,7 +46,7 @@ public MockProvider(bool signedIn = true)
}
///
- public Task AuthenticateRequestAsync(HttpRequestMessage request)
+ public override Task AuthenticateRequestAsync(HttpRequestMessage request)
{
request.AddSdkVersion();
@@ -84,7 +56,7 @@ public Task AuthenticateRequestAsync(HttpRequestMessage request)
}
///
- public async Task LoginAsync()
+ public override async Task LoginAsync()
{
State = ProviderState.Loading;
await Task.Delay(3000);
@@ -92,7 +64,7 @@ public async Task LoginAsync()
}
///
- public async Task LogoutAsync()
+ public override async Task LogoutAsync()
{
State = ProviderState.Loading;
await Task.Delay(3000);
diff --git a/Microsoft.Toolkit.Graph.Providers/Properties/AssemblyInfo.cs b/Microsoft.Toolkit.Graph.Providers/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..c244792
--- /dev/null
+++ b/Microsoft.Toolkit.Graph.Providers/Properties/AssemblyInfo.cs
@@ -0,0 +1,11 @@
+// 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.Resources;
+using System.Runtime.CompilerServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: NeutralResourcesLanguage("en-US")]
\ No newline at end of file
diff --git a/Microsoft.Toolkit.Graph.Providers/Properties/Microsoft.Toolkit.Graph.Providers.rd.xml b/Microsoft.Toolkit.Graph.Providers/Properties/Microsoft.Toolkit.Graph.Providers.rd.xml
new file mode 100644
index 0000000..b4f2d7f
--- /dev/null
+++ b/Microsoft.Toolkit.Graph.Providers/Properties/Microsoft.Toolkit.Graph.Providers.rd.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/Microsoft.Toolkit.Graph.Controls/Providers/ScopeSet.cs b/Microsoft.Toolkit.Graph.Providers/ScopeSet.cs
similarity index 100%
rename from Microsoft.Toolkit.Graph.Controls/Providers/ScopeSet.cs
rename to Microsoft.Toolkit.Graph.Providers/ScopeSet.cs
diff --git a/Microsoft.Toolkit.Graph/Microsoft.Toolkit.Graph.csproj b/Microsoft.Toolkit.Graph/Microsoft.Toolkit.Graph.csproj
index b29ab1d..6312d24 100644
--- a/Microsoft.Toolkit.Graph/Microsoft.Toolkit.Graph.csproj
+++ b/Microsoft.Toolkit.Graph/Microsoft.Toolkit.Graph.csproj
@@ -20,6 +20,12 @@
$(DefineConstants);WINRT
+
+
+
+
+
+
diff --git a/Microsoft.Toolkit.Graph/Providers/IProvider.cs b/Microsoft.Toolkit.Graph/Providers/IProvider.cs
index ea59b80..c6a4f07 100644
--- a/Microsoft.Toolkit.Graph/Providers/IProvider.cs
+++ b/Microsoft.Toolkit.Graph/Providers/IProvider.cs
@@ -29,7 +29,7 @@ public interface IProvider : IAuthenticationProvider
///
/// Event called when the login changes.
///
- event EventHandler StateChanged;
+ event EventHandler StateChanged;
///
/// Login the user.
diff --git a/Microsoft.Toolkit.Graph/Providers/ProviderManager.cs b/Microsoft.Toolkit.Graph/Providers/ProviderManager.cs
index e417de0..301c912 100644
--- a/Microsoft.Toolkit.Graph/Providers/ProviderManager.cs
+++ b/Microsoft.Toolkit.Graph/Providers/ProviderManager.cs
@@ -72,7 +72,7 @@ private ProviderManager()
// Use Instance
}
- private void ProviderStateChanged(object sender, StateChangedEventArgs e)
+ private void ProviderStateChanged(object sender, ProviderStateChangedEventArgs e)
{
ProviderUpdated?.Invoke(this, new ProviderUpdatedEventArgs(ProviderManagerChangedState.ProviderStateChanged));
}
diff --git a/Microsoft.Toolkit.Graph/Providers/StateChangedEventArgs.cs b/Microsoft.Toolkit.Graph/Providers/ProviderStateChangedEventArgs.cs
similarity index 80%
rename from Microsoft.Toolkit.Graph/Providers/StateChangedEventArgs.cs
rename to Microsoft.Toolkit.Graph/Providers/ProviderStateChangedEventArgs.cs
index f2f65d0..37b1c95 100644
--- a/Microsoft.Toolkit.Graph/Providers/StateChangedEventArgs.cs
+++ b/Microsoft.Toolkit.Graph/Providers/ProviderStateChangedEventArgs.cs
@@ -9,14 +9,14 @@ namespace Microsoft.Toolkit.Graph.Providers
///
/// event arguments.
///
- public class StateChangedEventArgs : EventArgs
+ public class ProviderStateChangedEventArgs : EventArgs
{
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
/// Previous .
/// Current .
- public StateChangedEventArgs(ProviderState oldState, ProviderState newState)
+ public ProviderStateChangedEventArgs(ProviderState oldState, ProviderState newState)
{
OldState = oldState;
NewState = newState;
diff --git a/Microsoft.Toolkit.Wpf.Graph.Providers/AssemblyInfo.cs b/Microsoft.Toolkit.Wpf.Graph.Providers/AssemblyInfo.cs
deleted file mode 100644
index a06202d..0000000
--- a/Microsoft.Toolkit.Wpf.Graph.Providers/AssemblyInfo.cs
+++ /dev/null
@@ -1,14 +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.Windows;
-
-[assembly: ThemeInfo(
- ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
- //(used if a resource is not found in the page,
- // or application resource dictionaries)
- ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
- //(used if a resource is not found in the page,
- // app, or any theme specific resource dictionaries)
-)]
diff --git a/Microsoft.Toolkit.Wpf.Graph.Providers/Behaviors/BehaviorBase.cs b/Microsoft.Toolkit.Wpf.Graph.Providers/Behaviors/BehaviorBase.cs
deleted file mode 100644
index 800df3c..0000000
--- a/Microsoft.Toolkit.Wpf.Graph.Providers/Behaviors/BehaviorBase.cs
+++ /dev/null
@@ -1,169 +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.Windows;
-using Microsoft.Xaml.Behaviors;
-
-namespace Microsoft.Toolkit.Wpf.UI.Behaviors
-{
- ///
- /// INTERNAL DO NOT USE, please thumb-up this comment https://github.com/windows-toolkit/Microsoft.Toolkit.Win32/issues/93#issuecomment-545091683 if you think this would be useful to you.
- /// Base class for behaviors that solves 2 problems:
- /// 1. Prevent duplicate initialization that can happen (prevent multiple OnAttached calls);
- /// 2. Whenever initially fails, this method will subscribe to to allow lazy initialization.
- ///
- /// The type of the associated object.
- ///
- ///
- /// For more info, see https://github.com/windows-toolkit/WindowsCommunityToolkit/issues/1008.
- ///
- public abstract class BehaviorBase : Behavior
- where T : UIElement
- {
- private bool _isAttaching;
- private bool _isAttached;
-
- ///
- /// Gets a value indicating whether this behavior is attached.
- ///
- ///
- /// true if this behavior is attached; otherwise, false.
- ///
- protected bool IsAttached
- {
- get { return _isAttached; }
- }
-
- ///
- /// Called after the behavior is attached to the .
- ///
- ///
- /// Override this to hook up functionality to the
- ///
- protected override void OnAttached()
- {
- base.OnAttached();
-
- HandleAttach();
-
- var frameworkElement = AssociatedObject as FrameworkElement;
- if (frameworkElement != null)
- {
- frameworkElement.Loaded += OnAssociatedObjectLoaded;
- frameworkElement.Unloaded += OnAssociatedObjectUnloaded;
- frameworkElement.SizeChanged += OnAssociatedObjectSizeChanged;
- }
- }
-
- ///
- /// Called when the behavior is being detached from its .
- ///
- ///
- /// Override this to unhook functionality from the
- ///
- protected override void OnDetaching()
- {
- base.OnDetaching();
-
- var frameworkElement = AssociatedObject as FrameworkElement;
- if (frameworkElement != null)
- {
- frameworkElement.Loaded -= OnAssociatedObjectLoaded;
- frameworkElement.Unloaded -= OnAssociatedObjectUnloaded;
- frameworkElement.SizeChanged -= OnAssociatedObjectSizeChanged;
- }
-
- HandleDetach();
- }
-
- ///
- /// Called when the associated object has been loaded.
- ///
- protected virtual void OnAssociatedObjectLoaded()
- {
- }
-
- ///
- /// Called when the associated object has been unloaded.
- ///
- protected virtual void OnAssociatedObjectUnloaded()
- {
- }
-
- ///
- /// Initializes the behavior to the associated object.
- ///
- /// true if the initialization succeeded; otherwise false.
- protected virtual bool Initialize()
- {
- return true;
- }
-
- ///
- /// Uninitializes the behavior from the associated object.
- ///
- /// true if uninitialization succeeded; otherwise false.
- protected virtual bool Uninitialize()
- {
- return true;
- }
-
- private void OnAssociatedObjectLoaded(object sender, RoutedEventArgs e)
- {
- if (!_isAttached)
- {
- HandleAttach();
- }
-
- OnAssociatedObjectLoaded();
- }
-
- private void OnAssociatedObjectUnloaded(object sender, RoutedEventArgs e)
- {
- OnAssociatedObjectUnloaded();
-
- // Note: don't detach here, we'll let the behavior implementation take care of that
- }
-
- private void OnAssociatedObjectSizeChanged(object sender, SizeChangedEventArgs e)
- {
- if (!_isAttached)
- {
- HandleAttach();
- }
- }
-
- private void HandleAttach()
- {
- if (_isAttaching || _isAttached)
- {
- return;
- }
-
- _isAttaching = true;
-
- var attached = Initialize();
- if (attached)
- {
- _isAttached = true;
- }
-
- _isAttaching = false;
- }
-
- private void HandleDetach()
- {
- if (!_isAttached)
- {
- return;
- }
-
- var detached = Uninitialize();
- if (detached)
- {
- _isAttached = false;
- }
- }
- }
-}
\ No newline at end of file
diff --git a/Microsoft.Toolkit.Wpf.Graph.Providers/Microsoft.Toolkit.Wpf.Graph.Providers.csproj b/Microsoft.Toolkit.Wpf.Graph.Providers/Microsoft.Toolkit.Wpf.Graph.Providers.csproj
deleted file mode 100644
index ae43cf0..0000000
--- a/Microsoft.Toolkit.Wpf.Graph.Providers/Microsoft.Toolkit.Wpf.Graph.Providers.csproj
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
- netcoreapp3.1
- true
- AnyCPU;x86;x64
- Debug;Release;CI
-
-
-
- DOTNET
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Microsoft.Toolkit.Wpf.Graph.Providers/Providers/ScopeSetTypeConverter.cs b/Microsoft.Toolkit.Wpf.Graph.Providers/Providers/ScopeSetTypeConverter.cs
deleted file mode 100644
index 2ce2951..0000000
--- a/Microsoft.Toolkit.Wpf.Graph.Providers/Providers/ScopeSetTypeConverter.cs
+++ /dev/null
@@ -1,45 +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.ComponentModel;
-using System.Globalization;
-
-namespace Microsoft.Toolkit.Wpf.Graph.Providers
-{
- ///
- ///
- ///
- public class ScopeSetTypeConverter : TypeConverter
- {
- ///
- public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
- {
- return sourceType == typeof(string);
- }
-
- ///
- public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
- {
- return ScopeSet.ConvertToScopeArray(value as string);
- }
-
- ///
- public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
- {
- return destinationType == typeof(string[]);
- }
-
- ///
- public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
- {
- if (value is ScopeSet set)
- {
- return string.Join(",", set);
- }
-
- return null;
- }
- }
-}
\ No newline at end of file
diff --git a/SampleTest/App.xaml b/SampleTest/App.xaml
index ea9689d..313f7e0 100644
--- a/SampleTest/App.xaml
+++ b/SampleTest/App.xaml
@@ -1,4 +1,23 @@
+ xmlns:providers="using:Microsoft.Toolkit.Graph.Providers">
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SampleTest/MainPage.xaml b/SampleTest/MainPage.xaml
index 272dfa1..6008d19 100644
--- a/SampleTest/MainPage.xaml
+++ b/SampleTest/MainPage.xaml
@@ -1,8 +1,6 @@
-
-
-
-
-
@@ -280,8 +268,8 @@
+ ResponseType="graph:ChatMessage"
+ x:Name="TeamsMessagePresenter">
-
-
-
-
-
- SampleTest
- mhawker
- Assets\StoreLogo.png
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+ SampleTest
+ mhawker
+ Assets\StoreLogo.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SampleTest/SampleTest.csproj b/SampleTest/SampleTest.csproj
index d3d8e97..8e95ffc 100644
--- a/SampleTest/SampleTest.csproj
+++ b/SampleTest/SampleTest.csproj
@@ -131,6 +131,7 @@
+
@@ -160,6 +161,18 @@
{42252ee8-7e68-428f-972b-6d2dd3aa12cc}
Microsoft.Toolkit.Graph.Controls
+
+ {36d0b51d-111b-4fc3-84e0-ce085172b9cc}
+ Microsoft.Toolkit.Graph.Providers.Msal
+
+
+ {6bb9c83f-eaee-4d9c-b184-b8834592828b}
+ Microsoft.Toolkit.Graph.Providers.Uwp
+
+
+ {10dff17a-183c-4112-9b94-b9e2aac5e4c8}
+ Microsoft.Toolkit.Graph.Providers
+
{B2246169-0CD8-473C-AFF6-172310E2C3F6}
Microsoft.Toolkit.Graph
diff --git a/Samples/XAML Islands/WPF-Core-GraphApp/MainWindow.xaml b/Samples/XAML Islands/WPF-Core-GraphApp/MainWindow.xaml
index 073b839..1429795 100644
--- a/Samples/XAML Islands/WPF-Core-GraphApp/MainWindow.xaml
+++ b/Samples/XAML Islands/WPF-Core-GraphApp/MainWindow.xaml
@@ -21,10 +21,10 @@
See MSAL docs about running on .NET Core: https://aka.ms/msal-net-os-browser
-->
-
-
+
diff --git a/Windows-Toolkit-Graph-Controls.sln b/Windows-Toolkit-Graph-Controls.sln
index 3ee888b..b8b2294 100644
--- a/Windows-Toolkit-Graph-Controls.sln
+++ b/Windows-Toolkit-Graph-Controls.sln
@@ -36,7 +36,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WPF-Core-GraphApp", "Sample
EndProject
Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "WPF-Packaged-App", "Samples\XAML Islands\WPF-Packaged-App\WPF-Packaged-App.wapproj", "{FE713229-AEE5-489A-9251-C346A82C1AC3}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Toolkit.Wpf.Graph.Providers", "Microsoft.Toolkit.Wpf.Graph.Providers\Microsoft.Toolkit.Wpf.Graph.Providers.csproj", "{8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Toolkit.Graph.Providers", "Microsoft.Toolkit.Graph.Providers\Microsoft.Toolkit.Graph.Providers.csproj", "{10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Toolkit.Graph.Providers.Msal", "Microsoft.Toolkit.Graph.Providers.Msal\Microsoft.Toolkit.Graph.Providers.Msal.csproj", "{36D0B51D-111B-4FC3-84E0-CE085172B9CC}"
+ ProjectSection(ProjectDependencies) = postProject
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8} = {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}
+ EndProjectSection
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Toolkit.Graph.Providers.Uwp", "Microsoft.Toolkit.Graph.Providers.Uwp\Microsoft.Toolkit.Graph.Providers.Uwp.csproj", "{6BB9C83F-EAEE-4D9C-B184-B8834592828B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -311,46 +318,126 @@ Global
{FE713229-AEE5-489A-9251-C346A82C1AC3}.Release|x86.ActiveCfg = Release|x86
{FE713229-AEE5-489A-9251-C346A82C1AC3}.Release|x86.Build.0 = Release|x86
{FE713229-AEE5-489A-9251-C346A82C1AC3}.Release|x86.Deploy.0 = Release|x86
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.CI|Any CPU.ActiveCfg = CI|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.CI|Any CPU.Build.0 = CI|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.CI|ARM.ActiveCfg = CI|x86
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.CI|ARM.Build.0 = CI|x86
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.CI|ARM64.ActiveCfg = CI|x64
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.CI|ARM64.Build.0 = CI|x64
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.CI|x64.ActiveCfg = CI|x64
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.CI|x64.Build.0 = CI|x64
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.CI|x86.ActiveCfg = CI|x86
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.CI|x86.Build.0 = CI|x86
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Debug|ARM.ActiveCfg = Debug|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Debug|ARM.Build.0 = Debug|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Debug|ARM64.ActiveCfg = Debug|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Debug|ARM64.Build.0 = Debug|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Debug|x64.ActiveCfg = Debug|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Debug|x64.Build.0 = Debug|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Debug|x86.ActiveCfg = Debug|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Debug|x86.Build.0 = Debug|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Native|Any CPU.ActiveCfg = Debug|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Native|Any CPU.Build.0 = Debug|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Native|ARM.ActiveCfg = Debug|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Native|ARM.Build.0 = Debug|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Native|ARM64.ActiveCfg = Debug|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Native|ARM64.Build.0 = Debug|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Native|x64.ActiveCfg = Debug|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Native|x64.Build.0 = Debug|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Native|x86.ActiveCfg = Debug|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Native|x86.Build.0 = Debug|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Release|Any CPU.Build.0 = Release|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Release|ARM.ActiveCfg = Release|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Release|ARM.Build.0 = Release|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Release|ARM64.ActiveCfg = Release|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Release|ARM64.Build.0 = Release|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Release|x64.ActiveCfg = Release|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Release|x64.Build.0 = Release|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Release|x86.ActiveCfg = Release|Any CPU
- {8B9BFE42-F526-4961-A1FD-2D2B6AA0C305}.Release|x86.Build.0 = Release|Any CPU
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.CI|Any CPU.ActiveCfg = CI|Any CPU
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.CI|Any CPU.Build.0 = CI|Any CPU
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.CI|ARM.ActiveCfg = CI|ARM
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.CI|ARM.Build.0 = CI|ARM
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.CI|ARM64.ActiveCfg = CI|ARM64
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.CI|ARM64.Build.0 = CI|ARM64
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.CI|x64.ActiveCfg = CI|x64
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.CI|x64.Build.0 = CI|x64
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.CI|x86.ActiveCfg = CI|x86
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.CI|x86.Build.0 = CI|x86
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Debug|ARM.ActiveCfg = Debug|ARM
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Debug|ARM.Build.0 = Debug|ARM
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Debug|ARM64.Build.0 = Debug|ARM64
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Debug|x64.ActiveCfg = Debug|x64
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Debug|x64.Build.0 = Debug|x64
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Debug|x86.ActiveCfg = Debug|x86
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Debug|x86.Build.0 = Debug|x86
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Native|Any CPU.ActiveCfg = Debug|Any CPU
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Native|Any CPU.Build.0 = Debug|Any CPU
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Native|ARM.ActiveCfg = Debug|ARM
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Native|ARM.Build.0 = Debug|ARM
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Native|ARM64.ActiveCfg = Debug|ARM64
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Native|ARM64.Build.0 = Debug|ARM64
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Native|x64.ActiveCfg = Debug|x64
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Native|x64.Build.0 = Debug|x64
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Native|x86.ActiveCfg = Debug|x86
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Native|x86.Build.0 = Debug|x86
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Release|ARM.ActiveCfg = Release|ARM
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Release|ARM.Build.0 = Release|ARM
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Release|ARM64.ActiveCfg = Release|ARM64
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Release|ARM64.Build.0 = Release|ARM64
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Release|x64.ActiveCfg = Release|x64
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Release|x64.Build.0 = Release|x64
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Release|x86.ActiveCfg = Release|x86
+ {10DFF17A-183C-4112-9B94-B9E2AAC5E4C8}.Release|x86.Build.0 = Release|x86
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.CI|Any CPU.ActiveCfg = CI|Any CPU
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.CI|Any CPU.Build.0 = CI|Any CPU
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.CI|ARM.ActiveCfg = CI|ARM
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.CI|ARM.Build.0 = CI|ARM
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.CI|ARM64.ActiveCfg = CI|ARM64
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.CI|ARM64.Build.0 = CI|ARM64
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.CI|x64.ActiveCfg = CI|x64
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.CI|x64.Build.0 = CI|x64
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.CI|x86.ActiveCfg = CI|x86
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.CI|x86.Build.0 = CI|x86
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Debug|ARM.ActiveCfg = Debug|ARM
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Debug|ARM.Build.0 = Debug|ARM
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Debug|ARM64.Build.0 = Debug|ARM64
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Debug|x64.ActiveCfg = Debug|x64
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Debug|x64.Build.0 = Debug|x64
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Debug|x86.ActiveCfg = Debug|x86
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Debug|x86.Build.0 = Debug|x86
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Native|Any CPU.ActiveCfg = Debug|Any CPU
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Native|Any CPU.Build.0 = Debug|Any CPU
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Native|ARM.ActiveCfg = Debug|ARM
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Native|ARM.Build.0 = Debug|ARM
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Native|ARM64.ActiveCfg = Debug|ARM64
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Native|ARM64.Build.0 = Debug|ARM64
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Native|x64.ActiveCfg = Debug|x64
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Native|x64.Build.0 = Debug|x64
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Native|x86.ActiveCfg = Debug|x86
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Native|x86.Build.0 = Debug|x86
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Release|ARM.ActiveCfg = Release|ARM
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Release|ARM.Build.0 = Release|ARM
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Release|ARM64.ActiveCfg = Release|ARM64
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Release|ARM64.Build.0 = Release|ARM64
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Release|x64.ActiveCfg = Release|x64
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Release|x64.Build.0 = Release|x64
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Release|x86.ActiveCfg = Release|x86
+ {36D0B51D-111B-4FC3-84E0-CE085172B9CC}.Release|x86.Build.0 = Release|x86
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.CI|Any CPU.ActiveCfg = CI|Any CPU
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.CI|Any CPU.Build.0 = CI|Any CPU
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.CI|ARM.ActiveCfg = CI|ARM
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.CI|ARM.Build.0 = CI|ARM
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.CI|ARM64.ActiveCfg = CI|ARM64
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.CI|ARM64.Build.0 = CI|ARM64
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.CI|x64.ActiveCfg = CI|x64
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.CI|x64.Build.0 = CI|x64
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.CI|x86.ActiveCfg = CI|x86
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.CI|x86.Build.0 = CI|x86
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Debug|ARM.ActiveCfg = Debug|ARM
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Debug|ARM.Build.0 = Debug|ARM
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Debug|ARM64.Build.0 = Debug|ARM64
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Debug|x64.ActiveCfg = Debug|x64
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Debug|x64.Build.0 = Debug|x64
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Debug|x86.ActiveCfg = Debug|x86
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Debug|x86.Build.0 = Debug|x86
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Native|Any CPU.ActiveCfg = Debug|Any CPU
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Native|Any CPU.Build.0 = Debug|Any CPU
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Native|ARM.ActiveCfg = Debug|ARM
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Native|ARM.Build.0 = Debug|ARM
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Native|ARM64.ActiveCfg = Debug|ARM64
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Native|ARM64.Build.0 = Debug|ARM64
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Native|x64.ActiveCfg = Debug|x64
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Native|x64.Build.0 = Debug|x64
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Native|x86.ActiveCfg = Debug|x86
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Native|x86.Build.0 = Debug|x86
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Release|ARM.ActiveCfg = Release|ARM
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Release|ARM.Build.0 = Release|ARM
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Release|ARM64.ActiveCfg = Release|ARM64
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Release|ARM64.Build.0 = Release|ARM64
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Release|x64.ActiveCfg = Release|x64
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Release|x64.Build.0 = Release|x64
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Release|x86.ActiveCfg = Release|x86
+ {6BB9C83F-EAEE-4D9C-B184-B8834592828B}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE