View Models in ASP.NET MVC - Simon Ince's Blog - Site Home - MSDN Blogs

Simon Ince's Blog

Ramblings of an Application Development Consultant in the UK

View Models in ASP.NET MVC

View Models in ASP.NET MVC

  • Comments 40

Q: Should I have a view Model in my ASP.NET MVC architecture?

A: Yes.

Well, that was a short post! J

Being more serious, this is an interesting topic that the advisors and p&p team discussed a few times while they were building the Reference Implementation for the soon-to-be-complete Web Client Guidance, and it is something I've heard discussed time and time again out in the field.

I usually describe the "M" in both MVC and MVP as "the rest of the application", i.e. the business logic and business entities, and implicitly everything below in the stack. Some people don't like this analogy, saying the "M" refers only to the classes used to pass data between Controller and View. I agree it is arguably inaccurate, but I find it a useful way to think about a design based on these patterns... not least because of some of the variations in design I've seen that reflect those described below.

Where discussion gets interesting is when people start asking what the View can depend upon (and for the rest of this post think MVC, not MVP). To dodge a lot of detail this comes down to the following options;

1.       Business Entities are passed to a View as the "Model". Therefore the View has detailed knowledge of part of the business layer.

2.       Business Entities are never passed to a View – instead the relevant data is extracted and placed in a new entity reserved purely for use by the UI layer... or a "View Model" as people call it today (back when I coded as a day job we called these UI Entities so don't go thinking this is something new!)

These options become particularly interesting when you consider that in many modern systems the Business Entities are actually basically Data Transfer Objects generated or consumed by a tool such as the Entity Framework, nHibernate, etc, etc. This is useful because they may have validation behaviour built in. Business Logic is usually implemented as POCOs that manipulate, create, or return these DTOs.

This means that in option 1 the UI has access to all the validation goodness that exists on these entities. What's more, you don't need to create a new set of View Models that almost exactly match your data layer, and a set of "mappers" that convert Business Entities into a View Model.

However... note that I said "... almost exactly match...". You see, in the vast majority of systems there is something other than just what is stored in your database that needs passing to the view. This could be the current user's login name, or the current date and time. Or perhaps we must pass Boolean flags to indicate whether or not various regions of the screen should be displayed based on the user's roles.

To illustrate the differences, let's see 3 different examples as to how you might pass model data to a view. I've blatantly plagiarised some of the great comments that Francis, Julian, and the advisors made here so don't credit me with all the hard work J

Variant 1: No View Model

In Variant 1 we have no View Model at all, so our controller simply retrieves data from the business logic as a business entity, and passes it to the view...

public class ModelController : Controller

{

    public ActionResult Index(int someparameter)

    {

        BusinessEntity model = BusinessLogic.GetModel(someparameter);

        return View(model);

    }

}

The code for this is simple, concise, and requires very little work on my part. However, what if I want to add a property to indicate whether or not the "login" region of the view should be rendered? What if the view needs some other model data? This approach very tightly couples not only the business logic to the UI, but potentially the database to the UI (depending on your ORM tool, and how your business entities are created).

To summarise;

1.       (con) This approach is unlikely to suit real MVC applications, as there is usually additional data that must be passed across.

2.       (con) It is not flexible – it is more likely to lead to additional code churn after go-live other than in the simplest of cases.

3.       (con) Developers that don't know these patterns well may consider adding UI-focused fields to your business entity, which compromises your business layer.

4.       (pro) MVC can take advantage of the same validation mark-up attributes (or other scheme) that your business layer uses.

5.       You can use it, but be prepared to take the hit for changes later, and make sure your developers know how to evolve it into Variants 2 or 3.

The bottom line is that I would use this if I knew it was very unlikely that the view (perhaps a very focused partial view in a very simple system) would ever need more than a single business entity... but other people, including the p&p guys, rightly have strong concerns about this approach.

Variant 2: Container View Model

In Variant 1 we saw how little code was needed for the simple case, but there are warnings about the inflexibility and risk to the integrity of the business layer. Variant 2 aims to maximise the benefits of Variant 1, whilst minimising the code you must hand-crank by using a simple View Model container to pass multiple business entities (and potentially other types) to the view...

public class ModelController : Controller

{

    public ActionResult Index(int someparameter)

    {

        BusinessEntity model =

            BusinessLogic.GetModel(someparameter);

        OtherBusinessEntity othermodel =

            BusinessLogic.GetOtherModel(someparameter, model);

 

        ViewModelContainer container = new ViewModelContainer

        {

            ShowLogin = !User.Identity.IsAuthenticated,

            LoggedInName = User.Identity.Name ?? "",

            TheEntity = model,

            AnotherEntity = othermodel

        };

 

        return View(container);

    }

}

 

public class ViewModelContainer

{

    public bool ShowLogin { get; set; }

    public string LoggedInName { get; set; }

    public BusinessEntity TheEntity { get; set; }

    public OtherBusinessEntity AnotherEntity { get; set; }

}

Here we have the "ViewModelContainer" class, that is designed to carry our payload of a couple of business entities and some other primitives. Our Controller is responsible for fetching the business entities and then assembling this container, before passing it to the view.

So let's think about our pro's and con's;

1.       (pro) Any data not contained in our business entities can easily be passed across.

2.       (pro) Change is easy to handle when it consists of additive data.

3.       (pro) Developers will most likely add UI fields to the View Model container, not to the business entity.

4.       (pro) MVC can take advantage of the same validation mark-up attributes (or other scheme) that your business layer uses.

5.       (con) But... your business entities must still match the precise requirements of your view. If you want to convert or translate internal system concepts into something easier to display, this is difficult using this model.

Overall, this is my personal favourite as it provides flexibility and future proofing for little extra effort over and above Variant 1. However, it is by no means perfect and you must be willing to consider replacing your business entities with custom View Model entities if the needs of UI and business layer diverge... i.e. convert to Variant 3.

Variant 3: View Model and Mappers

Variant 3 is what could be called the utopia practice, in that it ensures your business and UI layers are suitably separated, with "mapper" classes (often referred to as the "Entity Translation" pattern) marshalling the relationship between the two. However, it comes at a price – and that is a little coding effort.

Let's see how this looks;

public class ModelController : Controller

{

    public ActionResult Index(int someparameter)

    {

        BusinessEntity entity = BusinessLogic.GetModel(someparameter);

        MyEntityViewModel model =

            MyEntityViewModelMapper.ConvertFromBusinessEntity(entity);

       

        return View(model);

    }

}

 

public class MyEntityViewModel

{

    public bool ShowLogin { get; set; }

    public string LoggedInName { get; set; }

    public string Name { get; set; }

    public bool IsOver18 { get; set; }

}

 

public class BusinessEntity

{

    public string Name { get; set; }

    public int Age{ get; set; }

}

This time I've showed the BusinessEntity class too so that you can see how it differs from the View Model. We can see that the Controller fetches this entity and then uses a mapper class to convert it to the View Model class. This mapper might also access environmental variables (e.g. User.Identity) or I might pass in other data.

The point with this approach is that the business entities are never passed to the view - only View Model classes can be consumed by views. This leads us to some findings;

1.       (pro) Any data not contained in our business entities can easily be passed across.

2.       (pro) Change is easy to handle when it consists of data that should be added, removed (or not displayed), or even altered / mapped (such as our Age field).

3.       (pro) Developers will add UI fields to the View Model, not to the business entity.

4.       (pro) The UI's needs are kept distinct from that of the business logic.

5.       (con) But... MVC cannot take advantage of the same validation mark-up attributes (or other scheme) that your business layer uses. Instead you must duplicate this.

Conclusion

The great news is that the p&p Web Client Guidance Reference Implementation includes some great examples of Variant 3. Check out the SongDetailsViewModel, and the Mapper classes. It quickly becomes clear how much freedom this separation of concerns gives us, and how easy to follow the pattern becomes when you use it as a convention.

Hopefully the Variants above help you understand why this approach was chosen, and help you pick an approach yourself. Make sure you check out the Reference Implementation to see how this can work in practice.

 

Leave a Comment
  • Please add 2 and 8 and type the answer here:
  • Post
  • Very well put! I like how you explain this as an evolving process when you start with a simple view. I'd only suggest variant 1 if and only if the whole team is willing to make the jump to the other variants when needed. Updating the business entities because of your UI is too big a risk if this is not an identified risk.

  • I don't agree at all about DTOs and POCOs, its behavioral domain models that predominate most of the discussion you'll find.

    One other point I'd make, if you go for option 3 you have a definition of how to map from the domain model to the view model. If you can then access metadata that describes what rules to apply to particular properties on the domain AND if you have tool like PostSharp then you have the option to copy/map the rules from the domain onto the view model as part of the build.

    Its tricksy code, and gets very hard when the rules are attributes, but it is basically possible and I can provide a code sample showing it if it is useful.

  • @ Colin,

    interesting points.

    I agree that a lot of discussion is out there about domain models, but I don't think that is a true reflection of how most people write systems... but rather it's a smaller minority that happen to be vocal. I'm more than happy to be wrong here though as I don't think one or the other is a clear winner; it depends on the scenario.

    Also, I completely agree about copying rules to View Models - I had this tooling approach in the back of my mind when I wrote the text above but I guess that isn't clear. If you do blog any code about how you've done that I'd love to see a link so feel free to post here :-)

    Thanks,

    Simon

  • @simonince

    Vocal, yes. They're also the small group thats influenced key technologies including ASP.NET MVC and EF. It does depend on your scenario, but I think too many people make uninformed decisions based just on what the latest Microsoft tooling offers, and I don't think thats the way modern systems should be developed.

    Most people who use domain models also realize that they aren't always the best option, but many people who use DTO based business logic don't seem to know enough about the alternatives for my liking.

    I can definitely put together some of the code and e-mail it to you, it definitely seemed a workable option but it'd need further development. In particular it worked for code-based rules and for attributes with no arguments. Anyway I'll send you something in the next week or two if you're interested.

  • 1) You can use projection instead of mapping to project EF entities onto view models.

    2) View models often have different validation rules than EF entities, since non-UI layers may provide some of the inputs after the user.

  • Hi Colin,

    Some good points... and some long running debates :-)

    I'd love to see a blog post on how you've done that! It's easy to digest that way, and time is money, as they say!

    Hi Craig,

    1) I agree, but fundamentally that is still mapping... just using a funky technology. It also depends on the rest of your architecture - your View Model and EF context might be many layers apart!

    2) That's a very interesting comment... it "feels right" to me, but then the more I think about it I'm not so sure... you see if I can possibly push any validation up from the database or business layer all the way to the browser client (and repeat it server side of course!) then I will. That means that if the field is displayed on the screen and it has validation, I want to "push it up the architecture stack".

    What I think you're probably referring to is what I meant by;

    "...your business entities must still match the precise requirements of your view..."

    ... when I was discussing Variant 2. If the EF entity doesn't match your needs for the UI, you should probably be using Variant 3. Does that make sense?

    Or have I misunderstood?

    Cheers,

    Simon

  • Well, I'm of the opinion that one should nearly always use "Variant 3" anyway.

    Regarding #2, consider the following. Imagine a system which collects timecards for employees. Employees are permitted to fill in a start time and a stop time, in which case the system will calculate elapsed time for them, or to fill in and elapsed time without a start time and a stop time. Timecards are represented at the Entity Framework by the type TimecardEntity, and at the UI level by the type TimecardPresentation.

    At the TimecardEntity level, it certainly makes sense to have the ElapsedTime property be required. Whether or not the user fills it in directly, it must be present before the entity can be persisted to the database. On the other hand, StartTime and StopTime are not required.

    The user interface's validation rules are different. The user must fill in either StartTime and StopTime (in which case, any value for ElapsedTime would be ignored and replaced with a calculated value by the system) or just the ElapsedTime. So it does not make sense to make ElapsedTime required, but it does make sense to validate that either ElapsedTime or both StartTime on TimecardPresentation are filled in.

    Validations, of course, are not the only thing which can vary. Other attributes you might put on your presentation model, like Description could be different if the same Entity Framework data might be displayed on two different user interfaces, via two different presentation models.

  • I would add a radical view on this topic. Lets consider Variant 4 - "No Domain Model". Or in other words "Only View Model".

    (pro) - maintain only one domain model (the model defined in the database). No need to maintain artificial abstraction layer of classes having exactly the same structure as the tables in the database.

    (pro) - higher performance and scalability. We need to show a list with 3 columns - lets extract only the data for these columns and fill the appropriate view model objects with these 3 properties, instead of pulling all data for all 20 properties/fields in our domain model and show only 3 of them. Less data reads, less internal network usage, less memory usage, faster UI response time and better scalability.

    (con) - duplication of the validation markup and/or validation methods (for more complex validation scenarios)

    Just to clarify - by "No Domain Model" I don't mean direct database access in the UI with no abstraction between. What I mean is to model in the middleware objects suitable for the consumer layer (in this case the UI) instead of recreating the database model.

    There are scenarios where the duplicated domain model is usefull (when an API has to be provided for integration with third party systems and the exact data usage is not specified - i.e. it is not possible to define view models in advance), but when considering a common web based application, its API is only by itself.

  • Craig;

    All good points; any system that has these kinds of complexities is a very strong contender for Variant 3, and that's why the p&p guys went with that approach in their guidance.

    Hi Nikolay,

    you make an interesting point. I must admit I initially thought "what?!" but then I read through your comment again and I see what you're saying.

    I think it's basically very similar to the age old discussion about whether or not data access classes should represent a database table or the needs of the UI. I forget the pattern names but this has been a huge discussion on and off in various forms.

    To be honest I think modern ORM tools mean that you can do what you describe using a framework like nHibernate or the EF, mapping just the database fields you need for the UI, and then use Variant 2 of my approaches above... this gives a very close approximation of what you describe. I also probably wouldn't recommend this for performance reasons; in reality most "average" systems have much bigger and more serious bottlenecks, and a well structured, clearly coded system is far more likely to be maintainable, and IMHO to perform well.

    Good spot on the forgotten variant though :-)

    Simon

  • Most of the O/R mapping frameworks support lazy loading, but its efficiency compared to explicit and selective data loading is another story.

    It is clear that for many systems the performance and scalability are rarely the biggest problem. This is especially true for enterprise level solutions usually accessed by a small number of internal users.

    As you said the maintainability is one of the most important aspects and in such cases it is usually priority #1.

    The number of view model entities is much higher than the number of domain model entities, so if one wants less maintenance overhead, probably the best balance is provided by the hybrid solution (Variant 2: Container View Model) - no need to create and maintain explicit view models, but still having the ability to add view specific information without breaking the domain model integrity.

  • This is a really nice walk through the ways to get a model up to the view.  I tried Variant 2 for a while, thinking views composed of business entities plus anything extra was the best way to go.  But I had properties and methods in my business entities I really didn't want the view going near.

    They really are separate concerns.  They may overlap a lot, but they ultimately serve different purposes.

    So I'm all about Variant 3 these days with AutoMapper to make the conversions easier.  I also think one view model per view will become more valuable with the new html helpers in MVC2 that spit out your entire view model for display/edit.

    It does seem like the last mile on Variant 3 is getting centralized validation rules from the business domain up to the view model so your controller can take advantage of the model binder validating for you.

    I'm just decorating my view models with the Data Annotations attributes and living with that for now.

  • Nikolay;

    good comments - thanks for the thoughts. I'd be interested to hear what others think to your perspective...

    Simon

  • Nikolay,

    When you project from an EF context onto a presentation model, the EF does *not* materialize full objects. In other words, if I do:

       from e in Context.Entities

       where e.Id == id

       select new

       {

           Name = e.Name,

           ChildName = e.Child.Name,

           GrandchildName = e.Child.Child.Name

       }

    ...then only three columns are returned from the DB, not every column for every entity. I realize many ORMs don't work that way, but it's a limit of that ORM, not a reason to avoid ORMs in general.

  • @ Joe,

    Thanks! I think your story sounds very reasonable; there are many cases where you just have to go with Variant 3, and there's no doubt it's the "grown up" solution.

    Simon

  • Simon,

    I also would like to thank you for this article; it is well structured and very helpful. Now I have kind of a dictionary of the modelling options, so even the the conversation inside my head is much easier when thinking on the topic.

    There is something that could be added as a pro for variants 2 and 3 (having view models): no security concerns regarding automatic model binding - when a view model is used there is no chance for the hacker to update data in fields not supposed to be updated (role, user rights etc.). The exclusion from binding works, but what happens when somebody adds properties to the entities in the domain model and forgets to go and add some or all of them to the list of excluded properties for binding.

    Nikolay

Page 1 of 3 (40 items) 123