Skip to content

Commit

Permalink
feat(templates): improve SignalR implementation in Boilerplate (#8557) (
Browse files Browse the repository at this point in the history
  • Loading branch information
ysmoradi authored Sep 14, 2024
1 parent de8c80d commit a5c6700
Show file tree
Hide file tree
Showing 15 changed files with 180 additions and 182 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
//+:cnd:noEmit
using Microsoft.Extensions.Logging;
//#if (signalr == true)
using Microsoft.AspNetCore.SignalR.Client;
//#endif

namespace Boilerplate.Client.Core.Components;

public partial class AppInitializer : AppComponentBase
{
//#if (signalr == true)
private HubConnection? hubConnection;
//#endif

[AutoInject] private MessageBoxService messageBoxService = default!;
[AutoInject] private AuthenticationManager authManager = default!;
[AutoInject] private IJSRuntime jsRuntime = default!;
[AutoInject] private IBitDeviceCoordinator bitDeviceCoordinator = default!;
[AutoInject] private IStorageService storageService = default!;
[AutoInject] private CultureInfoManager cultureInfoManager = default!;
[AutoInject] private ILogger<AuthenticationManager> authLogger = default!;

protected async override Task OnInitAsync()
{
AuthenticationManager.AuthenticationStateChanged += AuthenticationStateChanged;

AuthenticationStateChanged(AuthenticationManager.GetAuthenticationStateAsync());

if (AppPlatform.IsBlazorHybrid)
{
if (CultureInfoManager.MultilingualEnabled)
{
cultureInfoManager.SetCurrentCulture(await storageService.GetItem("Culture") ?? // 1- User settings
CultureInfo.CurrentUICulture.Name); // 2- OS settings
}

await SetupBodyClasses();
}

await base.OnInitAsync();
}

protected override async Task OnAfterFirstRenderAsync()
{
await base.OnAfterFirstRenderAsync();

if (AppPlatform.IsBlazorHybrid is false)
{
AppPlatform.OSDescription = await jsRuntime.GetBrowserPlatform();
}
}

private async void AuthenticationStateChanged(Task<AuthenticationState> task)
{
try
{
var user = (await AuthenticationStateTask).User;

var (isUserAuthenticated, userId, userName, email, sessionId) = user.IsAuthenticated() ? (user.IsAuthenticated(), user.GetUserId().ToString(), user.GetUserName(), user.GetEmail(), user.GetSessionId()) : default;

LogAuthenticationState(authLogger, isUserAuthenticated, userId, userName, email, sessionId);

//#if (signalr == true)
if (InPrerenderSession is false)
{
await ConnectSignalR();
}
//#endif
}
catch (Exception exp)
{
ExceptionHandler.Handle(exp);
}
}

[LoggerMessage(Level = LogLevel.Information, Message = "Authentication State: {IsUserAuthenticated}, {UserId}, {UserName}, {Email}, {UserSessionId}")]
private static partial void LogAuthenticationState(ILogger logger, bool isUserAuthenticated, string userId, string userName, string? email, string? userSessionId);

//#if (signalr == true)
private async Task ConnectSignalR()
{
if (hubConnection is not null)
{
await hubConnection.DisposeAsync();
}

var access_token = await AuthTokenProvider.GetAccessTokenAsync();

hubConnection = new HubConnectionBuilder()
.WithUrl($"{Configuration.GetServerAddress()}/app-hub?access_token={access_token}")
.Build();

hubConnection.On<string>("TwoFactorToken", async (token) =>
{
await messageBoxService.Show(Localizer[nameof(AppStrings.TwoFactorTokenPushText), token]);

// The following code block is not required for Bit.BlazorUI components to perform UI changes. However, it may be necessary in other scenarios.
/*await InvokeAsync(async () =>
{
StateHasChanged();
});*/

// You can also leverage IPubSubService to notify other components in the application.
});

await hubConnection.StartAsync(CurrentCancellationToken);
}
//#endif

private async Task SetupBodyClasses()
{
var cssClasses = new List<string> { };

if (AppPlatform.IsWindows)
{
cssClasses.Add("bit-windows");
}
else if (AppPlatform.IsMacOS)
{
cssClasses.Add("bit-macos");
}
else if (AppPlatform.IsIOS)
{
cssClasses.Add("bit-ios");
}
else if (AppPlatform.IsAndroid)
{
cssClasses.Add("bit-android");
}

var cssVariables = new Dictionary<string, string>();
var statusBarHeight = bitDeviceCoordinator.GetStatusBarHeight();

if (AppPlatform.IsMacOS is false)
{
//For iOS this is handled in css using safe-area env() variables
//For Android there's an issue with keyboard in fullscreen mode. more info: https://github.com/bitfoundation/bitplatform/issues/5626
//For Windows there's an issue with TitleBar. more info: https://github.com/bitfoundation/bitplatform/issues/5695
statusBarHeight = 0;
}

cssVariables.Add("--bit-status-bar-height", $"{statusBarHeight.ToString("F3", CultureInfo.InvariantCulture)}px");
await jsRuntime.ApplyBodyElementClasses(cssClasses, cssVariables);
}

//#if (signalr == true)
protected override async ValueTask DisposeAsync(bool disposing)
{
if (hubConnection is not null)
{
await hubConnection.DisposeAsync();
}

await base.DisposeAsync(disposing);
}
//#endif
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ protected override async Task OnInitializedAsync()
{
try
{
authManager.AuthenticationStateChanged += IsUserAuthenticated;
authManager.AuthenticationStateChanged += AuthenticationStateChanged;

isUserAuthenticated = await prerenderStateService.GetValue(async () => (await AuthenticationStateTask).User.IsAuthenticated());

Expand Down Expand Up @@ -64,7 +64,7 @@ private void ToggleMenuHandler()
isMenuOpen = !isMenuOpen;
}

private async void IsUserAuthenticated(Task<AuthenticationState> task)
private async void AuthenticationStateChanged(Task<AuthenticationState> task)
{
try
{
Expand All @@ -91,7 +91,7 @@ protected virtual void Dispose(bool disposing)
{
if (disposed || disposing is false) return;

authManager.AuthenticationStateChanged -= IsUserAuthenticated;
authManager.AuthenticationStateChanged -= AuthenticationStateChanged;

unsubscribeCultureChange();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,4 @@
<div class="content-container danger-panel">
<DeleteAccountSection />
</div>
</div>

@*#if (signalr == true)*@
<BitSnackBar @ref="snackBar" />
@*#endif*@
</div>
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
//+:cnd:noEmit
//#if (signalr == true)
using Microsoft.AspNetCore.SignalR.Client;
//#endif
using Boilerplate.Shared.Dtos.Identity;
using Boilerplate.Shared.Controllers.Identity;

Expand All @@ -12,10 +9,6 @@ public partial class ProfilePage
{
private UserDto? user;
private bool isLoading;
//#if (signalr == true)
private HubConnection? hubConnection;
private BitSnackBar snackBar = default!;
//#endif

[AutoInject] private IUserController userController = default!;

Expand All @@ -35,40 +28,4 @@ protected override async Task OnInitAsync()

await base.OnInitAsync();
}

//#if (signalr == true)
protected async override Task OnAfterFirstRenderAsync()
{
await base.OnAfterFirstRenderAsync();

var access_token = await AuthTokenProvider.GetAccessTokenAsync();

hubConnection = new HubConnectionBuilder()
.WithUrl($"{Configuration.GetServerAddress()}/identity-hub?access_token={access_token}")
.Build();

hubConnection.On<UserSessionDto>("NewUserSession", async (userSession) =>
{
await snackBar.Info(Localizer[nameof(AppStrings.NewUserSessionSnackbarTitle)], Localizer[nameof(AppStrings.DeviceDetails), userSession.Device!]);

// The following code block is not required for Bit.BlazorUI components to perform UI changes. However, it may be necessary in other scenarios.
/*await InvokeAsync(async () =>
{
StateHasChanged();
});*/
});

await hubConnection.StartAsync();
}

protected override async ValueTask DisposeAsync(bool disposing)
{
if (hubConnection is not null)
{
await hubConnection.DisposeAsync();
}

await base.DisposeAsync(disposing);
}
//#endif
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<CascadingAuthenticationState>
<AuthenticationStateLogger />
<AppInitializer />
<LayoutView Layout="@typeof(MainLayout)">
<Router AppAssembly="@GetType().Assembly"
AdditionalAssemblies="@(AssemblyLoadContext.Default.Assemblies.Where(asm => asm.GetName().Name?.Contains("Boilerplate") is true))">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,73 +2,6 @@

public partial class Routes
{
[AutoInject] IJSRuntime jsRuntime = default!;
[AutoInject] IBitDeviceCoordinator bitDeviceCoordinator = default!;
[AutoInject] IStorageService storageService = default!;
[AutoInject] CultureInfoManager cultureInfoManager = default!;

protected override async Task OnInitializedAsync()
{
if (AppPlatform.IsBlazorHybrid)
{
if (CultureInfoManager.MultilingualEnabled)
{
cultureInfoManager.SetCurrentCulture(await storageService.GetItem("Culture") ?? // 1- User settings
CultureInfo.CurrentUICulture.Name); // 2- OS settings
}

await SetupBodyClasses();
}

await base.OnInitializedAsync();
}

private async Task SetupBodyClasses()
{
var cssClasses = new List<string> { };

if (AppPlatform.IsWindows)
{
cssClasses.Add("bit-windows");
}
else if (AppPlatform.IsMacOS)
{
cssClasses.Add("bit-macos");
}
else if (AppPlatform.IsIOS)
{
cssClasses.Add("bit-ios");
}
else if (AppPlatform.IsAndroid)
{
cssClasses.Add("bit-android");
}

var cssVariables = new Dictionary<string, string>();
var statusBarHeight = bitDeviceCoordinator.GetStatusBarHeight();

if (AppPlatform.IsMacOS is false)
{
//For iOS this is handled in css using safe-area env() variables
//For Android there's an issue with keyboard in fullscreen mode. more info: https://github.com/bitfoundation/bitplatform/issues/5626
//For Windows there's an issue with TitleBar. more info: https://github.com/bitfoundation/bitplatform/issues/5695
statusBarHeight = 0;
}

cssVariables.Add("--bit-status-bar-height", $"{statusBarHeight.ToString("F3", CultureInfo.InvariantCulture)}px");
await jsRuntime.ApplyBodyElementClasses(cssClasses, cssVariables);
}

protected async override Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);

if (firstRender && AppPlatform.IsBlazorHybrid is false)
{
AppPlatform.OSDescription = await jsRuntime.GetBrowserPlatform();
}
}

[AutoInject] NavigationManager? navigationManager { set => universalLinksNavigationManager = value; get => universalLinksNavigationManager; }
public static NavigationManager? universalLinksNavigationManager;

Expand Down
Loading

0 comments on commit a5c6700

Please sign in to comment.