patterncsharpMinor
Links controller in MVC N-layer architecture
Viewed 0 times
layerarchitecturemvccontrollerlinks
Problem
I have a common issue that I face in my applications (because I don't know any better) and I want to improve.
This is my usual structure:
LinksConfigurationController
LinksConfiguration (In Project.BLL)
LinksConfigurationRepository (In Project.DAL)
IRepo
```
public interface IRepository where T : Entity
{
T Find(int id);
Task FindAsync(int id);
IEnumerable GetAll();
Task> GetAllAsync();
T Insert(T entity);
IEnumerable Insert(IEnumerable entity);
Task> InsertAsync(IEnumerable entity);
Task Inser
This is my usual structure:
- Project.UI (MVC Project)
- Project.BLL (Class Lib)
- Project.DAL (Class Lib)
LinksConfigurationController
public class LinksConfigurationController : BaseController
{
public async Task Index()
{
var config = new LinksConfiguration();
var result = await config.GetLinksAsync();
if (result == null) return View(new List());
var model = result.Select(item => new LinksViewModel
{
Id = item.Id,
LinkEndpoint = new Uri(item.LinkEndpoint),
LinkName = item.LinkName
}).ToList();
return View(model);
}
}LinksConfiguration (In Project.BLL)
public class LinksConfiguration
{
public LinksConfiguration()
{
Repo = new LinksConfigurationRepository();
}
public LinksConfigurationRepository Repo { get; set; }
public async Task> GetLinksAsync()
{
var reuslt = await Repo.GetAllAsync();
var dto = reuslt.Select(r => new LinksConfigurationDto
{
LinkEndpoint = r.LinkEndpoint,
Id = r.Id,
LinkName = r.LinkName
}).ToList();
return dto;
}
}LinksConfigurationRepository (In Project.DAL)
public class LinksConfigurationRepository : IRepository
{
public LinksConfigurationRepository()
{
Db = new NZBDashContext();
}
private NZBDashContext Db { get; set; }
public async Task> GetAllAsync()
{
return await Db.LinksConfiguration.ToListAsync();
}
// Rest of the implemented members from the interface
}IRepo
```
public interface IRepository where T : Entity
{
T Find(int id);
Task FindAsync(int id);
IEnumerable GetAll();
Task> GetAllAsync();
T Insert(T entity);
IEnumerable Insert(IEnumerable entity);
Task> InsertAsync(IEnumerable entity);
Task Inser
Solution
Do you need it?
From your question it seems that you don't and your Data Access Layer simply forward calls to underlying layer/framework and map properties back/forward.
Complexity (paired with flexibility) comes at a cost (as you see) and for unneeded complexity you pay this cost without any benefit. Drop unneeded complexity! EF abstracts many underlying DB access details and you may won't need to reintroduce Repository pattern. See also Implementing the Repository and Unit of Work Patterns in an ASP.NET MVC Application (read more for further details about when - IMO - Repository pattern is needed).
In a different context this kind of refactoring has even a name: Remove Middle Man. When a class (or an entire layer, in your case) is doing nothing but delegation/direct mapping then you should remove it entirely.
You'll then have just your presentation DLL and your model DLL (with EF to hide/abstract database access and mapping). You may want to introduce another level of abstraction in your presentation layer (View Model) when underlying model is too different from model you present to your users (or when interaction model is very complex) but there you should follow common pattern/practice of your UI framework (MVC, MVP, MVVM, MVCVM or whatever else).
If, in your scenario, you start designing model layer then a code-first approach will let you design your domain classes adding little or nothing code for mapping (no ORM is perfect). With this path (requisites, domain model, presentation) I usually add View Model classes to fit presentation needing otherwise using Model classes directly).
Repository Pattern, When?
I'd add a 3rd layer for Data Access only for these (not exhaustive list of) scenarios:
For simpler scenarios (such as adding a Service layer) mediator, proxy and similars will (usually) do the job.
Note About Testing
With an ORM you (usually) have harder time to write tests because it's directly connected to underlying database. In this case to test extreme error conditions and/or to simulate network issues/speed can be harder. If you can't automate these tests elsewhere (for example with dedicated system tests instead of unit testing) you may want to introduce a different
From your question it seems that you don't and your Data Access Layer simply forward calls to underlying layer/framework and map properties back/forward.
Complexity (paired with flexibility) comes at a cost (as you see) and for unneeded complexity you pay this cost without any benefit. Drop unneeded complexity! EF abstracts many underlying DB access details and you may won't need to reintroduce Repository pattern. See also Implementing the Repository and Unit of Work Patterns in an ASP.NET MVC Application (read more for further details about when - IMO - Repository pattern is needed).
In a different context this kind of refactoring has even a name: Remove Middle Man. When a class (or an entire layer, in your case) is doing nothing but delegation/direct mapping then you should remove it entirely.
You'll then have just your presentation DLL and your model DLL (with EF to hide/abstract database access and mapping). You may want to introduce another level of abstraction in your presentation layer (View Model) when underlying model is too different from model you present to your users (or when interaction model is very complex) but there you should follow common pattern/practice of your UI framework (MVC, MVP, MVVM, MVCVM or whatever else).
If, in your scenario, you start designing model layer then a code-first approach will let you design your domain classes adding little or nothing code for mapping (no ORM is perfect). With this path (requisites, domain model, presentation) I usually add View Model classes to fit presentation needing otherwise using Model classes directly).
Repository Pattern, When?
I'd add a 3rd layer for Data Access only for these (not exhaustive list of) scenarios:
- I need to map deeply different storage methods: relational database, XML file(s), file-system, NoSQL database.
- I have to switch between different technologies: Entity Framework, LINQ to SQL, NHibernate.
For simpler scenarios (such as adding a Service layer) mediator, proxy and similars will (usually) do the job.
Note About Testing
With an ORM you (usually) have harder time to write tests because it's directly connected to underlying database. In this case to test extreme error conditions and/or to simulate network issues/speed can be harder. If you can't automate these tests elsewhere (for example with dedicated system tests instead of unit testing) you may want to introduce a different
DbContext base class to be used for testing however details depends on ORM you're using, designing approach you selected and specific tests you need to perform.Context
StackExchange Code Review Q#109868, answer score: 3
Revisions (0)
No revisions yet.