Skip to content

Commit 2e3fbef

Browse files
committed
Merge branch 'dev/7.1.0' of https://github.com/windows-toolkit/Graph-Controls into dev/7.1.0
2 parents ee0e531 + 9f9b5c5 commit 2e3fbef

File tree

10 files changed

+92
-133
lines changed

10 files changed

+92
-133
lines changed

CommunityToolkit.Authentication.Uwp/WindowsProvider.cs

Lines changed: 48 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ public class WindowsProvider : BaseProvider
6363
/// </summary>
6464
public WebAccountProviderConfig WebAccountProviderConfig => _webAccountProviderConfig;
6565

66+
/// <summary>
67+
/// Gets or sets which DispatcherQueue is used to dispatch UI updates.
68+
/// </summary>
69+
public DispatcherQueue DispatcherQueue { get; set; }
70+
6671
/// <summary>
6772
/// Gets a cache of important values for the signed in user.
6873
/// </summary>
@@ -71,7 +76,7 @@ public class WindowsProvider : BaseProvider
7176
private readonly string[] _scopes;
7277
private readonly AccountsSettingsPaneConfig? _accountsSettingsPaneConfig;
7378
private readonly WebAccountProviderConfig _webAccountProviderConfig;
74-
private WebAccount _webAccount;
79+
private WebAccount _webAccount = null;
7580

7681
/// <summary>
7782
/// Initializes a new instance of the <see cref="WindowsProvider"/> class.
@@ -80,7 +85,8 @@ public class WindowsProvider : BaseProvider
8085
/// <param name="accountsSettingsPaneConfig">Configuration values for the AccountsSettingsPane.</param>
8186
/// <param name="webAccountProviderConfig">Configuration value for determining the available web account providers.</param>
8287
/// <param name="autoSignIn">Determines whether the provider attempts to silently log in upon construction.</param>
83-
public WindowsProvider(string[] scopes = null, WebAccountProviderConfig? webAccountProviderConfig = null, AccountsSettingsPaneConfig? accountsSettingsPaneConfig = null, bool autoSignIn = true)
88+
/// <param name="dispatcherQueue">The DispatcherQueue that should be used to dispatch UI updates, or null if this is being called from the UI thread.</param>
89+
public WindowsProvider(string[] scopes = null, WebAccountProviderConfig? webAccountProviderConfig = null, AccountsSettingsPaneConfig? accountsSettingsPaneConfig = null, bool autoSignIn = true, DispatcherQueue dispatcherQueue = null)
8490
{
8591
_scopes = scopes ?? DefaultScopes;
8692
_webAccountProviderConfig = webAccountProviderConfig ?? new WebAccountProviderConfig()
@@ -89,7 +95,7 @@ public WindowsProvider(string[] scopes = null, WebAccountProviderConfig? webAcco
8995
};
9096
_accountsSettingsPaneConfig = accountsSettingsPaneConfig;
9197

92-
_webAccount = null;
98+
DispatcherQueue = dispatcherQueue ?? DispatcherQueue.GetForCurrentThread();
9399

94100
State = ProviderState.SignedOut;
95101

@@ -198,21 +204,7 @@ public override async Task<string> GetTokenAsync(bool silentOnly = false)
198204
}
199205

200206
// Attempt to authenticate interactively.
201-
var tcs = new TaskCompletionSource<WebTokenRequestResult>();
202-
var taskQueued = DispatcherQueue.GetForCurrentThread().TryEnqueue(async () =>
203-
{
204-
var result = await AuthenticateInteractiveAsync(_scopes);
205-
tcs.SetResult(result);
206-
});
207-
208-
if (taskQueued)
209-
{
210-
authResult = await tcs.Task;
211-
}
212-
else
213-
{
214-
tcs.SetCanceled();
215-
}
207+
authResult = await AuthenticateInteractiveAsync(_scopes);
216208
}
217209

218210
if (authResult?.ResponseStatus == WebTokenRequestStatus.Success)
@@ -249,15 +241,15 @@ public override async Task<string> GetTokenAsync(bool silentOnly = false)
249241
/// Display AccountSettingsPane for the management of logged-in users.
250242
/// </summary>
251243
/// <returns><see cref="Task"/>.</returns>
252-
public async Task ShowAccountManagementPaneAsync()
244+
public Task ShowAccountManagementPaneAsync()
253245
{
254246
if (_webAccount == null)
255247
{
256248
throw new InvalidOperationException("A logged in account is required to display the account management pane.");
257249
}
258250

259251
var tcs = new TaskCompletionSource<bool>();
260-
_ = DispatcherQueue.GetForCurrentThread().TryEnqueue(async () =>
252+
var taskQueued = DispatcherQueue.TryEnqueue(async () =>
261253
{
262254
AccountsSettingsPane pane = null;
263255
try
@@ -284,7 +276,12 @@ public async Task ShowAccountManagementPaneAsync()
284276
}
285277
});
286278

287-
await tcs.Task;
279+
if (!taskQueued)
280+
{
281+
tcs.SetException(new InvalidOperationException("Failed to enqueue the operation."));
282+
}
283+
284+
return tcs.Task;
288285
}
289286

290287
/// <summary>
@@ -392,34 +389,45 @@ private async Task<WebTokenRequestResult> AuthenticateSilentAsync(string[] scope
392389
}
393390
}
394391

395-
private async Task<WebTokenRequestResult> AuthenticateInteractiveAsync(string[] scopes)
392+
private Task<WebTokenRequestResult> AuthenticateInteractiveAsync(string[] scopes)
396393
{
397-
try
394+
var tcs = new TaskCompletionSource<WebTokenRequestResult>();
395+
var taskQueued = DispatcherQueue.TryEnqueue(async () =>
398396
{
399-
WebTokenRequestResult authResult = null;
400-
401-
var account = _webAccount;
402-
if (account != null)
397+
try
403398
{
404-
// We already have the account.
405-
var webAccountProvider = account.WebAccountProvider;
406-
var webTokenRequest = GetWebTokenRequest(webAccountProvider, _webAccountProviderConfig.ClientId, scopes);
407-
authResult = await WebAuthenticationCoreManager.RequestTokenAsync(webTokenRequest, account);
399+
WebTokenRequestResult authResult = null;
400+
401+
var account = _webAccount;
402+
if (account != null)
403+
{
404+
// We already have the account.
405+
var webAccountProvider = account.WebAccountProvider;
406+
var webTokenRequest = GetWebTokenRequest(webAccountProvider, _webAccountProviderConfig.ClientId, scopes);
407+
authResult = await WebAuthenticationCoreManager.RequestTokenAsync(webTokenRequest, account);
408+
}
409+
else
410+
{
411+
// We don't have an account. Prompt the user to provide one.
412+
var webAccountProvider = await ShowAccountSettingsPaneAndGetProviderAsync();
413+
var webTokenRequest = GetWebTokenRequest(webAccountProvider, _webAccountProviderConfig.ClientId, scopes);
414+
authResult = await WebAuthenticationCoreManager.RequestTokenAsync(webTokenRequest);
415+
}
416+
417+
tcs.SetResult(authResult);
408418
}
409-
else
419+
catch (Exception e)
410420
{
411-
// We don't have an account. Prompt the user to provide one.
412-
var webAccountProvider = await ShowAccountSettingsPaneAndGetProviderAsync();
413-
var webTokenRequest = GetWebTokenRequest(webAccountProvider, _webAccountProviderConfig.ClientId, scopes);
414-
authResult = await WebAuthenticationCoreManager.RequestTokenAsync(webTokenRequest);
421+
tcs.SetException(e);
415422
}
423+
});
416424

417-
return authResult;
418-
}
419-
catch (HttpRequestException)
425+
if (!taskQueued)
420426
{
421-
throw; /* probably offline, no point continuing to interactive auth */
427+
tcs.SetException(new InvalidOperationException("Failed to enqueue the operation."));
422428
}
429+
430+
return tcs.Task;
423431
}
424432

425433
/// <summary>

CommunityToolkit.Graph.Uwp/CommunityToolkit.Graph.Uwp.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
</ItemGroup>
2323

2424
<ItemGroup>
25-
<PackageReference Include="Microsoft.Graph" Version="3.31.0" />
25+
<PackageReference Include="Microsoft.Graph" Version="4.0.0" />
2626
<PackageReference Include="Microsoft.Toolkit.Uwp.UI" Version="7.0.1" />
2727
<PackageReference Include="Microsoft.Toolkit.Uwp.UI.Controls.Input" Version="7.0.1" />
2828
</ItemGroup>

CommunityToolkit.Graph.Uwp/Controls/GraphPresenter/GraphPresenter.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,7 @@ private async void GraphPresenter_Loaded(object sender, RoutedEventArgs e)
7777
var request = new BaseRequest(
7878
RequestBuilder.RequestUrl,
7979
RequestBuilder.Client); // TODO: Do we need separate Options here?
80-
////request.Method = HttpMethods.GET;
81-
request.Method = "GET";
80+
request.Method = HttpMethods.GET;
8281
request.QueryOptions = QueryOptions?.Select(option => (Microsoft.Graph.QueryOption)option)?.ToList() ?? new List<Microsoft.Graph.QueryOption>();
8382

8483
// Handle Special QueryOptions

CommunityToolkit.Graph/CommunityToolkit.Graph.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
</PropertyGroup>
1414

1515
<ItemGroup>
16-
<PackageReference Include="Microsoft.Graph" Version="3.31.0" />
16+
<PackageReference Include="Microsoft.Graph" Version="4.0.0" />
1717
</ItemGroup>
1818

1919
<ItemGroup>

SampleTest/App.xaml.cs

Lines changed: 27 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,8 @@ sealed partial class App : Application
2424
public App()
2525
{
2626
this.InitializeComponent();
27-
this.Suspending += OnSuspending;
2827
}
2928

30-
// Which provider should be used for authentication?
31-
private readonly ProviderType _providerType = ProviderType.Mock;
32-
3329
// List of available authentication providers.
3430
private enum ProviderType
3531
{
@@ -38,42 +34,42 @@ private enum ProviderType
3834
Windows
3935
}
4036

37+
// Which provider should be used for authentication?
38+
private readonly ProviderType _providerType = ProviderType.Mock;
39+
4140
/// <summary>
4241
/// Initialize the global authentication provider.
4342
/// </summary>
44-
private async void InitializeGlobalProvider()
43+
private void InitializeGlobalProvider()
4544
{
4645
if (ProviderManager.Instance.GlobalProvider != null)
4746
{
4847
return;
4948
}
5049

51-
await Window.Current.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
52-
{
53-
// Provider config
54-
string clientId = "YOUR_CLIENT_ID_HERE";
55-
string[] scopes = { "User.Read", "User.ReadBasic.All", "People.Read", "Calendars.Read", "Mail.Read", "Group.Read.All", "ChannelMessage.Read.All" };
56-
bool autoSignIn = true;
50+
// Provider config
51+
string clientId = "YOUR_CLIENT_ID_HERE";
52+
string[] scopes = { "User.Read", "User.ReadBasic.All", "People.Read", "Calendars.Read", "Mail.Read", "Group.Read.All", "ChannelMessage.Read.All" };
53+
bool autoSignIn = true;
5754

58-
switch (_providerType)
59-
{
60-
// Mock provider
61-
case ProviderType.Mock:
62-
ProviderManager.Instance.GlobalProvider = new MockProvider(signedIn: autoSignIn);
63-
break;
64-
65-
// Msal provider
66-
case ProviderType.Msal:
67-
ProviderManager.Instance.GlobalProvider = new MsalProvider(clientId: clientId, scopes: scopes, autoSignIn: autoSignIn);
68-
break;
69-
70-
// Windows provider
71-
case ProviderType.Windows:
72-
var webAccountProviderConfig = new WebAccountProviderConfig(WebAccountProviderType.Msa, clientId);
73-
ProviderManager.Instance.GlobalProvider = new WindowsProvider(scopes, webAccountProviderConfig: webAccountProviderConfig, autoSignIn: autoSignIn);
74-
break;
75-
}
76-
});
55+
switch (_providerType)
56+
{
57+
// Mock provider
58+
case ProviderType.Mock:
59+
ProviderManager.Instance.GlobalProvider = new MockProvider(signedIn: autoSignIn);
60+
break;
61+
62+
// Msal provider
63+
case ProviderType.Msal:
64+
ProviderManager.Instance.GlobalProvider = new MsalProvider(clientId: clientId, scopes: scopes, autoSignIn: autoSignIn);
65+
break;
66+
67+
// Windows provider
68+
case ProviderType.Windows:
69+
var webAccountProviderConfig = new WebAccountProviderConfig(WebAccountProviderType.Msa, clientId);
70+
ProviderManager.Instance.GlobalProvider = new WindowsProvider(scopes, webAccountProviderConfig: webAccountProviderConfig, autoSignIn: autoSignIn);
71+
break;
72+
}
7773
}
7874

7975
/// <summary>
@@ -84,63 +80,23 @@ await Window.Current.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.
8480
protected override void OnLaunched(LaunchActivatedEventArgs e)
8581
{
8682
Frame rootFrame = Window.Current.Content as Frame;
87-
88-
// Do not repeat app initialization when the Window already has content,
89-
// just ensure that the window is active
9083
if (rootFrame == null)
9184
{
92-
// Create a Frame to act as the navigation context and navigate to the first page
9385
rootFrame = new Frame();
94-
95-
rootFrame.NavigationFailed += OnNavigationFailed;
96-
97-
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
98-
{
99-
//TODO: Load state from previously suspended application
100-
}
101-
102-
// Place the frame in the current Window
10386
Window.Current.Content = rootFrame;
10487
}
10588

10689
if (e.PrelaunchActivated == false)
10790
{
10891
if (rootFrame.Content == null)
10992
{
110-
// When the navigation stack isn't restored navigate to the first page,
111-
// configuring the new page by passing required information as a navigation
112-
// parameter
11393
rootFrame.Navigate(typeof(MainPage), e.Arguments);
11494
}
115-
// Ensure the current window is active
95+
11696
Window.Current.Activate();
11797

11898
InitializeGlobalProvider();
11999
}
120100
}
121-
122-
/// <summary>
123-
/// Invoked when Navigation to a certain page fails
124-
/// </summary>
125-
/// <param name="sender">The Frame which failed navigation</param>
126-
/// <param name="e">Details about the navigation failure</param>
127-
void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
128-
{
129-
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
130-
}
131-
132-
/// <summary>
133-
/// Invoked when application execution is being suspended. Application state is saved
134-
/// without knowing whether the application will be terminated or resumed with the contents
135-
/// of memory still intact.
136-
/// </summary>
137-
/// <param name="sender">The source of the suspend request.</param>
138-
/// <param name="e">Details about the suspend request.</param>
139-
private void OnSuspending(object sender, SuspendingEventArgs e)
140-
{
141-
var deferral = e.SuspendingOperation.GetDeferral();
142-
//TODO: Save application state and stop any background activity
143-
deferral.Complete();
144-
}
145101
}
146102
}

SampleTest/SampleTest.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@
168168
</ItemGroup>
169169
<ItemGroup>
170170
<PackageReference Include="Microsoft.Graph">
171-
<Version>3.31.0</Version>
171+
<Version>4.0.0</Version>
172172
</PackageReference>
173173
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
174174
<Version>6.2.12</Version>

Samples/ManualGraphRequestSample/App.xaml.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ protected override void OnLaunched(LaunchActivatedEventArgs e)
3131
{
3232
rootFrame.Navigate(typeof(MainPage), e.Arguments);
3333
}
34+
3435
Window.Current.Activate();
3536
}
3637
}

Samples/UwpMsalProviderSample/App.xaml.cs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,12 @@ public App()
2222
/// </summary>
2323
void ConfigureGlobalProvider()
2424
{
25-
DispatcherQueue.GetForCurrentThread().TryEnqueue(DispatcherQueuePriority.Normal, () =>
25+
if (ProviderManager.Instance.GlobalProvider == null)
2626
{
27-
if (ProviderManager.Instance.GlobalProvider == null)
28-
{
29-
string clientId = "YOUR-CLIENT-ID-HERE";
30-
string[] scopes = new string[] { "User.Read" };
31-
ProviderManager.Instance.GlobalProvider = new MsalProvider(clientId, scopes);
32-
}
33-
});
27+
string clientId = "YOUR-CLIENT-ID-HERE";
28+
string[] scopes = new string[] { "User.Read" };
29+
ProviderManager.Instance.GlobalProvider = new MsalProvider(clientId, scopes);
30+
}
3431
}
3532

3633
protected override void OnLaunched(LaunchActivatedEventArgs e)
@@ -48,6 +45,7 @@ protected override void OnLaunched(LaunchActivatedEventArgs e)
4845
{
4946
rootFrame.Navigate(typeof(MainPage), e.Arguments);
5047
}
48+
5149
Window.Current.Activate();
5250

5351
ConfigureGlobalProvider();

0 commit comments

Comments
 (0)