实施ASP.NET MVC Repository模式 [英] Implementing the Repository Pattern in ASP.NET MVC

查看:421
本文介绍了实施ASP.NET MVC Repository模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我仍然有一个很难包装我的头解决这个问题。我想我的分离层(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类的lib吗?

几个关注点:

1)现在我的库与EF正常工作,他们将取决于System.Data.Objects,现在我有EF紧密耦合在我的仓库层,是坏?

2)我使用的UnitOfWork模式。应该住在哪里?它有一个属性背景信息ObjectContext的,所以这是紧耦合的EF为好。坏了?

3)如何使用DI来简化这个过程?

我想这是一个用于测试的松耦合越好。有什么建议?

---------- ----------修改

请让我知道如果我在正确的轨道上。此外,这样的服务获取与IRepository权(类)注入,它如何知道和具体类EFRepository(中T)之间的区别?同样用的UnitOfWork和服务?

一旦有人帮我想出解决办法的地方,我明白,我知道它会都显得微不足道,但人我有一个时间赫克包装我的头解决这个!

控制器搜索

 公共类CategoryController
    私人_Service作为Domain.Interfaces.IService    的Public Sub New(BYVAL服务作为Domain.Interfaces.IService)
        _Service =服务    结束小组    功能ListCategories()为的ActionResult
        昏暗的型号作为新CategoryViewModel        使用UOW作为新Repositories.EFUnitOfWork
            Mapper.Map(类,CategoryViewModel)(_ Service.GetCategories)
        使用完        返回查看(型号)
    结束功能末级

服务结果

 公共类CategoryService    私人存储库作为Domain.Interfaces.IRepository(中Domain.Category)
    私人的UnitOfWork作为Domain.Interfaces.IUnitOfWork    的Public Sub New(BYVAL的UnitOfWork作为Domain.Interfaces.IUnitOfWork,BYVAL资源库作为Domain.Interfaces.IRepository(中Domain.Category))
        的UnitOfWork =的UnitOfWork
        库库=    结束小组    公共职能GetCategories()为IEnumerable(中Domain.Category)
        返回Repository.GetAll()
    结束功能末级

信息库和的UnitOfWork结果

 公开为MustInherit类RepositoryBase(中T作为类)
    实现Domain.Interfaces.IRepository(中T)末级公共类EFRepository(中T作为类)
    继承RepositoryBase(T OF)末级公共类EFUnitOfWork
    实现Domain.Interfaces.IUnitOfWork    公共属性背景信息的ObjectContext    公用Sub提交()实现Domain.Interfaces.IUnitOfWork.Commit    结束小组末级


解决方案

原来的答案


  1. 没有。然而,为了避免服务耦合到这一点,在你的领域层的 ISomethingRepository 接口。这将通过您的IoC容器来解决。


  2. 工作模式的单位应该与您的存储库来实现。使用相同的解决方案,去耦这是我从你的服务去耦版本库建议。创建一个 IUnitOfWork IUnitOfWork< TContext> 在你的领域层,并把实施你的版本库层。我没有看到你的版本库的实现需要从您的数据层分开的任何原因,如果所有的库做的是在数据层持久化数据到的ObjectContext 资源库接口是域的逻辑,但执行是数据关注


  3. 您可以使用DI到你的服务变成控制器和您的存储库注入到你的服务。随着DI,您的服务将有库接口 ISomethingRepository 的依赖关系,并且将获得 EFSomethingRepository 的实施不耦合到数据/库组件。基本上,你的 IControllerFactory 的实施将得到IoC容器来提供所有的控制器构造函数依赖。这将要求IoC容器还提供了所有控制器的构造函数依赖(服务)的构造函数依赖关系(库)也是如此。您的所有组件都将有您的域名层上的依赖,(具有资源库和服务接口),但不会对对方的依赖,因为它们是依赖接口而不是实现。你要么需要依赖解析一个单独的程序,或者您需要在您的Web项目code。 (我会建议一个单独的程序)。与依赖解析组件的依赖唯一的组装将是UI组件,但即使你使用 IHttpModule的实施在注册您的依赖,这不是完全必要的的Application_Start 事件(该项目将仍然需要DLL的副本,你的bin文件夹,但项目的引用是没有必要的)。有很多适合开源的IoC容器。最好的一个要看你选择什么样了很多。我个人喜欢StructureMap。无论它,Ninject是可靠的,有据可查的DI框架。


响应山姆斯特里亚诺的编辑

这已经多年,因为我已经在VB codeD,以便我的语法可能会关闭。

 公共类CategoryController
  私人_Service作为Domain.Interfaces.IService  这是好事。
  的Public Sub New(BYVAL服务作为Domain.Interfaces.IService)
      _Service =服务
  结束小组
  功能ListCategories()为的ActionResult
      昏暗的型号作为新CategoryViewModel
      使用UOW作为新Repositories.EFUnitOfWork

这并不需要是在控制器中。移动到存储库,并围绕它的实际交易。此外,你不希望你的控制器有数据层上的依赖关系。

  Mapper.Map(类别,CategoryViewModel)(_ Service.GetCategories)

这是到AutoMapper打个电话?没有涉及到你原来的问题,但是,这样你的回报只是返回查看(_Service.GetCategories)

您应该重新定位映射功能到ActionFilter

 结束使用      返回查看(型号)
  结束功能

Service类没有问题。

工作的信息库和单位看多为不完全。你的版本库要新出的ObjectContext并将它注入到工作单元,然后执行工作中(类似于你在控制器做了什么)的单位范围内的所有交易。与控制器有它的问题是,它可能是一个单一的服务电话,可以作用域为多个工作单元。下面是关于如何实现工作单位的好文章。 http://martinfowler.com/eaaCatalog/unitOfWork.html 。 Martin Fowler的书籍和网站都对这些类型的主题信息来源很大。

I am still having a hard time wrapping my head around this. I want to separate my layers (dlls) like so:

1) MyProject.Web.dll - MVC Web App (Controllers, Models (Edit/View), Views)
2) MyProject.Services.dll - Service Layer (Business Logic)
3) MyProject.Repositories.dll - Repositories
4) MyProject.Domain.dll - POCO Classes
5) MyProject.Data.dll - EF4

Workflow:

1) Controllers call Services to get objects to populate View/Edit Models.
2) Services call Repositories to get/persist objects.
3) Repositories call EF to get/persist objects to and from SQL Server.

My Repositories return IQueryable(Of T) and inside them they utilize ObjectSet(Of T).

So as I see this, the layers depend on exactly the next layer down and the lib that contains the POCO classes?

A few concerns:

1) Now for my Repositories to work correctly with EF, they will depend on System.Data.Objects, now I have a tight coupling with EF in my repository layer, is that bad?

2) I am using the UnitOfWork pattern. Where should that live? It has a Property Context As ObjectContext, so that is tightly coupled to EF as well. Bad?

3) How can i use DI to make this easier?

I want this to be a loosely coupled as possible for testing. Any suggestions?

---------- Edit ----------

Please let me know if I am on the right track here. Also, so the Service gets injected with an IRepository(Of Category) right, how does it know the difference between that and the concrete class of EFRepository(Of T)? Same with the UnitOfWork and the Service?

Once someone helps me figure this out to where I understand it, I know it will have seemed trivial, but man I am having a heck of a time wrapping my head around this!!

Controller

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

Service

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

Repository and UnitOfWork

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

解决方案

Original Answer

  1. No. However, to avoid coupling the Services to this, have an ISomethingRepository interface in your domain layer. This will be resolved by your IoC container.

  2. The Unit of Work patterns should be implemented with your Repositories. Use the same solution to decoupling this as I suggested with decoupling your repositories from your services. Create an IUnitOfWork or IUnitOfWork<TContext> in your domain layer, and put the implementation in your Repository layer. I don't see any reason that your repository implementation needs to be separate from your Data layer, if all the Repositories do is persist data to the ObjectContext in data layer. The Repository interface is domain logic, but the implementation is a data concern

  3. You can use DI to inject your services into the controllers and your repositories into your services. With DI, your service will have a dependency on the repository interface ISomethingRepository, and will receive the implementation of the EFSomethingRepository without being coupled to the data/repository assembly. Basically, your IControllerFactory implementation will get the IoC container to provide all the constructor dependencies for the Controller. This will require that the IoC container also provides all the controllers' constructor dependencies (service) their constructor dependencies (repositories) as well. All of your assemblies will have a dependency on your domain layer, (which has the repository and service interfaces), but will not have dependencies on each other, because they are dependent on the interface and not the implementation. You will either need a separate assembly for the Dependency Resolution or you will need to include that code in your Web project. ( I would recommend a separate assembly). The only assembly with a dependency on the Dependency Resolution assembly will be the UI assembly, although even this is not completely necessary if you use an IHttpModule implementation to register your dependencies at the Application_Start event (the project will still need a copy of the dll in your bin folder, but a project reference is not necessary). There are plenty of suitable open source IoC containers. The best one depends a lot on what you choose. I personally like StructureMap. Both it, and Ninject are reliable and well documented DI frameworks.

Response to Sam Striano's Edits

It's been years since I've coded in VB so my syntax may be off.

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

This doesn't need to be in the controller. Move it into the Repository and have it surround the actual transaction. Also, you don't want your controller to have a dependency on the data layer.

          Mapper.Map(Of Category, CategoryViewModel)(_Service.GetCategories)

Is this a call to AutoMapper? Not related to your original question, but, you should relocate the mapping functionality to an ActionFilter so your return is just Return View(_Service.GetCategories)

      End Using

      Return View(Model)
  End Function

The Service class had no problems.

The Repository and Unit of Work look mostly incomplete. Your Repository should new up the ObjectContext and inject it into the Unit of Work, then execute all transactions in the scope of the Unit of Work (similar to what you did in the controller). The problem with having it in the Controller is it's possible that a single Service call could be scoped to multiple units of work. Here is a good article on how to implement Unit of Work. http://martinfowler.com/eaaCatalog/unitOfWork.html. Martin Fowler's books and website are great sources of information on these types of topics.

这篇关于实施ASP.NET MVC Repository模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆