Since I released version 1.0 of Page Type Builder in august of 2009 there hasn’t been any major updates to it. Sure, there has been new releases, usually 4-5 months apart, but they have mainly contained fixes or small new features.
As Page Type Builder has gained greater adoption in the EPiServer community I’ve gotten a few feature requests. I’ve also come up with some ideas myself. While a few ideas have been pursued, developed and included in PTB most haven’t.
Some of the ideas that I haven’t implemented have been disregarded because they have violated one or several of the principles for how Page Type Builder should work. But there has also been quite a few ideas that I think would be interesting to try out and possible include in the core library in the future.
The problem is that there’s no easy way to extend how PTB works. There are two primary reasons for that. First, while PTB is pretty well componentized internally I didn’t want to force users to use a Dependency Injection container and therefor I didn’t open up the possibility to modify which components are used. Fixing that is pretty simple. The other problem is trickier as it has to do with the core of how PTB works.
As you probably know, PTB maps from .NET classes to EPiServer page types using meta data, attributes, found in the classes. This means that developers use classes and attribute to specify, in code, what properties and attributes a page type should have. Page Type Builder then uses these attributes as specifications to create and update the corresponding page types. This works well as long as the attributes actually are specifications of page types and properties.
However, often we want to introduce special cases. Introducing these special cases, even if we could replace whatever component we wanted inside PTB, would be quite nasty. Primarily because we would have to do it either at the stage where PTB locates and reads the attributes or at the stage where PTB updates page type and properties based on the attributes. In both cases we would violate the Single Responsibility Principle and thereby make the process of updating page types much more complex and error prone.
How synchronization currently works
Before we go into what I would like to do, let’s first look at how things currently work. Below is a description of the major steps that Page Type Builder performs at startup to update page types based on the classes with PageType and PageTypeProperty attributes that it finds.
1. Locate classes with the PageType attribute
The first step is to locate non-abstract classes that have been annotated with the PageType attribute in the application domain. For each such class a new PageTypeDefinition object is created. PageTypeDefinitions contains a reference to the original class as well as a reference to the PageType attribute found in it. In other words, while this step produces a collection of PageTypeDefinitions that’s
2. Validate Page Type Definitions
Validate all PageTypeDefinitions. This includes validating the page type but also retrieving all the page type’s properties and validating those.
This step is absolutely crucial. It ensures that the update process is an “all or nothing process”. If there is a problem with the classes and attributes the process shouldn’t fail mid-way, having done some but not updates. Instead any problems should be caught during the validation step. It also relieves the rest of the code from much of the error handling that it otherwise would have to do. Another nice side-effect is that it gives the developer very rapid feedback whenever something is wrong.
3. Create any completely new page types
Any PageTypeDefinition for which a corresponding page type doesn’t exist is located and a new page type is created for it. This is a separate step from the next where page types are updated as page types can refer to each other. First adding any new page types relieves the update step from having to consider whether any page type that the page type it is currently updating refers to exists.
4. Update page types
For each PageTypeDefinition the corresponding page type is located. The page types’ attributes are first serialized to a string. Thereafter the page type’s (code) properties are updated using values from the PageTypeDefinition. Finally, all of it’s attributes are again serialized and compared to the old serialized value. If the two differs the page type is saved.
The serialization is done in order to check if a page type should be updated or not. An alternative would of course be to check if each individual property had been changed, and that is also how it used to work in some early versions, but using the serialization method demands much less logic and thereby leaves less room for error.
5. Update page type’s properties
The last step of the synchronization process is updating each page type’s properties. This process involves retrieving each class’ properties and then ensuring that the class’ corresponding page type has a an (EPiServer) property that matches those. The process of updating properties is very similar to the previous step so I wont go into details about that.
As you might note the classes and attributes are located in the first step and are then, packaged into PageTypeDefinition objects, used in all of the subsequent steps.
How synchronization could work
What I would like to do is to separate the classes that developers use to define page types in code from the specification used when updating page types. This would mean introducing new classes used that are used to specify the attributes of page types and page type’s properties.
Using this approach the above described process of synchronization would be split up into two mutually independent processes. One for locating classes with the PageType attribute in the application domain and creating page type definitions based on those:
- Locate classes with PageType attributes
- Validate the located classes and attributes
- Create page type specifications based on the classes, attributes and properties
The other process would take a number or page type specifications, without caring about where they came from, and synchronize the site’s page types with those:
- Using some source, which is resolved at runtime, locate a set of page type specifications.
- Validate the page type specifications.
- Create any new page types
- Update page types
- Update page type’s properties
Doing this would require quite a lot of work but it would open up some interesting possibilities. It would be much simpler to add special rules and conventions. Creating some sort of admin mode functionality for removing unused page types and properties would be much simpler as that could rely on the current set of page type specifications used rather than a bunch of classes that it would have to reflect over. It would also be possible to specify page types by other means than by code.
Will it happen?
This, or something like this, is really something that I would like to do. But it would take quite a lot of time and it would also have to involve more work than just rewriting PTB. I would first like to create suite of integration tests that could be used to ensure that everything is compatible with the old version at a high level. Then the code would have to be rewritten/modified along with writing new, and modifying old, unit tests. Finally it would need to be thoroughly profiled and tested to ensure good performance.
Considering that I have a few other things on my plate freeing up the time required might be hard. I’m also not sure that the benefits outweigh the costs. Therefor I’d love to hear what you think about this idea! Does it seem like a good idea? Would it’s realization be useful to you? In what way(s)? Wondering what I’ve been smoking?
- Ideas for new features in Page Type Builder 2.0
- Page Type Builder planned development timeline
- Page Type Builder 2 Preview 2
- Page Type Builder 2 Preview 1 released!
- Limiting content and page reference properties to values of a specific type in EPiServer CMS
- Page Type Builder 1.2 Released!
- Page Type Builder 1.3 Released
- The new initialization process in Page Type Builder 1.2