. net MAUI,如何在构造函数中从SecureStorage获取数据



我正在努力从SecureStorage获得JWT,因为它的get方法是异步的,我们都知道构造函数不支持异步调用。

更新:

我想做的是检查我是否有一个令牌,并在应用程序开始时显示LoginPage或MainPage。

我试过这样做:

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));
}

当它到达StorageService.Secure.GetAsync方法的行时,我不想获得像

这样的数据
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;
}
}

它直接跳出方法。

UPDATE:我更新了ewerspej建议的代码。错误仍然存在,当SecureStore试图从方法中跳出值时,没有例外,我得到了以下错误:

系统。InvalidOperationException: 'No Content for ShellContent, Title:, Route D_FAULT_ShellContent2'

更新后的代码:

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));
}
}

更新2:将逻辑移动到App类:

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>

仍未成功读取令牌。但是查看输出,我可以看到线程#8已经启动(可能会产生一些影响)。现在我得到一个新的错误:

系统。NotImplementedException: '要么设置主页,要么重写CreateWindow.'

任何想法?非常感谢

不要直接在构造函数中加载令牌,你应该把它推迟到一个异步方法中,这个方法仍然可以从构造函数中调用,但是你不能await它,你也不应该使用阻塞调用。

您可以在App.xaml.cs中执行此操作,这是应用程序启动时加载数据的常见位置。当数据加载时,您可以将MainPage对象设置为某种类型的加载页面,一旦令牌加载,您可以将MainPage设置为AppShellLoginPage实例,例如:

public App()
{
InitializeComponent();
MainPage = new LoadingPage();
Load();
}
private async void Load()
{
if (await LoadTokenAsync())
{
MainPage = new AppShell();
}
else
{
MainPage = new LoginPage();
}
}
private async Task<bool> LoadTokenAsync()
{
var jwt = await StorageService.Secure.GetAsync<JWTokenModel>(StorageKeys.Secure.JWT);
return !(jwt is null || jwt?.Expiration < DateTime.Now);
}

这只是为了演示如何解决这个问题。在AppShell.xaml.cs中不应该这样做,而应该在App.xaml.cs中这样做。显然,您需要将令牌存储在内存中的某个地方。

最新更新