0

Learning ASP.NET MVC with a new project, and a little unsure of where some things should happen. I've read that ViewModels are a Good Thing (tm) and had planned on doing it in a similar fashion anyway, but I'm still not entirely clear on the responsibilities of the Model vs. the Controller.

Should the ViewModel be responsible for actually loading itself from the ORM? Thus the controller would just call ViewModel.GetObject() and pass the result back to the view?

Or should I load the data in the Controller, and then transform it into the ViewModel? Seems like that puts a lot of work in the Controller though, which is supposed to be kept somewhat lightweight.

I guess I could also have a third party that is responsible for pulling the data, then the Controller would call that and transform it for the appropriate ViewModel.

So any thoughts on what is the "best" approach?

CodeRedick
  • 7,346
  • 7
  • 46
  • 72
  • The model handles logic such as DB access, the view should only contain enough logic to output your data. – The Muffin Man Mar 28 '11 at 18:43
  • I think either is ok. MVC is not chiseled in stone. Do what works for you. The more abstract the more time it takes up front, but the more flexible later. – CrazyDart Mar 28 '11 at 18:48
  • @hunter, You don't have to agree with me or anyone else, but the experts will tell you that the Model holds your application logic such as database access logic. I suggest watching this video on the MVC website http://www.asp.net/mvc/videos/understanding-models-views-and-controllers and then write a comment and tell them they are wrong. – The Muffin Man Mar 28 '11 at 20:04
  • @hunter, I did not claim to be the expert and clearly quoted a video from the official site to back up my claim. Your quote from my profile is unrelated to our conversation. – The Muffin Man Mar 28 '11 at 20:24
  • @hunter, Like you said, it's okay to put the logic wherever you want, but (not being an expert) I still know that best practice is to have fat models and skinny controllers. See http://stackoverflow.com/questions/235233/asp-net-mvc-should-business-logic-exist-in-controllers. If we'ere going to compare 3rd party projects lets look at projects like Nerd dinner and examples from the mvc web site. This is my second reference to back up my claim, I still have not seen anything from you, yet you are still arguing your side. – The Muffin Man Mar 28 '11 at 20:44
  • @hunter, It's rude and childish to answer questions with questions. Since it appears that you are incapable of forming thoughtful responses maybe you can use all of your experience to create an application that can do it for you (Hopefully you don't build it with the MVC framework). – The Muffin Man Mar 29 '11 at 06:08

2 Answers2

5

The controller will create the viewmodel object and fill it out using the model. The model should use the ORM to get the data.

The ViewModel is always specific to the view only, and the model is specific to the domain. In CQRS you would actually just get the ViewModel and send it to the view.

From the controller you can do what ever it takes to make your CRUD happen for the view. If you use the Repo pattern thats ok, if you use NHibernate or EF directly thats cool tool. Once the ViewModel goes to the view it will be disconnected from everything like the DB, so fill it out before it gets there.

CrazyDart
  • 3,803
  • 2
  • 23
  • 29
  • 100% correct. The Model concept is a bit vague in the MVC definition and that's probably why the ViewModel was introduced in ASP.Net MVC. (I'm not saying that ms created the ViewModel concept, just that they made a pretty clear distinction between Model and ViewModel). – jgauffin Mar 28 '11 at 18:57
1

Personally I use a repository. So the controller queries a repository and gets a model, then maps the model to a view model and passes the view model to the view. Example:

public class ProductsController: Controller
{
    private readonly IProductsRepository _repository;
    private readonly IMapperEngine _mapper;
    public ProductsController(IProductsRepository repository, IMapperEngine mapper)
    {
        _repository = repository;
        _mapper = mapper;
    }

    public ActionResult Index(int id)
    {
        Product product = _repository.GetProduct(id);    
        ProductViewModel viewModel = _mapper.Map<Product, ProductViewModel>(product);
        return View(viewModel);
    }
}

And because this is repetitive logic I use custom action filters:

public class ProductsController: Controller
{
    private readonly IProductsRepository _repository;
    public ProductsController(IProductsRepository repository)
    {
        _repository = repository;
    }

    [AutoMap(typeof(Product), typeof(ProductViewModel))]
    public ActionResult Index(int id)
    {
        Product product = _repository.GetProduct(id);    
        return View(product);
    }
}

in this case the custom action filter intercepts the result of the action and replaces it using the corresponding mapping layer.

The way this repository is implemented is not the responsibility of the controller (whether it is an ORM, direct SQL queries, or even distant web service calls). As long as it is injected some proper implementation it will work which allows for weaker coupling between the different parts of the application and easier unit testing in isolation. So in this example it is the implementation of the repository that is responsible for fetching data.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928