如何确保Ninject自动调用Dispose()方法?

4

1)

public class DataProvider : IProvider , IDisposable{

       private SqlConnection connection = null;
       public DataProvider(string ConnectionString) {
            this.connection = new SqlConnection(ConnectionString);
           this.connection.Open();
       }

       public object GetUniqueData(SqlCommand CommandSql){}

       public void ExecuteInsertDeleteUpdate(SqlCommand CommandSql){}

       public void Dispose(){
          if (this.connection != null) {
              this.connection.Close();
              this.connection.Dispose();
          }
       }
}

2)

public class ManageBrandDAL : IManageBrandDAL {

      private IProvider provider = null;

      [Inject]
      public ManageBrandDAL (IProvider provider_){
           this.provider  = provider_;
      }

      public void RegisterBrand(string a_BrandName){
           SqlCommand SQLCommand =
               new SqlCommand("INSERT INTO Brand(name) VALUES(@pm_brandname)");
           SqlParameter pm_brandname= new SqlParameter();
           pm_brandname.ParameterName = "@pm_brandname";
           pm_brandname.DbType = DbType.String;
           pm_brandname.Value = a_BrandName;
           SQLCommand.Parameters.Add(pm_brandname);
           this.provider.ExecuteInsertDeleteUpdate(SQLCommand);
       }

3)

public class ModuleInfra : Ninject.Modules.NinjectModule
{
      public override void Load(){
            Bind<IProvider>()
                .To<ProvedorDados()
                .InTransientScope()
                .WithConstructorArgument("ConnectionString", Manage.ConnectionString);
      }
}

我该如何保证 Ninject 容器会在 ManageBrandDAL 使用 DataProvider 对象后调用 DataProvider 类中的 Dispose() 方法?
在这种情况下,InTransientScope() 生命周期是最合适的吗?如果不是,什么生命周期更适合?

2
为什么要在 DataProvider 类中保持连接处于打开状态?如果您在单个方法内打开和关闭连接,则无需实现“DIsposable”。 - Steven
1
请参阅https://dev59.com/9mkv5IYBdhLWcg3w9lWi。 - Daniel Marbach
除了保持数据库连接处于打开状态之外,我认为还有一个通用规则,即构造函数不应该抛出异常。你的设计很容易发生这种情况。 - Yuck
请看这里 https://github.com/ninject/ninject/wiki/Object-Scopes 然后再看这里 http://kohari.org/2009/03/06/cache-and-collect-lifecycle-management-in-ninject-20/ - dotjoe
@Yuck 避免在构造函数中抛出异常的原理是什么?我曾经看到过这种情况的唯一地方是在Symbian操作系统上,那里平台强加的限制使得像基于约定的2阶段构建这样的丑陋Hack成为必要。 - anton.burger
1个回答

4
当您将 DataProvider InTransientScope()绑定时,它不会被Ninject处理,因为实际上瞬态作用域根本没有范围。 Ninject在为您创建一个对象后不会跟踪绑定在瞬态作用域中的对象。
Ninject会在底层作用域对象被GC收集时立即释放实现 IDisposable 的对象的实例(但是如我所说,对于绑定到瞬态作用域的对象,这是无效的,因为没有这样的作用域对象)。
您应该将 DataProvider 绑定到适合您的应用程序的作用域中。 它可以是:
  • Web应用程序的 InRequestScope()(Ninject将在http请求结束后释放实现 IDisposable 的对象的实例 - 不要忘记包括 OncePerWebRequest 模块)
  • InSingletonScope() - 对象实例将在整个应用程序生命周期内重复使用 - 就我而言,对于持有资源(例如 SqlConnection )的对象来说,这不是一个选择
  • InThreadScope() - 对象实例将在同一线程内重复使用
  • InScope() - 这可以用于创建自定义作用域,因此根据您的应用程序类型,您可以考虑创建适合您需求的自定义作用域。
Ninject还提供了一些有趣的扩展,提供了额外的范围定义:https://github.com/ninject/ninject.extensions.namedscope/wiki
提示:
  • 您不需要同时调用 Close() Dispose()来关闭 SqlConnection Dispose()就足够了,因为它在内部调用了 Close()
  • 我没有看到整个代码,但是不要忘记也要释放 SqlCommand
  • 如果您让Ninject创建 ManageBrandDAL 实例,则不需要在其构造函数上使用 InjectAttribute 。 它将使您摆脱使用特定的IOC提供程序。

亲爱的Mipe34,对于一个Windows服务,哪种SCOPE更适合?该应用程序将在每20秒打开/关闭数据库连接以更新一些表格?提前感谢。 - rol
嗯,我对Windows服务不是很了解。但我会使用InScope()方法进行自定义范围,或者更好的选择是使用ninject扩展中的InNamedScope()InParentScope()。阅读这篇文章http://www.planetgeek.ch/2010/12/08/how-to-use-the-additional-ninject-scopes-of-namedscope/,了解如何使用附加作用域。 - mipe34
Transient作用域中的对象何时被处理并释放? - Ozkan
当它们被垃圾回收时。请参见此链接:https://dev59.com/9mkv5IYBdhLWcg3w9lWi?noredirect=1&lq=1 - mipe34

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接