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.