在Blazor WebAssembly项目中引入Entity Framework Core,本质上是把原本运行在服务端的对象关系映射能力移植到浏览器沙箱里。得益于Mono Wasm与.NET运行时的支持,EF Core的SQLite提供程序可以直接在客户端工作,让前端应用拥有结构化数据存储与查询能力,而不必每次都依赖远程API。

一、技术原理与适用场景
Blazor Wasm执行的.NET代码最终被编译为Wasm指令,在浏览器中通过JavaScript胶水层调用。EF Core本身与具体数据库解耦,只要提供程序能在Wasm环境运行即可。SQLite的官方移植版(如sql.js或基于Wasm的SQLite)配合Microsoft.EntityFrameworkCore.Sqlite,能够在内存或浏览器存储中维护一个数据库文件。
这种方案适合离线优先的轻量级应用,例如本地记账、表单草稿缓存、小型目录管理。它不适合高并发写入或需要强一致性的多用户系统,因为数据仅存在于单个浏览器。理解这一点,才能合理设计上下文生命周期与同步策略。
二、基础集成步骤
首先通过NuGet安装必要包。注意不能引用SqlServer相关包,否则会在Wasm中触发平台异常。推荐组合为Microsoft.EntityFrameworkCore.Sqlite与Microsoft.EntityFrameworkCore.Tools(仅开发期使用)。
// 安装命令示例(包管理器控制台)
// Install-Package Microsoft.EntityFrameworkCore.Sqlite
// Install-Package Microsoft.EntityFrameworkCore.Tools
using Microsoft.EntityFrameworkCore;
public class AppDbContext : DbContext
{
public DbSet<TodoItem> Todos { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
// 在Blazor Wasm中,路径需结合JS互操作写入IndexedDB
options.UseSqlite("Data Source=local.db");
}
}
public class TodoItem
{
public int Id { get; set; }
public string Title { get; set; }
public bool IsDone { get; set; }
}
上面代码定义了一个最简上下文。在Wasm里,local.db并不会直接落到磁盘,而是依赖底层存储抽象。你需要编写JS互操作代码,将SQLite文件流保存到IndexedDB,启动时再读取回来。这一步常被忽略,导致刷新页面后数据丢失。
在服务注册方面,应在Program.cs中将上下文注册为Scoped,这样每个用户会话拥有独立实例,避免多线程冲突。Wasm是单线程模型,但Scoped有助于逻辑隔离。
// Program.cs 部分代码 using Microsoft.Extensions.DependencyInjection; var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.Services.AddScoped<AppDbContext>(); await builder.Build().RunAsync();
三、数据持久化与JS互操作
因为浏览器禁止直接文件API,我们必须借助IJSRuntime。典型方案是用sql.js的Wasm构建,将整个数据库导出为Uint8Array,存入IndexedDB。以下示例展示保存与加载的简化逻辑。
// wwwroot/interop.js
window.dbStorage = {
save: async function (name, data) {
let db = await indexedDB.open('efcore');
// 简化写入逻辑
return new Promise(res => {
var tx = db.transaction('files', 'readwrite');
tx.objectStore('files').put(data, name);
tx.oncomplete = () => res(true);
});
},
load: async function (name) {
let db = await indexedDB.open('efcore');
return new Promise(res => {
var tx = db.transaction('files', 'readonly');
var rq = tx.objectStore('files').get(name);
rq.onsuccess = () => res(rq.result);
});
}
};
在C#侧,通过IJSRuntime调用上述方法。要注意的是,EF Core的SaveChanges会写内存库,随后你需要主动触发导出。很多开发者误以为UseSqlite会自动持久化,结果丢失数据。
此外,包体积是个痛点。EF Core与SQLite Wasm加起来可能让首屏下载超过数MB。可通过裁剪 unused 程序集、启用IL链接器减少体积,或者采用延迟加载数据库脚本的方式优化体验。
四、常见误区与优化建议
第一个误区是混用服务端DbContext工厂。在Wasm中不要使用AddDbContextFactory连接远程SQL,那违背了离线初衷。第二个误区是在UI线程执行大批量查询,造成界面卡顿。应将重查询放入Task.Run,尽管Wasm单线程,但可让出渲染机会。
| 问题 | 表现 | 解决 |
|---|---|---|
| 数据刷新丢失 | 重新加载页面后记录为空 | 实现IndexedDB导出导入 |
| 包过大 | 首屏缓慢 | 启用链接裁剪、懒加载 |
| 平台异常 | 引用SqlServer包报错 | 仅用Sqlite提供程序 |
经过上述处理,你的Blazor Wasm应用就能以EF Core管理本地数据。后续可结合Web Worker进一步提升查询响应,或利用EF迁移生成初始结构,保持客户端与服务端模型一致。
EF_CoreBlazor_WasmSQLite修改时间:2026-08-01 20:30:26