Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing the Repository Pattern in ASP.NET MVC

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
like image 466
Sam Avatar asked Mar 03 '11 19:03

Sam


People also ask

What is repository pattern in MVC?

The repository pattern is intended to create an abstraction layer between the data access layer and the business logic layer of an application. It is a data access pattern that prompts a more loosely coupled approach to data access.

What is repository in asp net core MVC?

A Repository pattern is a design pattern that mediates data from and to the Domain and Data Access Layers ( like Entity Framework Core / Dapper). Repositories are classes that hide the logics required to store or retreive data.

Which design pattern is used in ASP NET MVC?

The MVC design pattern is a popular design pattern for the user interface layer of a software application. In larger applications, you typically combine a model-view-controller UI layer with other design patterns in the application, like data access patterns and messaging patterns.


1 Answers

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.

like image 118
smartcaveman Avatar answered Oct 06 '22 01:10

smartcaveman