ASP.NET项目使用EF Core Migrate时触发System.ExecutionEngineException异常
解决ASP.NET WebApi + EF Core 2.0.2 + SQLite进程回收后迁移异常的问题
我之前维护WebApi项目时也碰到过几乎一模一样的问题,结合你的描述,核心问题大概率是SQLite文件锁机制+迁移执行时机不当导致的——尤其是Release模式下没有调试器兜底,异常直接中断了流程。下面给你几个针对性的解决方案:
1. 不要在应用启动同步流程中执行迁移
很多人习惯在Startup.Configure里同步调用dbContext.Database.Migrate(),但进程回收重启时,IIS可能还没完全释放之前的数据库连接句柄,导致SQLite文件被锁。建议把迁移改成后台异步执行,避开应用启动的关键流程:
public void Configure(IApplicationBuilder app, IServiceProvider serviceProvider) { // 其他中间件配置(路由、CORS等)... // 把迁移放到后台任务执行,不阻塞应用启动 Task.Run(async () => { using (var scope = serviceProvider.CreateScope()) { var dbContext = scope.ServiceProvider.GetRequiredService<YourDbContext>(); try { await dbContext.Database.MigrateAsync(); } catch (Exception ex) { // 添加日志记录,方便排查异常原因 // 比如:scope.ServiceProvider.GetRequiredService<ILogger<Startup>>().LogError(ex, "数据库迁移失败"); } } }); }
2. 调整SQLite连接字符串参数,减少锁冲突
SQLite是文件级锁,进程回收后的残留连接很容易导致锁异常。修改你的连接字符串,添加几个关键参数:
"ConnectionStrings": { "YourDbConnection": "Data Source=your_database.db;Cache=Shared;Mode=ReadWriteCreate;Pooling=false" }
Cache=Shared:允许多个进程共享数据库缓存,降低锁竞争概率Pooling=false:关闭连接池,避免旧的连接池连接持有文件锁不释放Mode=ReadWriteCreate:确保应用有读写权限,同时不存在数据库时自动创建
3. 给迁移添加重试机制,处理临时锁异常
Debug模式下你点击取消后能成功,本质是第一次迁移因为锁失败,第二次尝试时锁已经释放了。在Release模式下,我们可以用重试策略自动处理这种情况,推荐用Polly库实现:
首先安装Polly包:
Install-Package Polly
然后在迁移代码中添加重试逻辑:
using Polly; // ... 后台任务中的迁移代码 var retryPolicy = Policy .Handle<Microsoft.Data.Sqlite.SqliteException>(ex => ex.Message.Contains("locked")) .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); // 指数退避重试 await retryPolicy.ExecuteAsync(async () => { await dbContext.Database.MigrateAsync(); });
这样如果第一次迁移碰到锁异常,会自动重试3次,每次间隔时间翻倍,大概率能等到锁释放后成功执行。
4. 检查Release模式下的文件权限
虽然Debug和Release权限通常一致,但还是可以确认一下:应用池的运行身份是否对数据库文件所在目录(比如App_Data)有读写权限,避免因为权限问题导致迁移失败。
按照上面的步骤调整后,应该就能解决进程回收后的迁移异常问题了,我当时就是这么搞定的😉
内容的提问来源于stack exchange,提问作者peterc
相关产品推荐
相关产品推荐

