27

I have recently started working as a web developer. I work with ASP .NET MVC 4 and NHibernate.

At my work-place, we are strictly made to use viewmodels to transfer data to and fro between a controller and a view. And the viewmodels are not supposed to contain any object of a model. I understand that it is a sort of a tier between the controller and the view.

But I find it repetitive and redundant to write a viewmodel class even if we can directly send the model's object to the view (in most cases).

For example, if i want to display an order i can do this in the controller's action -

return View(Repository.Get<Order>(id));

But instead, I have to write a viewmodel, fill it with the fetched order and then pass it to the view.

So, my question is, what purpose does writing viewmodels serve when we can use the model's object as it is?

mridula
  • 3,203
  • 3
  • 32
  • 55
  • 1
    For consistency, it's always good to have done it the abstracted way as opposed to the Controller doing the actual work. The thing that we don't often realize is, how requirements changes over time. Technically speaking, a Controller's job is to coordinate and not to do the actual hard work (although you have entity framework do that for you already). The next issue is, what if you want to change your Database implementation, or just want to test. ViewModel is basically an abstraction that wraps multiple methods so it can easily be consumed by view. ie, your working model, UI bindings, etc. – Dennis Rongo Jan 20 '13 at 09:42
  • 1
    Another great benefit of having a ViewModel is that, once you have written your controller, you never have to touch it again. All the work in the future that needs to be done (re-shaping the data, business rules, additional requirements, validation, list goes on) can all be done in the ViewModel. – Dennis Rongo Jan 20 '13 at 09:52
  • Your view probably doesn't need all the fields and properties found in your Order, so why waste bandwidth with unneeded data/info? – PmanAce Nov 30 '16 at 16:47

4 Answers4

19

For smaller projects, you're right. I hear your argument and sympathise - however there are good reasons for this, drudged and repetitive work, especially in larger and more complicated applications:

  • It's essential to perform all processing within the Controller's action. However in the example you've given, the Repository.Get method might return a lazily-evaluated IQueryable object, which would mean the DB wouldn't be hit until the View is evaluated. For a variety of reasons this is bad. (A workaround is to call .ToList while still in the controller).
  • "A view should not contain any non-presentational logic" and "You should not trust the View" (because a View could be user-provided). By providing a Model object (potentially still connected to an active DatabaseContext) a view can make malicious changes to your database.
  • A View's data-to-display does not always map 1:1 with its Model's data, for example consider a User Details page:

    A User's EF Model object represents its entity in the database, so it probably looks like this: User { UserId, UserName, PasswordHash, PasswordSalt, EmailAddress, CreatedDate }, whereas the fields on a "User details" page are going to be User { UserId, UserName, Password, ConfirmYourPassword, EmailAddress }, do you see the difference? Ergo, you cannot use the EF User model as the view model, you have to use a separate class.

  • The dangers of model manipulation: if you let ASP.NET MVC (or any other framework) do the model binding to the incoming HTTP POST Request then (taking the User details example above), a user could reset anyone's password by faking the UserId property value. ASP.NET will rewrite that value during binding and unless you specifically sanitize it (which will be just as drudgeful as making individual ViewModels anyway) then this vulnerability will remain.

  • In projects with multiple developers working in a team situation, is is important that everything is consistent. It is not consistent to have some pages using bespoke ViewModels but other pages using EF Models because the team does not share a concious mind, things have to be documented and generally make-sense. For the same reason a single developer can get away without putting excessive XML documentation in his source code, but in a team situation you'll fall apart if you don't.

There is a slight workaround in your case I'll share with you, but please note the preconditions:

  • Your views can be fully trusted
  • Your views contain only presentational logic
  • Your application is largely CRUD
  • Your views correspond 1:1 with each EF entity model (i.e. no JOINs)
  • Your views only deal with single Simple models for POST forms, not Complex models (i.e. an object graph)

...then you can do this:

  • Put all one-way, non-form-related data into your ViewData collection, or the ViewBag in MVC 4 (or even a generic ViewData<T> if you're hardcore). This is useful for storing HTML page titles and sharing data with Master pages.
  • Use your fully-evaluated and loaded EF models as your View<TModel> models.

But use this approach with caution because it can introduce inconsistency.

Dai
  • 141,631
  • 28
  • 261
  • 374
  • 1
    I'm still thinking how it can be safe to use view model on your security problem example (faking UserId value) since in the view model there is also UserId property – Agung Setiawan Nov 11 '15 at 06:20
  • @AgungSetiawan Your ViewModel should not contain any immutable (read-only) fields. Immutable values should be in your `ViewData`. And your Controller Action code must not trust any data provided by the user. The heart of the Entity-as-ViewModel security problem comes from the auto-binding provided by the framework and the webapp then assuming that data from the client can be trusted not to overwrite sensitive Entity members. By manually populating the entity from the viewmodel, performing security checks where necessary, this problem is averted. – Dai Nov 12 '15 at 05:04
  • 1
    @AgungSetiawan You *can* actually use an Entity, with sensitive fields as a ViewModel, provided you **do not** reattach it to your DbContext, but instead manually copy member values between it and a new, attached, entity object; however, as before, you must ensure you do not copy-over and overwrite sensitive members. – Dai Nov 12 '15 at 05:05
  • In case any future visitors have similar confusions to mine about the "viewmodels prevent malicious database changes" bit: https://stackoverflow.com/questions/45307963/how-do-viewmodels-prevent-malicious-database-changes – Sinjai Jul 28 '17 at 17:45
4

Well, i'm starting to think the pragmatic approach to every problem is required and not to just subscribe to the purist architectural standards out there. Your app may be required to run in the wild and be maintained by many developers serving a large set of client etc. and this may direct or drive your architecture.

  • The ViewModel is essential when you want a separation of concerns between your DomainModel (DataModel) and the rest of your code.

The less dependencies you have between the Model, View and Controller the easier down the line it will be to make changes to the DomainModel without breaking the interface contracts in the View and Controller etc. etc. But once again it's something to be pragmatic. I like the approach as code re-factoring is a big part of system maintenance - refactoring may include a simple spelling mistake on a property of a Model - that change could ripple through the code to the Contract level if the dependencies are not separated; for example.

  • The ViewModel is used to translate the data between your DomainModel and you Views

A simple example of a datetime stored in Informix has to be translated to a .Net DateTime. The ViewModel is the perfect place to do this translation and does not force you to put translation code in all sorts of unwanted places.

One attribute of a good design [of anything] is the ability to replace or modify a part of the implementation with little or no affects to the rest of the parts of the system. But this takes effort and time to achieve - it's up to you to find that practical balance between a perfect design and a design that is just enough

But yeah, there are many other good reasons to use certain patterns - but the bottom line is this:

Nothing forces you to use ViewModels... ASP.NET MVC won't force you. Take advice from the pragmatist inside you.

Quinton Bernhardt
  • 4,773
  • 19
  • 28
  • I agree, adding a layer of separation means adding a layer of extra code! for e.g. the addition of unit tests so that when a column is removed that you know about it and the Model->ViewModel translation can be fixed. But this does help isolate the Model changes affects to a single layer of code and limits the re-testing required to only those code changes....anyway - we all have our own opinion and i'm still learning everyday and my opinion will change to suit ;) – Quinton Bernhardt Jan 20 '13 at 09:37
  • I'll add that I think more should be done to differentiate between unidirectional `ViewData` data and the bidirectional `ViewModel` data. People shouldn't be passing things like HTML page titles and meta-data in `Model`. – Dai Jan 20 '13 at 09:39
  • I hadn't thought of using ViewModels as translators as in the example you gave! Thank you for the insight. – mridula Jan 20 '13 at 16:19
3

If you use same Models as your ViewModels, your application should be very small and simple and should contain only CRUD operations. But if you are building large or enterprise applications with large teams (with two or probably more developers), you should have concepts like Dependency Injection, Services, Repositories, Façades, Units of Work, Data Access Objects etc.

To simplify your mapping needs between Models and ViewModels, you can use AutoMapper https://github.com/AutoMapper/AutoMapper

or install with nuget Install-Package AutoMapper

Mert Sakarya
  • 105
  • 1
  • 5
1

According to me, it is essential to have one more layer(ViewModel) on top of Model layer for complex applications that performs most of the CRUD operations because it has following advantages:

  1. To establish loose coupling between Model and Controller. So that any DataModel related modifications will not be affected to Controller.
  2. If you've implemented your application's ViewModel layer correctly by providing maximum level of IOC(Inversion of Control) via DI(dependency Injection using Unity/other frameworks), etc., it will also help you to MOQ your ViewModels(dependencies) for testing only the controller's logic.
Bugs
  • 4,491
  • 9
  • 32
  • 41
hari teja
  • 77
  • 3