Blazor Server应用System.ObjectDisposedException异常排查求助
错误描述
System.ObjectDisposedException: 无法访问已释放的上下文实例。此错误的常见原因是将通过依赖注入解析的上下文实例释放后,又在应用的其他位置尝试使用同一实例。这可能是因为您调用了上下文实例的'Dispose'方法,或是将其包裹在using语句中。如果您使用依赖注入,应让依赖注入容器负责处理上下文实例的释放。
对象名称: 'MyDbContext'。
相关代码
模型类
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace SAPConnection.Data { public class LeaveModel { [Key] public int Id { get; set; } public String Reason { get; set; } = ""; public DateTime RequestDate { get; set; } = DateTime.Now; public DateTime ToDate { get; set; } = DateTime.Now; public DateTime FromDate { get; set; } = DateTime.Now; public LeaveTypeModel LeaveType { get; set; } [NotMapped] public byte[] Attachment { get; set; } } } public enum LeaveTypeModel { Casual, Sick, Annual }
LeaveService类
using Microsoft.EntityFrameworkCore; using System.Collections.Generic; using System.Threading.Tasks; namespace SAPConnection.Data { public class LeaveService { private readonly MyDbContext _context; public LeaveService(MyDbContext context) { _context = context; } public async Task<List<LeaveModel>> GetLeavesAsync() { return await _context.leaveModel.ToListAsync(); } public async Task<LeaveModel> GetLeaveAsync(int id) { return await _context.leaveModel.FindAsync(id); } public async Task CreateLeaveAsync(LeaveModel leave) { _context.leaveModel.Add(leave); await _context.SaveChangesAsync(); } public async Task UpdateLeaveAsync(LeaveModel leave) { _context.Entry(leave).State = EntityState.Modified; await _context.SaveChangesAsync(); } public async Task DeleteLeaveAsync(int id) { var leave = await _context.leaveModel.FindAsync(id); _context.leaveModel.Remove(leave); await _context.SaveChangesAsync(); } } }
提交请假申请函数
private async Task submitLeaves() { await leaveService.CreateLeaveAsync(newLeave); NavigationManager.NavigateTo("/"); }
Program.cs类
using Blazored.Toast; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; using SAPConnection.Data; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using SAPConnection.Areas.Identity.Data; using System.Configuration; var builder = WebApplication.CreateBuilder(args); var connectionString = builder.Configuration.GetConnectionString("SAPConnectionContextConnection") ?? throw new InvalidOperationException("Connection string 'SAPConnectionContextConnection' not found."); builder.Services.AddDbContext<SAPConnectionContext>(options => options.UseSqlServer(connectionString)); builder.Services.AddDbContext<MyDbContext>(options => options.UseSqlServer(connectionString)); builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true).AddEntityFrameworkStores<SAPConnectionContext>(); // Add services to the container. builder.Services.AddRazorPages(); builder.Services.AddServerSideBlazor(); builder.Services.AddSingleton<WeatherForecastService>(); builder.Services.AddScoped<LeaveService>(); builder.Services.AddBlazoredToast(); var app = builder.Build(); // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.MapBlazorHub(); app.MapFallbackToPage("/_Host"); app.Run();
问题排查与解决方案
核心原因
Blazor Server中,DbContext默认生命周期为Scoped,但Blazor的SignalR长连接作用域和ASP.NET Core传统请求作用域逻辑不同。如果MyDbContext被手动释放(如调用Dispose、用using块包裹创建),或服务/组件中错误管理了上下文生命周期,后续操作就会触发已释放异常。
具体修复步骤
确认DbContext注册规范
当前Program.cs中MyDbContext注册未显式指定生命周期,默认是Scoped,符合Blazor Server要求。可修改为显式注册,提升代码可读性:builder.Services.AddDbContext<MyDbContext>(options => options.UseSqlServer(connectionString), ServiceLifetime.Scoped);禁止手动管理DbContext生命周期
检查所有使用MyDbContext的代码,确保没有调用_context.Dispose(),也没有手动new MyDbContext并在using块中使用的情况。依赖注入的上下文实例,生命周期完全由容器负责。组件注入方式校验
确保组件中通过构造函数或属性注入LeaveService,禁止手动创建实例:// 组件中正确注入示例 [Inject] public LeaveService leaveService { get; set; } [Inject] public NavigationManager NavigationManager { get; set; }优化SubmitLeaves方法
确认newLeave对象无已释放上下文关联引用,NavigationManager.NavigateTo("/")跳转操作不会导致上下文释放,但需保证CreateLeaveAsync执行完成后无异步操作持有上下文引用。特殊场景:使用DbContext工厂
若服务需在长生命周期组件中多次使用上下文,可改用IDbContextFactory<MyDbContext>创建实例,使用后手动释放:- 修改Program.cs注册:
builder.Services.AddDbContextFactory<MyDbContext>(options => options.UseSqlServer(connectionString)); - 修改LeaveService:
public class LeaveService { private readonly IDbContextFactory<MyDbContext> _contextFactory; public LeaveService(IDbContextFactory<MyDbContext> contextFactory) { _contextFactory = contextFactory; } public async Task CreateLeaveAsync(LeaveModel leave) { using var context = _contextFactory.CreateDbContext(); context.leaveModel.Add(leave); await context.SaveChangesAsync(); } // 其他方法同理,用using块创建上下文 }
- 修改Program.cs注册:
内容的提问来源于stack exchange,提问作者abraKajapa

