3

I have only been working with the MVC framework (ASP.NET MVC2/3/Razor) for a few months now and I am really enjoying it, however I am having a hard time figuring out a standard for View Models. In my projects, I have a Models folder (Contains my data models - Linq DBML, Repository[ies], Extension methods) and a Models/ViewModels folder. My view models are usually reusable classes which usually just contain simple get/set properties for the LINQ objects or collections of objects I need to access for a particular view.

Now the problem I am having is figuring out when to create a view model. My goal is to use the LINQ object as the view model as often as possible, especially when it is an Edit action. My problem is what if I have other bits of data that I might want to use for display purposes only? I don't like to use the ViewData/ViewBag collections, as accessing members of these requires knowledge of the collection item's key (not easy for a designer/front-end guy to "guess"). I also don't like the idea of creating a ViewModel for each View, as it seems like unnecessarily messy code.

For example, imagine I have a data model for an Employee, and I want to display some information unrelated to that employee - say, site statistics, dynamic menus, and whatever else you can think of that might come from the database. What model should I pass the /Employee/Edit action? The Employee object with a bunch of ViewData[] for the rest, or a custom EmployeeView?

Is there a gold standard? What am I missing? What are you doing different that I should look into? Thanks in advance!

tereško
  • 58,060
  • 25
  • 98
  • 150
Keith
  • 5,311
  • 3
  • 34
  • 50

3 Answers3

3

I never use my entity classes directly as view models. I always create a view-specific model for each view containing the data for that view. I've started using AutoMapper to map between view models and entity models. I mediate this through a ModelMapper class that has a ToViewModel<TEntity,TViewModel>() method for handing standard mappings (just invokes the automapper) and specialized mapping methods for custom mappings, especially to support creating and updating entities from view models.

tvanfosson
  • 524,688
  • 99
  • 697
  • 795
  • What do your View Models look like? I've seen everything from near-copies of the LINQ objects they represent to complex classes with tons of business logic methods (which seems like a NO-NO for a View Model). Mine are, as described above, simple classes with get/set properties for my LINQ data objects. – Keith May 20 '11 at 21:58
  • 1
    @Keith - typically simple containers, but I do model-level validation so the properties are decorated with appropriate attributes (as are the entity models). Business logic (other than attribute-based validation) is isolated in the model mapping class and in the repository infrastructure. In addition I have a specification provider for query specifications that implements business-level access policies, etc. – tvanfosson May 20 '11 at 22:05
2

You've named three things here:

  • Site statistics
  • Dynamic menus
  • Whatever else [...] might come from the database

That third point is a trap; just because something is in your database, doesn't mean it's part of your domain model.

Navigation might be based on a database. It might also be be in a site map or hard-coded into the application. It's actually not application data, it's application configuration. If you're storing it in the application database, that's OK (well, not really), but it is not part of the model itself.

Similarly, site statistics usually are stored in a database, but they're stored in a different database, specifically an analytics database (and many people just "outsource" this to Google). So again, they are a kind of data, but they are not your model.

If you want your application to make sense, you need to separate these concerns at a conceptual level. Navigation gets done in your master page/layout, including whatever dynamic code is necessary to make it work. It is pure view logic - don't let it leak into your model. It's completely OK and usually preferable to use the ViewData/ViewBag for concerns that are ancillary to the actual feature that is currently in use.

Now, assuming there are other kinds of view data that actually are application data: It's true in principle that views are supposed to be connected directly to models - that is after all what "MVC" means - but in practice, it's just a re-implementation of the ill-conceived "canonical data model" idea. Domain and presentation are separate concerns, and as such, imply different contextual models - in the latter case, that's a View Model.

When I first started doing MVC work, I was reluctant to use view models as well. But after I became more accustomed to the idea, I realized that it was really the only tenable solution - especially when your "model" is mostly a thin wrapper over the database itself. Views and data change in different ways and at different rates; if you don't want to be worrying about a constant stream of bugs and regressions then you need some insulation between the two. Build a mapping layer and call it a day.

At this point I've taken to creating a different view model for every view, whether I think I need it or not. At the beginning, it might be nothing but a carbon copy of a model class, but it means I can tweak it at any time and in any manner without having to screw around with the underlying model - and vice versa. As tv says, the initial view model is trivially easy to generate with AutoMapper, and will take up maybe 30 seconds of your time.

Just use view models, and hope that eventually the tools support view-model auto-generation.

Community
  • 1
  • 1
Aaronaught
  • 120,909
  • 25
  • 266
  • 342
  • While I understand the separation of concerns, I love the simplicity of calling UpdateModel(). Why add yet another layer with AutoMapper (which I have to be honest, I haven't looked at yet) if its seemingly unnecessary? I agree that if View Models were intended to be such an important part of the MVC framework, why weren't they included as a part of the tools/wizards? Something seems off here, to me at least. – Keith May 21 '11 at 13:16
  • @Keith: First, AutoMapper isn't a "layer", it's a convention-based mapper which virtually eliminates all the mapping code you'd otherwise have to write. Second, it only seems unnecessary at the very beginning; inevitably it becomes necessary soon after. Last but not least, the term "View" tends to get taken too literally, just as "Model" does - View Models are part of the View just as Repositories are part of the Model. This is in fact how most good architectures are designed; each layer or component has its own contextual model and when you want to jump from one to the next, you map. – Aaronaught May 21 '11 at 16:49
  • @Keith: As for "I love the simplicity of calling UpdateModel()" - [You still do that, you just use the parameterized method overload](http://www.joe-stevens.com/2010/02/17/asp-net-mvc-using-controller-updatemodel-when-using-a-viewmodel/). – Aaronaught May 21 '11 at 16:52
  • if my viewmodel has two different models (suppose, model1 and model2) in it, then how do i load the viewmodel using which repository? model1's repository or model2's repository? – Foyzul Karim Jan 07 '12 at 04:40
0

If You create page for editing employee but You also display things You mentioned (site statistics/menus) why not put them in partial views or layout files?

Piotr Perak
  • 10,718
  • 9
  • 49
  • 86