.NET MAUI多用户切换后数据未更新问题求助
问题根源分析
你的问题核心是单例服务生命周期与静态FirebaseHelper实例导致用户切换后资源未更新:
- 所有ViewModel和服务都注册为
Singleton,意味着它们在应用启动时创建后就不会重建,用户切换后仍复用旧实例; FirebaseHelper的静态Instance在首次登录后被User1的实例占据,登出清空后登录User2时,虽然重新new了实例,但依赖注入的服务还是旧的单例,导致数据仍加载User1的内容。
解决方案
1. 调整服务注册生命周期(MauiProgram.cs)
将与用户强相关的服务从Singleton改为Scoped,这样每次登录可以创建全新的实例:
// 替换原有Singleton注册 builder.Services.AddScoped<IProductService, ProductService>(); builder.Services.AddScoped<ProductListViewModel>(); builder.Services.AddScoped<SettingsViewModel>(); builder.Services.AddScoped<AccountViewModel>(); builder.Services.AddScoped<ProductList>(); builder.Services.AddScoped<SettingsPage>(); // FirebaseHelper改为Scoped,根据当前登录用户信息创建实例 builder.Services.AddScoped<FirebaseHelper>(sp => { var authToken = SecureStorage.GetAsync("AuthToken").Result; var userEmail = Preferences.Get("UserEmailKey", string.Empty); if (!string.IsNullOrEmpty(authToken) && !string.IsNullOrEmpty(userEmail)) { return new FirebaseHelper(userEmail, authToken); } throw new InvalidOperationException("无法创建FirebaseHelper,请检查登录状态"); });
2. 重构FirebaseHelper,移除静态单例
去掉静态实例逻辑,让它完全由依赖注入管理:
public class FirebaseHelper { private readonly string _accountEmail; private readonly string _authToken; private readonly FirebaseClient _firebaseClient; public FirebaseHelper(string accountEmail, string authToken) { _accountEmail = accountEmail.Replace(".", "_"); _authToken = authToken; _firebaseClient = new FirebaseClient("https://app-name.firebasedatabase.app", new FirebaseOptions { AuthTokenAsyncFactory = () => Task.FromResult(_authToken) }); } public async Task<List<Product>> GetAllProductsAsync() { return (await _firebaseClient.Child(_accountEmail).Child("Products") .OnceAsync<Product>()).Select(p => p.Object).ToList(); } }
3. 修改登出逻辑,彻底清理用户资源
登出时清空所有用户相关存储,确保后续登录能创建全新服务实例:
public class SettingsViewModel { public ICommand LogOutCommand => new Command(async () => { // 清空所有用户存储 Preferences.Remove("AccountIdKey"); Preferences.Remove("AccountEmailKey"); Preferences.Remove("FirebaseRefresher"); await SecureStorage.RemoveAsync("AuthToken"); // 跳转登录页 Application.Current.MainPage = new NavigationPage(new LogInPage()); }); }
4. 调整登录逻辑,用新作用域创建AppShell
登录成功后创建新的服务作用域,确保AppShell内的所有Scoped服务都是全新实例:
public ICommand LogInCommand => new Command<Tuple<object, object>>(async (parameters) => { // ... 原有登录验证逻辑(省略) ... if (emailVerified) { // 保存用户信息到存储 await SecureStorage.SetAsync("AuthToken", auth.FirebaseToken); Preferences.Set("FirebaseRefresher", serializedcontent); Preferences.Set("UserEmailKey", userEmailEntry.ToLower()); // 创建新服务作用域,确保所有Scoped服务都是新实例 using var scope = App.Current.Services.CreateScope(); var shell = scope.ServiceProvider.GetRequiredService<AppShell>(); // 跳转新的AppShell并手动触发数据加载 App.Current.MainPage = shell; var productVm = scope.ServiceProvider.GetRequiredService<ProductListViewModel>(); await productVm.GetAllProducts(); } });
5. 修改App启动逻辑,使用服务作用域初始化
public App(IServiceProvider serviceProvider) { InitializeComponent(); try { var firebaseRefresher = Preferences.Get("FirebaseRefresher", ""); var accountIdKey = Preferences.Get("AccountIdKey", string.Empty); if (!string.IsNullOrEmpty(firebaseRefresher) && !string.IsNullOrEmpty(accountIdKey)) { using var scope = serviceProvider.CreateScope(); MainPage = scope.ServiceProvider.GetRequiredService<AppShell>(); } else { MainPage = new NavigationPage(new LogInPage()); } } catch { MainPage = new NavigationPage(new LogInPage()); } }
额外注意事项
- 确保所有依赖
FirebaseHelper的服务(比如ProductService)通过构造函数注入实例,禁止使用静态Instance:
public class ProductService : IProductService { private readonly FirebaseHelper _firebaseHelper; public ProductService(FirebaseHelper firebaseHelper) { _firebaseHelper = firebaseHelper; } public async Task<List<Product>> GetAllProductsAsync() { return await _firebaseHelper.GetAllProductsAsync(); } }
- 移除所有代码中对
FirebaseHelper.Instance的引用。
内容的提问来源于stack exchange,提问作者Noah
相关产品推荐
相关产品推荐

