静态方法与数据访问层的依赖注入

时间:2015-10-29 07:56:50

标签: c# asp.net-mvc dependency-injection inversion-of-control

对于我的ASP.NET MVC项目,我过去非常依赖静态方法来进行数据访问,如下所示:

public class MyTable
{

    public static IEnumerable<MyTable> findAll()
    {
        using (var connection = new SqlConnection(Provider.connString))
        {
            //implementation here
        }


        return datas;
    }

    public static MyTable find(guid id)
    {
        using (var connection = new SqlConnection(Provider.connString))
        {
            //implementation here
        }

    }

}

所以我可以在我的控制器中像这样调用它们:

var datas = MyTable.findAll();

我对此感到满意,但我怀疑我是否正在通过它进行数据访问。

现在,我试图将依赖注入仅仅用于某些学习目的,我的数据访问类是这样的:

public class MyTable
{

    public IDatabaseEngine _engine = null;

    public MyTable()
    {
    }

    public MyTable(IDatabaseEngine engine)
    {
        _engine = engine;
    }

    public IEnumerable<MyTable> findAll()
    {
        using (var connection = _engine.getConnection())
        {
            //implementation here
        }
        return datas;
    }

    public MyTable find(guid id)
    {
        using (var connection = _engine.getConnection())
        {
            //implementation here
        }
        return data;
    }
}

问题是,这意味着我必须创建一个MyTable类的实例来调用我的控制器上的数据访问方法,如下所示:

var table = new MyTable(new MSSQLEngine(provider.connString));
var datas = table.findAll(); 

我要非常缺乏经验来解决这个问题,或者我做错了,我觉得在为我需要的每个数据访问实例化对象时感到不舒服。

我的问题是

  1. 我执行依赖注入错了吗? (我想我是)
  2. 创建要调用的数据访问类的对象是一种好习惯 控制器或其他类中的数据访问方法?
  3. 使用静态方法代替它是一种好习惯吗? (就像我一样 在第一个例子中做)
  4. 如果我的DI实施错误,我该怎么做?

3 个答案:

答案 0 :(得分:1)

您的问题的答案:

  1. 不,见下面的详细答案
  2. DI的主要优点是依赖抽象而不是实现。你不需要创建类的实例,DI会为你做的。您只需要在您的类中注入接口并在IoC中注册它们。
  3. 不,因为您将无法为您的方法编写单元测试。
  4. 见下文。
  5. 要正确使用DI,首先需要将MyTable类解压缩到接口中,然后将该接口注入控制器。

    public interface IMyTable 
    {
        IEnumerable<MyTable> findAll();
        // other methods
    }
    
    public class MyTable : IMyTable 
    {
        // your implementation
    }
    

    然后你的控制器应该是这样的:

    public class YourController : Controller
    { 
        private IMyTable myTable;
        public YourController(IMyTable myTable)
        {
            this.myTable = myTable;
        }
    
        public ActionResult YourAction()
        {
            var result = myTable.findAll();
            // ...
        }
    }
    

    我个人使用Castle Windsor作为IoC容器,here is an example在ASP.NET MVC应用程序中使用Castle Windsor

答案 1 :(得分:1)

虽然DI在某些情况下很酷,但在大多数情况下是过度工程!

我解释一下。如何创建静态方法。只需在方法前放置“静态”。你可以通过调用Class.Method()轻松调用它。此外,它对系统有效,因为该方法只创建一次。

亲:效率很高。 缺点:不可变

虽然DI,你可能需要一些容器,然后是一个接口,你可以添加一个类,任何实现该接口的类。而且,在代码的某些部分,您将需要创建该类的实例(ergo是该方法的新实例)。

亲:是可变的 缺点:效率不高,其冗长。

答案 2 :(得分:0)

  1. 依赖注入只是一种在实例字段中存储依赖关系的技术,因此您基本上是在MyTable实现中正确执行。

  2. 如果要在控制器的构造函数中获取IDatabaseEngine的实例,如果要在控制器的测试中模拟数据库引擎,则可以从依赖注入中受益。您仍然需要一种在应用程序中注入实例的方法。至于现在,您正在控制器中创建具体类MSSQLEngine的实例,因此没有任何好处。

  3. 在这种情况下使用静态方法并不好,因为在您决定实现数据库无关的测试时,您需要重构使用实例。从最小的测试设置开始是一个很好的做法,因此您可以在项目生命周期的早期阶段实现可测试性。我建议在你的代码库变大之前做这个很难的部分。

  4. 了解如何在控制器中注入IDatabaseEngine的实例,并编写一个利用依赖注入的最小测试。大多数MVC框架允许设置作为工厂的IoC容器。在测试中,您需要使用一些模拟实现或模拟框架(如Moq)来组成IDatabaseEngine的实例。