Consider the following example of a typical situation with a Component view for rendering a component presentation. It comes from the sample project from the Google Code website.
It’s nice and easy, because you can access your fields without too much code. However, a couple of days, maybe hours, later when more functionality is added to the view, more logic becomes part of the view. It might end up in something like the following:
What happened? Where is my clean code? Quite depressing when this happens to all your Component views. The result is a very messy and bloated View. Maintenance becomes a hell and your Views can’t be read by anyone. The root of this issue is the generic nature of the Component content model. All the logic is in the view, because that’s the easiest way to access the component. Sure, you can tuck away a lot of that logic in MVC HTML helpers, but there must be some better way, right?
Wouldn’t it be great if we didn’t had to deal with a Component model in our Razor view, but actually dealt with more specific business models where all Component logic was already processed? Where all the component links are already resolved to URLs and the only thing to do in the Razor view is to display them?
Introducing Builders. It is a layer between the Component model creation process and the View outputting process. But instead of handing them directly, the Component is passed into a Builder which creates a viewmodel where logic is already processed and the only job of the View is to render the viewmodel properties with the right HTML. Let’s look at an example. In this example the Builder gets a ComponentPresentation and processes all the logic to create a more domain specific model which will be the model to use in the Razor View. Your view will look something like this:
Note there is no usage of Component, ComponentPresentation or anything Tridion related. This will make your view more reusable in many other ways. The View doesn’t care where the content is coming from, as long as it’s poured into the same Model it will be happy to render it. What do we need to achieve this?
- A ModelFactory that will build your ViewModel.
- A BuilderFactory that creates a custom Builder for each Model type.
- A Builder to create the ViewModel from a ComponentPresentation.
- A View with a strongly typed ViewModel.
The idea is to have a Builder class for each type of View that can convert a Component Presentation into a fully processed ViewModel. In a typical project you’ll have Builders with names like “NewsBuilder” and “ArticleBuilder” that can each create the ViewModel from a given IComponentPresentation object.
You might have seen the ModelFactory in the code before in the sample code, but you probably haven’t seen it in action. Well, the purpose of having a ModelFactory is as its name applies, to create Models. Here is the code of an example ModelFactory:
You can put ALL the model creating logic in the ModelFactory for ALL the models. But that would be ugly and hard to keep it structured. So, that’s where the BuilderFactory comes in. The BuilderFactory is where most of the magic happens. Because you don’t want to stuff all the Model creation logic in one big ModelFactory class, it makes sense to create self contained Builder classes. Creating separate Builder classes for each view make these classes testable and easier to understand. This is what a BuilderFactory would look like:
These Builder classes will do all the conversion work from ComponentPresentation to ViewModels. The BuilderFactory will create a new Builder object, based on the configured View name in your Component Template metadata, through reflection. So, if you have a View name configured as “News”, the BuilderFactory will try to create an instance of the class “NewsBuilder”. The name of the class is important in this case as this will be used to find the corresponding Builder for the view. After creating an instance of the class the BuilderFactory will start the creation by invoking a create method on the Builder instance. This will return a business specific Model which can be used in your View.
Let's look at an example of a Builder to construct a GeneralDetail ViewModel. GeneralDetail is a plain old C# object that will be given to the View to do the further rendering.
After getting a business specific Model for the view, it’s time for the ComponentController to actually render the newly created Model with the View. The default DD4T behaviour is to use the view configured in your Component Template’s component metadata. Of course this View will need to be adjusted to use the new business specific ViewModel.
We’ve taken a look at the basic concepts of using Builders and the ModelFactory. After looking at these from a higher level it’s time to look at an example of how this all fits together. We’ll save this for next time when walking through a sample DD4T project. For now, please take a look at the pieces of code to see if you can figure out how the puzzle pieces fit together.
Albert Romkes wrote a great blog about DD4T, ViewModels and using it with Experience Manager.