From 37f8dacba2d782e533847756ccf3b36457259fbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Fi=C5=A1era?= Date: Wed, 6 Mar 2019 20:52:13 +0100 Subject: [PATCH] #218 - Events for managing sign-in and out notifications on client. --- .../Bootstrap/BootstrapTask.cs | 1 + src/Money.UI.Blazor/Events/UserSignedIn.cs | 14 +++ src/Money.UI.Blazor/Events/UserSignedOut.cs | 14 +++ src/Money.UI.Blazor/Layouts/LoginInfo.cshtml | 30 ++----- .../Layouts/LoginInfo.cshtml.cs | 90 +++++++++++++++++++ src/Money.UI.Blazor/Services/ApiClient.cs | 22 +++-- .../Services/CategoryMiddleware.cs | 9 +- .../Services/CurrencyMiddleware.cs | 9 +- .../Services/Events/BrowserEventDispatcher.cs | 6 +- .../Services/UserMiddleware.cs | 10 ++- 10 files changed, 168 insertions(+), 37 deletions(-) create mode 100644 src/Money.UI.Blazor/Events/UserSignedIn.cs create mode 100644 src/Money.UI.Blazor/Events/UserSignedOut.cs create mode 100644 src/Money.UI.Blazor/Layouts/LoginInfo.cshtml.cs diff --git a/src/Money.UI.Blazor/Bootstrap/BootstrapTask.cs b/src/Money.UI.Blazor/Bootstrap/BootstrapTask.cs index 8ed45c6f..d356746e 100644 --- a/src/Money.UI.Blazor/Bootstrap/BootstrapTask.cs +++ b/src/Money.UI.Blazor/Bootstrap/BootstrapTask.cs @@ -71,6 +71,7 @@ public void Initialize() .AddTransient(typeof(ILog<>), typeof(DefaultLog<>)) .AddSingleton(eventDispatcher) .AddSingleton(eventDispatcher.Handlers) + .AddSingleton(eventDispatcher.Dispatcher) .AddSingleton(exceptionHandler) .AddSingleton(exceptionHandler.Handler) .AddSingleton(exceptionHandler.HandlerBuilder); diff --git a/src/Money.UI.Blazor/Events/UserSignedIn.cs b/src/Money.UI.Blazor/Events/UserSignedIn.cs new file mode 100644 index 00000000..042a5590 --- /dev/null +++ b/src/Money.UI.Blazor/Events/UserSignedIn.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Money.Events +{ + /// + /// An event raised when a user has signed in. + /// + public class UserSignedIn : UserEvent + { } +} diff --git a/src/Money.UI.Blazor/Events/UserSignedOut.cs b/src/Money.UI.Blazor/Events/UserSignedOut.cs new file mode 100644 index 00000000..f183b601 --- /dev/null +++ b/src/Money.UI.Blazor/Events/UserSignedOut.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Money.Events +{ + /// + /// An event raised when a user has signed in. + /// + public class UserSignedOut : UserEvent + { } +} diff --git a/src/Money.UI.Blazor/Layouts/LoginInfo.cshtml b/src/Money.UI.Blazor/Layouts/LoginInfo.cshtml index f35820df..3beff792 100644 --- a/src/Money.UI.Blazor/Layouts/LoginInfo.cshtml +++ b/src/Money.UI.Blazor/Layouts/LoginInfo.cshtml @@ -1,37 +1,17 @@ -@inject IQueryDispatcher Queries -@inject Navigator Navigator -@inject ApiClient ApiClient +@using Money.Layouts +@inherits LoginInfoBase - -@functions -{ - public ProfileModel Profile { get; private set; } - - protected LoadingContext Loading { get; } = new LoadingContext(); - - protected override async Task OnInitAsync() - { - using (Loading.Start()) - Profile = await Queries.QueryAsync(new GetProfile()); - } - - protected async Task OnLogoutAsync() - { - await ApiClient.LogoutAsync(); - Navigator.OpenLogin(); - } -} diff --git a/src/Money.UI.Blazor/Layouts/LoginInfo.cshtml.cs b/src/Money.UI.Blazor/Layouts/LoginInfo.cshtml.cs new file mode 100644 index 00000000..eca8f8b8 --- /dev/null +++ b/src/Money.UI.Blazor/Layouts/LoginInfo.cshtml.cs @@ -0,0 +1,90 @@ +using Microsoft.AspNetCore.Blazor.Components; +using Money.Events; +using Money.Models; +using Money.Models.Loading; +using Money.Queries; +using Money.Services; +using Neptuo.Events; +using Neptuo.Events.Handlers; +using Neptuo.Queries; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Money.Layouts +{ + public class LoginInfoBase : BlazorComponent, IDisposable, IEventHandler, IEventHandler + { + [Inject] + public IQueryDispatcher Queries { get; set; } + + [Inject] + public IEventHandlerCollection EventHandlers { get; set; } + + [Inject] + internal Navigator Navigator { get; set; } + + [Inject] + public ApiClient ApiClient { get; set; } + + public ProfileModel Profile { get; private set; } + protected LoadingContext Loading { get; } = new LoadingContext(); + + protected async override Task OnInitAsync() + { + BindEvents(); + + await LoadProfileAsync(); + } + + private async Task LoadProfileAsync() + { + using (Loading.Start()) + Profile = await Queries.QueryAsync(new GetProfile()); + } + + protected async Task OnLogoutAsync() + { + await ApiClient.LogoutAsync(); + Navigator.OpenLogin(); + } + + public void Dispose() + { + UnBindEvents(); + } + + #region Events + + private void BindEvents() + { + EventHandlers + .Add(this) + .Add(this); + } + + private void UnBindEvents() + { + EventHandlers + .Remove(this) + .Remove(this); + } + + async Task IEventHandler.HandleAsync(UserSignedIn payload) + { + await LoadProfileAsync(); + StateHasChanged(); + } + + Task IEventHandler.HandleAsync(UserSignedOut payload) + { + Profile = null; + StateHasChanged(); + return Task.CompletedTask; + } + + #endregion + } +} diff --git a/src/Money.UI.Blazor/Services/ApiClient.cs b/src/Money.UI.Blazor/Services/ApiClient.cs index 79e9155f..d6be5cec 100644 --- a/src/Money.UI.Blazor/Services/ApiClient.cs +++ b/src/Money.UI.Blazor/Services/ApiClient.cs @@ -1,7 +1,9 @@ using Microsoft.AspNetCore.Blazor; +using Money.Events; using Money.Models.Api; using Money.Users.Models; using Neptuo; +using Neptuo.Events; using Neptuo.Exceptions.Handlers; using System; using System.Collections.Generic; @@ -23,17 +25,20 @@ public class ApiClient private readonly CommandMapper commandMapper; private readonly QueryMapper queryMapper; private readonly IExceptionHandler exceptionHandler; + private readonly IEventDispatcher eventDispatcher; - public ApiClient(HttpClient http, CommandMapper commandMapper, QueryMapper queryMapper, IExceptionHandler exceptionHandler) + public ApiClient(HttpClient http, CommandMapper commandMapper, QueryMapper queryMapper, IExceptionHandler exceptionHandler, IEventDispatcher eventDispatcher) { Ensure.NotNull(http, "http"); Ensure.NotNull(commandMapper, "commandMapper"); Ensure.NotNull(queryMapper, "queryMapper"); Ensure.NotNull(exceptionHandler, "exceptionHandler"); + Ensure.NotNull(eventDispatcher, "eventDispatcher"); this.http = http; this.commandMapper = commandMapper; this.queryMapper = queryMapper; this.exceptionHandler = exceptionHandler; + this.eventDispatcher = eventDispatcher; http.BaseAddress = new Uri(rootUrl); EnsureAuthorization(); @@ -41,10 +46,15 @@ public ApiClient(HttpClient http, CommandMapper commandMapper, QueryMapper query private void ClearAuthorization() { - token = null; - http.DefaultRequestHeaders.Authorization = null; - Interop.SaveToken(null); - Interop.StopSignalR(); + if (token != null) + { + token = null; + http.DefaultRequestHeaders.Authorization = null; + Interop.SaveToken(null); + Interop.StopSignalR(); + + eventDispatcher.PublishAsync(new UserSignedOut()); + } } private void EnsureAuthorization() @@ -53,6 +63,8 @@ private void EnsureAuthorization() { http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); Interop.StartSignalR(rootUrl + "/api", token); + + eventDispatcher.PublishAsync(new UserSignedIn()); } } diff --git a/src/Money.UI.Blazor/Services/CategoryMiddleware.cs b/src/Money.UI.Blazor/Services/CategoryMiddleware.cs index 14a80127..4c5700f2 100644 --- a/src/Money.UI.Blazor/Services/CategoryMiddleware.cs +++ b/src/Money.UI.Blazor/Services/CategoryMiddleware.cs @@ -17,7 +17,8 @@ internal class CategoryMiddleware : HttpQueryDispatcher.IMiddleware, IEventHandler, IEventHandler, IEventHandler, - IEventHandler + IEventHandler, + IEventHandler { private readonly List models = new List(); private Task listAllTask; @@ -108,5 +109,11 @@ Task IEventHandler.HandleAsync(CategoryColorChanged payloa Task IEventHandler.HandleAsync(CategoryDeleted payload) => Update(payload.AggregateKey, model => models.Remove(model)); + + Task IEventHandler.HandleAsync(UserSignedOut payload) + { + models.Clear(); + return Task.CompletedTask; + } } } diff --git a/src/Money.UI.Blazor/Services/CurrencyMiddleware.cs b/src/Money.UI.Blazor/Services/CurrencyMiddleware.cs index 90e80bc6..e065a99f 100644 --- a/src/Money.UI.Blazor/Services/CurrencyMiddleware.cs +++ b/src/Money.UI.Blazor/Services/CurrencyMiddleware.cs @@ -16,7 +16,8 @@ internal class CurrencyMiddleware : HttpQueryDispatcher.IMiddleware, IEventHandler, IEventHandler, IEventHandler, - IEventHandler + IEventHandler, + IEventHandler { private readonly List models = new List(); private Task listAllTask; @@ -88,5 +89,11 @@ Task IEventHandler.HandleAsync(CurrencySymbolChanged payl Task IEventHandler.HandleAsync(CurrencyDeleted payload) => Update(payload.UniqueCode, model => models.Remove(model)); + + Task IEventHandler.HandleAsync(UserSignedOut payload) + { + models.Clear(); + return Task.CompletedTask; + } } } diff --git a/src/Money.UI.Blazor/Services/Events/BrowserEventDispatcher.cs b/src/Money.UI.Blazor/Services/Events/BrowserEventDispatcher.cs index 76a2d180..8fb5182f 100644 --- a/src/Money.UI.Blazor/Services/Events/BrowserEventDispatcher.cs +++ b/src/Money.UI.Blazor/Services/Events/BrowserEventDispatcher.cs @@ -26,10 +26,8 @@ public BrowserEventDispatcher(FormatterContainer formatters, ILogFactory logFact this.log = logFactory.Scope("BrowserEventDispatcher"); } - public IEventHandlerCollection Handlers - { - get => manager; - } + public IEventHandlerCollection Handlers => manager; + public IEventDispatcher Dispatcher => manager; public void Raise(string rawPayload) { diff --git a/src/Money.UI.Blazor/Services/UserMiddleware.cs b/src/Money.UI.Blazor/Services/UserMiddleware.cs index cea3e8b6..3a2bf8ab 100644 --- a/src/Money.UI.Blazor/Services/UserMiddleware.cs +++ b/src/Money.UI.Blazor/Services/UserMiddleware.cs @@ -12,7 +12,8 @@ namespace Money.Services { internal class UserMiddleware : HttpQueryDispatcher.IMiddleware, - IEventHandler + IEventHandler, + IEventHandler { private ProfileModel profile; private Task getProfileTask; @@ -47,5 +48,12 @@ Task IEventHandler.HandleAsync(EmailChanged payload) return Task.CompletedTask; } + + Task IEventHandler.HandleAsync(UserSignedOut payload) + { + profile = null; + + return Task.CompletedTask; + } } }