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

C# MAUI:DI上下文能否在AndroidX WorkManager与UI页面间共享?

MAUI中SQLite单例服务在UI与AndroidX WorkManager间共享问题解决

问题描述

在MAUI Android应用中,已将SQLite数据库服务注册为单例DI服务,但UI页面(主线程)和AndroidX WorkManager后台工作器获取的是不同的数据库服务实例,无法复用单例,导致无法有效控制SQLite的单写入者限制,存在并发写入损坏数据库的风险。核心需求是全应用共用同一数据库服务单例,确保数据库操作的准确性与写入控制。

现有代码

MauiProgram.cs

public static MauiApp CreateMauiApp()
{
    var builder = MauiApp.CreateBuilder();
    builder.Services.AddSingleton<Services.IDatabaseService, Services.DatabaseService>();

#if ANDROID
    builder.Services.AddSingleton<CustomWorkManagerFactory>();
    builder.Services.AddSingleton<Platforms.Android.Sync.SyncWorker>();
#endif
    var app = builder.Build();
    Helpers.ServiceLocator.ServiceProvider = builder.Services.BuildServiceProvider(); // 问题点:重复构建服务容器
#if ANDROID
    var context = Android.App.Application.Context;
    var customFactory = Helpers.ServiceLocator.ServiceProvider.GetRequiredService<Platforms.Android.Helpers.CustomWorkManagerFactory>();
    var configuration = new AndroidX.Work.Configuration.Builder()
       .SetWorkerFactory(customFactory)
       .Build();
    AndroidX.Work.WorkManager.Initialize(context, configuration);
#endif
 return app;
}

数据库服务写入逻辑

private readonly SemaphoreSlim _writeSemaphore = new SemaphoreSlim(1, 1);

public async Task<int> InsertDB(object item) 
{ 
    await _writeSemaphore.WaitAsync(); 
    try 
    { 
        int result = await Database().InsertAsync(item); 
        return result; 
    } 
    catch (Exception ex) 
    { 
        throw; 
    } 
    finally 
    { 
        _writeSemaphore.Release(); 
    } 
} 

解决方案

1. 修复DI服务容器重复构建问题

代码中builder.Services.BuildServiceProvider()会创建新的独立服务容器,导致WorkManager和UI使用不同的DI上下文。应直接使用builder.Build()返回的MauiApp的ServiceProvider:

修改后的MauiProgram.cs关键部分:

var app = builder.Build();
Helpers.ServiceLocator.ServiceProvider = app.Services; // 使用已构建的主服务容器
#if ANDROID
var context = Android.App.Application.Context;
var customFactory = app.Services.GetRequiredService<Platforms.Android.Helpers.CustomWorkManagerFactory>(); // 从主容器获取实例
var configuration = new AndroidX.Work.Configuration.Builder()
   .SetWorkerFactory(customFactory)
   .Build();
AndroidX.Work.WorkManager.Initialize(context, configuration);
#endif

2. 确保WorkManager与UI同进程运行

默认情况下WorkManager与APP主进程同进程,但如果在AndroidManifest.xml中为Worker配置了android:process属性,会导致WorkManager运行在独立进程,此时单例无法跨进程共享。检查并移除该配置:

移除类似如下的配置:

<service
    android:name=".Sync.SyncWorker"
    android:process=":sync_process" /> <!-- 这个属性会导致跨进程 -->

3. 正确实现自定义WorkManagerFactory

自定义Factory需从主DI容器获取Worker实例,确保Worker依赖的数据库服务是单例:

public class CustomWorkManagerFactory : WorkerFactory
{
    private readonly IServiceProvider _serviceProvider;

    public CustomWorkManagerFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public override ListenableWorker CreateWorker(
        Context appContext,
        string workerClassName,
        WorkerParameters workerParameters)
    {
        var workerType = Type.GetType(workerClassName);
        if (workerType == typeof(SyncWorker))
        {
            // 从主容器获取Worker实例,保证依赖的单例性
            return _serviceProvider.GetRequiredService<SyncWorker>();
        }
        // 其他Worker使用默认创建逻辑
        return base.CreateWorker(appContext, workerClassName, workerParameters);
    }
}

4. 跨进程场景的备选方案(若必须使用独立进程)

如果业务需求要求WorkManager运行在独立进程,单例共享不可行,可通过以下方式保证数据库安全:

  • 启用SQLite WAL模式:WAL模式支持多进程安全读写,比传统的独占锁模式更适合跨进程场景。在数据库初始化时开启:
    var db = new SQLiteAsyncConnection(dbPath);
    await db.ExecuteAsync("PRAGMA journal_mode=WAL;");
    
  • 使用ContentProvider封装数据库访问:ContentProvider由Android系统管理,天然支持跨进程访问,可将所有数据库操作封装到ContentProvider中,确保统一的写入控制。
  • 通过IPC机制转发数据库操作:后台Worker通过Messenger或AIDL与主进程通信,由主进程统一执行数据库操作,避免多进程直接操作数据库文件。

5. 强化写入控制

确保_writeSemaphore在数据库服务单例中是唯一实例,初始化时设置最大并发数为1:

private readonly SemaphoreSlim _writeSemaphore = new SemaphoreSlim(1, 1);

这样即使在多线程场景下,也能保证同一时间只有一个写入操作执行。


内容的提问来源于stack exchange,提问作者EdwinD

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 12:15:57