0

我正在努力理解接口和依赖注入在多层 MVC 项目中的作用。

我的项目中有两层:WebCore

Core为所有实体“IProjectDb”定义了一个接口。 Web具有此接口“ProjectDb”的实现。

  1. Core 项目中的接口什么时候使用?我们是否给它提供接口以便 EF 可以访问数据库?
  2. 接口只是Core用来访问实现版本的代理,以便EF可以访问真实数据吗?
  3. 如果是这样,依赖注入在这里扮演什么角色?我们要注入什么依赖项(核心取决于 web,web 取决于核心),在哪里,为什么?

我知道接口的目标是解耦项目以进行更好的测试。

现在,假设我想为这个项目添加一个服务层。

  1. 假设服务层管理所有数据访问,我可以将“ProjectDb”移动到服务项目中,对吧?
  2. Web 现在需要访问服务......所以我想我需要在 Web 项目中创建一个接口,该接口在 Services 项目中实现。在另一个问题中,有人告诉我这是错误的,接口和定义都应该存在于服务层中,这对我来说违背了接口的目的。有人可以为我澄清一下吗?
4

2 回答 2

2

Core 项目中的接口什么时候使用?我们是否给它提供接口以便 EF 可以访问数据库?

ProjectDb 是 IProjectDb 的一种具体实现,因此从技术上讲它已经在使用。通过拥有 IProjectDb,您可以提供各种额外的实现来支持单元测试,或者可能为不同的部署场景使用不同的数据存储。

这要求您提供一种方法来指定实现(依赖注入或显式)。

public HomeController : Controller
{
    private IProjectDb _projectDb;

    public HomeController() : this(new ProjectDb())
    {}

    public HomeController(IProjectDb projectDb)
    {
        _projectDb = projectDb;
    }

    ...
}

这与 EF 无关。您的 IProjectDb 实现可以使用 EF,但这样您的控制器并不关心它使用什么。

接口只是Core用来访问实现版本的代理,以便EF可以访问真实数据吗?

接口只是定义了实现必须遵守的契约。使用上面的 Controller 示例,您可以IProjectDb _projectDb始终如一地使用该属性,而不管IProjectDb. 同样,这与 EF 无关。

如果是这样,依赖注入在这里扮演什么角色?我们要注入什么依赖项(核心取决于 web,web 取决于核心),在哪里,为什么?

依赖注入允许您定义要在运行时使用的 IProjectDb 的实现,而不是在编译时定义硬编码的实现。拥有它的主要原因是支持单元测试,但不限于此。

假设服务层管理所有数据访问,我可以将“ProjectDb”移动到服务项目中,对吧?

是的,但将其放入 Core 也是有效的(假设 Core 是一个类库)。我更喜欢使用类库,因为它可以让您在需要时在其他地方使用实现。即:如果您需要提供另一个服务来在同一个数据存储上运行后台任务,您可以只引用 Core 并重用相同的实现。

Web 现在需要访问服务......所以我想我需要在 Web 项目中创建一个接口,该接口在 Services 项目中实现。在另一个问题中,有人告诉我这是错误的,接口和定义都应该存在于服务层中,这对我来说违背了接口的目的。有人可以为我澄清一下吗?

在 Web 项目中创建接口将为服务创建一个笨拙的依赖关系,这违背了分离层/层的目的。通俗地说,您是说服务依赖于 Web 应用程序,但事实并非如此。Web 应用程序应该依赖于服务,而服务不一定关心谁在使用它。

接口的目的是支持已定义合同的多种实现,并且在服务项目中定义它不会违反这一点(忽略服务项目通常编译为无法引用的可执行文件的事实)。

于 2013-02-19T06:00:35.060 回答
0

正如您所提到的,该接口用于解耦Core系统和Web应用程序之间的关系。假设您将所有业务逻辑放在项目的Core中,并让Web应用程序使用此业务逻辑,接口表示您要在.Core

回答您的每个问题:

1 - Core项目中的接口什么时候使用?我们是否给它提供接口以便 EF 可以访问数据库?

您的Web应用程序是使用(或使用)您的IBusinessLayer界面的应用程序,它公开了对您的数据存储的访问权限(通过实体框架)。

2 - 接口是否只是Core用来访问实现版本的代理,以便EF可以访问真实数据?

是的。但在这种情况下,您谈论的是一个不同的接口,IDataAccessObject由 实现EFDataAccessObject。这里的想法是,将来您可能希望切换到另一个 ORM,例如OtherORMDataAccessObject实现IDataAccessObject,并保持项目的其余部分(CoreWeb)保持不变。

3 - 如果是这样,依赖注入在这里扮演什么角色?我们要注入什么依赖项(核心取决于 web,web 取决于核心),在哪里,为什么?

依赖注入就是这样:一种通过注册单个具体类型来为所有这些接口注入实现的方法,您可以动态配置和计算。基本上,对于每个,

public WebClass
{
    public IBusinessLayer BusinessLayer { get; set; } // <-- Dependency
}

public BusinessClass
{
    public IProjectDB ProjectDB { get; set; } // <-- Dependency
}
... 

public Main()
{
    DependencyInjector
        .Register<IBusinessLayer>().With<ConcreteBusinessLayer>().
        .Register<IProjectDB>().With<EntityFrameworkProjectDB>();
}

...

1 - 假设服务层管理所有数据访问,我可以将“ProjectDb”移动到服务项目中,对吗?

是的。只需使系统成为您层Core的依赖项,Service

public ServiceClass
{
    public IBusinessLayer BusinessLayer { get; set; } // <-- Dependency
}

public WebClass
{
    public IServiceLayer ServiceLayer { get; set; } // <-- Dependency
}

如您所见,Core层和层的实现ProjectDB保持不变,您只需将Business依赖项从Webto移动Service并创建对层的Service依赖项。Web

2 - Web 现在需要访问服务......所以我想我需要在 Web 项目中创建一个接口,该接口在服务项目中实现。在另一个问题中,有人告诉我这是错误的,接口和定义都应该存在于服务层中,这对我来说违背了接口的目的。有人可以为我澄清一下吗?

这与上一个问题有关:接口是在层项目IServiceLayer中定义和实现的。Service您使用此接口从Web层使用您的服务,但这只是一个依赖项,因此,

public WebClass
{
    public IServiceLayer ServiceLayer { get; set; } // <-- Dependency
}
于 2013-02-19T06:18:20.690 回答