The controllers in my ASP.NET MVC web app are starting to get a bit bloated with business logic. The examples on the web all show simple controller actions that simply pull dat
Your controllers (in the MVC project) should be calling your objects in the Service project. The services project is where all the business logic is handled.
A good example is this:
public ActionResult Index()
{
ProductServices productServices = new ProductServices();
// top 10 products, for example.
IList<Product> productList = productServices.GetProducts(10);
// Set this data into the custom viewdata.
ViewData.Model = new ProductViewData
{
ProductList = productList;
};
return View();
}
or with Dependency Injection (my fav)
// Field with the reference to all product services (aka. business logic)
private readonly ProductServices _productServices;
// 'Greedy' constructor, which Dependency Injection auto finds and therefore
// will use.
public ProductController(ProductServices productServices)
{
_productServices = productServices;
}
public ActionResult Index()
{
// top 10 products, for example.
// NOTE: The services instance was automagically created by the DI
// so i din't have to worry about it NOT being instansiated.
IList<Product> productList = _productServices.GetProducts(10);
// Set this data into the custom viewdata.
ViewData.Model = new ProductViewData
{
ProductList = productList;
};
return View();
}
Now .. what's the Service project (or what is ProductServices)? that's a class library with your business logic. For example.
public class ProductServices : IProductServices
{
private readonly ProductRepository _productRepository;
public ProductServices(ProductRepository productRepository)
{
_productRepository = productRepository;
}
public IList<Product> GetProducts(int numberOfProducts)
{
// GetProducts() and OrderByMostRecent() are custom linq helpers...
return _productRepository.GetProducts()
.OrderByMostRecent()
.Take(numberOfProducts)
.ToList();
}
}
but that might be all so hardcore and confusing... so a simple version of the ServiceProduct class could be (but i wouldn't really recommend) ...
public class ProductServices
{
public IList<Product> GetProducts(int numberOfProducts)
{
using (DB db = new Linq2SqlDb() )
{
return (from p in db.Products
orderby p.DateCreated ascending
select p).Take(10).ToList();
}
}
}
So there you go. You can see that all the logic is in the Service projects, which means u can reuse that code in other places.
Where did i learn this?
From Rob Conery's MVC StoreFront media and tutorials. Best thing since sliced bread. His tutorials explain (what i did) in good detail with full solution code examples. He uses Dependency Injection which is SOO kewl now that i've seen how he uses it, in MVC.
HTH.
Well, its really up to you, i like to keep the controllers as simple as possible, and to archive this i need to encapsulate the bussines logic in a separate layer, and here is the big thing, mainly you have 2 options, assuming you are using Linq2SQL or Entity Framework:
You can use the extender methods and partial class to validate your Models just before Saving the Changes (hooks method, you can see an example of this in Nerdinner sample by Scott Gu).
The other way (and my favorite, because i feel more control over the app flow), is to use a totally separate layer for bussines logic like Services Layer (you can see this aprroach in the series of tutorials by Stephen Walther in asp.net/mvc zone).
With this two methods you got DRY and clean up your otherwise messy controllers.
Your business logic should be encapsulated in business objects - if you have an Order object (and you do, don't you?), and a business rule states that an email should be sent when the Order is fulfilled, then your Fulfill method (or, if more appropriate, the setter for IsFulfilled) should trigger that action. I would probably have configuration information that pointed the business object at an appropriate email service for the application, or more generally to a "notifier" service so that other notification types could be added when/if necessary.
If you are going to have a business layer, then I think that it is best to have only the business layer talk to the data layer. I can understand why in a simple use case, you'd have the presentation layer (the controller) talk to the data layer directly, but once you identify a need for an isolated business layer, then mixing usage of the two in higher levels gets to be dangerous.
For example, what if controller A calls a method in the business layer to fetch a List of Object A (and this method applies the business rules - maybe some filtering or sorting), but then Controller B comes along, needs the same piece of data, but forgets about the business layer and calls the data layer directly ?
It would help if we could stop seeing this example over and over again ...
public ActionResult Index()
{
var widgetContext = new WidgetDataContext();
var widgets = from w in widgetContext.Widget
select w;
return View(widgets);
}
I do realize that this isn't helpful to your question but it seems to be part of a lot of demo-ware that I think can be misleading.
It might seem annoying to see lot of this in business services:
public Customer GetCustomer(int id)
{
return customerRepository.Get(id);
}
And it's natural to have a strong urge to bypass the service. But you are better off in the long run allowing your business services intermediate between controllers and repositories.
Now, for a very simple CRUD type application, you could have your controllers consume repositories directly instead of going through business services. You could still have something like an EmailerService, but IMO when it comes to fetching and doing things with entities, best not to mix and match business service and repository calls in your controllers.
As for having entities (business objects) call services or any infrastructure components, I would not do that. I prefer to keep entities POCO and free of dependencies.