Monday, December 5, 2011

Stop using MVC's ViewBag in most places, please!

Even the built in templates give us support for ViewBag. The scaffolding templates create ViewBag.SomeEnumerable to use for our pages.
Sure - its quick code and since it's auto-generated will likely work ok. The problem comes in from the fact that ViewBag is a dynamic object. There are no compile time type checks. If you misspell something you won't be notified from the compiler.

I've seen this used in such bad ways, I would love to see it's usage curbed and applications cleaned up.

So in a controller:
ViewBag.SomeProperty = "10"
and in the view:
@ViewBag.Som3Pr0p3rty
We won't ever know of this error. It won't even generate a runtime error since the misspelled name just generated a null.


Use ViewModels and save yourself from these potential problems. Our templates set a page title in ViewBag as well.


There are several options in setting a page title. Since this is a well known property one could argue that using it just for Title is ok. I wouldn't argue this. There are other options.
1. Set it in a section in the layout and render it from the client.
2. Use ViewBag.Title
3. Use a filter (seems much too complicated for a title)
4. Use a Model.Title field.

Since by default we have a ViewBag.Title field created and our templates also get it by default, I'll yield that in this case, its ok.

What about select lists?
Rather than the default

 ViewBag.CustomerId = new SelectList(db.Customers, "CustomerId", "FirstName", order.CustomerId);


Do something like
yourViewModel.Customers = customers; //a loaded collection

and in your view
@Html.DropDownListFor(x => x.CustomerId, new SelectList(Model.Customers, "CustomerId", "Name"))

Or if you prefer to set your ViewModel to contain the SelectList


yourViewModel.Customers = new SelectList(db.Customers, "CustomerId", "Name", order.CustomerId);

and now your view would be slightly cleaner as:
@Html.DropDownListFor(x => x.CustomerId, x.Customers)

See, that's not so difficult now is it? Enjoy!

4 comments:

  1. Hello Adam, I'm a begginer and I couldn't follow your examples here, so is it possible to have an example with more details?, let's say how to build the model, the controler and the view, to work the way you show us. I'm interesting in not to use the viewbag.

    ReplyDelete
  2. Hi Gilmer, Simply:
    1. in your controller create an instance of your ViewModel. This is just a model (some lightweight class with no persistence logic) that wont be used anywhere else but this controller and view.
    2. populate the viewmodel.
    3. send it to the view from your controller's method via "return View(yourViewModel)"
    This is just like you see the examples that use a model, but instead of using an entity framework model (for ex.) you are creating your own class specific to this view and populating it. Am I making sense? If you have a specific question I can answer more on please let me know

    ReplyDelete
  3. Hi Adam, I want to thank you for your time and concern, yes, it make sense, I have a better understanding, I also made another research and I found more material to build Views with less code, specially the dropdownlist.
    once again thank you.

    ReplyDelete
  4. Yes.Nice explanation.Good one about not to use ViewBag.
    Use ViewModel instead of.Keep it up good work.

    ReplyDelete