Generally, you want your Controllers to do only a few things:
- Handle the incoming request
- Delegate the processing to some business object
- Pass the result of the business processing to the appropriate view for rendering
There shouldn't be any data access or complex business logic in the controller.
[In the simplest of apps, you can probably get away with basic data CRUD actions in your controller, but once you start adding in more than simple Get and Update calls, you are going to want to break out your processing into a separate class.]
Your controllers will usually depend on a 'Service' to do the actual processing work. In your service class you may work directly with your data source (in your case, the DbContext), but once again, if you find yourself writing a lot of business rules in addition to the data access, you will probably want to separate your business logic from your data access.
At that point, you will probably have a class that does nothing but the data access. Sometimes this is called a Repository, but it doesn't really matter what the name is. The point is that all of the code for getting data into and out of the database is in one place.
For every MVC project I've worked on, I've always ended up with a structure like:
Controller
public class BookController : Controller
{
ILibraryService _libraryService;
public BookController(ILibraryService libraryService)
{
_libraryService = libraryService;
}
public ActionResult Details(String isbn)
{
Book currentBook = _libraryService.RetrieveBookByISBN(isbn);
return View(ConvertToBookViewModel(currentBook));
}
public ActionResult DoSomethingComplexWithBook(ComplexBookActionRequest request)
{
var responseViewModel = _libraryService.ProcessTheComplexStuff(request);
return View(responseViewModel);
}
}
Business Service
public class LibraryService : ILibraryService
{
IBookRepository _bookRepository;
ICustomerRepository _customerRepository;
public LibraryService(IBookRepository bookRepository,
ICustomerRepository _customerRepository )
{
_bookRepository = bookRepository;
_customerRepository = customerRepository;
}
public Book RetrieveBookByISBN(string isbn)
{
return _bookRepository.GetBookByISBN(isbn);
}
public ComplexBookActionResult ProcessTheComplexStuff(ComplexBookActionRequest request)
{
// Possibly some business logic here
Book book = _bookRepository.GetBookByISBN(request.Isbn);
Customer customer = _customerRepository.GetCustomerById(request.CustomerId);
// Probably more business logic here
_libraryRepository.Save(book);
return complexBusinessActionResult;
}
}
Repository
public class BookRepository : IBookRepository
{
LibraryDBContext _db = new LibraryDBContext();
public Book GetBookByIsbn(string isbn)
{
return _db.Books.Single(b => b.ISBN == isbn);
}
// And the rest of the data access
}
EDIT: To summarise, I think understand where you're coming from - at first glance, the ASP.Net MVC framework seems to have (too) many parts, and it's difficult to start understanding it. Having said this, I'd argue that you're looking at this wrong. ASP.Net MVC is not a particularly heavy MVC framework (you should compare it to PHP MVC frameworks to be fair), but yes, it is very much conventions-based. There is a lot of good reasoning behind that design choice, and your first priority in learning the framework would be to learn its conventions, and perhaps the reasoning for them. If for some reason you absolutely want to go deeper, the framework is open source, and you can dig into it here.
I can just skip frameworks altogether, and toss random PHP along with my HTML on a single file and make it work
Well, not with an MVC framework (even in PHP). You're going to at least have a model, a view, and a controller. Those are a bit of a minimum, so I'm not really sure what you're looking for here; it's an apples and oranges comparison.
After that, there's going to be a few other files that you will probably need; such as configuration for the routing, etc. This is fairly standard and comparable to PHP MVC frameworks.
If you want a "single page" model, you could try WebForms, although that technology typically tries to move logic into a separate "code behind" page. I'm pretty sure you could skip the latter, however, and have .aspx files logically identical to .php files sitting there.
Do I really need to create a whole bloat of files and folders...
The default VS project template does tend to copy a lot of potentially unnecessary stuff (scripts, etc), but you could remove most of those. Again, you will probably have a minimum number of things there. Do these really cause you major worry? Have you seen what a Symfony installation looks like?
... for the sake of convention?
Convention is a great thing. The concept is called "convention over configuration", and for most non-trivial projects, it is wonderful thing. It stops people from reinventing things, and gives standards that should be followed.
Since you mention this is a learning exercise, I would suggest that you stop worrying about these things too much. ASP.Net MVC is very much about convention, and you are doing yourself a disservice by trying to work around those. In fact, to learn MVC, you should learn the conventions as much as any of the internals.
Best Answer
A typical multi-tier application looks like this:
In an MVC application, the data tier and logic tier reside in the Model, while the presentation tier resides in the View. In between the Model and the View, the Controller provides a switchyard, routing web requests and responses to the appropriate methods, views and model logic.
Within the Model, you can have as many or as few libraries as you like. For the View and the Controllers, I would say a good rule of thumb is one DLL per web application or service. Services might include a REST web API for external applications.
The Model typically contains at least three things: the database, the Business Logic, and a Service Layer. The Service Layer is implemented as a series of classes and methods that represent the domain objects called Repositories. Within these Repositories, it is not uncommon to use an ORM to provide object-level abstraction for the database.
Rules of thumb: Fat Model, thin controllers. The View historically has as little domain logic as possible, although nowadays the web interfaces are getting smarter from a client-side standpoint, with jQuery, HTML5 and sophisticated client-side frameworks like Kendo.