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
}
No, this doesn't answer your question directly, but mostly because I believe your problem is rooted elsewhere.
Personally I tend to stay away from "helper classes" and libraries. Such code tends to be a dumping ground for code that doesn't have a home, and leads to poor design. From what I've gathered your suggesting to have an assembly attached to each of your 'real' projects so that it can share some common code. And what I see happening is a bunch of code that gets loaded into the app domain, and maybe 10% of it actually used by any given segment of your domain. Which may end up costing you more than a few checks on public members.
I would suggest analyzing what parts of your domain will actually need specific code shared, and design the reusable code around that. Personally I prefer the usage of extension methods; You can tie specific reusable code to a specific type (avoid extending string
, int
or the like) giving it a nice comfortable home, and easy to understand code.
When all else fails remember: "Performance is not a problem until it is a problem. Your time is more valuable than a few CPU cycles"
Best Answer
I think static classes are nice in many cases. I could just say "use them when it's useful" but that's not very helpful.
My rule of thumb is (as always): Am I hiding any dependencies? If you feel like a "helper class" is useful (although beware of low cohesion) then by all means, go ahead. Just make sure your methods don't access global state though. Pure static methods are lovely. Static methods that depend on some globals or that open DB connections or read from disk/some config file are ticking time bombs.
They make testing the application really hard (the only way of doing it will be manually running the whole system, or with brittle automatic full-system tests, you'll get no granularity). They also make it impossible to swap out implementations.
Just remember the dependency inversion principle and the open/closed principle! Make sure your classes are pluggable. Make sure they don't pull stuff out of thin air. If you do that, then go ahead and make as many static methods as you want!