.NET6中使用EF遇System.ObjectDisposedException错误求助
我在.NET6环境中尝试实现UnitOfWork模式,运行应用访问数据库后,收到错误:System.ObjectDisposedException: 'Cannot access a disposed context instance'。
最初基于UnitOfWork的实现
Register.cshtml中的OnPost方法:
// Register.cshtml public async void OnPost(string name, string email, string emailConfirm, string password, string passworConfirm) { try { var user = mapUser(name, email, password); await _securityService.RegisterNewUserAsync(user); } catch(Exception ex) { } }
报错的SecurityService.RegisterNewUserAsync方法:
namespace CompanyMannager.Services.Security { public class SecurityService : ISecurityService { private readonly IUserService _userService; public SecurityService(IUserService userService) { _userService = userService; } public async Task RegisterNewUserAsync(User user) { // var userTokenService = new UserTokenService(_unitOfWork); var users = await _userService.GetByNameOrEmailAsync(user.Name, user.Email); if (users.Any()) { throw new DuplicateNameException("The name or email is already in use, please try when other email and name."); } await _userService.CreateUser(user, Convert.ToBase64String(salt)); } } }
UserService代码:
namespace CompanyMannager.Services { public class UserService : IUserService { private readonly IUnitOfWork _unitOfWork; public UserService(IUnitOfWork unitOfWork) { _unitOfWork = unitOfWork; } public async Task<IEnumerable<User>> GetByNameOrEmailAsync(string name, string email) { return await _unitOfWork._userRepository.GetAsync(x => x.Name == name || x.Email == email); } } }
UserRepository代码:
public class UserRepository : BaseRepository<User>, IUserRepository { public UserRepository(CompanyMannagerDBContext context) : base(context) { } }
BaseRepository代码:
public class BaseRepository<TEntity> : IBaseRepository<TEntity> where TEntity : class { private readonly CompanyMannagerDBContext _Context; internal DbSet<TEntity> dbSet; public BaseRepository(CompanyMannagerDBContext context) { _Context = context; dbSet = context.Set<TEntity>(); } public async Task<IEnumerable<TEntity>> GetAsync(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "") { IQueryable<TEntity> query = dbSet; if (filter != null) query = query.Where(filter); foreach (var includeProperty in includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) { query = query.Include(includeProperty); } if (orderBy != null) return await orderBy(query).ToListAsync(); else return await query.ToListAsync(); } }
UnitOfWork代码:
public class UnitOfWork : IUnitOfWork { public IUserRepository _userRepository { get; } public IUserTokenRepository _userTokenRepository { get; } private readonly CompanyMannagerDBContext _context; public UnitOfWork(CompanyMannagerDBContext context, IUserRepository userRepository, IUserTokenRepository userTokenRepository) { _context = context; _userRepository = userRepository; _userTokenRepository = userTokenRepository; /* public IUserRepository UserRepository => _userRepository ??= new UserRepository(_context); public IUserTokenRepository UserTokenRepository => _userTokenRepository ??= new UserTokenRepository(_context); */ } public async Task<int> CommitAsync() { return await _context.SaveChangesAsync(); } public void Dispose() { _context.Dispose(); } }
我尝试修改依赖注入配置,但错误依旧。之后我改为直接使用EntityFramework的基础实现,错误仍然存在,具体错误信息为:
System.ObjectDisposedException: 'Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
ObjectDisposed_ObjectName_Name'
修改后的基础EF实现代码
Register.cshtml代码:
using Microsoft.AspNetCore.Mvc.RazorPages; namespace CompanyMannager.UI.Areas.Identity.Pages { public class RegisterModel : PageModel { public bool RegisterError = false; private readonly ISecurityService _securityService; public RegisterModel (ISecurityService securityService) { _securityService = securityService; } public void OnGet() { } public async void OnPost(string name, string email, string emailConfirm, string password, string passworConfirm) { try { var user = mapUser(name, email, password); await _securityService.RegisterNewUserAsync(user); } catch(Exception ex) { } } private User mapUser(string name, string email, string password) { var user = new User() { Name = name, Email = email, PasswordHash = password }; return user; } } }
UserService代码:
public class UserService : IUserService { private readonly CompanyMannagerDBContext _companyMannagerDBContext; public UserService(CompanyMannagerDBContext context) { _companyMannagerDBContext = context; } public async Task<User> CreateUser(User user, string salt) { try { var usrCreated = await _companyMannagerDBContext.Users.AddAsync(user); await _companyMannagerDBContext.SaveChangesAsync(); return await GetUserById(usrCreated.Entity.UserId); } catch (Exception ex) { //_unitOfWork.Dispose(); throw new ApplicationException($"Create user error - {ex.Message} "); } } public async Task<IEnumerable<User>> GetByNameOrEmailAsync(string name, string email) { return await _companyMannagerDBContext.Users.Where(x => x.Name == name || x.Email == email).ToListAsync(); } }
User实体代码:
public partial class User { public int UserId { get; set; } public string? Name { get; set; } public string? NormalizedName { get; set; } public string? PasswordHash { get; set; } public string? CreateUser { get; set; } public DateTime? CreateDate { get; set; } public string? LastUpdatedUser { get; set; } public DateTime? LasteUpdatedDate { get; set; } public string? Email { get; set; } public string? NormalizeEmail { get; set; } public string? EmailVerified { get; set; } public DateTime? ExpirationDate { get; set; } public User() { } }
Program.cs代码:
using CompanyMannager.Core.Interfaces.Repositories; using CompanyMannager.Core.Interfaces.Services; using CompanyMannager.Infraestructure.Data; using CompanyMannager.Infraestructure.Repositories; using CompanyMannager.Services; using CompanyMannager.Services.Security; using Microsoft.EntityFrameworkCore; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddRazorPages(); builder.Services.AddDbContext<CompanyMannagerDBContext>(options =>options.UseSqlServer(builder.Configuration.GetConnectionString("DbConnection"))); builder.Services.AddScoped<IUserTokenRepository, UserTokenRepository>(); builder.Services.AddScoped<IUserService, UserService>(); builder.Services.AddScoped<ISecurityService, SecurityService>(); var app = builder.Build(); // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); app.UseHsts(); } using (var scope = app.Services.CreateScope()) { var services = scope.ServiceProvider; try { var context = services.GetRequiredService<CompanyMannagerDBContext>(); await DbInitializer.Initialize(context); } catch (Exception ex) { var logger = services.GetRequiredService<ILogger<Program>>(); logger.LogError(ex, "An error occurred creating the DB."); } } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.MapRazorPages(); app.Run();
DbInitializer代码:
using CompanyMannager.Core.Entities; using Microsoft.EntityFrameworkCore; namespace CompanyMannager.Infraestructure.Data { public static class DbInitializer { public static async Task Initialize(CompanyMannagerDBContext context) { context.Database.EnsureCreated(); // Look for any user. if (context.Users.Any()) { await context.Users.AnyAsync(); } else { // Create test user var users = new User[] { new User() { Name="Prueba", PasswordHash="miPassWord", CreateDate= DateTime.Now, CreateUser= "1", Email="prueba@yahoo.com.ar", EmailVerified= "1", ExpirationDate= DateTime.Now.AddDays(90), LasteUpdatedDate = DateTime.Now, LastUpdatedUser= "1", NormalizedName= "PRUEBA", NormalizeEmail = "PRUEBA@YAHOO.COM.AR" }, }; foreach (User user in users) { await context.Users.AddAsync(user); } await context.SaveChangesAsync(); var usersTokens = new UserToken[] { new UserToken() { UserId= 1, TokenHash = "hash" }, }; foreach (UserToken usersToken in usersTokens) { await context.UsersTokens.AddAsync(usersToken); } await context.SaveChangesAsync(); } } } }
我修改了DbInitializer中的查询逻辑,将同步查询改为异步,但插入用户时仍会触发相同错误,希望有人能帮我排查问题所在。
内容的提问来源于stack exchange,提问作者Mariano Ezequiel Carioni

