views:

50

answers:

4

There seem to be multiple means of passing model data from controllers in asp.net mvc to views. Its not clear to me if there's a recommended approach in the mvc v1 and v2 releases or if like most things in life, it depends. I've seen several approaches:

Option 1 - Populate the controller's ViewData dixtionary in either an icky string-based indexing way with casting in the view, or the in a strongly typed way by creating a strongly typed custom model class and passing that via ViewData.

Option 2 - Use ViewData.Model, which I'm not sure I even understand.

Option 3 - Use ViewPage.Model, in which case I'm not sure how you pass the model data from the controller.

I've seen a number of posts poo-pooing options 1 and 2 but I don't understand why. These posts seem to highly recommend 3 in most cases.

How do you approach this? Is there a standard way?

+2  A: 

Every view 'should' have a specific model. This is sometimes more work so people use short cuts like ViewData, which works but is just not as clean and type safe in my opinion, so I prefer to have everything in the view's model.

You can then make all your views stongly typed. This is a very clean way to do so. Then in your controller you just call the view like:

YourViewModel model = new YourViewModel()
{
    // initialize the data here
};
View(model);

Then in your views you can access all the data via ViewPage Model and it is all type safe and enforced from the controller as well.

EDIT from comments:

You don't need to use ViewData at all if you don't want. You can encapsulate all the data your view needs in a model. Just like the example you quoted with ProductsListViewData. It's just a model that contains all the items that were going to be stored in the ViewData. Both ways work but when you encapsulate it in a class (preferred method where everything is in the model) then all the bits and pieces are strongly typed.

ViewData is a generic container so even though you can just put anything you want into it, it is not type safe and therefore not as 'clean'. It comes down to preference and maintainability. There is only option 1 and 3. Your option 2 is misunderstood and is just option 3 in reality. There is no ViewData.Model just ViewPage.Model.

Kelsey
+1 for being flexible and not saying you always need a strongly typed model.
jfar
@Kelsey - Thanks for the great answer. Couple of follow-ups: First, is your YourViewModel class the same type of thing as ProductsListViewData which is shown in the "Approach 2: Passing ViewData using Strongly Typed Classes" section of http://bit.ly/eWN6R? Second, my Option 1 and Option 2 both refer to ViewData but it's not clear to me when you'd access ViewData via ViewPage.ViewData["whatever"] vs. via ViewData.Model?
Emilio
@Kelsey - Thanks a lot, you totally cleared it up for me on both points.
Emilio
@Emilio if this answered your question, don't forget to set it as the accepted answer :) I will move my comments up to the answer so that others will not miss them.
Kelsey
@Kelsey - all set. What do you think of the answer and the comment to that answer below?
Emilio
A: 

This might be of some help:

When is it right to use ViewData instead of ViewModels?

DaveDev
@DaveDev - excellent, ty.
Emilio
+1  A: 

One approach you may wish to consider as your views become more complex, is to reserve the use of Models for input fields, and use ViewData to support anything else the View needs to render.

There are at least a couple of arguments to support this:

  1. You have a master-page that requires some data to be present (e.g. something like the StackOverflow user information in the header). Applying a site-wide ActionFilter makes it easy to populate this information in ViewData after every action. To put it in model would require that every other Model in the site then inherit from a base Model (this may not seem bad initially, but it can become complicated quickly).

  2. When you are validating a posted form, if there are validation errors you are probably going to want to rebind the model (with the invalid fields) back to the view and display validation messages. This is fine, as data in input fields is posted back and will be bound to the model, but what about any other data your view requires to be re-populated? (e.g. drop-down list values, information messages, etc) These will not be posted back, and it can become messy re-populating these onto the model "around" the posted-back input values. It is often simpler to have a method which populates the ViewData with the..view data.

In my experience I have found this approach works well.

And, in MVC3, the dynamic ViewModels means no more string-indexing!

MJ Richardson
I totally agree. Using Models for absolutely everything will get real messy and very unmanagable real fast. Use the ViewData where it's applicable. They didn't put it in there so that we wouldn't use it.
Yngve B. Nilsen
A: 

(I know the following answer is highly arguable, but it's just the way I like to do it)

I would say use ViewData for simple data-tasks, and use the Model for the main purpose of the View. Check out Rob Conerys ViewData helper-classes here to give them a bit more Strongly typed feel:

http://blog.wekeroad.com/2010/01/20/my-favorite-helpers-for-aspnet-mvc

Using Models for absolubtely everything will bloat your project with hundreds of models just to achieve the smallest thing. I mean if you have a User-setting page, you would normally pass a User-model into the view, but if you decide to show some related data like Customers related to this User. You're stuck with the following solutions

  1. You might have to add a List property to the User-model in order to expose the customers to the view. This leads to the Customer-property always being applied to the User-model everywhere else in the project - or make a new simpler User-model.
  2. Make a new action that returns a partial of customers, which you can use with Html.RenderAction.

OR

you could do ViewData["Customers"] = myRepo.GetCustomersRelatedTo(user); // or something like that.

and (if using Robs helpers) in your view:

<%= Html.RenderPartial("CustomerList", Html.ViewData("Customers")) %> add a PartialView called CustomerList that takes IEnumerable

In my humble opinion this is a cleaner solution and sure - you end up with a magic string here and there, but I'll stick to this approach until someone shows me a project with not a single magic string.

Use the tools we have in the Framework to get the job done. and Keep it simple s... ;)

Yngve B. Nilsen