Asp.net mvc 在ASP.NET MVC中实现存储库模式

Asp.net mvc 在ASP.NET MVC中实现存储库模式,asp.net-mvc,entity-framework-4,repository-pattern,unit-of-work,service-layer,Asp.net Mvc,Entity Framework 4,Repository Pattern,Unit Of Work,Service Layer,我仍然很难理解这一点。我想像这样分离我的层(DLL): 1) MyProject.Web.dll-MVC Web应用程序(控制器、模型(编辑/查看)、视图) 2) MyProject.Services.dll-服务层(业务逻辑) 3) MyProject.Repositories.dll-存储库 4) MyProject.Domain.dll-POCO类 5) MyProject.Data.dll-EF4 工作流程: 1) 控制器调用服务获取对象以填充视图/编辑模型。 2) 服务调用存储库以获取

我仍然很难理解这一点。我想像这样分离我的层(DLL):

1) MyProject.Web.dll-MVC Web应用程序(控制器、模型(编辑/查看)、视图)
2) MyProject.Services.dll-服务层(业务逻辑)
3) MyProject.Repositories.dll-存储库
4) MyProject.Domain.dll-POCO类
5) MyProject.Data.dll-EF4

工作流程:

1) 控制器调用服务获取对象以填充视图/编辑模型。
2) 服务调用存储库以获取/持久化对象。
3) 存储库调用EF从SQL Server获取/持久化对象

我的存储库返回IQueryable(Of T),在它们内部使用ObjectSet(Of T)

如我所见,这些层完全取决于下一层和包含POCO类的库

一些关注:

1) 现在,为了使我的存储库能够正确地使用EF,它们将依赖于System.Data.Objects,现在我在存储库层中与EF紧密耦合,这是不是很糟糕

2) 我使用的是UnitOfWork模式。它应该住在哪里?它有一个属性上下文作为ObjectContext,因此它也与EF紧密耦合。糟糕

3) 如何使用DI使这更容易

我希望这是一个松散耦合的测试尽可能。有什么建议吗

------编辑----

请让我知道我是否在正确的轨道上。另外,服务被注入了一个IRepository(属于类别),对吧,它如何知道它与eRepository(属于T)的具体类之间的区别?工作单位和服务单位也一样吗

一旦有人帮我弄明白了我的理解,我知道这看起来很琐碎,但伙计,我现在正忙着把脑袋绕在这上面呢

控制器

Public Class CategoryController
    Private _Service As Domain.Interfaces.IService

    Public Sub New(ByVal Service As Domain.Interfaces.IService)
        _Service = Service

    End Sub

    Function ListCategories() As ActionResult
        Dim Model As New CategoryViewModel

        Using UOW As New Repositories.EFUnitOfWork
            Mapper.Map(Of Category, CategoryViewModel)(_Service.GetCategories)
        End Using

        Return View(Model)
    End Function

End Class
服务

Public Class CategoryService

    Private Repository As Domain.Interfaces.IRepository(Of Domain.Category)
    Private UnitOfWork As Domain.Interfaces.IUnitOfWork

    Public Sub New(ByVal UnitOfWork As Domain.Interfaces.IUnitOfWork, ByVal Repository As Domain.Interfaces.IRepository(Of Domain.Category))
        UnitOfWork = UnitOfWork
        Repository = Repository

    End Sub

    Public Function GetCategories() As IEnumerable(Of Domain.Category)
        Return Repository.GetAll()
    End Function

End Class
存储库和工作单元

Public MustInherit Class RepositoryBase(Of T As Class)
    Implements Domain.Interfaces.IRepository(Of T)

End Class

Public Class EFRepository(Of T As Class)
    Inherits RepositoryBase(Of T)

End Class

Public Class EFUnitOfWork
    Implements Domain.Interfaces.IUnitOfWork

    Public Property Context As ObjectContext

    Public Sub Commit() Implements Domain.Interfaces.IUnitOfWork.Commit

    End Sub

End Class

我建议使用MEF。它为您提供了所需的依赖注入框架,但它还没有成熟;它非常适合单元测试。以下是一个相关问题的一些答案:

依次回答您的问题

1) 不一定不好,这取决于你坚持EF的可能性有多大。你可以做一些事情来减少这种情况。一个相对较低的成本(假设您有一些控制反转设置,如果不跳到3的话)是仅从您的服务引用存储库的接口

2) 同样,我认为您可能会花费大量时间使您的应用程序不与EF耦合,但您必须问问自己,这种方向的改变是否也会导致其他更改。同样,可以通过接口引入间接层,并在以后轻松地将一个存储库实现与另一个存储库实现交换

3) 控制反转应再次允许所有您想要的测试。因此,根本不需要许多直接引用,也不需要单独测试任何层

更新请求的样本

public class QuestionService : IQuestionService
{

    private readonly IQuestionRepository _questionRepository;

    public QuestionService(IQuestionRepository questionRepository){
           _questionRepository = questionRepository
    }
}
因此,您的服务只知道可以在单元测试中模拟或伪造的接口。这些都是国际奥委会标准的东西。关于这一点,有很多很好的参考资料,如果你对其中的很多内容都是新的,那么我推荐一些a给你完整的故事。

原始答案
  • 不可以。但是,为了避免将服务与此耦合,请在域层中使用
    ISomethingRepository
    接口。这将由您的IoC容器解决

  • 工作单元模式应该在存储库中实现。使用与我建议的将存储库与服务分离相同的解决方案来实现此分离。在域层中创建一个
    IUnitOfWork
    IUnitOfWork
    ,并将实现放在存储库层中。如果存储库所做的只是将数据持久化到数据层中的
    ObjectContext
    ,那么我看不出存储库实现需要与数据层分离的任何原因存储库接口是域逻辑,但实现是一个数据问题

  • 您可以使用DI将服务注入控制器,将存储库注入服务。使用DI,您的服务将依赖于存储库接口
    ISomethingRepository
    ,并将接收
    EFSomethingRepository
    的实现,而无需耦合到数据/存储库程序集。基本上,您的
    IControllerFactory
    实现将使IoC容器提供控制器的所有构造函数依赖项。这将要求IoC容器还提供所有控制器的构造函数依赖项(服务)以及它们的构造函数依赖项(存储库)。所有程序集都将依赖于域层(具有存储库和服务接口),但不会相互依赖,因为它们依赖于接口而不是实现。您需要为依赖项解析使用单独的程序集,或者需要在Web项目中包含该代码。(我建议单独举行一次大会)。依赖于依赖项解析程序集的唯一程序集将是UI程序集,尽管如果您在
    应用程序启动
    事件中使用
    IHttpModule
    实现注册依赖项,则UI程序集也不是完全必要的(项目仍然需要bin文件夹中的dll副本,但不需要项目参考)。有很多合适的开源IoC容器。最好的一个取决于您选择的内容。我个人喜欢StructureMap。它和Ninject都是可靠的、文档完整的DI框架

  • 对山姆·斯特里亚诺编辑的回应 我已经多年没有用VB编程了,所以我的语法可能不正确

    Public Class CategoryController
      Private _Service As Domain.Interfaces.IService
    
      'This is good.
      Public Sub New(ByVal Service As Domain.Interfaces.IService)
          _Service = Service
      End Sub
    
    
      Function ListCategories() As ActionResult
          Dim Model As New CategoryViewModel
    
    
          Using UOW As New Repositories.EFUnitOfWork
    
    这不需要在控制器中。
              Mapper.Map(Of Category, CategoryViewModel)(_Service.GetCategories)
    
          End Using
    
          Return View(Model)
      End Function