Dynamic Methods in View Data

asp.net, asp.net mvc, code 0 comments suggest edit

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);
}

Tags: aspnetmvc, dynamic, viewdata

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

59 responses

  1. Avatar for Winston
    Winston August 2nd, 2010

    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

  2. Avatar for Kim
    Kim August 2nd, 2010

    That's great.
    I've a request: a default resource to data annotations
    something like this
    DataAnnotations.DefaultResource = typeof(CustomResource);
    thanks!

  3. Avatar for Troy Goode
    Troy Goode August 2nd, 2010

    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.

  4. Avatar for Turnkey
    Turnkey August 2nd, 2010

    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

  5. Avatar for Chad Lansford
    Chad Lansford August 2nd, 2010

    Great post, thanks! Just a quick comment - your first sample after the "The New Way" heading uses "ViewData.", should it be "ViewModel." instead?

  6. Avatar for Martin Aatmaa
    Martin Aatmaa August 2nd, 2010

    @Winston:
    MVC 3 takes a dependency on .NET 4.0+, and will therefore not support .NET 3.5.

  7. Avatar for Michael Monteleone
    Michael Monteleone August 2nd, 2010

    What about "ViewState"?

  8. Avatar for Winston
    Winston August 2nd, 2010

    Ah I see, my bad for not thoroughly reading :)

  9. Avatar for Pierrick
    Pierrick August 2nd, 2010

    what about ModelData?

  10. Avatar for Luke Sampson
    Luke Sampson August 2nd, 2010

    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.

  11. Avatar for Oskar Austegard
    Oskar Austegard August 2nd, 2010

    Html5 uses data-foo for custom, ad hoc data attributes, how about simply using Data as the name in both controller and view?

  12. Avatar for Brian Donahue
    Brian Donahue August 2nd, 2010

    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.

  13. Avatar for Aidan Boyle
    Aidan Boyle August 2nd, 2010

    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.

  14. Avatar for Rick
    Rick August 2nd, 2010

    +1 for "Bag"
    or how about possibly "Items" or "Data" - a quick look didn't turn up any members with those names.

  15. Avatar for Daniel
    Daniel August 2nd, 2010

    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.

  16. Avatar for Prabir Shrestha
    Prabir Shrestha August 2nd, 2010

    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.

  17. Avatar for Andrey Shchekin
    Andrey Shchekin August 2nd, 2010

    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

  18. Avatar for Adam
    Adam August 2nd, 2010

    How about just "Data" as the property name on both controller and view??

  19. Avatar for Johannes Hansen
    Johannes Hansen August 2nd, 2010

    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.

  20. Avatar for Robin Osborne
    Robin Osborne August 2nd, 2010

    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!

  21. Avatar for Bob Cravens
    Bob Cravens August 2nd, 2010

    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.

  22. Avatar for Will
    Will August 2nd, 2010

    How about "DynamicView"? Lets you know what you're up for.

  23. Avatar for ali62b
    ali62b August 2nd, 2010

    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

  24. Avatar for larry
    larry August 2nd, 2010

    +1 for Bag also

  25. Avatar for Andy West
    Andy West August 2nd, 2010

    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.

  26. Avatar for Shlomo Abraham
    Shlomo Abraham August 2nd, 2010

    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.

  27. Avatar for haacked
    haacked August 2nd, 2010

    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!

  28. Avatar for Aidan Boyle
    Aidan Boyle August 3rd, 2010

    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.

  29. Avatar for Jarrett Vance
    Jarrett Vance August 3rd, 2010

    +1 Bag
    +2 Data

  30. Avatar for Cria&#231;&#227;o de Site
    Cria&#231;&#227;o de Site August 3rd, 2010

    very good feature, intelissense works with that ?

  31. Avatar for Henrik
    Henrik August 3rd, 2010

    You replaced magic string with magic property

  32. Avatar for haacked
    haacked August 3rd, 2010

    @Aidan believe me, we're going to beg the C# team for that. Or the Visual Studio team. Whichever is responsible. ;)

  33. Avatar for Filip
    Filip August 4th, 2010

    +1 ViewBag or Bag
    could also be a "Bundle" (Java style :)

  34. Avatar for cowgaR
    cowgaR August 4th, 2010

    -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)

  35. Avatar for cowgaR
    cowgaR August 4th, 2010

    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.

  36. Avatar for Shlomo Abraham
    Shlomo Abraham August 5th, 2010

    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...

  37. Avatar for Dody Gunawinata
    Dody Gunawinata August 5th, 2010

    @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.

  38. Avatar for jmorris
    jmorris August 6th, 2010

    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

  39. Avatar for haacked
    haacked August 6th, 2010

    @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.

  40. Avatar for Dody Gunawinata
    Dody Gunawinata August 6th, 2010

    Sweet. I can create filters that inject functions to ViewModel so it is clear what is available on each action.

  41. Avatar for Colin Jack
    Colin Jack August 7th, 2010

    I share the opinion of some others, namely View and ViewModel don't seem to be good names.

  42. Avatar for Hector Minaya
    Hector Minaya August 7th, 2010

    How about ViewInfo

  43. Avatar for Andrei Rînea
    Andrei Rînea August 8th, 2010

    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!

  44. Avatar for Adam
    Adam August 12th, 2010

    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!

  45. Avatar for Jessica
    Jessica August 12th, 2010

    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.

  46. Avatar for Anton
    Anton August 12th, 2010

    Microsoft likes words like Context. Maybe you could call it something like: Context, ViewContext or DataContext to make it consistent with WPF world.

  47. Avatar for Adam
    Adam August 12th, 2010

    @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.

  48. Avatar for [ICR]
    [ICR] August 17th, 2010

    "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.

  49. Avatar for Thanigainathan
    Thanigainathan August 18th, 2010

    Hi,
    Is this somewhat related to Javascript dynamic methods ?
    Is this some kind of general programming concept ?
    Thanks,
    Thanigainathan.S

  50. Avatar for Gpan
    Gpan August 18th, 2010

    How about: Vd [pronounced - VooDoo] to remind "magic".

  51. Avatar for Carlo
    Carlo August 19th, 2010

    I vote for a breaking change.

  52. Avatar for schrodinger
    schrodinger August 19th, 2010

    how about MagicView or SuperView or MvcView

  53. Avatar for Marcus Wendt
    Marcus Wendt September 3rd, 2010

    What about ViewContent?

  54. Avatar for jacko
    jacko September 13th, 2010

    I vote for a breaking change too, it's view data.

  55. Avatar for John Kyle
    John Kyle September 15th, 2010

    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.

  56. Avatar for Kozlow
    Kozlow September 30th, 2010

    +1 ViewBag both sides.

  57. Avatar for Wilson
    Wilson December 16th, 2010

    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 :(

  58. Avatar for dermatologist
    dermatologist January 5th, 2011


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

  59. Avatar for Fred .
    Fred . July 3rd, 2013

    Use CSS3 with :odd and :even class to style instead.
    td:odd {background-color: gray}