MAUI Hybrid-Blazor应用SQLite Error 14数据库无法打开问题求助
问题背景
连续两天卡在这个问题上:开发首个搭载本地SQLite数据库的MAUI Hybrid-Blazor应用时,触发错误SQLite Error 14: 'unable to open database file',报错栈指向ServiceData.cs第26行。单独用控制台应用测试时,数据库连接和查询都正常运行,怀疑遗漏了MAUI专属配置。
相关代码
ServiceData.cs
public class ServiceData { private readonly string _connectionString; public ServiceData(string connectionString) { _connectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString)); } public async Task<List<Cryptocurrency>?> GetAllCryptocurrenciesAsync() { try { var items = new List<Cryptocurrency>(); using (var connection = new SqliteConnection(_connectionString)) { await connection.OpenAsync(); using (var command = connection.CreateCommand()) { command.CommandText = "SELECT * FROM cryptocurrencies;"; using (var reader = await command.ExecuteReaderAsync()) { while (await reader.ReadAsync()) { var item = new Cryptocurrency { Id = reader.GetInt32(0), Name = reader.GetString(1), Icon = reader.GetString(2) }; items.Add(item); } } } } return items; } catch (Exception ex) { string exceptionmsg = $"[*] - {ex.Message} - {ex.StackTrace} - [{DateTime.Now}]"; return null; } } }
MauiProgram.cs(原代码)
public static class MauiProgram { private static readonly string _databasePath = Path.Combine(FileSystem.AppDataDirectory, "Data/theboss.db"); public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); builder .UseMauiApp<App>() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); }); // Add SQLite connection var connectionStringBuilder = new SqliteConnectionStringBuilder { DataSource = $"Data Source= " + _databasePath }; var connection = new SqliteConnection(connectionStringBuilder.ConnectionString); builder.Services.AddSingleton(connection); builder.Services.AddMauiBlazorWebView(); #if DEBUG builder.Services.AddBlazorWebViewDeveloperTools(); builder.Logging.AddDebug(); #endif return builder.Build(); } }
已做排查(未解决)
尝试路径:
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Data", "theboss.db")- 实际路径:
/data/user/0/com.theboss.myapp/files/Data/theboss.db - 报错:
Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 14: 'unable to open database file'.
- 实际路径:
尝试路径:
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "theboss.db3")- 实际路径:
/data/user/0/com.theboss.myapp/files/theboss.db3 - 报错:
Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 1: 'no such table: cryptocurrencies'.
- 实际路径:
问题根源及修正方案
1. 连接字符串格式错误
原代码中SqliteConnectionStringBuilder.DataSource被错误拼接了"Data Source= "前缀,导致最终连接字符串变成Data Source= Data Source= /xxx/xxx.db的无效格式,直接去掉前缀即可。
2. 数据库目录未创建
FileSystem.AppDataDirectory下的Data文件夹默认不存在,SQLite无法在不存在的目录中创建数据库文件,需要手动创建目录。
3. 服务注册逻辑错误
直接注册SqliteConnection单例不合理,SQLite连接应随用随创建,建议注册ServiceData服务并传入正确的连接字符串。
修正后的MauiProgram.cs
public static class MauiProgram { public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); builder .UseMauiApp<App>() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); }); // 创建数据库目录 var dataDir = Path.Combine(FileSystem.AppDataDirectory, "Data"); if (!Directory.Exists(dataDir)) { Directory.CreateDirectory(dataDir); } var databasePath = Path.Combine(dataDir, "theboss.db"); // 构建正确的连接字符串 var connectionString = new SqliteConnectionStringBuilder { DataSource = databasePath, Mode = SqliteOpenMode.ReadWriteCreate // 不存在时自动创建数据库 }.ConnectionString; // 注册ServiceData服务 builder.Services.AddSingleton<ServiceData>(sp => new ServiceData(connectionString)); builder.Services.AddMauiBlazorWebView(); #if DEBUG builder.Services.AddBlazorWebViewDeveloperTools(); builder.Logging.AddDebug(); #endif return builder.Build(); } }
4. 预生成数据库部署(若使用现有数据库)
如果theboss.db是预先创建好的数据库文件,需完成两步操作:
- 将文件添加到项目中,设置复制到输出目录为
如果较新则复制 - 在应用启动时将文件从资源目录复制到目标路径,示例代码(可放在
App.xaml.cs的OnStart方法中):
var targetPath = Path.Combine(FileSystem.AppDataDirectory, "Data/theboss.db"); if (!File.Exists(targetPath)) { using var stream = await FileSystem.OpenAppPackageFileAsync("Data/theboss.db"); using var outputStream = File.OpenWrite(targetPath); await stream.CopyToAsync(outputStream); }
补充说明
第二个排查案例中出现no such table错误,是因为指定路径下无数据库文件,SQLite自动创建了空数据库,自然不存在cryptocurrencies表,解决上述路径和目录问题后即可避免。
内容的提问来源于stack exchange,提问作者Maryan

