2

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.

  • 1
    I'm not really sure what a "strongly typed view" is, I'm afraid. Could you link somewhere that has an example of that kind of view? – Jules Dec 18 '14 at 20:14
  • Edited original post to include link. – Legion Dec 18 '14 at 20:19
  • Is there a circumstance where you'd have to edit the ViewModel that wouldn't also cause the code to crash at run time if everything was glued dynamically? – Doval Dec 18 '14 at 20:25
  • Is this a suggestion to Microsoft? Your code wont work, but view models give you the capability to do exactly what you'd like to do. Alternatively you could use the viewbag. Whatever you prefer. – Andrew Hoffman Dec 18 '14 at 20:26
  • It's not a suggestion, it's a question. – Legion Dec 18 '14 at 21:53
4

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);
}
  • It seems as though this would be better served by using extension methods that operate on your models themselves. That way, you don't have to keep viewmodels in sync, while you can still have view-specific methods. Finally, you can likely make some of these generic (like filtering functions, for instance) that can be reused across multiple instances. – lunchmeat317 Mar 29 '16 at 18:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.