【问题标题】:Provide a Repository class for my asp.net mvc web application. How to make sure i am disposing eveything correctly为我的 asp.net mvc web 应用程序提供一个 Repository 类。如何确保我正确处理一切
【发布时间】:2016-04-02 16:38:21
【问题描述】:

当我在我的 asp.net mvc Web 应用程序中实现一个存储库类时,我有一个关于如何管理我的 Dispose 方法的问题。

目前我有以下:-

  1. 我正在使用 VS 2013,并创建了一个新的 asp.net mvc-5 Web 应用程序。
  2. 我使用实体框架 6.0 在我的 Web 应用程序中映射我的数据库表并生成一个 .edmx 文件。
  3. 我使用“MVC 5 控制器,使用实体框架”脚手架为我的一个模型对象创建了一个新的 Controller 类。

现在在生成的控制器类中,我得到了这个 dispose 方法:-

 public class DeptsController : Controller
    {
        private ApplicationDbContext db = new ApplicationDbContext();
//code goes here
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }
    }

现在我想将我的数据访问代码移动到一个单独的 Repository 类中,并在 Repository 类中而不是在控制器类中启动我的 DbContext 对象。

所以我创建了以下存储库类:-

public class repository

    {
        private ApplicationDbContext db = new ApplicationDbContext();
        //code goes here...
        public void Dispose()
        {
            db.Dispose();
        }

我修改了我的控制器类以使用存储库类,如下所示:-

 public class DeptsController : Controller
    {
        //private ApplicationDbContext db = new ApplicationDbContext();
        private repository repo = new repository();
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                repo.Dispose();
            }
            base.Dispose(disposing);
        }
    }

所以任何人都可以就以下内容提出建议:-

  1. 因为我将把我的数据访问逻辑移动到我的存储库中,所以除了 DbContext 之外我还需要处理什么?我的意思是在使用存储库之前,在控制器内部调用base.Dispose(disposing); 将确保正确处理所有非托管资源.. 但是当我将数据访问移动到存储库内部时,我如何确保消耗所有非托管资源由存储库处置??并且在控制器类中调用 base.Disposed(disposing) ,也会释放存储库类中消耗的任何非托管资源?

任何人都可以对此提出建议吗?

【问题讨论】:

    标签: c# asp.net-mvc asp.net-mvc-5 dispose


    【解决方案1】:

    据我所知,您无需执行任何其他操作即可在 Repository 类中处理 DbContext

    如果您在Repository 类中有更多资源,那么您需要在Repository.Dispose 中添加他们的.Dispose() 调用,这样就可以了。

    base.Dispose(disposing)DeptsController 类中调用它的基类Dispose 方法,即Controller...这样基类就可以处理它在内部使用的资源 - 你不应该担心。

    【讨论】:

    • 现在假设我必须打开文件,上传图像,从我的存储库类中的外部 .csv 文件中读取,我如何确保所有这些非托管资源得到正确处理??...现在作为我知道最后的任何 Controller 类都会调用 Garabage Collector,因此在我的控制器类中调用 base.Dispose() 将确保所有这些非托管资源都被释放,但在我的情况下,我正在创建一个新的存储库类,它没有任何基类来处理垃圾收集器,......
    • 例如在这个链接asp.net/mvc/overview/older-versions/… 他们称之为“GC.SuppressFinalize(this);”在存储库类中,存储库类也实现了 IDisposable ,所以不确定我是否也需要遵循这种方法?
    • @johnG 如果您有那么深入的思考,您肯定需要开始测试具体示例并在 Visual Studio 中跟踪内存使用情况。但是你提到的所有东西都很容易处理 - 如果你开始上传图像/读取外部 csv 文件等 - 你可能会在 using() 块中这样做,这些块会立即处理,所以它们不应该是问题。
    • @johnG 请注意,您正在查看的链接已经有 3 年历史了。从那以后,实体框架发生了很大的变化——现在完全不同了。因此,我绝对建议您开始编写代码并测试您想做的事情——此时您可能正处于分析麻痹领域;)
    • 你不能。如果客户端调用Dispose 那么你会没事的,如果没有,那么一旦没有对存储库的引用,GC 就会清理它,你只是不知道什么时候。 当你有一个终结器时,你只需要调用 GC.SuppressFinalize。当您创建非托管资源时,您只需要一个终结器。在您提到的情况下,您不是。
    【解决方案2】:

    上下文并不意味着无限期地保持打开状态。它们旨在在需要时创建、使用并在您完成后处置。

    此外,ASP.NET 是一个无状态平台,因此当响应完成时,您的上下文将被垃圾回收。

    因此您的存储库不需要实现IDispoasable,因此您的控制器也不需要。在您的存储库中的 using 块内创建 DbContext,它将自动释放。

    不过……

    我如何确保存储库消耗的所有非托管资源都被释放?

    这就是Dispose 的用途。任何产生一次性物品的东西都应负责处理它们。因此,如果您在存储库中创建一次性对象并且不能立即处置它们(无论出于何种原因),那么您需要在 Dispose 方法中处置它们。如果您不从一次性基类继承,则没有要调用的基类;否则你应该调用 base dispose 来确保基类处理所有资源

    在控制器类中调用base.Disposed(disposing),也会释放存储库类中消耗的任何非托管资源?

    没有。调用base.Dispose 调用基类的Dispose 方法。基类不知道存储库,因此调用base.Dispose 对处置存储库没有任何作用。当您调用 repo.Dispose() 时,这是在控制器的 Dispose 方法中完成的。

    调用 base.Dispose(disposing);控制器内部将确保正确处理所有非托管资源。

    嗯,它确保所有非托管(和托管IDisposable)资源由基类创建都被处理掉了。由您的派生控制器创建的资源应该在覆盖的 Dispose 方法中处理(您正在这样做)。

    【讨论】:

    • @D Stanley 我的问题不是专门处理 DBConect,现在我的存储库类可能会处理和消耗非托管资源,例如读取 .csv 文件、上传图像等,所以我如何确保这些不受管理资源被正确处置。我的意思是在拥有存储库类之前,在控制器类中调用 base.Dispose() 将确保这些非托管资源将被处置,因为基控制器类将调用垃圾收集器。但在我的情况下,我引入了一个新的存储库类,它没有任何处理 GC 的基类?这是正确的吗?
    • 任何创建一次性对象的人都负责处理它们。因此,如果您在存储库中创建了一次性对象并且无法立即处置它们(无论出于何种原因),那么您需要在 Dispose 方法中处置它们。如果您不从一次性基类继承,那么就没有要调用的基类;否则,您应该调用基类 dispose 以确保基类释放任何资源。
    • 您应该在不再需要它们时立即处理掉它们。如果出于某种原因您使用类属性来保留这些资源,这意味着将它们丢弃在Dispose 中。然而,最好的方法是使用using 块将它们在创建它们的方法中 处理掉。这就是为什么我建议不要在上下文中使用类成员。处理完上下文后处理它,而您不必担心处理它,
    • 否 - 您在处理完项目后将其处置,如果开发人员不处置他/她创建的资源,最糟糕的情况是它会在垃圾收集器运行时被释放. Dispose 的重点是尽快 - 无论哪种方式,它最终都会被清理干净。您不能强制一个类“自行处理”。
    • GC 将清理所有没有活动引用的托管资源。 非托管资源应该在 Dispose 方法中被清理,终结器是最后的手段。但是,您不是在处理非托管资源 - 您是在处理托管的 FileDbContext,因此它们将在处理它们时清理它们创建的非托管资源(文件句柄、数据库连接)(或由 GC 清除)。
    猜你喜欢
    • 2016-11-28
    • 2010-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-29
    • 2021-05-17
    • 1970-01-01
    相关资源
    最近更新 更多