Blazor .NET 8应用SignalR更新后数据不显示问题排查
问题分析与解决方案
问题根源
核心原因是EF Core的上下文跟踪缓存机制:当View页面首次加载时,EF Core的ApplicationDbContext会跟踪加载的Debtor实体实例。当Edit页面更新数据库中的数据后,View页面通过SignalR触发RefreshData执行查询时,EF Core会直接返回上下文缓存中的旧实体,而非从数据库获取最新数据。这种情况在.NET 8的Interactive Server模式下更易显现,因为该模式下组件的生命周期更长,上下文缓存的实体不会被及时清理。
解决方案
方案1:关闭查询跟踪(推荐)
修改Repository中的查询方法,添加AsNoTracking(),确保每次查询都跳过上下文缓存,直接从数据库获取最新数据:
public class Repository<T> : IRepository<T> where T : class { private ApplicationDbContext _db; public Repository(ApplicationDbContext db) { _db = db; } public async Task<T> GetSingleOrDefaultWhereIncludeAsync(Expression<Func<T, bool>> where, string include) { // 添加AsNoTracking()关闭跟踪 return await _db.Set<T>().Include(include).AsNoTracking().SingleOrDefaultAsync(where); } }
方案2:分离旧实体(如需保留跟踪场景)
如果业务需要保持实体跟踪(比如后续要修改该实体),可以在RefreshData方法中先将旧的_debtor实例从上下文分离,再执行查询:
private async Task RefreshData(bool? firstrender = false) { // 分离旧的跟踪实体 var entry = _db.Entry(_debtor); if (entry.State != EntityState.Detached) { entry.State = EntityState.Detached; } _debtor = await _debtorRepos.GetSingleOrDefaultWhereIncludeAsync(x => x.Deleted == false && x.Id == DebtorId, "Contacts"); StateHasChanged(); }
额外验证
确保ApplicationDbContext的注册方式为Scoped(Blazor Server的默认推荐生命周期),避免因上下文单例导致的全局缓存问题:
// Program.cs中的DbContext注册 builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")), ServiceLifetime.Scoped);
为什么.NET 7正常?
在.NET 7的Blazor Server模式下,组件的Scoped生命周期与上下文的匹配度更高,组件销毁时上下文也会被及时回收,缓存的实体不会长期存在。而.NET 8的Interactive Server模式优化了组件存活机制,上下文缓存的问题更容易暴露。
内容的提问来源于stack exchange,提问作者Jeremy
相关产品推荐
相关产品推荐

