You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 14:49:51