Added ProviderStateChanged event to ProviderManager (#112)

* Added ProviderStateChanged event to ProviderManager and adjust ProviderUpdated usage

* Removed unused ProviderUpdatedEventArgs and ProviderManagerChangedState

* Fixed provider pattern in ProviderStateTrigger
This commit is contained in:
Shane Weaver 2021-06-11 10:28:54 -07:00 коммит произвёл GitHub
Родитель 0a762c6213
Коммит e875ff5703
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
19 изменённых файлов: 83 добавлений и 160 удалений

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

@ -7,12 +7,10 @@
This package includes .NET Standard authentication helpers such as: This package includes .NET Standard authentication helpers such as:
- BaseProvider: - BaseProvider:
- IProvider: - IProvider:
- MockPRovider: - MockProvider:
- ProviderManager: - ProviderManager:
- ProviderManagerChangedState:
- ProviderState: - ProviderState:
- ProviderStateChangedEventArgs: - ProviderStateChangedEventArgs:
- ProviderUpdatedEventArgs:
</Description> </Description>
<PackageTags>Community Toolkit Provider Authentication Auth</PackageTags> <PackageTags>Community Toolkit Provider Authentication Auth</PackageTags>
</PropertyGroup> </PropertyGroup>

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

@ -15,7 +15,7 @@ namespace CommunityToolkit.Authentication
/// ProviderManager.Instance.GlobalProvider = await MsalProvider.CreateAsync(...); /// ProviderManager.Instance.GlobalProvider = await MsalProvider.CreateAsync(...);
/// </code> /// </code>
/// </example> /// </example>
public partial class ProviderManager : INotifyPropertyChanged public partial class ProviderManager
{ {
/// <summary> /// <summary>
/// Gets the name of the toolkit client to identify self in Graph calls. /// Gets the name of the toolkit client to identify self in Graph calls.
@ -28,12 +28,14 @@ namespace CommunityToolkit.Authentication
public static ProviderManager Instance { get; } = new ProviderManager(); public static ProviderManager Instance { get; } = new ProviderManager();
/// <summary> /// <summary>
/// Event called when the <see cref="IProvider"/> changes. /// Event called when the <see cref="IProvider"/> instance changes.
/// </summary> /// </summary>
public event EventHandler<ProviderUpdatedEventArgs> ProviderUpdated; public event EventHandler<IProvider> ProviderUpdated;
/// <inheritdoc/> /// <summary>
public event PropertyChangedEventHandler PropertyChanged; /// Event called when the <see cref="IProvider"/> state changes.
/// </summary>
public event EventHandler<ProviderStateChangedEventArgs> ProviderStateChanged;
private IProvider _provider; private IProvider _provider;
@ -49,6 +51,7 @@ namespace CommunityToolkit.Authentication
set set
{ {
var oldState = _provider?.State;
if (_provider != null) if (_provider != null)
{ {
_provider.StateChanged -= ProviderStateChanged; _provider.StateChanged -= ProviderStateChanged;
@ -56,14 +59,14 @@ namespace CommunityToolkit.Authentication
_provider = value; _provider = value;
var newState = _provider?.State;
if (_provider != null) if (_provider != null)
{ {
_provider.StateChanged += ProviderStateChanged; _provider.StateChanged += ProviderStateChanged;
} }
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(GlobalProvider))); ProviderUpdated?.Invoke(this, _provider);
ProviderUpdated?.Invoke(this, new ProviderUpdatedEventArgs(ProviderManagerChangedState.ProviderChanged)); ProviderStateChanged?.Invoke(this, new ProviderStateChangedEventArgs(oldState, newState));
ProviderUpdated?.Invoke(this, new ProviderUpdatedEventArgs(ProviderManagerChangedState.ProviderStateChanged));
} }
} }
@ -71,10 +74,5 @@ namespace CommunityToolkit.Authentication
{ {
// Use Instance // Use Instance
} }
private void ProviderStateChanged(object sender, ProviderStateChangedEventArgs e)
{
ProviderUpdated?.Invoke(this, new ProviderUpdatedEventArgs(ProviderManagerChangedState.ProviderStateChanged));
}
} }
} }

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

@ -1,22 +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.
namespace CommunityToolkit.Authentication
{
/// <summary>
/// Enum representing reasons for provider state changing.
/// </summary>
public enum ProviderManagerChangedState
{
/// <summary>
/// The <see cref="IProvider"/> itself changed.
/// </summary>
ProviderChanged,
/// <summary>
/// The <see cref="IProvider.State"/> changed.
/// </summary>
ProviderStateChanged,
}
}

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

@ -16,7 +16,7 @@ namespace CommunityToolkit.Authentication
/// </summary> /// </summary>
/// <param name="oldState">Previous <see cref="ProviderState"/>.</param> /// <param name="oldState">Previous <see cref="ProviderState"/>.</param>
/// <param name="newState">Current <see cref="ProviderState"/>.</param> /// <param name="newState">Current <see cref="ProviderState"/>.</param>
public ProviderStateChangedEventArgs(ProviderState oldState, ProviderState newState) public ProviderStateChangedEventArgs(ProviderState? oldState, ProviderState? newState)
{ {
OldState = oldState; OldState = oldState;
NewState = newState; NewState = newState;
@ -25,11 +25,11 @@ namespace CommunityToolkit.Authentication
/// <summary> /// <summary>
/// Gets the previous state of the <see cref="IProvider"/>. /// Gets the previous state of the <see cref="IProvider"/>.
/// </summary> /// </summary>
public ProviderState OldState { get; private set; } public ProviderState? OldState { get; private set; }
/// <summary> /// <summary>
/// Gets the new state of the <see cref="IProvider"/>. /// Gets the new state of the <see cref="IProvider"/>.
/// </summary> /// </summary>
public ProviderState NewState { get; private set; } public ProviderState? NewState { get; private set; }
} }
} }

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

@ -1,28 +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;
namespace CommunityToolkit.Authentication
{
/// <summary>
/// <see cref="EventArgs"/> class for <see cref="ProviderManager.ProviderUpdated"/> event.
/// </summary>
public class ProviderUpdatedEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="ProviderUpdatedEventArgs"/> class.
/// </summary>
/// <param name="reason"><see cref="ProviderManagerChangedState"/> value for reason for update.</param>
public ProviderUpdatedEventArgs(ProviderManagerChangedState reason)
{
Reason = reason;
}
/// <summary>
/// Gets the reason for the provider update.
/// </summary>
public ProviderManagerChangedState Reason { get; private set; }
}
}

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

@ -34,7 +34,7 @@ namespace CommunityToolkit.Graph.Uwp.Controls
{ {
this.DefaultStyleKey = typeof(LoginButton); this.DefaultStyleKey = typeof(LoginButton);
ProviderManager.Instance.ProviderUpdated += (sender, args) => LoadData(); ProviderManager.Instance.ProviderStateChanged += (sender, args) => LoadData();
} }
/// <inheritdoc/> /// <inheritdoc/>

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

@ -91,7 +91,7 @@ namespace CommunityToolkit.Graph.Uwp.Controls
_defaultImage = new BitmapImage(new Uri(_defaultImageSource)); _defaultImage = new BitmapImage(new Uri(_defaultImageSource));
ProviderManager.Instance.ProviderUpdated += (sender, args) => LoadData(); ProviderManager.Instance.ProviderStateChanged += (sender, args) => LoadData();
} }
/// <inheritdoc/> /// <inheritdoc/>

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

@ -47,16 +47,16 @@ namespace CommunityToolkit.Graph.Uwp
{ {
_dispatcherQueue = DispatcherQueue.GetForCurrentThread(); _dispatcherQueue = DispatcherQueue.GetForCurrentThread();
var weakEvent = var weakEvent =
new WeakEventListener<ProviderStateTrigger, object, ProviderUpdatedEventArgs>(this) new WeakEventListener<ProviderStateTrigger, object, ProviderStateChangedEventArgs>(this)
{ {
OnEventAction = (instance, source, args) => OnProviderUpdated(source, args), OnEventAction = (instance, source, args) => OnProviderStateChanged(source, args),
OnDetachAction = (weakEventListener) => ProviderManager.Instance.ProviderUpdated -= weakEventListener.OnEvent, OnDetachAction = (weakEventListener) => ProviderManager.Instance.ProviderStateChanged -= weakEventListener.OnEvent,
}; };
ProviderManager.Instance.ProviderUpdated += weakEvent.OnEvent; ProviderManager.Instance.ProviderStateChanged += weakEvent.OnEvent;
UpdateState(); UpdateState();
} }
private void OnProviderUpdated(object sender, ProviderUpdatedEventArgs e) private void OnProviderStateChanged(object sender, ProviderStateChangedEventArgs e)
{ {
_ = _dispatcherQueue.EnqueueAsync(UpdateState, DispatcherQueuePriority.Normal); _ = _dispatcherQueue.EnqueueAsync(UpdateState, DispatcherQueuePriority.Normal);
} }

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

@ -12,60 +12,30 @@ namespace CommunityToolkit.Graph.Extensions
/// </summary> /// </summary>
public static class ProviderExtensions public static class ProviderExtensions
{ {
private static GraphServiceClient _client;
private static GraphServiceClient _betaClient;
static ProviderExtensions()
{
ProviderManager.Instance.ProviderUpdated += OnProviderUpdated;
}
private static void OnProviderUpdated(object sender, ProviderUpdatedEventArgs e)
{
var providerManager = sender as ProviderManager;
if (e.Reason == ProviderManagerChangedState.ProviderChanged || !(providerManager.GlobalProvider?.State == ProviderState.SignedIn))
{
_client = null;
_betaClient = null;
}
}
/// <summary> /// <summary>
/// Lazily gets a GraphServiceClient instance based on the current GlobalProvider. /// Gets a GraphServiceClient instance based on the current GlobalProvider.
/// The client instance is cleared whenever the GlobalProvider changes.
/// </summary> /// </summary>
/// <param name="provider">The provider for authenticating Graph calls.</param> /// <param name="provider">The provider for authenticating Graph calls.</param>
/// <returns>A GraphServiceClient instance.</returns> /// <returns>A GraphServiceClient instance.</returns>
public static GraphServiceClient GetClient(this IProvider provider) public static GraphServiceClient GetClient(this IProvider provider)
{ {
if (_client == null && provider?.State == ProviderState.SignedIn) return new GraphServiceClient(new DelegateAuthenticationProvider(async (requestMessage) =>
{ {
_client = new GraphServiceClient(new DelegateAuthenticationProvider(async (requestMessage) => await provider.AuthenticateRequestAsync(requestMessage);
{ }));
await provider.AuthenticateRequestAsync(requestMessage);
}));
}
return _client;
} }
/// <summary> /// <summary>
/// Lazily gets a GraphServiceClient instance based on the current GlobalProvider, but configured for the beta endpoint. /// Gets a GraphServiceClient instance based on the current GlobalProvider, but configured for the beta endpoint.
/// The beta client instance is cleared whenever the GlobalProvider changes.
/// </summary> /// </summary>
/// <param name="provider">The provider for authenticating Graph calls.</param> /// <param name="provider">The provider for authenticating Graph calls.</param>
/// <returns>A GraphServiceClient instance configured for the beta endpoint.</returns> /// <returns>A GraphServiceClient instance configured for the beta endpoint.</returns>
public static GraphServiceClient GetBetaClient(this IProvider provider) public static GraphServiceClient GetBetaClient(this IProvider provider)
{ {
if (_betaClient == null && provider?.State == ProviderState.SignedIn) return new GraphServiceClient("https://graph.microsoft.com/beta", new DelegateAuthenticationProvider(async (requestMessage) =>
{ {
_betaClient = new GraphServiceClient("https://graph.microsoft.com/beta", new DelegateAuthenticationProvider(async (requestMessage) => await provider.AuthenticateRequestAsync(requestMessage);
{ }));
await provider.AuthenticateRequestAsync(requestMessage);
}));
}
return _betaClient;
} }
} }
} }

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

@ -144,7 +144,7 @@ private async Task<IList<TodoTask>> GetDefaultTaskListAsync()
**That's all you need to get started!** **That's all you need to get started!**
You can use the `ProviderManager.Instance` to listen to changes in authentication status with the `ProviderUpdated` event or get direct access to the [.NET Graph Beta API](https://github.com/microsoftgraph/msgraph-beta-sdk-dotnet) through `ProviderManager.Instance.GlobalProvider.GetBetaClient()`, just be sure to check if the `GlobalProvider` has been set first and its `State` is `SignedIn`: You can use the `ProviderManager.Instance` to listen to changes in authentication status with the `ProviderStateChanged` event or get direct access to the [.NET Graph Beta API](https://github.com/microsoftgraph/msgraph-beta-sdk-dotnet) through `ProviderManager.Instance.GlobalProvider.GetBetaClient()`, just be sure to check if the `GlobalProvider` has been set first and its `State` is `SignedIn`:
```csharp ```csharp
using CommunityToolkit.Authentication; using CommunityToolkit.Authentication;

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

@ -33,13 +33,12 @@ namespace SampleTest
this.InitializeComponent(); this.InitializeComponent();
ProviderManager.Instance.ProviderUpdated += this.OnProviderUpdated; ProviderManager.Instance.ProviderUpdated += this.OnProviderUpdated;
ProviderManager.Instance.ProviderStateChanged += this.OnProviderStateChanged;
} }
private void OnProviderUpdated(object sender, ProviderUpdatedEventArgs e) private void OnProviderStateChanged(object sender, ProviderStateChangedEventArgs e)
{ {
if (e.Reason == ProviderManagerChangedState.ProviderStateChanged if (e.NewState == ProviderState.SignedIn)
&& sender is ProviderManager pm
&& pm.GlobalProvider.State == ProviderState.SignedIn)
{ {
var graphClient = ProviderManager.Instance.GlobalProvider.GetClient(); var graphClient = ProviderManager.Instance.GlobalProvider.GetClient();
@ -50,13 +49,26 @@ namespace SampleTest
} }
else else
{ {
CalendarViewBuilder = null; ClearRequestBuilders();
MessagesBuilder = null;
PlannerTasksBuilder = null;
TeamsChannelMessagesBuilder = null;
} }
} }
private void OnProviderUpdated(object sender, IProvider provider)
{
if (provider == null)
{
ClearRequestBuilders();
}
}
private void ClearRequestBuilders()
{
CalendarViewBuilder = null;
MessagesBuilder = null;
PlannerTasksBuilder = null;
TeamsChannelMessagesBuilder = null;
}
public static string ToLocalTime(DateTimeTimeZone value) public static string ToLocalTime(DateTimeTimeZone value)
{ {
// Workaround for https://github.com/microsoft/microsoft-ui-xaml/issues/2407 // Workaround for https://github.com/microsoft/microsoft-ui-xaml/issues/2407

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

@ -55,7 +55,7 @@ namespace SampleTest.Samples
_keyInputText = string.Empty; _keyInputText = string.Empty;
_valueInputText = string.Empty; _valueInputText = string.Empty;
ProviderManager.Instance.ProviderUpdated += (s, e) => CheckState(); ProviderManager.Instance.ProviderStateChanged += (s, e) => CheckState();
CheckState(); CheckState();
} }

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

@ -23,15 +23,13 @@ namespace ManualGraphRequestSample
{ {
InitializeComponent(); InitializeComponent();
ProviderManager.Instance.ProviderUpdated += OnProviderUpdated; ProviderManager.Instance.ProviderStateChanged += OnProviderStateChanged;
ProviderManager.Instance.GlobalProvider = new WindowsProvider(new string[] { "User.Read", "Tasks.ReadWrite" }); ProviderManager.Instance.GlobalProvider = new WindowsProvider(new string[] { "User.Read", "Tasks.ReadWrite" });
} }
private async void OnProviderUpdated(object sender, ProviderUpdatedEventArgs e) private async void OnProviderStateChanged(object sender, ProviderStateChangedEventArgs e)
{ {
IProvider provider = ProviderManager.Instance.GlobalProvider; switch (e.NewState)
switch (provider?.State)
{ {
case ProviderState.Loading: case ProviderState.Loading:
SignInButton.Content = "Loading..."; SignInButton.Content = "Loading...";

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

@ -14,25 +14,24 @@ namespace UwpMsalProviderSample
{ {
this.InitializeComponent(); this.InitializeComponent();
ProviderManager.Instance.ProviderUpdated += OnProviderUpdated; ProviderManager.Instance.ProviderStateChanged += OnProviderStateChanged;
} }
private async void OnProviderUpdated(object sender, ProviderUpdatedEventArgs e) private async void OnProviderStateChanged(object sender, ProviderStateChangedEventArgs e)
{ {
var provider = ProviderManager.Instance.GlobalProvider; if (e.NewState == ProviderState.SignedIn)
if (provider == null || provider.State != ProviderState.SignedIn)
{
SignedInUserTextBlock.Text = "Please sign in.";
}
else
{ {
SignedInUserTextBlock.Text = "Signed in as..."; SignedInUserTextBlock.Text = "Signed in as...";
var graphClient = provider.GetClient(); var graphClient = ProviderManager.Instance.GlobalProvider.GetClient();
var me = await graphClient.Me.Request().GetAsync(); var me = await graphClient.Me.Request().GetAsync();
SignedInUserTextBlock.Text = "Signed in as: " + me.DisplayName; SignedInUserTextBlock.Text = "Signed in as: " + me.DisplayName;
} }
else
{
SignedInUserTextBlock.Text = "Please sign in.";
}
} }
} }
} }

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

@ -14,27 +14,26 @@ namespace UwpWindowsProviderSample
{ {
this.InitializeComponent(); this.InitializeComponent();
ProviderManager.Instance.ProviderUpdated += OnProviderUpdated; ProviderManager.Instance.ProviderStateChanged += OnProviderStateChanged;
} }
private async void OnProviderUpdated(object sender, ProviderUpdatedEventArgs e) private async void OnProviderStateChanged(object sender, ProviderStateChangedEventArgs e)
{ {
var provider = ProviderManager.Instance.GlobalProvider; if (e.NewState == ProviderState.SignedIn)
if (provider == null || provider.State != ProviderState.SignedIn)
{
SignedInUserTextBlock.Text = "Please sign in.";
ManagerButton.IsEnabled = false;
}
else
{ {
ManagerButton.IsEnabled = true; ManagerButton.IsEnabled = true;
SignedInUserTextBlock.Text = "Signed in as..."; SignedInUserTextBlock.Text = "Signed in as...";
var graphClient = provider.GetClient(); var graphClient = ProviderManager.Instance.GlobalProvider.GetClient();
var me = await graphClient.Me.Request().GetAsync(); var me = await graphClient.Me.Request().GetAsync();
SignedInUserTextBlock.Text = "Signed in as: " + me.DisplayName; SignedInUserTextBlock.Text = "Signed in as: " + me.DisplayName;
} }
else
{
SignedInUserTextBlock.Text = "Please sign in.";
ManagerButton.IsEnabled = false;
}
} }
} }
} }

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

@ -18,7 +18,7 @@ namespace WpfMsalProviderSample
{ {
InitializeComponent(); InitializeComponent();
ProviderManager.Instance.ProviderUpdated += (s, e) => UpdateState(); ProviderManager.Instance.ProviderStateChanged += (s, e) => UpdateState();
UpdateState(); UpdateState();
} }

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

@ -17,25 +17,24 @@ namespace WpfMsalProviderSample
{ {
InitializeComponent(); InitializeComponent();
ProviderManager.Instance.ProviderUpdated += this.OnProviderUpdated; ProviderManager.Instance.ProviderStateChanged += OnProviderStateChanged;
} }
private async void OnProviderUpdated(object sender, ProviderUpdatedEventArgs e) private async void OnProviderStateChanged(object sender, ProviderStateChangedEventArgs e)
{ {
var provider = ProviderManager.Instance.GlobalProvider; if (e.NewState == ProviderState.SignedIn)
if (provider == null || provider.State != ProviderState.SignedIn)
{
SignedInUserTextBlock.Text = "Please sign in.";
}
else
{ {
SignedInUserTextBlock.Text = "Signed in as..."; SignedInUserTextBlock.Text = "Signed in as...";
var graphClient = provider.GetClient(); var graphClient = ProviderManager.Instance.GlobalProvider.GetClient();
var me = await graphClient.Me.Request().GetAsync(); var me = await graphClient.Me.Request().GetAsync();
SignedInUserTextBlock.Text = "Signed in as: " + me.DisplayName; SignedInUserTextBlock.Text = "Signed in as: " + me.DisplayName;
} }
else
{
SignedInUserTextBlock.Text = "Please sign in.";
}
} }
} }
} }

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

@ -136,7 +136,7 @@ namespace UnitTests.UWP.Helpers
{ {
var provider = new WindowsProvider(new string[] { "User.Read", "Files.ReadWrite" }, autoSignIn: false); var provider = new WindowsProvider(new string[] { "User.Read", "Files.ReadWrite" }, autoSignIn: false);
ProviderManager.Instance.ProviderUpdated += (s, e) => ProviderManager.Instance.ProviderStateChanged += (s, e) =>
{ {
var providerManager = s as ProviderManager; var providerManager = s as ProviderManager;
if (e.Reason == ProviderManagerChangedState.ProviderStateChanged && providerManager.GlobalProvider.State == ProviderState.SignedIn) if (e.Reason == ProviderManagerChangedState.ProviderStateChanged && providerManager.GlobalProvider.State == ProviderState.SignedIn)

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

@ -136,7 +136,7 @@ namespace UnitTests.UWP.Helpers
{ {
var provider = new WindowsProvider(new string[] { "User.ReadWrite" }, autoSignIn: false); var provider = new WindowsProvider(new string[] { "User.ReadWrite" }, autoSignIn: false);
ProviderManager.Instance.ProviderUpdated += (s, e) => ProviderManager.Instance.ProviderStateChanged += (s, e) =>
{ {
var providerManager = s as ProviderManager; var providerManager = s as ProviderManager;
if (e.Reason == ProviderManagerChangedState.ProviderStateChanged && providerManager.GlobalProvider.State == ProviderState.SignedIn) if (e.Reason == ProviderManagerChangedState.ProviderStateChanged && providerManager.GlobalProvider.State == ProviderState.SignedIn)