Update 22/04/2013 The source code is now available here: https://github.com/rsleggett/BuildingBlocks.DD4T.MarkupModels
Update 15/04/2013: The library has been updated to version v0.16.0.0-alpha on Nuget and documentation can be found here: BuildingBlocks.DD4T.MarkupModels.UserManual. New features include the NestedComponent attributes and Helpers for outputting Inline Editable markup. To get the latest version in an existing project you can use:
PM> Update-Package BuildingBlocks.DD4T.MarkupModels -Pre
Recently there has been a lot of discussion in the SDL Tridion community about how to approach the Model for Views in a DD4T project. To get some context read the following two posts:
The consensus seems to be for moving away from using the IComponent class from the DD4T.ContentModel.Contracts assembly and towards using specific classes for each Component View. This feels a lot more towards the MVC way of thinking and has some nice advantages like strong typing, Intellisense and removal of the logic that tends to creep into your views as projects go on.
We’ve been using HTML helpers to wrap up our Component data retrieval logic (I don’t know if that’s the right term), so our views aren’t too bad but they definitely could be better. Here’s an example.
I really liked the ideas presented in Kah’s and Albert’s blog posts but I didn’t like the fact I had to write a builder for every new Component Template I created. This seemed like it could get unwieldy and I felt like I would be repeating myself, even with the nice reflection tricks suggested by Kah.
I’d used AutoMapper on other projects to map models for database or web service calls onto View Models so I thought that would be a good start as a first attempt for trying to make the creation of View Models as easy as possible.
I had a spare Saturday so thought I’d have a go. Well, bad news. AutoMapper doesn’t really fit. It’s more geared towards mapping objects with specific properties to those with other specific properties. The problem with DD4Ts IComponent is that it uses the Fields and MetadataFields collections to store the data and then to map you need to know whether the item in the Fields collection is a Component Link, a Text value or a DateTime etc. So I started to end up with more code than with the Builders.
Then I found the ConvertUsing extension method in Automapper which uses an ITypeConverter implementation, a more generic way to convert the items started to emerge but I needed a way to tell the TypeConverter how to map each property. As I was doing this I remembered Albert’s [InlineEditable] attribute and thought I could take this one step further. So started to write attributes like TextField and ComponentLinkedField. Pretty soon I had a model like this:
The TridionViewModel attribute is purely for documentation, so developers know what we’re mapping from.
The other attributes available are:
You just specify the field name, whether the item is a from metadata or not and in the case of the ComponentLink fields, the field name on that component.
Once this happened I realised I didn’t really need AutoMapper and rewrote my TypeConverter as my own static class called ComponentViewBuilder with a single method that takes a generic parameter of the ViewModel class – the only constraint is that it has a no argument constructer. Here’s what my Controller Action looks like:
And here’s the new strongly typed View (same as above)
It’s worth noting that in order to achieve this I had to set the Controller and Action metadata values on my Component templates and add an Action for each of my CTs to my Component Controller but this is not so big an overhead.
I’m releasing the library onto NuGet as a pre release. To install it run the following command in your Package Manager Console:
PM> Install-Package BuildingBlocks.DD4T.MarkupModels -Pre
Alternatively you can use the Package Manager UI in Visual Studio or see the package on NuGet here: http://nuget.org/packages/BuildingBlocks.DD4T.MarkupModels/0.9.0.0-alpha
There will likely be lots of updates in the coming weeks.
A few caveats:
I am also thinking about how to do sub models or embedded schemas. For example where you had a carousel and wanted to auto-populate a list of slides to get a model like:
I’ve had a go at this but it resulted in a bit of type conversion hell due to the need to runtime bind generic parameters. So maybe in a future version.
Anyway, have a go with it and let me know what you think. The idea of this is for it to be a plugin for DD4T rather than part of the framework. I’m not saying this is always how View Models should be done, but is supposed to be a nice automatic way of doing most Component Views without to much extra work when you add new Component Templates.
I’ll also release the source onto GitHub soon.