I am struggling to get JWT from SecureStorage, as it's Get method is async, and we all know that constructor doesn't support async calls.
UPDATE:
What I want to do is check if I have a token and at the app start show the LoginPage or the MainPage.
I tried something like this:
public AppShell()
{
JWTokenModel jwt = null;
Task.Run(async () =>
{
jwt = await StorageService.Secure.GetAsync<JWTokenModel>(StorageKeys.Secure.JWT);
});
InitializeComponent();
RegisterRoutes();
shellContent.Title = "Amazons of Volleyball";
if (jwt is null || jwt?.Expiration < DateTime.Now)
{
shellContent.Route = PageRoutes.LoginPage;
shellContent.ContentTemplate = new DataTemplate(typeof(LoginPage));
}
else
{
shellContent.Route = PageRoutes.HomePage;
shellContent.ContentTemplate = new DataTemplate(typeof(MainPage));
}
}
private void RegisterRoutes()
{
Routing.RegisterRoute(PageRoutes.LoginPage, typeof(LoginPage));
Routing.RegisterRoute(PageRoutes.HomePage, typeof(MainPage));
Routing.RegisterRoute(PageRoutes.DetailsPage, typeof(PlayerDetailsPage));
Routing.RegisterRoute(PageRoutes.AddOrUpdatePage, typeof(AddOrUpdatePlayer));
}
When it hits the StorageService.Secure.GetAsync method's line, where I wan't to get the data like
public static async Task<T> GetAsync<T>(string key)
{
try
{
var value = await SecureStorage.Default.GetAsync(key);
if (string.IsNullOrWhiteSpace(value))
return (T)default;
var data = JsonSerializer.Deserialize<T>(value);
return data;
}
catch(Exception ex)
{
return (T)default;
}
}
it simple jumps out of the method.
UPDATE: I update the code suggested by ewerspej. The error still stands, when the SecureStore tries to get the value it jumps out from the method, no exception and I got the following error:
System.InvalidOperationException: 'No Content found for ShellContent, Title:, Route D_FAULT_ShellContent2'
The updated code:
public partial class AppShell : Shell
{
public AppShell()
{
InitializeComponent();
RegisterRoutes();
SetShellContentTemplate();
}
private async void SetShellContentTemplate()
{
var hasValidJWT = await LoadTokenAsync();
if (hasValidJWT)
{
shellContent.ContentTemplate = new DataTemplate(typeof(MainPage));
shellContent.Route = PageRoutes.HomePage;
shellContent.Title = "Amazons of Volleyball";
}
else
{
shellContent.ContentTemplate = new DataTemplate(typeof(LoginPage));
shellContent.Route = PageRoutes.LoginPage;
shellContent.Title = "Amazons of Volleyball";
}
}
private async Task<bool> LoadTokenAsync()
{
var jwt = await StorageService.Secure.GetAsync<JWTokenModel>(StorageKeys.Secure.JWT);
return !(jwt is null || jwt?.Expiration < DateTime.Now);
}
private void RegisterRoutes()
{
Routing.RegisterRoute(PageRoutes.LoginPage, typeof(LoginPage));
Routing.RegisterRoute(PageRoutes.HomePage, typeof(MainPage));
Routing.RegisterRoute(PageRoutes.DetailsPage, typeof(PlayerDetailsPage));
Routing.RegisterRoute(PageRoutes.AddOrUpdatePage, typeof(AddOrUpdatePlayer));
}
}
UPDATE 2: Moved the logic to App class:
public static class PageRoutes
{
public static string LoginPage = "login";
public static string HomePage = "home";
public static string AddOrUpdatePage = "add-or-update";
public static string DetailsPage = "/details";
}
public partial class App : Application
{
private readonly ISecurityClient securityClient;
public App(ISecurityClient securityClient)
{
this.securityClient = securityClient;
InitializeComponent();
SetStartPage();
}
private async void SetStartPage()
{
var hasValidJWT = await ReatJwtAsync();
MainPage = hasValidJWT ?
new AppShell() :
new LoginPage(securityClient);
}
private async Task<bool> ReatJwtAsync()
{
var jwt = await StorageService.Secure.GetAsync<JWTokenModel>(StorageKeys.Secure.JWT);
return !(jwt is null || jwt?.Expiration < DateTime.Now);
}
}
public partial class AppShell : Shell
{
public AppShell()
{
RegisterRoutes();
InitializeComponent();
}
private void RegisterRoutes()
{
Routing.RegisterRoute(PageRoutes.LoginPage, typeof(LoginPage));
Routing.RegisterRoute(PageRoutes.HomePage, typeof(MainPage));
Routing.RegisterRoute(PageRoutes.DetailsPage, typeof(PlayerDetailsPage));
Routing.RegisterRoute(PageRoutes.AddOrUpdatePage, typeof(AddOrUpdatePlayer));
}
}
AppShell.xaml
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
x:Class="MauiUI.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MauiUI"
xmlns:pages="clr-namespace:MauiUI.Pages"
Shell.FlyoutBehavior="Disabled">
<ShellContent
Title="Amazons of Volleyball"
ContentTemplate="{DataTemplate local:MainPage}"
Route="HomePage" />
</Shell>
Still not reading a token successfully. But looking at the output I can see that Thread #8 started (might have some impact). Now I am getting a new error:
System.NotImplementedException: 'Either set MainPage or override CreateWindow.'
any idea? thnx