简体   繁体   English

使用DBContext和依赖注入的分歧

[英]Ramifications of using DBContext with Dependency Injection

I'm still kind of new to using dependency injection to manage my DBContext in an ASP.NET MVC application I'm writing. 在我正在编写的ASP.NET MVC应用程序中,使用依赖注入来管理我的DBContext仍然是一个新手。

I'm attempting to follow the approach outlined in the article Managing Entity Framework DbContext Lifetime in ASP.NET MVC . 我试图遵循ASP.NET MVC中的管理实体框架DbContext Lifetime一文中概述的方法。 Basically, this approach says to use Ninject and dependency injection and to add my DBContext as a parameter to the constructor in my controllers. 基本上,这种方法说使用Ninject和依赖注入,并将我的DBContext作为参数添加到我的控制器中的构造函数中。

Further, I am implementing this in a base controller, or which all my controller classes will be derived. 此外,我在基本控制器中实现它,或者我的所有控制器类将被派生。

This is working, but I'm hitting on the following issues. 这是有效的,但我正在努力解决以下问题。

  1. This approach requires that every derived controller class also implements a constructor that accepts any arguments requires by my controller base class. 这种方法要求每个派生的控制器类还实现一个构造函数,该构造函数接受我的控制器基类所需的任何参数。 Not only does this seem like a lot of extra typing that I must remember to add to any new derived class, but it also means that if I change the data passed to the constructor then I must modify the constructor in every derived controller class. 这不仅仅是我必须记住添加到任何新派生类的额外输入,但它也意味着如果我更改传递给构造函数的数据,那么我必须修改每个派生控制器类中的构造函数。

  2. This gives me a DBContext for all my controller classes. 这为我的所有控制器类提供了一个DBContext。 But what about other classes in my model that need the DBContext? 但是我的模型中需要DBContext的其他类呢? Should I need to manually pass the instance to the DBContext to all these classes? 我是否需要手动将实例传递给DBContext到所有这些类? Or is there a way to use DI for each of these classes to get their own copy of the DBContext? 或者有没有办法为每个类使用DI来获取自己的DBContext副本?

This approach requires that every derived controller class also implements a constructor that accepts any arguments requires by my controller base class. 这种方法要求每个派生的控制器类还实现一个构造函数,该构造函数接受我的控制器基类所需的任何参数。 Not only does this seem like a lot of extra typing that I must remember to add to any new derived class, but it also means that if I change the data passed to the constructor then I must modify the constructor in every derived controller class. 这不仅仅是我必须记住添加到任何新派生类的额外输入,但它也意味着如果我更改传递给构造函数的数据,那么我必须修改每个派生控制器类中的构造函数。

This is one of the approach (Heavy Controller) that you may choose to use EF into your application, IMO its not the cleanest approach. 这是您可以选择将EF用于您的应用程序的方法之一(重型控制器),IMO并不是最干净的方法。 And you correctly noticed the drawbacks your self. 你正确地注意到了你自己的缺点。

If we relate this approach to design principle, it breaks Single Responsibility Principle as controller is expected to do more (fetch or update DB) than just collecting the data and return the appropriate view with data. 如果我们将这种方法与设计原则联系起来,它会破坏单一责任原则,因为控制器需要做的更多(获取或更新数据库),而不仅仅是收集数据并返回带有数据的相应视图。 And how about business rules, would controller apply it, if you need to send an email, would controller does that as well. 如果需要发送电子邮件,控制器会应用它来管理业务规则,控制器也可以这样做。 You ought to have another layer of business/service classes that are specifically designed for a set of requirement eg EmailHelper would send emails. 您应该有另一层业务/服务类,专门针对一组需求而设计,例如EmailHelper会发送电子邮件。

It also breaks Open Close Principle as you need to change the constructors every time you change the input parameter. 它还会打破Open Close Principle,因为每次更改输入参数时都需要更改构造函数。

This gives me a DBContext for all my controller classes. 这为我的所有控制器类提供了一个DBContext。 But what about other classes in my model that need the DBContext? 但是我的模型中需要DBContext的其他类呢? Should I need to manually pass the instance to the DBContext to all these classes? 我是否需要手动将实例传递给DBContext到所有这些类?

As far as dependency injection is concerned one of the goal is, to inject the dependency where it is needed directly. 就依赖注入而言,其中一个目标是将依赖注入直接需要的地方。 If you have a model class that needs DbContext, you should inject it in your model class constructor (most DI framework support property injection as well but constructor remains favourite approach). 如果你有一个需要DbContext的模型类,你应该将它注入你的模型类构造函数中(大多数DI框架支持属性注入,但构造函数仍然是最喜欢的方法)。

With DI Framework, you will configure the dependencies at one place (application initialization code) and then each class that need a dependency just accept it in constructor. 使用DI Framework,您将在一个位置配置依赖项(应用程序初始化代码),然后每个需要依赖项的类只在构造函数中接受它。

DI Container can be compared to a dictionary where key is interface and the value is a cooked object. DI容器可以与字典进行比较,其中键是接口,值是熟化对象。 Once its setup, you can anytime ask for any object by using the right key through out your application. 设置完成后,您可以随时在整个应用程序中使用正确的密钥来询问​​任何对象。

Or is there a way to use DI for each of these classes to get their own copy of the DBContext? 或者有没有办法为每个类使用DI来获取自己的DBContext副本?

The DI framework supports different ways of instantiation to allow controlling the lifetime of the instance. DI框架支持不同的实例化方式,以允许控制实例的生命周期。 Typically, per request, per thread and singleton. 通常,每个请求,每个线程和单例。 More information here . 更多信息在这里 If you want each controller to get a copy of DbContext, you can use per request configuration when you set up DbContext instantiation. 如果希望每个控制器都获得DbContext的副本,则可以在设置DbContext实例化时使用每个请求配置。

Alternate Solution: 替代解决方案:

Most of my MVC applications, I have had a service layer (set of classes that apply business rule). 我的大多数MVC应用程序都有一个服务层(一组应用业务规则的类)。 Each of these classes were injected with DbContext (not exactly a DbContext but IDataContext). 这些类中的每一个都注入了DbContext(不完全是DbContext而是IDataContext)。 The controllers were injected with the service class that they need to retrieve or update the data. 控制器注入了他们需要检索或更新数据的服务类。

Have abstracted the DbContext behind IDataContext, I could setup a stub data context in my test or tomorrow if I want to switch from EF to NHibernate or something more smart DI Framework, i will just have to implement IDataContext and change the dependency initialization code. 已经抽象了IDataContext背后的DbContext,我可以在我的测试或明天设置存根数据上下文,如果我想从EF切换到NHibernate或更智能的DI框架,我将只需要实现IDataContext并更改依赖关系初始化代码。

Hope this helps. 希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM