views:

179

answers:

3

most of the time in the service code I would have something like this:

public SomeService : ISomeService
{
    ISomeRepository someRepository;
    public Do(int id)
    {
        someRepository.Do(id);
    }
}

so it's kinda redundant

so I started to use the repositories directly in the controller

is this ok ? is there some architecture that is doing like this ?

+2  A: 

If you use repositories in your controllers, you are going straight from the Data Layer to the Presentation Layer. You lose the ability to have business logic in between.

Now, if you say you will only use Services when you need business logic, and use Repositories everywhere else, your code becomes a nightmare. The Presentation Layer is now calling both the Business and Data Layer, and you don't have a nice separation of concerns.

I would always go this route: Repositories -> Services -> UI. As soon as you don't think you need a business layer, the requirements change, and you will have to rewrite EVERYTHING.

Martin
@Martin I disagree, Business Logic isn't all or nothing. I'm not going to create a business logic layer just in-case I might need business logic down the road. It's pre-optimization. If you adhere to the SOLID principles, then a change in requirements can easily be dealt with. Calling Repositories from the controller is perfectly fine when it's a crud operation there is no business logic. If something changes and logic is needed, wrap the repository in a service and call the new service in the controller.
Chuck Conway
@Martin @Chuck from where do You guys think that calling repositories from controllers prohibits complex business logic?
Arnis L.
@Chuck - Yeah, YAGNI. But I have never seen CRUD operations without some sort of business logic.
Martin
@Arnis - You can have business logic when calling repositories from controllers, but I like to have a separate layer for the business logic. Why not separate the business logic from the data logic and presentation logic?
Martin
@Martin You are right, it's good to separate those things in 99% cases. but I believe that thing You miss is so called 'rich domain model' (http://bit.ly/blT6NN).
Arnis L.
+3  A: 

You lose the ability to have business logic in between.

I disagree with this one.

If business logic is where it should be - in domain model, then calling repo in controller (or better - use model binder for that) to get aggregate root and call method on it seems perfectly fine to me.

Application services should be used when there's too much technical details involved what would mess up controllers.


I've seen several people mention using model binders to call into a repo lately. Where is this crazy idea coming from?

I believe we are talking about 2 different things here. I suspect that Your 'model binder' means using model simultaneously as a view model too and binding changed values from UI directly right back to it (which is not a bad thing per se and in some cases I would go that road).

My 'model binder' is a class that implements 'IModelBinder', that takes repository in constructor (which is injected and therefore - can be extended if we need caching with some basic composition) and uses it before action is called to retrieve aggregate root and replace int id or Guid id or string slug or whatever action argument with real domain object. Combining that with input view model argument lets us to write less code. Something like this:

public ActionResult ChangeCustomerAddress
 (Customer c, ChangeCustomerAddressInput inp){
  c.ChangeCustomerAddress(inp.NewAddress);
  return RedirectToAction("Details", new{inp.Id});
}

In my actual code it's a bit more complex cause it includes ModelState validation and some exception handling that might be thrown from inside of domain model (extracted into Controller extension method for reuse). But not much more. So far - longest controller action is ~10 lines long.

You can see working implementation (quite sophisticated and (for me) unnecessary complex) here.

Are you just doing CRUD apps with Linq To Sql or trying something with real domain logic?

As You can (hopefully) see, this kind of approach actually almost forces us to move towards task based app instead of CRUD based one.

By doing all data access in your service layer and using IOC you can gain lots of benefits of AOP like invisible caching, transaction management, and easy composition of components that I can't imagine you get with model binders.

...and having new abstraction layer that invites us to mix infrastructure with domain logic and lose isolation of domain model.

Please enlighten me.

I'm not sure if I did. I don't think that I'm enlightened myself. :)


Here is my current model binder base class. Here's one of controller actions from my current project. And here's "lack" of business logic.

Arnis L.
I've seen several people mention using model binders to call into a repo lately. Where is this crazy idea coming from? Are you just doing CRUD apps with Linq To Sql or trying something with real domain logic? By doing all data access in your service layer and using IOC you can gain lots of benefits of AOP like invisible caching, transaction management, and easy composition of components that I can't imagine you get with model binders. Please enlighten me.
Ryan
@Ryan check my answer
Arnis L.
c.ChangeCustomerAddress(inp.Address)Does this method contain repository call to save the customer ? If so, how do you inject the repository inside customer ?
mathieu
@mathieu it does not. I'm using NHibernate. that fella automatically updates dirty instances when session gets flushed. I like idea of encapsulated domain model. http://www.udidahan.com/2008/02/29/how-to-create-fully-encapsulated-domain-models/
Arnis L.
A: 

Even with "rich domain model" you will still need a domain service for handling business logic which involves several entities. I have also never seen CRUD without some business logic, but in simple sample code. I'd always like to go Martin's route to keep my code straightforward.

Tiendq