views:

1402

answers:

3

I've been using MVC frameworks for a short while now and I really like how the concerns are separated out. I've got into a bad habit of letting the controllers do quite a bit of work. So I'm really looking for some advice.

When I first started using MVC I quite often had the controller doing manipulation on the models after database work had been done. I knew this was bad so moved that work into the models. However I'm not happy with that as I want my models to be very learn.

I've done a bit of reading and I see that people are keeping their controllers and models lean by having a service layer, which I like the look of.

I'm just trying to understand how a service layer and repository should all work together. Here are my assumptions, can you please let me know if this is a good way of working?

  1. The controller can call the repository directly if no manipulation needs to be done on the data and as such a service layer does not need to get involved
  2. Once any work needs to be done to data (business logic) then this should be done in the service layer and the controller will make a simple call to the service layer as and when required
  3. Once a service has done it's business logic it will then use the repository as necessary (if data needs to be persisted).
  4. Models ideally should be kept lean, ideally actings as nothing more than DTOs
  5. Validation of data will be done within the models (using MonoRail validation attributes). I appreciate not even one likes polluting their models with lots of attributes, but that is a different discussion. I like the benefit of MonoRail's validation attributes for the automatic jQuery validation in the UI.

I'm trying to turn all my code around to the single responsibility principle, hence trying to sort out my coding practices.

Thanks

+13  A: 

First, there is no set of rules that's going to work in every situation. How you model you're application depends a lot on the type and complexity of the project. Having said that, here are some ideas:

  1. Nothing wrong with calling the repository from a controller. Just make sure the controller does not contain business logic.
  2. The service takes care of (some) business logic and uses other services to do so. The repository is a type of service, there's nothing wrong with calling it from a service.
  3. The model should contain business logic, actually you should always try to put it in the model first. If you need external data to perform that business logic (from another model or from the repository) then you should create a service.
  4. Nothing wrong with validation in the models. Using attributes or not is a question of taste (if you like it then it's good). Move the validation outside of the model if it gets too complex (create a external set of rules).

Most important, do what feels right (that's usually the right answer).

gcores
My only concern with putting the business logic in the models is that when passing collections of models to the UI via the PropertyBag (or however), you are potentially opening up the business logic to the UI.
John Polling
I agree with your comments, I just feel that an excessive amount of business logic should be stored in a separate service layer. Try to keep your Models, Views and Controllers as small as possible
FailBoy
+2  A: 

Ian Cooper has just written a blog post called The Fat Controller on just this subject.

Macka
+2  A: 

hi john,

i have got very similar assumptions as you have got. but i am in bit of a dilemma about few things.

as you have mentioned, if there is business logic to be done in data, it will be in service layer else in repository layer. controller will have access to both service layer and repository layer. that's all fine but how would one know if there is business logic in service layer and service layer is to be called instead of repository layer? since the controller will have access to repository layer, they can directly call repository layer instead. how can that be prevented?

btw, i am using webforms (not using MVP pattern). if using MVC, i guess i can make sure of that using mocking framework. i also tried using service layer as wrapper for repository layer so all the calls has to go through service layer. but doing that i am just repeating all the methods of repository layer in service layer and all i do in service layer is delegate it to repository layer.

it would be interesting to hear how people go about it.

ashik_gurung
Hi,I've recently started a fresh project, where the controllers only have access to the service layer and it's working very well. We are using Linq and Nhibernate.Linq for creating the queries and so far no repetition. See here http://code.google.com/p/membranecms/source/browse/#svn/trunk
John Polling