当我尝试添加评论时,出现以下错误:
ObjectDisposedException:无法访问已处置的对象。
当代码运行第二行时:
m_context.Comments.Add(comment);
m_context.SaveChanges();
为什么要处理上下文?如果将TryAddComment方法移入控制器,则不会提早调用Dispose。
这是我的Controller和Repository类的样子(简化)。
CommentsController.cs:
public class CommentsController : Controller
{
private ICommentRepository m_commentRepository;
public CommentsController(ICommentRepository commentRepository)
{
m_commentRepository = commentRepository;
}
// POST: api/Comments
[HttpPost]
public async Task<IActionResult> PostComment([FromBody] CommentAddViewModel commentVM)
{
Comment comment = new Comment
{
ApplicationUserId = User.GetUserId(),
PostId = commentVM.PostId,
Text = commentVM.Text
};
bool didAdd = m_commentRepository.TryAddComment(comment);
if (!didAdd)
{
return new HttpStatusCodeResult(StatusCodes.Status409Conflict);
}
return CreatedAtRoute("GetComment", new { id = comment.CommentId }, comment);
}
}
CommentRepository.cs:
public class CommentRepository : ICommentRepository, IDisposable
{
public ApplicationDbContext m_context;
public CommentRepository(ApplicationDbContext context)
{
m_context = context;
}
public bool TryAddComment(Comment comment)
{
m_context.Comments.Add(comment);
m_context.SaveChanges();
return true;
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
m_context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
编辑:
如果我使用本地CommentRepository,它将按预期工作。例如:
CommentRepository localCommentRepo = new CommentRepository(m_context);
bool didAdd = localCommentRepo.TryAddComment(comment);
编辑2:
在Startup.cs中,我将IcommentRepository注册为Scoped并按预期工作。最初是Singleton。为什么单身人士会导致此问题?
services.AddSingleton<ICommentRepository, CommentRepository>(); //breaks
services.AddScoped<ICommentRepository, CommentRepository>(); //works
编辑3:
ApplicationDbContext.cs:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
}
public DbSet<Post> Posts { get; set; }
public DbSet<Comment> Comments { get; set; }
}
您的存储库和您的存储库都不DbContext
应该是单例。注册它们的正确方法是services.AddScoped
或services.AddTransient
,因为DbContext
生存期不应长于请求,而AddScoped
恰恰是为此目的。
AddScoped
将DbContext
在范围的生命周期(在ASP.NET Core中等于请求的生命周期)的范围内返回一个(和存储库,如果您以此方式注册的)相同实例。
使用时,AddScope
您不应该自己处置上下文,因为解析存储库的下一个对象将具有处置的上下文。
实体框架默认情况下将上下文注册为作用域,因此您的存储库应为作用域(与上下文和请求相同的生存期)或临时的(每个服务实例获取其自己的存储库实例,但请求中的所有存储库仍共享相同的存储库)语境)。
使上下文单例会导致严重的问题,尤其是在内存方面(您处理的越多,上下文消耗的内存越多,因为它必须跟踪更多的记录)。因此,aDbContext
应该尽可能短命。
上下文的持续时间的优势在于,如果出现问题,您仍然可以回滚请求期间的所有操作,并将其作为一个事务处理。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句