我不知道如何描述标题,抱歉。
我正在使用 .net Maui。 我面临的问题很难解释,所以我会添加尽可能多的代码,希望能解决这个问题。
我有登录和注销页面。 当应用程序启动时,我使用此代码
public App()
{
InitializeComponent();
try
{
var accountIdKey = Preferences.Get("AccountIdKey", string.Empty);
var accountEmailKey = Preferences.Get("AccountEmailKey", string.Empty);
if (!string.IsNullOrEmpty(Preferences.Get("FirebaseRefresher", "")) && !string.IsNullOrEmpty(accountIdKey))
{
var authToken = SecureStorage.GetAsync("AuthToken").Result;
var firebaseHelper = new FirebaseHelper(accountEmailKey, authToken);
MainPage = new AppShell();
}
else
{
MainPage = new NavigationPage(new LogInPage());
}
}
catch
{
MainPage = new NavigationPage(new LogInPage());
}
}
我注册了这样的服务(在 MauiProgran.cs 中)
builder.Services.AddSingleton<IProductService, ProductService>();
builder.Services.AddSingleton<ProductList>();
builder.Services.AddSingleton<SettingsPage>();
builder.Services.AddSingleton<ProductListViewModel>();
builder.Services.AddSingleton<SettingsViewModel>();
builder.Services.AddSingleton<AccountViewModel>();
这就是我登录的方式(AccountViewModel)
public class AccountViewModel : BaseViewModel
{
IAccountService accountService;
public string WebAPIKey = "my_web_api_key";
private string emailFromAuth;
public AccountViewModel()
{
}
public AccountViewModel(IAccountService accountService)
{
this.accountService = accountService;
}
public ICommand LogInCommand => new Command<Tuple<object, object>>(async (parameters) =>
{
string userEmailEntry = "";
string userPasswordEntry = "";
if (parameters != null && parameters.Item1 is Entry emailEntry && parameters.Item2 is Entry passwordEntry)
{
userEmailEntry = emailEntry.Text;
userPasswordEntry = passwordEntry.Text;
}
var authProvider = new FirebaseAuthProvider(new FirebaseConfig(WebAPIKey));
var auth = await authProvider.SignInWithEmailAndPasswordAsync(userEmailEntry.ToLower(), userPasswordEntry);
var emailVerified = auth.User.IsEmailVerified;
if (emailVerified)
{
await SecureStorage.SetAsync("AuthToken", auth.FirebaseToken);
var firebaseClient = new FirebaseClient("https://app-name.firebasedatabase.app/",
new FirebaseOptions
{
AuthTokenAsyncFactory = () => Task.FromResult(auth.FirebaseToken)
});
var userEmail = userEmailEntry.ToLower().Replace(".", "_");
var userFromDB = await firebaseClient.Child(userEmail).Child("User").OnceSingleAsync<AccountProfile>();
AccountProfile accountProfile = new();
if (userFromDB == null)
{
accountProfile = new AccountProfile
{
AccountId = Guid.NewGuid(),
AccountEmail = userEmailEntry.ToLower()
};
await firebaseClient.Child(userEmail).Child("User").PutAsync(accountProfile);
}
else
{
accountProfile.AccountId = userFromDB.AccountId;
accountProfile.AccountEmail = userFromDB.AccountEmail;
}
var firebaseHelper = new FirebaseHelper(accountProfile.AccountEmail, auth.FirebaseToken);
var content = await auth.GetFreshAuthAsync();
var serializedcontent = JsonConvert.SerializeObject(content);
Preferences.Set("FirebaseRefresher", serializedcontent);
Preferences.Set("UserEmailKey", userEmailEntry.ToLower());
App.Current.MainPage = new AppShell();
}
else { }
});
}
而且,这是 FirebaseHelper
public class FirebaseHelper
{
private static FirebaseHelper instance = null;
public static FirebaseHelper Instance
{
get
{
if (instance == null)
throw new Exception("Null instance.");
return instance;
}
}
private string _accountEmail;
private string _authToken;
FirebaseClient firebaseClient;
public FirebaseHelper(string accountEmail, string authToken)
{
_accountEmail = accountEmail.Replace(".", "_");
_authToken = authToken;
instance = this;
firebaseClient = new FirebaseClient("https://app-name.firebasedatabase.app",
new FirebaseOptions
{
AuthTokenAsyncFactory = () => Task.FromResult(_authToken)
});
}
public void ClearInstance()
{
instance = null;
}
public async Task<List<Product>> GetAllProductsAsync()
{
return (await firebaseClient.Child(_accountEmail).Child("Products")
.OnceAsync<Product>()).Select(p => p.Object).ToList();
}
}
因为我几乎包含了我的整个项目......这就是我获取列表的方式
public partial class ProductListViewModel : BaseViewModel
{
readonly IProductService productService;
public ObservableCollection<Product> ProductList { get; set; } = new();
public ProductListViewModel(IProductService productService)
{
this.productService = productService;
(GetAllProductsCommand = new Command(async () => await GetAllProducts())).Execute(null);
}
public ICommand GetAllProductsCommand { get; }
public async Task GetAllProducts()
{
try
{
var products = await productService.GetAllProductsAsync();
if (ProductList.Count != 0)
ProductList.Clear();
ProductList.AddRange(products);
}
catch {}
}
}
所以...这就是我登录的完整方式。
这是我的注销代码
public class SettingsViewModel
{
public ICommand LogOutCommand => new Command(async () =>
{
Preferences.Remove("AccountIdKey", string.Empty);
Preferences.Remove("AccountEmailKey", string.Empty);
try
{
Helper.FirebaseHelper.Instance.ClearInstance();
Preferences.Remove("FirebaseRefresher");
}
catch { }
Application.Current.MainPage = new NavigationPage(new LogInPage());
});
}
一切都运转良好。 但是,当我登录时,应用程序会遍历(初始化)所有 Viewmodel、FirebaseHelper 等...... 我通过登录用户(我称之为 User1)获得
ProductList
。
问题是: 当我注销时,它会将我带到“LogInPage”,如果我使用不同的用户(比方说 User2)登录,它仍然会记住 User1 并且不会通过(初始化)Viewmodels、FirebaseHelper 等... 并且它没有更新
ProductList
(它显示了 User1 的 ProductList
)
而且,在该代码上
public async Task<List<Product>> GetAllProductsAsync()
{
return (await firebaseClient.Child(_accountEmail).Child("Products")
.OnceAsync<Product>()).Select(p => p.Object).ToList();
}
"_accountEmail"
显示的是 User1 电子邮件而不是 User2
最后一件事,如果我注销并重新启动应用程序......一切正常。
我知道这是一个很长的故事,我只是没有找到任何简单的方法来解释这个问题。
非常感谢。
在注册中使用
AddSingleton<T>
时,这意味着该对象的单个实例将在应用程序的生命周期中保留。
在注册中使用
AddTransient<T>
时,它将在解析期间根据请求创建对象的新实例。
这种情况的解决方法是将
AddSingleton<T>
更改为AddTransient<T>
。然后,当您执行导航时,将重新创建注册的视图模型。另外,_accountEmail
字段应更改为静态。
更多信息可以参考依赖注入注册