MVC – Strongly Typed Views and ViewModel

asp.net-mvcmvcmvvm

I'm learning MVC and the book I'm using favors strongly-typed views. Some of these concepts are new to me and I'm trying to better understand the design philosophy. Strongly typed views typically result in having to create a ViewModel since the domain entities are unlikely to have all the information a particular view may need. The problem is now I need to update my ViewModel whenever the associated domain entities or view changes. I also don't see the ViewModel being much use when porting an application to another platform, say web to desktop, or web to mobile.

Wouldn't it be better if we could declare our objects, collections, etc and populate them in the controller and then be able to access these variables directly in the view?

The controller would look something like:

    public ActionResult Index() {
        User user = db.Users.Where(u => u.UserId = userId);
        List<Car> carList = db.Cars.Where(c => c.OwnerId = userId).ToList();
        return View("UserCars");
    }

The view would look like:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Title</title>
</head>
<body>
    <div id="username">
        @{user.UserName;}
    </div>
    <div id="carlist">
        @foreach (var car in carList) {
            car.Name
            <br />
        }
    </div>
</body>
</html>

What is wrong with this approach and what makes strongly typed views, and by extension, ViewModels better?

Edit: Strongly typed view explanation: http://www.c-sharpcorner.com/UploadFile/abhikumarvatsa/strongly-typed-views-in-mvc/

Edit: I know that code won't work, it's there to illustrate my question.

My concern is keeping a model, viewmodel and view in sync. If the view changes, I have to change the viewmodel. If I change a bool to a nullable bool in the model, I have to change that in any viewmodels that reference that model. If I have a separate viewmodel for every view and my web site is reasonably large, that's a lot of places to update. I don't just change things in one place, I change them in 50 places, or 100 places. I thought good programming practices try to avoid this sort of issue.

Best Answer

I also prefer strongly-typed views with dedicated ViewModels.

To get around the problem you are seeing I sometimes construct my ViewModels like:

public class UserCarsViewModel
{
    public User User { get; set; }
    public List<Car> Cars { get; set; }

    public bool SomeCalculationIDontWantToHaveToDoInRazor
    {
        get { return _some mildly complex code here_ }
    }

    public List<Car> SomeFilteringIDontWantToHaveToDoInRazor
    {
        get { return _some mildly complex code here_ }
    }

    public bool SomeOtherConditionIDontWantToHaveToDoInRazor
    {
        get { return _some mildly complex code here_ }
    }
}

All of the more-than-dead-simple processing that would otherwise have to be in the view code (Razor) would be placed in the ViewModel, where is can be more easily tested. The Razor code is, in turn, much easier to read.

But, my Models are also in there, ready to be used as-is. If the Models change, but the changes don't affect my ViewModel calculations, my ViewModels don't need to change.

My controller ends up looking like:

public ActionResult Index() 
{
    var viewModel = new UserCarsViewModel();
    viewModel.User = db.Users.Where(u => u.UserId = userId);
    viewModel.Cars = db.Cars.Where(c => c.OwnerId = userId).ToList();
    return View("UserCars", viewModel);
}