Dynamic Methods in View Data

In ASP.NET MVC 3 Preview 1, we introduced some syntactic sugar for creating and accessing view data using new dynamic properties.

sugarSugar, it’s not just for breakfast.

Within a controller action, the ViewModel property of Controller allows setting and accessing view data via property accessors that are resolved dynamically at runtime. From within a view, the View property provides the same thing (see the addendum at the bottom of this post for why these property names do not match).

Disclaimer

This blog post talks about ASP.NET MVC 3 Preview 1, which is a pre-release version. Specific technical details may change before the final release of MVC 3. This release is designed to elicit feedback on features with enough time to make meaningful changes before MVC 3 ships, so please comment on this blog post if you have comments.

Let’s take a look at the old way and the new way of doing this:

The old way

The following is some controller code that adds a string to the view data.

public ActionResult Index() {
  ViewData["Message"] = "Some Message";
  return View();
}

The following is code within a view that accesses the view data we supplied in the controller action.

<h1><%: ViewData["Message"] %></h1>

The new way

This time around, we use the ViewModel property which is typed as dynamic. We use it like we would any property.

public ActionResult Index() {
  ViewModel.Message = "Some Message";
  return View();
}

And we reference it in a Razor view. Note that this also works in a WebForms View too.

<h1>@View.Message</h1>

Note that View.Message is equivalent to View["Message"].

Going beyond properties

However, what might not be clear to everyone is that you can also store and call methods using the same approach. Just for fun, I wrote an example of doing this.

In the controller, I defined a lambda expression that takes in an index and two strings. It returns the first string if the index is even, and the second string if the index is odd. It’s very simple.

The next thing I do is assign that lambda to the Cycle property of ViewModel, which is created on the spot since ViewModel is dynamic.

public ActionResult Index() {
  ViewModel.Message = "Welcome to ASP.NET MVC!";

  Func<int, string, string, string> cycleMethod = 
    (index, even, odd) => index % 2 == 0 ? even : odd;
  ViewModel.Cycle = cycleMethod;

  return View();
}

Now, I can dynamically call that method from my view.

<table>
@for (var i = 0; i < 10; i++) {
    <tr class="@View.Cycle(i, "even-css", "odd-css")">
        <td>@i</td>
    </tr>
}
</table>

As a fan of dynamic languages, I find this technique to be pretty slick. :)

The point of this blog post was to show that this is possible, but it raises the question, “why would anyone want to do this over writing a custom helper method?”

Very good question! Right now, it’s mostly a curiosity to me, but I can imagine cases where this might come in handy. However, if you re-use such view functionality or really need Intellisense, I’d highly recommend making it a helper method. I think this approach works well for rapid prototyping and maybe for one time use helper functions.

Perhaps you’ll find even better uses I didn’t think of at all.

Addendum: The Property name mismatch

Earlier in this post I mentioned the mismatch between property names, ViewModel vs View. I also talked about this in a video I recorded for MvcConf on MVC 3 Preview 1. Originally, we wanted to pick a nice terse name for this property so when referencing it in the view, there is minimal noise. We liked the property View for this purpose and implemented it for our view page first.

But when we went to port this property over to the Controller, we realized it wouldn’t work. Anyone care to guess why? Yep, that’s right. Controller already has a method named View so it can’t also have a property named the same thing. So we called it ViewModel for the time being and figured we’d change it once we came up with a better name.

So far, we haven’t come up with a better name that’s both short and descriptive. And before you suggest it, the acronym of “View Data” is not an option.

If you have a better name, do suggest it. :)

Addendum 2: Unit Testing

Someone on Twitter asked me how you would unit test this action method. Here’s an example of a unit tests that shows you can simply call this dynamic method directly from within a unit test (see the act section below).

[TestMethod]
public void CanCallCycle() {
  // arrange
  var controller = new HomeController();
  controller.Index();

  // act
  string even = controller.ViewModel.Cycle(0, "even", "odd");

  // assert
  Assert.AreEqual("even", even);
}

What others have said

Requesting Gravatar... Winston Aug 02, 2010 7:28 AM
# re: Dynamic Methods in View Data
A few curious questions I had when I first saw this was, 1)Would ViewData be eventually deprecated in future MVC versions? 2) Is the dynamic View essentially injecting into ViewData? 3) If point 1 is true, does this mean MVC would eventually be for .NET 4.0+ only, since previous frameworks don't support dynamic.

Cheers,


Winston
Requesting Gravatar... Kim Aug 02, 2010 7:58 AM
# re: Dynamic Methods in View Data
That's great.
I've a request: a default resource to data annotations
something like this

DataAnnotations.DefaultResource = typeof(CustomResource);
thanks!
Requesting Gravatar... Troy Goode Aug 02, 2010 8:11 AM
# re: Dynamic Methods in View Data
Winston: They've already said MVC3 will be .NET 4.0+ only anyway. I agree that it would be nice if they marked ViewData as deprecated.
Requesting Gravatar... Turnkey Aug 02, 2010 8:14 AM
# re: Dynamic Methods in View Data
For the ViewData question I would steer clear of ViewModel as it is confusing as that term usually refers to custom classes for passing structured data to the view. I think just sticking with the ViewData usage for both the controller and View is not that bad, it's just a few more characters and has some historical precedent that is familiar to the users.

Cheers,
Turnkey
Requesting Gravatar... Chad Lansford Aug 02, 2010 8:26 AM
# re: Dynamic Methods in View Data
Great post, thanks! Just a quick comment - your first sample after the "The New Way" heading uses "ViewData.", should it be "ViewModel." instead?
Requesting Gravatar... Martin Aatmaa Aug 02, 2010 8:33 AM
# re: Dynamic Methods in View Data
@Winston:

MVC 3 takes a dependency on .NET 4.0+, and will therefore not support .NET 3.5.
Requesting Gravatar... Michael Monteleone Aug 02, 2010 8:45 AM
# re: Dynamic Methods in View Data
What about "ViewState"?
Requesting Gravatar... Winston Aug 02, 2010 8:58 AM
# re: Dynamic Methods in View Data
Ah I see, my bad for not thoroughly reading :)
Requesting Gravatar... Pierrick Aug 02, 2010 8:59 AM
# re: Dynamic Methods in View Data
what about ModelData?
Requesting Gravatar... Luke Sampson Aug 02, 2010 9:32 AM
# re: Dynamic Methods in View Data
How about "Bag" or maybe "ViewBag" for the name of the view model? I don't know if it fits with the strict definition of a bag/multiset, but I like the idea of putting stuff in a bag - it fits with the dynamic nature of this object, because you can throw anything in the bag.

And Web Forms stores view state in a StateBag object... so it's a continuation of a theme, sort of.
Requesting Gravatar... Oskar Austegard Aug 02, 2010 10:18 AM
# re: Dynamic Methods in View Data
Html5 uses data-foo for custom, ad hoc data attributes, how about simply using Data as the name in both controller and view?
Requesting Gravatar... Brian Donahue Aug 02, 2010 10:43 AM
# re: Dynamic Methods in View Data
This seems like a pretty bad violation of SoC to me... even though you don't execute your lambda in your controller, you are defining it there, which is making the code more complex/harder to read.

I know it's just sample code, but I think it's an example of "dynamic abuse" here. That rendering logic should live in the view, probably in a view helper class. I can't think of a good reason to add dynamic methods to a view model, not that means there isn't one - but it seems to me controller logic belongs in the controller, and view logic belongs in the view, and the ViewModel should just be a dumb model.
Requesting Gravatar... Aidan Boyle Aug 02, 2010 10:44 AM
# re: Dynamic Methods in View Data
A couple of people have suggested in the comments of this Hanselminutes-on-9 video that the ViewData dictionary could implement IDynamicMetaObjectProvider so that keys added to ViewData could be accessed as properties dynamically.
I haven't tested it myself to see if it works but it seems to me that combining the ViewData/ViewModel properties together would make things easier to understand? It would also eliminate the problem of what to call the new ViewModel property.
Requesting Gravatar... Rick Aug 02, 2010 10:45 AM
# re: Dynamic Methods in View Data
+1 for "Bag"

or how about possibly "Items" or "Data" - a quick look didn't turn up any members with those names.
Requesting Gravatar... Daniel Aug 02, 2010 10:46 AM
# re: Dynamic Methods in View Data
I'm not sure I like these all that much. I see a lot of "Field msseage not found" style errors as there is no way to strongly type these items. At least with the strings you can have strongly typed constants referencing the viewdata entry.

I'm also not sure what the dynamic methods offer over HTML helpers really.

But that said at least it's available for when it is appropriate which is nice to have.
Requesting Gravatar... Prabir Shrestha Aug 02, 2010 12:25 PM
# re: Dynamic Methods in View Data
extending with IDynamicMetaObjectProvider might be good.
so devs can use which ever ones they feel comfortable with.

would love to see the performance of dynamic vs dictionary viewdata.
Requesting Gravatar... Andrey Shchekin Aug 02, 2010 2:27 PM
# re: Dynamic Methods in View Data
I think ViewModel is not a good idea (as Turnkey says).
I would prefer it to be on top of ViewData, actually (as Aidan Boyle said), but if that is impossible for compatibility, then it could be:
ViewData.Dynamic
DynamicData
Dynamic
Requesting Gravatar... Adam Aug 02, 2010 3:32 PM
# re: Dynamic Methods in View Data
How about just "Data" as the property name on both controller and view??
Requesting Gravatar... Johannes Hansen Aug 02, 2010 3:44 PM
# re: Dynamic Methods in View Data
A dynamic ViewModel is awesome and very helpful. However, I think you should shorten the property name from "ViewModel" to "Model", since being a property on a view the word "View" seems redundant. Also while the "Cycle" example you give is fancy, it seems to me as if it belongs in the world of Html helpers/extension methods. :) Other than that keep up the awesome work you are doing.
Requesting Gravatar... Robin Osborne Aug 02, 2010 4:48 PM
# re: Dynamic Methods in View Data
Given that these are dynamic properties, presumably we won't get the helping hand of intellisense? Just a little concerned that splitting work between developers working on the Controller and those on the View may bring in extra bugs related to typos on the property names.

Other than that, great little addition making for some very pretty code!
Requesting Gravatar... Bob Cravens Aug 02, 2010 8:44 PM
# re: Dynamic Methods in View Data
I am not understanding if this API change will break existing code. If so, then please rename. After upgrading a project to a new version of mvc, the first thing I like to see is that every thing still works.
Requesting Gravatar... Will Aug 02, 2010 9:45 PM
# re: Dynamic Methods in View Data
How about "DynamicView"? Lets you know what you're up for.
Requesting Gravatar... ali62b Aug 02, 2010 10:43 PM
# re: Dynamic Methods in View Data
What about "Transporter" Because it transports data to view or maybe "Transformer" because of its Dynamic nature !
(This way we add Hollywood's products to MVC.NET :D)

example : Transporter.Message or Transformer.Massage
Requesting Gravatar... larry Aug 02, 2010 10:52 PM
# re: Dynamic Methods in View Data
+1 for Bag also
Requesting Gravatar... Andy West Aug 02, 2010 11:55 PM
# re: Dynamic Methods in View Data
I have to agree with Brian Donahue on this - the first thing that crossed my mind was that this must violate SoC. If it's view logic, why are you defining it in the controller? If it's controller logic, then why are you calling it from the view?

Some developers want to keep code out of the view at all costs, but I think that's a misguided approach. There are times when you need it.
Requesting Gravatar... Shlomo Abraham Aug 03, 2010 12:07 AM
# re: Dynamic Methods in View Data
I don't understand the gain of this, and I instinctively dislike it. What's gained by changing from ViewData["Message"] to ViewWhatever.Message? I keep hearing 'cleaner code', but to me it's not cleaner: The former makes it look like a dictionary (which it is), the latter makes it look like a strongly-typed, compile-checked property (which it isn't).

As for names, I would suggest ViewDynamo. ViewModel is too easily confused with the view model pattern.
Requesting Gravatar... haacked Aug 03, 2010 12:57 AM
# re: Dynamic Methods in View Data
The reason we probably won't make ViewDataDictionary implement IDynamicMetaObjectProvider is twofold:

1. Even if we did that, we'd still need to change the existing property type of the ViewData property to be dynamic. That's a breaking change, and a pretty bad one.

2. There are methods on ViewDataDictionary that might be important. Unfortunately, with Visual Studio, there's no Intellisense if you declare a variable as dynamic, even if that property implements other interfaces.

I'm guessing in the future, #2 won't be such a big issue. I think #1 will be. Thanks for the feedback!
Requesting Gravatar... Aidan Boyle Aug 03, 2010 5:41 AM
# re: Dynamic Methods in View Data
Its been a while since I looked at the dynamic stuff and my understanding was that as long as a class implemented IDynamicMetaObjectProvider then C# would let you access dynamic members on it while still having Intellisense for the static members.
I've had a closer look now and I can see that even if a class implements the interface you have to cast the object to "dynamic" before it lets you access anything dynamically.
Maybe they could add that in C# 5? I'm used to interchanging obj["property"] and obj.property in JavaScript and its often quite useful.
Requesting Gravatar... Jarrett Vance Aug 03, 2010 6:13 AM
# re: Dynamic Methods in View Data
+1 Bag
+2 Data
Requesting Gravatar... Criação de Site Aug 03, 2010 12:25 PM
# re: Dynamic Methods in View Data
very good feature, intelissense works with that ?
Requesting Gravatar... Henrik Aug 04, 2010 12:31 AM
# re: Dynamic Methods in View Data
You replaced magic string with magic property
Requesting Gravatar... haacked Aug 04, 2010 12:37 AM
# re: Dynamic Methods in View Data
@Aidan believe me, we're going to beg the C# team for that. Or the Visual Studio team. Whichever is responsible. ;)
Requesting Gravatar... Filip Aug 04, 2010 12:49 PM
# re: Dynamic Methods in View Data
+1 ViewBag or Bag
could also be a "Bundle" (Java style :)
Requesting Gravatar... cowgaR Aug 05, 2010 2:29 AM
# re: Dynamic Methods in View Data
-1 for Bag (reminds me of ORMs)
+1 for Transporter
+2 for Data (although it crosses name with the recent MS.Data project...)

+100 that you are "replacing a magic string with magic property" problem, or as Mr Abraham said, it is a very bad masked dictionary.


-1000 for me is "View.Something" in the View code, as "View" identifier/name should stay only (and only only) for a method in controllers code for calling Views.

Eventhough I'm reading HTML, C# and HTML can sometimes mix so good (with a help of razor syntax) that readability suffers (say for newcommer), as I need to realize it is the VIEW code I'm reading now, thus View != View().

in this way, ViewData was 10 times better and descriptive name...(so why not to change both of them to ModelData? make sense even when called from View)
Requesting Gravatar... cowgaR Aug 05, 2010 2:35 AM
# re: Dynamic Methods in View Data
now I re-read the issues that you have been looking for the shortest possible name not to produce "spaghetti code" in Views, thus View instead of ViewData.

I have to correct myself and "Bag/ViewBag" would seem as a best option for the View and for the Controller code.

Short, descriptive, and not confusing anybody. I like the old ViewState term as well, not so short in Views though.
Requesting Gravatar... Shlomo Abraham Aug 05, 2010 8:18 AM
# re: Dynamic Methods in View Data
Cowga, are you against the concept or for it?

I still don't understand the benefit. IntelliSense may help a bit, but I don't see how this is anything more than *ahem* lipstick on a pig...
Requesting Gravatar... Dody Gunawinata Aug 05, 2010 8:28 PM
# re: Dynamic Methods in View Data
@Shlomo, View.Name is less typing that ViewData["Name"] and it's nicer to type and look. Individually they might not mean much but the less friction, the better.

@haacked, please BEG the C# team for an interpreted mode for their upcoming C# compiler service so we can run tests or site without recompilation during development.
Requesting Gravatar... jmorris Aug 06, 2010 9:14 AM
# re: Dynamic Methods in View Data
I second (or third) the comments that this violates Separation of Concerns, however useful it is. The properties are one thing, but invoking method from the view seems to be a violation or at the least a slippery slope.

Since you asked about a name (and not our opinion about the feature), I'd simple call DynamicData or DynamicView or something to that effect.

-Jeff
Requesting Gravatar... haacked Aug 06, 2010 12:47 PM
# re: Dynamic Methods in View Data
@jmorris, why would calling a property be ok but a method not be ok?

I dispute the claim that this must be an SOC violation. SOC is about the direction of knowledge. For example, when you look at an MVC diagram (en.wikipedia.org/...), you can see that the controller has a direct association to the view. In other words, it has knowledge about the view.

But the view has an indirect association to the controller. In the example I blogged, the view is given a method and it's told to call it. It doesn't have internal knowledge of the controller.

Another way to think about it is to think of the method as a method of the model. Calling methods is allowed in a view.

I agree, this can be abused, but I don't think it's automatically an SOC violation.
Requesting Gravatar... Dody Gunawinata Aug 06, 2010 8:31 PM
# re: Dynamic Methods in View Data
Sweet. I can create filters that inject functions to ViewModel so it is clear what is available on each action.
Requesting Gravatar... Colin Jack Aug 07, 2010 5:35 PM
# re: Dynamic Methods in View Data
I share the opinion of some others, namely View and ViewModel don't seem to be good names.
Requesting Gravatar... Hector Minaya Aug 07, 2010 10:12 PM
# re: Dynamic Methods in View Data
How about ViewInfo
Requesting Gravatar... Andrei Rinea Aug 08, 2010 4:34 AM
# re: Dynamic Methods in View Data
Oh noez...

I knew this was coming since I've seen the dynamic object in .NET 4. I knew there will be abuses and here's the proof.

This is PHP-style programming, a mistyped letter and you'll never know why something is not shown in the view.

All we need know is $ in front of the variables and replace the dereferrencing operator (.) with a " -> ".

-1!
Requesting Gravatar... Adam Aug 12, 2010 5:57 AM
# re: Dynamic Methods in View Data
Hi Phil!

I can see that changing ViewData to be dynamic will cause problems. I think many of us using MVC have typed view-models and so ViewModel isn't a good name. You could argue that dynamic view-data style stuff gets rid of ViewModels, and for simple stuff I agree. But normally you use ViewModels for more complicated scenarios (like putting together a GANNT chart.)

For me, I'm afraid ViewData does sum it all up!

Not suggesting it is, but maybe it's between the pain of us having to change our code (again) but it being right or having some duff name that doesn't really make sense.

Have a vote!

Requesting Gravatar... Jessica Aug 12, 2010 12:13 PM
# re: Dynamic Methods in View Data
I don't think it's a bad feature. I don't like having to type ViewData["Message"]. For me, View.Message works in the view page code, but ViewModel in the controller code doesn't; primarily because I don't use the ViewData dictionary for model state; just for passing extra useful data from the controller to the view (titles, messages, things like that).

It really is a shame ViewData is taken, and won't be chosen because of backwards compatibility. I think it is the best fit here.

I vote for a breaking change.
Requesting Gravatar... Anton Aug 12, 2010 6:22 PM
# re: Dynamic Methods in View Data
Microsoft likes words like Context. Maybe you could call it something like: Context, ViewContext or DataContext to make it consistent with WPF world.
Requesting Gravatar... Adam Aug 12, 2010 10:30 PM
# re: Dynamic Methods in View Data
@Anton

I think ViewContext is already used somewhere.

In my opinion DataContext sounds too much like LINQtoSQL and I don't like the name much in WPF. Please don't suggest that! You got any other suggestions? I'd rather DataContext be called Model in WPF. That's exactly what it is (though I guess 9 times out of 10 it is ViewModel...)

It is only my opinion, wait for the raft of people thinking "yeah, data-context is a brilliant idea! Plus I'm not liking WPF much at the moment, you can't easily run commands on GridViews or DataGrids?! Grrrr... That might be influencing my response somewhat...

I still think we need a vote.

1.) ViewContext
2.) DataContext
3.) ViewData
4.) Add your own suggestion...

Come on Haack, you've build your own blog engine and architected ASP.NETonRails... Why don't you just have an open Vote.
Requesting Gravatar... [ICR] Aug 17, 2010 5:00 AM
# re: Dynamic Methods in View Data
"This is PHP-style programming, a mistyped letter and you'll never know why something is not shown in the view."

Why would mistyping the name of a dynamic property be anything different to mistyping the key in a dictionary? Just because dynamic objects and PHP are both dynamic doesn't mean they handle failures the same - a dynamic object can still give an exception if the object isn't found.

They're not replacing a strongly typed object with a dynamic object - they're replacing a dynamic object with a different dynamic object with more syntactic sugar. The consequences of the potentially misleading syntactic sugar are debatable, but this isn't going to lead to any less errors being found.
Requesting Gravatar... Thanigainathan Aug 18, 2010 5:44 PM
# re: Dynamic Methods in View Data
Hi,

Is this somewhat related to Javascript dynamic methods ?
Is this some kind of general programming concept ?

Thanks,
Thanigainathan.S
Requesting Gravatar... Gpan Aug 18, 2010 9:38 PM
# re: Dynamic Methods in View Data
How about: Vd [pronounced - VooDoo] to remind "magic".
Requesting Gravatar... Carlo Aug 19, 2010 6:19 AM
# re: Dynamic Methods in View Data
I vote for a breaking change.
Requesting Gravatar... schrodinger Aug 19, 2010 10:24 AM
# re: Dynamic Methods in View Data
how about MagicView or SuperView or MvcView
Requesting Gravatar... Marcus Wendt Sep 03, 2010 9:03 PM
# re: Dynamic Methods in View Data
What about ViewContent?
Requesting Gravatar... jacko Sep 13, 2010 11:55 PM
# re: Dynamic Methods in View Data
I vote for a breaking change too, it's view data.
Requesting Gravatar... John Kyle Sep 15, 2010 6:35 PM
# re: Dynamic Methods in View Data
ViewData is the only sensible place. Otherwise you have two properties doing the same thing. That isn't tidy!

It isn't strong typing and it will have its issues if it isn't used right. But, I guess if you get the name wrong with a dictionary like ViewData["foo"] then it's the same.

I vote for a breaking change too.
Requesting Gravatar... Kozlow Sep 30, 2010 8:25 AM
# re: Dynamic Methods in View Data
+1 ViewBag both sides.
Requesting Gravatar... Wilson Dec 16, 2010 7:52 PM
# re: Dynamic Methods in View Data
Hi guys,

So now we have to deal with the ViewBag name in the RC2!! It's done!! My question is:

WHY if it's so clear that it is the ViewModel in the controller context and the Model in the View context??? Isn't it?? It's just me?? Is ViewBag something meaningful to you?? Really?? ... hmmmmmmm :(
Requesting Gravatar... dermatologist Jan 05, 2011 5:46 PM
# dermatologist

It’s a nice post!Thanks for your good work,it helps me a lot!I will come back again!


What do you have to say?

(will show your gravatar)
Please add 3 and 2 and type the answer here: