If you do Sitecore projects and have never tried to create strongly typed models, then most likely you are doing something wrong. :) Why? As soon as your project grows a bit, the logic becomes more complex or you decide to refactor a few components, you will suffer from all magic things - strings, numbers, GUIDs. Of cause, there are a few things that you can do about that.
Available Options
You could create a file with constants for templates and field IDs, which would help you keeping references in one place and make them more manageable. However, this is a lot of manual work that you would need to do over and over again for maintaining the project, and, honestly, I do not like that.
Ok, then we think about automation. You could write a code that would go through the templates tree and generate a file. This is getting better but what about the type check? By providing a field name to the fields dictionary you won’t know the type of this field. So you need to come up with some kind of a DTO object as a model and mapping, as you would use in any application with a connection to services or database.
It looks like that next stop is an ORM framework of some kind as it might do dirty work for you. Decorate your models with attributes, call a factory method that would populate data to your models and you have a strongly typed class that will give you full benefits of compilation, type check, IntelliSense, and yadda.
What if we train the code to create those models besides the constants? This would be our automatic code generation with blackjack and… you choose what comes next. And believe me, when you see 30 000 lines of autogenerated models and you do not need to change them manually this is a huge deal.
5 years ago we were writing a lot of code to generate code and wire up DTO with Sitecore and that code was web-based, but now there are a few products like TDS and Unicorn (with additional modules) that would help you generate code. Tooling for code generation most likely would be the same for .NET frameworks - is it Text Template Transformation Toolkit or T4 and it is used in both products mentioned above. However, you would still need to tell them how to do that.
Code Generation Approaches
Code generation should create an object model that describes Sitecore templates and their fields. Sitecore can inherit fields from other templates but unlike the majority of the programming languages where you see the inheritance concept, it supports multiple inheritances.
There are 3 approaches that you can use to map the Sitecore templates model to C# objects, which I will illustrate using Content and Meta templates referenced by the template Page.
Classes and Interface Inheritance
In this approach, interfaces are used to cover multiple **inheritance **of base templates. So, in this case, it would be possible to use both interfaces and classes, as classes would have the same flat model as the Sitecore fields dictionary provides. However, generated code would have tons of duplications as an implementation of the same fields would be repeated over and over again (the field in Content class reimplemented in Page class). Also, you are losing the ability to reuse properties manually implemented in partial classes in derived classes, as inheritance is done via interfaces.
|
|
Only Interface Inheritance
This is a trimmed-down version of an approach above - it doesn’t have classes at all. Most ORM frameworks would be able to work with it as they are generating proxy classes for those interfaces. However, you need to create an instance without ORM you would need to create your implementation. Also, additional functionality could be added only via extension methods.
|
|
Composition Pattern
In the case of model generation using composition patterns, base templates are used as property types for a derived class. It is possible to reuse already defined in base classes implementations and extend them with partial (extended implementation of Content class would be available in Page class). As with any other approached this would have some drawbacks: it is not possible to define the BasePage model and reference all derived pages using it.
|
|
For ORM frameworks like GlassMapper composition might be a bit tricky as all fields are represented in a Sitecore Item as a dictionary, which is mapped to the same flat class or interface. However, it could be solved by adding a simple method that would map a property to an item itself (I’ve sent a pull request to Glass, which hopefully will make to a release soon).
Composition over Inheritance
Over time I’ve tried all 3 variant and would suggest using the last one due to the following reasons:
- To favor composition over inheritance is a design principle that gives the design higher flexibility, giving business-domain classes and more stable business domain in the long term.
- In terms of Sitecore, while physically you items templates inherit fields meta-information, but from implementation perspective models HAS-A behavior related to those fields.
- Simplifies code-generation, minimizes duplication, and allows you to extend the model of the behavior via partials.
- Allows you to generate code sections using reflection, restoring minimal template info from DLLs.
The last point I will describe in a separate post.
Follow me on Twitter @true_shoorik. I would be glad to discuss the ideas above in the comments.