EPiServer  /  CMS January 10, 2011

Ideas for new features in Page Type Builder 2.0

A while ago I wrote about a couple of ideas that I have for a new major version of Page Type Builder. Since then I’ve slowly begun some work on Page Type Builder 2.0. So far nothing has happened feature wise but I have done some of the preparations the I deem necessary for a new major version. For instance I’ve moved the source code to GitHub which has been on my to do-list for quite a while. I’ve also started creating functional-/integration tests that actually test the whole process, from discovery using reflection to updating page types in the database (although the database has been abstracted). 

Meanwhile I’ve also done some more thinking about what changes and new features that the new version should contain. Below is a number of ideas that I have so far. I would love feedback on these as well as other ideas.

Pluggable architecture

I described this in some detail in the previous post, but what it means is that clients should be able to replace and extend the various components that Page Type Builder uses when it does what it does. This is already possible to a limited extent but I would like to make it possible to replace as many components as possible.

The motivation for this is accommodate different projects’ and developer’s needs to change how Page Type Builder work, to make it possible to create plug-ins for Page Type Builder as well as to make it easier to test internally.

A few challenges

This change isn’t trivial though. As most of the logic in Page Type Builder has to do with synchronizing page types at application start it would be nice to be able to change the components used for this before the updating process occurs, but it might not be good if it’s possible to change components after synchronization has happened. For instance, imagine a scenario where it’s possible to list discrepancies between the code and the database (like with Erik Nordin’s tool) and possibly even have those discrepancies fixed. If Page Type Builder does the synchronization at start up with one set of components and later on some of those components are changed, perhaps by some third party component, the discrepancies found would not be relevant in the same context as in which the synchronization was done. In other words we could end up with some really confusing scenarios where Page Type Builder’s view of the world changes during the application’s life time, leading to debug hell. I’m not sure that this really is a problem though, but it requires further thought and experimentation.

Another thing to think about with regards to this feature is how components are changed. Right now I’m leaning towards using an IoC container internally and either exposing that container directly or providing methods to modify the “contents” of the container.

Containers, containers, containers

Using a container raises another question: what container to use. Currently I think the three best candidates are Structure Map, Castle Windsor and AutoFac. They all have their pros and cons.

Structure Map is very mature, it might be the one most widely used in the EPiServer community and it's the one that I’m most comfortable with. It is also what EPiServer will probably use in it’s next major release. The fact that EPiServer might use it isn’t necessarily a good thing though as it might cause version conflicts. The current version of Structure Map also isn’t CLS compliant. That’s not a big deal, but using it would force Page Type Builder to stop being CLS compliant as well.

Castle.Windsor is also very mature. It has a rich set of features including AOP-style interception which could be utilized for logging, something that Structure Map lacks (although the hooks are there to implement it ourselves).

AutoFac is very lightweight making it attractive for internal bootstrapping of applications whose users doesn’t otherwise care about the container, which is probably true for the majority of Page Type Builder’s users.

There are of course other good containers as well but these three are the ones that I’m most comfortable with and I don’t see any other container offering something that these three can’t support.

Separate discovery from updating

This change was also described in detail in the previous post. In short it means that Page Type Builder could use other sources than classes in the application domain for creating and updating page types. This would make it easier to test and open up some interesting, but not necessarily useful, new ways of creating page types.

The main motivation for this change is that it would make Page Type Builder’s interface easier to work with, both internally and for clients, which in turn would make tools that list discrepancies between the code (and other sources) and the database easier to build. There has been a lot of talk about creating a tool that performs changes that Page Type Builder doesn’t, such as renaming and removing properties, and this would make it much easier to build such a tool.

This change would require quite a lot of thought and work and considering that it didn’t cause a lot of excitement when I mentioned it in the earlier post I could see a 2.0 release without it.

Property Groups

In the comments to the previous post both Patrik Akselsson and Lee Crowe requested a feature where several properties could be grouped together in non-page type classes. These groups could then be included in page type classes. Patrik called it “component support” and in later discussions the feature has been called “property groups”.

What it means is that if you create a class like this:

class Image : PropertyGroup
{
      [PageTypeProperty(Type=typeof(PropertyImageUrl)]
      string Image {get;set;}
      [PageTypeProperty(Type=typeof(PropertyString)]
      string AltText {get;set;}
}
…and you create a page type class with a property of that type like this:
class Page : TypedPageData
{
    [PropertyGroup]
    Image Logo {get;set;}
}

…Page Type Builder will create two EPiServer properties on that page type named Logo-Image and Logo-ImageAlt. You can them access them like this:

var imageUrl = CurrentPage.Logo.Image;
var imageAltText = CurrentPage.Logo.AltText;

I think that this would be a great new feature that could be very useful. It’s also fully possible to implement without any major changes to the rest of Page Type Builder’s code. In fact Lee Crowe and Mark Everard has already implemented this functionality in a forked version of Page Type Builder. If you’re interested you can check out this discussion about their implementation.

I’m not to keen on introducing major new functionality like this before I have a suite of integration tests in place which is why I don’t think I’ll do a new 1.x release of Page Type Builder with this functionality. However, this, or functionality very similar to this, has top priority right after the structural changes for version 2.

Page Objects Support

Using Page Type Builder you can already access Page Objects without using magic strings, but it would certainly be possible to abstract away the entire process of getting and setting Page Objects, much like it assists you with accessing EPiServer properties if you create code properties with empty getters and setters.

This would involve choosing a default association type (Page, PageLanguageBranch or PageVersion) for Page Objects and I’m not sure which would be the least surprising default. Any feedback on this would be appreciated.

Only overwriting admin mode settings when values has been explicitly set in code

In the current version of Page Type Builder it will always overwrite any changes that has been done in admin mode to page types unless you disable it’s synchronization process altogether. Since the release of version 1.0 well over a year ago I’ve hardly gotten any requests at all to change this. It seems there really are no administrators out there, only editors and developers :)

Lately though I’ve gotten some requests for this to change from a customer of mine. While I haven’t tried it it seems to me that it could easily be fixed by making all properties in the PageType and PageTypeProperty attributes that are value types nullable. If such a property (such as PageTypeAttribute.SortOrder), or a string property (such as PageTypeAttribute.Description), hasn’t been explicitly set in the code Page Type Builder could use the value found in the database instead of using a default value.

Migrations

Another thing that Patrik Akselsson mentioned in his comment to the previous post was that it would be good with functionality similar to that of Rails Migrations or Tarantino. What these tools, and other database migration tools do is basically check whether a database has a set of migration steps (such as adding or removing tables and columns) applied to them. If it hasn’t all steps that haven’t been applied are applied in order. By keeping track of which steps that have been applied in the database it can ensure that you don’t revert back to some old state, possibly loosing data, in the process.

By doing the same thing in Page Type Builder it would be possible to remove old page types or properties but it would require that the current migration step that the site/database currently is at is stored somewhere.

I don’t really see this happening for version 2.0 as it would require a lot of work and we would probably run in to quite a few “unknown unkowns” along the way,  but the changes described under the heading “Separate discovery from updating” would be a nice first step towards this type of functionality.

A simpler and less powerful solution that could more easily be implemented would be some sort of functionality for blocking Page Type Builder from creating certain new properties. That would take care of the main problem that migrations would address, properties being re-created by developers with an old version of the code. Something like this would probably be best as a plug-in rather than core functionality though.

Property Settings

The feature that I’ve heard requested the most lately is the ability to specify settings for XHTML string properties that are edited using the Tiny MCE editor. When CMS 6 was released I looked briefly at implementing support for property settings in general but found that it wouldn’t be possible without adding quite a lot of new, tricky functionality. Solving only settings for XHTML properties by mapping the existing LongStringSettings property of the PageTypeAttribute would probably be easier though.

However, I think it would be useful to be able to support settings for all types of properties so that will at least be the ambition. While I haven’t looked into it much yet I’m thinking that one possible solution would be to add an interface/base class for a new type of attribute. This could then be inherited from and used to specify settings that are specific for each property type. It, or some companion class, would also have to be responsible for handling the actual updating of the settings.

IPageData?

The thing that annoys me the most about the current EPiServer API is the fact that properties and methods in the PageData class isn’t virtual and that the class doesn’t implement an interface that specifies it’s members. This makes testing code that works with PageData objects in isolation very hard.

For instance, the PageData.LinkURL property uses a host of EPiServer components that in turn require a HTTP context and access to a database. And since the property isn’t virtual creating a unit test for code that needs to access the LinkURL property but otherwise doesn’t really care what it does is next to impossible and requires a lot of nasty workarounds.

I’ve complained quite a bit about this to EPiServer but they won’t make PageData’s members virtual in CMS 6 R2 as that would break binary compatibility. That in turn means that third party products would need to be recompiled and redistributed so I guess that’s understandable.

However, if possible I would like to find a workaround for this that doesn’t involve waiting for CMS 7 and hoping that they have fixed that there. One idea would be to create an IPageData interface in Page Type Builder and make the TypedPageData class implement that.

That definitely isn’t a silver bullet for this problem but it could help in some testing scenarios. I would love to hear thoughts about this as well as other ideas. 

Debugging attribute in TypedPageData

Marthin Freij wrote a great post (despite using the word “might” wrongfully ;-)) about a neat trick where you put a DebuggerDisplay attribute in your own page type classes to customize the tooltip displayed when hovering an instance of such a type while debugging.

I’ve been thinking back and forth about adding such an attribute to the TypedPageData class and so far I haven’t really found any drawbacks of doing that. The question remains what values to display in the tooltip though.

PS. For updates about new posts, sites I find useful and the occasional rant you can follow me on Twitter. You are also most welcome to subscribe to the RSS-feed.

Joel Abrahamsson

Joel Abrahamsson

I'm a passionate web developer and systems architect living in Stockholm, Sweden. I work as CTO for a large media site and enjoy developing with all technologies, especially .NET, Node.js, and ElasticSearch. Read more

Comments

comments powered by Disqus

My book

Want a structured way to learn EPiServer 7 development? Check out my book on Leanpub!

More about EPiServer CMS