Back in the day when we started designing our last project we’ve been presented with a following problem – a big number of templates with slightly different sidebars.
Is sidebar a part of content? No, rather not. We don’t want the editors to have to setup the sidebar for every article they write (and the site has a few dozens of articles created on it every day).
Is sidebar more of a template thing? Well… more like it, but still… we have articles all over the site with different sidebar elements when the articles are in different parts of the site (ok so we could add rules what controls display in which part of the site). But wait! There’s more! The sidebar will be different for every language (region). Now we’re talking a dozen of templates or a rules engine just to make the sidebar different. Customising the template with properties isn’t ideal either as it makes EPiServer UI very cluttered. Additionally we want to change sidebars across many templates so the whole branch/section of the site will be able to share the same sidebar.
To a degree this is an academic discussion as we’ve been through it with the previous version of the site and we already knew that integrating this stuff into templates just won’t work and we will be in a world of pain just changing the templates over and over adding little tweaks and changes while the customer ads promotions and performs ad campaigns. Well, we can do it, of course, but it’s not a work a programmer will enjoy, and we all want to do new and more exciting things, don’t we?
We have an internally developed module to make something like that, that is fully home-grown by another internal team (we now have 3 “squads” capable or making incredible things with EPiServer and we tend to share a lot of technologies and try to rotate people around to adopt the good habits and experiences) and I was (and still am) VERY impressed by it. The technology uses EPiServer pages for defining every module (which are located somewhere outside the site root branch. and then you can mix and match them either declaratively in the code) or by handpicking them in the UI. It’s really cool, though, during the discussions it turned out that we might have to add big chunks of functionality and might end up with separate branches of module-pages for different languages/regions, but… frankly… about that time an article by Ted Nyberg reminded me about a technology I have read about quite a while ago in an article by Stein-Viggo Grenersen and ooohhhhhh… I got seduced. I really wanted to try if for a long time and Ted’s article made it a snap to try and get convinced, and more important… convince Stu ;) that it’s the right way to explore.
So I started to dig.
Talked with Steve (the original creator of the Framework) a bit and learned that I can “customize a path rewriter” to suit my needs. Great! I just hoped I won’t have to deal with some nasty GUID’s matching, but no! Turns out, all it takes to identify a WebPart set is to have any unique string naming it.
So basically what we needed was a manager to deal with the naming templates and a way to determine the WebParts set to be used per page.
Till now the framework used template file name followed by the page ID, followed by an eventual language/region if a page was not the master branch, for example:
which makes them unique per page, which is not as appealing when you use EPiServer as it for a big part duplicates its functionality. Also a bit of a caveat here for agile programming methodology which promotes an often and early refactoring – if you move your page around or change its name – you lose the WebParts for all pages using it.
What we needed is a flexible and extensible scheme for reusing “WebParts sets” and that’s what our extension allows for.
Also since we’re very performance sensitive, and we operate in a multi server scenarios a lot we’ve added web parts blobs caching. Meaning that the site does not have to reach to the database every time a page is rendered.
The very appealing side of the framework is that it can be extended form the bottom (persistence) from the top (editors, controls, webparts), as well as being pluggable with custom plumbing.
The Sidebar Extensions for WebParts Framework
So to put all the requirements together, we needed the sidebars to be:
- customizable (out of the box)
- easy to use for both developers and editors (out of the box) Wow Steve, I can’t really appreciate enough how cool it is to code for it and how nice it is for the users!
- inheritable for site branches
WebParts path patterns
The main idea was to free the path names from the restriction they had – being hardcoded for a page. So to do it without hard-coding them I’ve introduced path patterns.
What is a pattern?
Basically a pattern is a way the framework is supposed to encode the WebParts id for the system to identify. Your site can have any number of “named patterns” and the framework gives you means of switching between them. Pattern allow for almost any string to be a part of it although some tokens have special meaning:
|%pageid%||id of the page the path is formed for|
|%region%||language/region of the WebParts|
|%pagetypeid%||type of the page|
|%template%||legacy token to make it possible to use template names as part of path.
This is just for compatibility so you can have some of the pages using an old scheme.
|%legacyregion%||legacy token for regionalizable pages (usage described later)|
|%inherited%||states that a page shoud inherit its WebParts from its parent in the page hierarchy (this can only be used as a complete pattern – cannot be a part of a larger pattern)|
|%root%||(again whole pattern) the %root% token is used when the inheritance based on hierarchy does not resolve into another token while reaching the root page.|
Some sample patterns
|Name||Pattern||Sample Instance of the Pattern||Description|
|Root pattern||%root%||%root%||The pattern that all inheritance automatically falls back to|
|Inherited||%inherit%||anything parent defines||Tells the page to use the web parts its parent is using – the inheritance is possible all the way up in the hierarchy to the %root% pattern, meaning – if my parent inherits its WebParts from its parent, so will I.|
|Legacy regionalized||%template%|%pageid%%legacyregion%||~/templates/Demo/WebPartPage.aspx|26|en-us||Creates legacy “non language independent path”|
|Legacy global||%template%|%pageid%||~/templates/Demo/WebPartPage.aspx|26||Creates legacy “language independent path”|
|Page/region specific||page|%pageid%|%region%||page|26|en-us||template independent per-page/per-language pattern|
|PageType specific||pagetype|%pagetypeid%||pagetype|5||page type specific path (notice how the previous pattern has “page” and this one has “pagetype” in it) – this is done to avoid conflicts in numbers between pages and page types of the same id|
|My Sidebar||my-sidebar||my-sidebar||You can create “named sets” that will stay the same across all pages using it|
|My Localizable Sidebar||my-sidebar|%region%||my-sidebar|en-us||A localized version of the previous “named set”|
This entry (Permalink) was posted on Thursday, January 8th, 2009 at 3:04 pm and is filed under .Net Framework, ASP.NET, C#, Downloadable, EPiCode, EPiServer, Internet Information Services, Open Source, Software, Software Development, Web applications, WebParts. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response , or trackback from your own site.