ViewData Dictionary vs. View typed Model
aspnetmvc, internet, programming, suggestion, Twitter June 17th, 2009This post exists because trying to explain something 140 characters at a time makes you sound insane.
Earlier Brad Wilson speculated:
Theory: in ASP.NET MVC, master pages cause users to use ViewData instead of strongly typed models more often than any other reason.
To which I replied:
@bradwilson That, plus keeping properties in sync on a class that exists only to stand between an action and view isn’t very DRY
It’s true there are a huge number of reasons to need data in a master layout like navigation, sidebar widgets, current user profile, ad codes, etc. But if that was the main cause should be pretty easy to address by having the master layout’s data in a layer superclass for all of your action-view models.
I believe another even more serious problem is the view model can make you repeat yourself a huge number of times.
One of the things that’s really nice about actions on a controller is you can avoid the proliferation of classes you get with the command pattern. If you make a model for each action you get that problem back in spades. You could keep track of commonality between actions to reduce the number of action/view model classes, but that’s more work and you’re playing a balancing act between how many classes you are making and how many unused properties are acceptable for actions that don’t produce strictly identical data.
Plus it’s not DRY… I’ve added the action to a controller, then I need to add the class to hold the data. I’ve acquired some data in the action, then I need to add the typed property to the action’s model. Some data’s refactored out of the action, then I need to remember to remove it from the data bucket class too.
Just to throw an idea out there, to have a DRY action-view model class, how about adding the idea of a dynamic partial class to the language? A partial class which merges with additional auto-implemented properties at compile-time, as a result of the property assignments on that type.
So here’s that you would have today. The following assumes DefaultMasterData members will be assigned by filters if the model has an appropriate base class.
public class DefaultMasterData
{
public UserProfile Profile {get;set;}
public string AdvertisementCampaignCode {get;set;}
}
public class HomeIndexData : DefaultMasterData
{
public Product Product {get;set;}
public Order CurrentOrder {get;set;}
}
[UserProfileFilter]
[AdvertisingFilter]
public class HomeController
{
public ActionResult Index()
{
...acquiring stuff here...
// return view of model
return View(new HomeIndexData {Product = mostRecentProduct, CurrentOrder = activeSessionOrder});
}
}
Here’s if you had a dynamic partial class. The assignment of non-existant properties results in an implicit partial with auto-implemented properties to be merged in at compile time.
public class DefaultMasterData
{
public UserProfile Profile {get;set;}
public string AdvertisementCampaignCode {get;set;}
}
public dynamic partial class HomeIndexData : DefaultMasterData
{
}
[UserProfileFilter]
[AdvertisingFilter]
public class HomeController
{
public ActionResult Index()
{
...acquiring stuff here...
// return view of model
// creates implicit partial with auto-implemented properties
return View(new HomeIndexData {Product = mostRecentProduct, CurrentOrder = activeSessionOrder});
}
}
And to kill just a bit more code, how about a the ability to declare the named type without the empty class statement?
public class DefaultMasterData
{
public UserProfile Profile {get;set;}
public string AdvertisementCampaignCode {get;set;}
}
[UserProfileFilter]
[AdvertisingFilter]
public class HomeController
{
public ActionResult Index()
{
...acquiring stuff here...
// return view of model
// creates implicit partial with auto-implemented properties
// also results in the initial declaration of the type HomeIndexData based on DefaultMasterData
return View(new dynamic partial HomeIndexData:DefaultMasterData
{Product = mostRecentProduct, CurrentOrder = activeSessionOrder}
);
}
}
There! Now I think you’ll see people using a base of ViewPage<HomeIndexData> in Index.aspx.
Clearly there are lots of questions about namespace, etc., but you get the idea.
Final note, to declare an anonymous type with a base class, it would be nice to support something like.
var x = new :MyBase {Foo="bar", Frap=5};
Another final note - you wouldn’t need to do it all inline of course.
[UserProfileFilter]
[AdvertisingFilter]
public class HomeController
{
public ActionResult Index()
{
var model = new dynamic partial HomeIndexData:DefaultMasterData();
...acquiring stuff here...
// assignments causing more auto-impl props here
model.Product = mostRecentProduct;
model.CurrentOrder = activeSessionOrder;
// return view of model
return View(model);
}
}


June 17th, 2009 at 4:20 pm
That’s a very interesting use of filters, to “complete” a partially filled in strongly-typed model. I hadn’t considered that!
June 17th, 2009 at 4:48 pm
Great approach: I’ve been doing it (the one with the 2 viewdata) as well.
I love the way filters allow you to “enrich” your view model with data that should not really be generated inside the action.
But I talked to many devs that don’t like this, and prefer having the Action doing all the data retrieval operation (and extracting the duplication in some external function or base controller).
I never tried with the dynamic partial trick (well.. I never tried C#4 yet)
June 17th, 2009 at 8:02 pm
Well, the dynamic partial doesn’t exist (at least I don’t think it does). That’s mostly a wishful thinking feature request.
I agree the use of filters on data depends on a lot of things, not the least of which is if it “feels right” for the developer. It probably makes the most sense when the type of information which doesn’t relate in any way whatsoever to the current action or to the current view.
For example if you have a user dock bar at the bottom of the screen like facebook… Gathering that data to me feels more natural hooking into the site-wide action processing, rather than assuming all of the controllers in the app will be built on top of something that will honor those requirements.
I guess I should write up another blog post about viewdata and filters that doesn’t mention dynamic partial classes at all. The filter sample cruft got more feedback than the actual topic. :)
June 18th, 2009 at 1:07 am
Interesting idea!
I like the syntax for specifying a base class for an anonymous class.
June 18th, 2009 at 2:35 am
@luis: exactly… but still.. many people prefer to place these kind of side-panel retrieval functions still inside action methods.
I’ve an openspace discussion about this topic in the next Italian alt.net conference at the end of June. I hope something good might come out of it :)
June 18th, 2009 at 4:25 am
Had a mull over and I’m not sure if I like this idea, but it all depends on tool support for dynamic refactoring.
If renaming a property in the action doesn’t renaming it everywhere, then I don’t see what this offers over the magic string based viewdata dictionary. If it does, your onto a winner.
As for the filters, we treat all cross-cutting UI concerns the same way, but we have (yes another) Dsl we use that looks like this: http://gist.github.com/131838
@Simone: Do you not find this leads to alot of duplicate code and a mingling of concerns in the action? I’m a massive AOP fan, and think a lot of the techniques work well in Asp.Net Mvc
June 18th, 2009 at 4:31 am
@Chris: yes… I do think it leads to code duplication and not separation of concerns. And in fact I prefer the action filter approach and this AOP kind of thinking.
What I was saying is that I talked to lot of people that don’t like that approach.
June 18th, 2009 at 8:07 am
[...] ViewData Dictionary vs. View typed Model (Louis) [...]
June 18th, 2009 at 11:58 am
@chris it’s all wishful thinking, of course, but if it was implemented I would expect the tool support to be the same you expect from partial classes themselves.
So the line:
var model = new dynamic partial HomeIndexData:DefaultMasterData();
Would become
var model = new HomeIndexData();
And //imply// the code:
public partial class HomeIndexData : DefaultMasterData { }
And the line:
model.CurrentOrder = activeSessionOrder;
Would imply the existence of the following in the compiler:
public partial class HomeIndexData
{public Order CurrentOrder {get;set;} }
I’m assuming the intellisense and refactor support of “CurrentOrder” in a partial class would apply, even though the declaration is implied instead of typed.
As far as what it offers over magic strings… Let’s see.
One nice thing is you can say <viewdata model=”HomeIndexData”/> and get all of your members strongly typed, with compile-time safety? The alternative is to declare each member by type and name individually, <viewdata CurrentOrder=”Order”/> or have a lot of var order = ((Order)ViewData["CurrentOrder"]) code.
Plus I’m sure there’s slightly better performance from Model.CurrentOrder compared to ((Order)ViewData["CurrentOrder"]), though it’s probably not significant.
Full disclosure - we’re using ViewData["yadda"] primarily at the office for the reasons mentioned. Maintaining dozens of additional property-bearing classes to avoid a dictionary didn’t fly.
July 30th, 2010 at 11:51 am
Grands articles & Nice un site ….
August 19th, 2010 at 5:13 am
http://uncommonplace.com/blog/?p=161