Area of responsibilities between Controller and Repository in ASP.Net MVC2
I'm trying to get an understanding of how to structure an ASP.Net MVC2 Web App using repositories.
A lot of examples, tutorials and books I have read structure the App like so:
public interface IProductsRepository
{
IQueryable<Product> Products { get; }
}
public class SqlProductsRepository : IProductsRepository
{
public Table<Product> productsTable;
public IQueryable<Product> Products
{
get { return productsTable }
}
}
public class ProductsController : Controller
{
IProductsRepository productsRepository;
public ProductsController(IProductsRepository productsRepository)
{
// set the Repository
}
public ActionResult GetLatestPublishedProducts(int pageSize, int page, ref int totalItemCount)
{
// Do LINQ query
return View(from p in productsRepository
where p.PublishedOn != null
orderby p.ProductId descending
select to(p))
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToList());
}
}
One thing I don't understand is why the Linq query lives in the controller.
I'd like to know why doing something like this is not correct:
public class SqlProductsRepository : IProductsRepository
{
// set data model stuff here
public List<Product> GetLatestPublishedProducts(int pageSize, int page, ref int totalItemCount) {
// DO LINQ Query in here
}
}
public class ProductsController : Controller
{
// set repository stuff here
public ActionResult GetLatestPublishedProducts(int pageSize, int page, ref int totalItemCount)
{
return View(productsRepositor开发者_开发知识库y.GetLatestPublishedProducts(pageSize, page, totalItemCount));
}
}
Your second example is what you should be doing. The repositories should handle all data access.
The controller should only get already filtered/sorted data and pass it to the view. The controller should not be reponsible for any data or business logic. It should only be responsible for retrieving data and passing it on.
When writing code in a controller, I ask myself this question;
Will I have to write this code again if I were to write this application in WinForms?
So your IProductsRepository
would have the method GetLatestPublishedProducts
, which you'd then implement in your SqlProductsRepository
.
The responsibilities are:
- Repository - Gets data from the database
- Controller - Passes data to the View for rendering
You can then take this a step further and separate any business logic out as well so that the Controller itself avoids using repositories. So you'd have a third Service layer that sits between the Controller and Repository.
Check the Intentions of the different classes.
- Repository: Provide Access to Database
- Controller: control the flow of your website (i know, there are better intentions)
that means, if you see the Linq as your main business logic, than it should NOT be in any of the 2. i would create a ProductService, that contains all of this abstracted calls, as they will be commonly reused.
what should be in the Service:
from p in productsRepository
where p.PublishedOn != null
orderby p.ProductId descending
select to(p))
what should be in the Controller:
from p in productService.GetLatestPublishedProducts()
.Skip((page - 1) * pageSize)
.Take(pageSize)
And, if possible, use the IEnumerable. not a list.
Make the goal to keep your controllers lean. This will help in keep things in order. Use repositories to handle all data access logic. I also include a service layer to handle other business and validation logic. So an my controller, service and repository methods something like Create would look like this:
// Controller
public ActionResult Create(MyModel myModel)
{
if (!_service.CreateMyModel(myModel))
{
return View(myModel);
}
return RedirectToAction("Index");
}
// Service
public bool CreateMyModel(MyModel myModel)
{
// Validation logic
if (!ValidateMyModel(myModel))
{
return false;
}
return _repository.CreateMyModel(myModel);
}
// Repository
public book CreateMyModel(MyModel myModel)
{
_entities.AddToMyModelsSet(myModel);
try
{
_entities.SaveChages();
return true;
}
catch
{
return false;
}
}
精彩评论