c# - ASP.Net Core MVC 存储库模式意外处置

标签 c# asp.net asp.net-core asp.net-core-mvc

当我尝试添加评论时,出现以下错误:

ObjectDisposedException: Cannot access a disposed object.

当代码运行到第二行时:

m_context.Comments.Add(comment);
m_context.SaveChanges();

为什么要释放上下文?如果将 TryAddComment 方法移动到 Controller 中,它不会提前调用 Dispose。

这是我的 Controller 和 Repository 类的样子(简化)。

评论 Controller .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);
    }

}

评论库.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 并按预期工作。最初是辛格尔顿。为什么单例会导致这个问题?

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.AddScopedservices.AddTransient , 作为 DbContext不应该比请求和 AddScoped 长正是为了这个。

AddScoped将返回 DbContext 的相同实例(和存储库,如果你这样注册的话)在范围的生命周期内(在 ASP.NET Core 中等于请求的生命周期)。

当您使用 AddScope 时你不应该自己处理上下文,因为解析你的存储库的下一个对象将有一个处理过的上下文。

Entity Framework 默认将上下文注册为作用域,因此您的存储库应该是作用域的(与上下文和请求的生命周期相同)或 transient 的(每个服务实例都有自己的存储库实例,但请求中的所有存储库仍然共享相同的上下文)。

使上下文成为单例会导致严重的问题,尤其是内存问题(您处理得越多,上下文消耗的内存就越多,因为它必须跟踪更多的记录)。所以一个DbContext应尽可能短命。

上下文持续时间的优势在于,如果出现问题,您仍然可以在请求期间回滚所有操作并将其作为单个事务处理。

关于c# - ASP.Net Core MVC 存储库模式意外处置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35545838/

相关文章:

c# - 如何让注册的用户控件在 C# 中进行代码隐藏?

asp.net - C# 部分类的 ColdFusion CFC 实现?

ASP.NET 5 OAuth 不记名 token 身份验证

c# - 异步执行方法的最快方法?

c# - 使用 SqlDataReader 执行一系列 SQL 查询

asp.net - 如何使两个文本框显示为一个?

asp.net-core - 在 Ubuntu 上使用 ASP.NET Core 的 SkiaSharp

asp.net-core - 从 Json.Net 中的 JsonReaderException 查找无效值

c# - 在 LINQ 查询中包含百分比计算

c# - 总和列表到新列表