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
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.
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.
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.
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.
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
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With