Simple validation of propertyvalues in EPiServer CMS 6

Last week I blogged about SEO lowercase URLs, a concept known to many, and I blatantly stole the idea for the post from someone else. Today I'm gonna try to build on the other post, actually providing some input of my own, and show how one can easily do custom property validation, without having to write your own custom property. Having custom properties can be a tedious way to work, when all you essentially have is a string property, or a PageReference. The other post contains the code for hooking into events, so I suggest you get it from there if you have no idea where to put this.

First, we hook into the event DataFactory.Instance.SavingPage.


void Instance_SavingPage(object sender, PageEventArgs e) {

    // Check if the page is a ReferenceContainer
    if (e.Page is ReferenceContainer) {
        var refContainer = e.Page as ReferenceContainer;
        // Check if the property OfficePage has a value
        if (!PageReference.IsNullOrEmpty(refContainer.OfficePage)) {
            var office = refContainer.OfficePage.GetPage();
            // Check if the page selected in the OfficePage property is of the correct type.
            if (!(office is OfficePage)) {
                e.CancelAction = true;
                e.CancelReason = LanguageManager.Instance.Translate("/errors/validation/properties/OfficePage");
            }
        }
    }

    // Check if the page is an OfficePage
    if (e.Page is OfficePage) {
        var officePage = e.Page as OfficePage;
        // Check if the property ReferenceContainer has a value
        if (!PageReference.IsNullOrEmpty(officePage.ReferenceContainer)) {
            var refContainer = officePage.ReferenceContainer.GetPage();
            // Check if the page selected in the ReferenceContainer property is of the correct type.
            if (!(refContainer is ReferenceContainer)) {
                e.CancelAction = true;
                e.CancelReason = LanguageManager.Instance.Translate("/errors/validation/properties/ReferenceContainer");
            }
        }
    }
}

Basically, we try to get the page from the PageReference property, if it's set, and check if it's of the correct type using functionality in PageTypeBuilder. PageTypeBuilder, I love you.

As always, comments are welcome, maybe I've tried to solve this whole issue the wrong way. Please let me know if I did :)

SEO lowercase urls, in EPiServer CMS 6

Yesterday I read a blog post by Lars Timenes, describing how one could easily generate a bit more friendly URL Segments in EPiServer. (Just an observation, but the EPiServer site hosting the blog post, doesn't seem to use his code.) His example uses the CMS 5 style of hooking into events, so I thought I'd give an example of how to do it in CMS 6 and the new Initialization engine. The back story here, is that sites like Google, sees all lower case URLs, and mixed case URLs as different URLs. Although this can be fixed by adding a <link rel="canonical" /> tag to your markup, I like to have more than one solution to things.

In order to get this to work, you'll need to add references to the EPiServer.Framework.dll and the System.ComponentModel.Composition.dll, both installed with CMS 6 and located in the "C:\Program Files (x86)\EPiServer\Framework\6.0.x.x\bin" directory.

Oh, and as a side note, Yes, I do write all those tedious documentation comments in my production code. It's how I do things. Sorry for being a goody two-shoes.

Edit: After reading Magnus's comment, I added the simple code to detach the event.

Edit: Karl, case doesn't matter to the server, but search engines may or may not (it's entirely up to them, not me), index URLs with different casing as different pages, severly affecting the PageRank of the URL in question. That's why I want my URLs to display consistently, and if I always render them in lowercase, I doubt someone will try to link to my site using a mixed-case URL of their own device.

using System;
using EPiServer;
using EPiServer.Framework;
using EPiServer.Framework.Initialization;
using EPiServer.Web;

namespace Development {

/// <summary>
/// An <see cref="EPiServer.Framework.IInitializableModule" /> enabling hooking into EPiServer events.
/// </summary>
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public class ModuleInitializer : IInitializableModule {


#region IInitializableModule Members
/// <summary>
/// <para>Initializes the Module and attaches custom eventhandlers.</para>
/// <para>Attaches a <see cref="System.EventHandler" /> for the EPiServer.Web.UrlSegment.
/// CreatedUrlSegment event.</para>
/// </summary>
/// <param name="context">The current 
/// <see cref="EPiServer.Framework.Initialization.InitializationEngine"/></param>
public void Initialize(InitializationEngine context) {

UrlSegment.CreatedUrlSegment += 
new EventHandler<UrlSegmentEventArgs>(UrlSegment_CreatedUrlSegment);
}

/// <summary>
/// Makes sure that all URL Segments are always lowercase, for increased SEO performance.
/// </summary>
void UrlSegment_CreatedUrlSegment(object sender, UrlSegmentEventArgs e) {

e.PageData.URLSegment = e.PageData.URLSegment.ToLowerInvariant();
}

/// <summary>
/// Perform pre-loading tasks.
/// </summary>
public void Preload(string[] parameters) {

}

/// <summary>
/// <para>Uninitializes the Module.</para>
/// <para>Detaches the <see cref="System.EventHandler" /> for the EPiServer.Web.UrlSegment.
/// CreatedUrlSegment event added during Initialization.</para>
/// </summary>
/// <param name="context">The current 
/// <see cref="EPiServer.Framework.Initialization.InitializationEngine"/></param>
public void Uninitialize(InitializationEngine context) {
UrlSegment.CreatedUrlSegment -= 
new EventHandler<UrlSegmentEventArgs>(UrlSegment_CreatedUrlSegment);
}
#endregion
}
}

Sleep deprivation is the most powerful of tortures.

This weekend has been rough. My son, at a whooping age of 5 months, keeps waking up at around 5 AM. I try to go to bed early to make up for this fact, but it doesn't matter, it still feels horrible to be awake when the paper guy delivers the morning paper at 5.30.

To top thing off, this weekend has been full of work. We're trying to sell the apartment, so we've been homestyling it extensively. To those of you who don't know what homestyling is, it can easily be explained as the process of removing everything in your home that can seem offensive, crowding, or otherwise undesirable. To anyone. What it means is, get rid of everything. Clear it out. Hide it, sell it, or throw it away. Our storage unit in the attic is so full of stuff, it will probably burst any day. But the apartment looks nice and stylish. Hopefully it'll bring a pretty penny. But keep in mind, clearing out an apartment, while trying to look after a 5-moth-old, is no walk in the park.

Next weekend, we're going to Berlin, for a well deserved vacation. Any tips for sights in need of seeing is welcome. Hopefully, Alfred won't keep us awake the whole trip.

My take on "ASP.NET MVC 2 Bootcamp" Workshop at MIX10.

First off, I chose not to bring my PC laptop, since I thought it would just be in the way, and that I'd do fine with just my MacBook Pro. I installed MonoDevelop on it a few weeks ago, and it seemed fine, it even ran MVC, and had a built-in MVC Project template. However, it doesn't run .NET 4.0, so I had plenty of time to listen and blog, instead of doing coding. Yeah, I know. I suck. Next time, I'll bring a Windows computer to a Microsoft event, I should have figured as much.

The setup here at MIX10 isn't really optimized for attendees with laptops requiring power, there are 100 people in the room, and approximately 12 utility outlets. I chose to move my chair to the wall, where my power cord would reach. And as Jon Galloway said, "I was hoping that people would be sitting with laptops and typing along". That won't be happening for a three and a half hour long workshop, obviously.

I don't really feel that Jon had prepared his session very well, I get that it's hard to set a target audience level, when you know nothing about your audience, but, you could assume that when you're doing a workshop, you shouldn't use a Visual Studio version (2010), that isn't released yet, and provide samples for attendees that won't run on the currently released version, 2008. That's not cool at all.

Most attendees started out with their laptops in their laps, (since there were no tables, just chairs), but after about 40 minutes, most of them had put them down.

I might seem very negative, but I think the workshop content was very interesting, however, not very well delivered. I might be wrong here, but all of the attendees have actually paid an extra $295 for the workshops, and in my book, that sets a requirement of quality for workshop content.

You can watch the Workshop over at Channel 9.

My take on "Design Fundamentals for Developers (and Other Non-Designers)" Workshop at MIX10.

"Kill your babies."
- Robby Ingebretsen

I fully agree, and I believe this is the key component to the creative process, be it design, development, writing or whatever you may partake in. Having the courage to throw away, redo, or in other ways alter your work or parts of it, is a crucial ability if you want to be successful.

All-in-all, having participated in this workshop, I feel that I have been given a new set of communicational tools, that enable me to convey my thoughts to a designer, in a way that the designer hopefully can understand.

However, it should also be said, that I really think the workshop should be named "Design Fundamentals for Professionals That Need Structure and Arguments For Why They Do What They Do in The Creative Process". There are way too many people in the industry that just do things, and have no rationale as to why they do them. This workshop is for you. And anyone wanting to work with you.

You can watch the workshop at Channel 9.

Finally arrived at MIX10.

I arrived yesterday, after a long long ride on various airplanes. But I've learned a few things so far:

1. Chicago O'Hare airport, is HUGE, and an incredibly boring airport.

2. At McCarran International in Las Vegas, the slot machines start at the gate.

3. Las Vegas is INSANE!

 

Today is workshop day, and I'm attending two workshops.

Right now I'm sitting in the first one, "Design Fundamentals for Developers". Let's see what it'll bring.

However, the one I'm really looking forward too is the "ASP.NET MVC Bootcamp" this afternoon.

Using Umbraco as an application platform: Part 4 - The final step

This post is part of a series, this being the fourth, and last part, if you're interested, read the first part here, the second part here, and the third part here.

In the previous part, I told you how I rendered the material template to the client, using XSLT, JavaScript, jQuery and jQuery UI. This time, I'm going to show you how I get that data back to the server for generation of an actual PDF. This is where the "ClientObjects" come in, might be a stupid name for them, but there are three different kinds of objects in play, and that was the best name I could think of at the time.

In .NET I have 2 kinds of objects, ClientObjects and DataObjects. Again, naming isn't my strong suit. Basically, the client (the UI), knows of one type, and that's the ClientObjects, they are small, lightweight and versatile, in the way that they have a Data property, that contains XML, so I could send whatever I wanted with it. Essentially, the JavaScript version of the ClientObject is the same as the .NET version of it. Why? Well, I get instant, no hassle, deserialization, of the object into .NET. But I'm getting ahead of myself.

The communication is done via a WCF Service, that expects JSON serialized data, and since I have jQuery on the client side, I simply serialize my ClientObject to JSON, and send it to my service with the jQuery ajax() method, leaving my user experience intact.

PDF Studio JavaScript ClientObjects

Once the actual data is on the server, I convert it in two steps. Basically the idea was to minimize the data sent between the client and the server, and to ensure that if one part was to be replaced later, it could easily be done without having to change everything else.

In the conversion from a ClientObject to a DataObject, the properties in the ClientObject are validated against the data stored in Umbraco, and it's also made sure that properties that the editor has disabled editing of, aren't modified, and if they are, reset their values to what the editor set them to, this is mainly done by mapping properties, and converting values, from one data type to another. It's also here that certain values from the client, e.g position, is converted from a percentage, to a fixed point value. This was done so that the preview area could have the same size, regardless of the size of the material being edited. I accomplished this by setting the preview area to 420x595 pixels. As a coincidence, this just happens to be the size, in points, of a portrait A5. From there it's just a matter of knowing the algorithm for converting between An sizes, and you're all set.

Once we have a DataObject, an object that contains all the aspects of what output should be generated, we're ready to generate a PDF from that. Again, conversion is done into the objects that DynamicPDF understands, but could just as easily be done for any of the other components I mentioned earlier, provided you want to work around the whole bottom-up issue.

Once the PDF is generated, it's all just a matter of saving the file to disk on the server, where it can be accessed by the client, and returning the path to the client. It's really simple actually.

In closing, I would like to mention that this project was very fun. Albeit, not very structured and thought through, it gave me the opportunity to learn a lot. Since I developed this entire application in five weeks, there where a lot of corners that were cut. Since then, I've developed a new version, with far more thought going into the design of things. It will feature a new UI, built using Adobe Flex, and the architecture of the server side is very modular, enabling easy extension. It has been built using Umbraco 4.1 as a template engine, but the communication between the server and the UI is done with Flex Remoting, using FluorineFx. It will be totally awesome once it's ready. I've been given permission (since I don't own the code) to showcase that at Codegarden '10, if I can only muster the courage to speak in front of so many people. If you're attending, and interested, please let me know.

Using Umbraco as an application platform: Part 3 - Rendering the UI

This post is part of a series, this being the third part, if you're interested, read the first part here, and the second part here.

In Umbraco, when rendering the UI, the standard ASP.NET approach with MasterPages apply. However, from there on, there are several different approaches, including standard .NET controls, custom WebControls, custom UserControls, (in 4.1 there is LINQ support), and finally, XSLT. To many developers XSLT is like the bastard sibling you never want to meet, but once you get around that "I don't know you, so I don't want to play with you" feeling, it's actually a very powerful tool for presentation. Since it's a fairly brutish language, it can't "operate heavy machinery", but that's where the combo Umbraco - XSLT really stands out. By enabling you to add your own code to the XSLT processing, through XSLT Extensions, you can do pretty much whatever you want with your data. Those are the calls in the XSLT that begin with "umbraco.library" (built-in), or "xsl.lib" (my own). To all you MVC fans, yes, that would be like doing logic in your view, and yes, that's a big no-no, I'm saying you can, not that you should. (Yes, I know, I do in the examples.). But I digress.

When rendering the application UI to the client, I've used MasterPages and POSH (Plain Old Semantic Html) up until the step where the users selects which material the would like to modify. I use XSLT to render the list of campaigns, and the list of materials, but that's just lists with links. Once the user selects a material, it's all JavaScript. I want my application to be a smooth user experience, and not something that'll make them call the marketing department asking what the hell they were thinking.

In most cases, XSLT is used to render markup, however, I've also used it to render the JavaScript used both for the editor controls, as well as for the preview. Since each material is unique, the basis for how they should work is shared, but the implementation is specific. The real XSLT is fairly large, and thus hard to show here, but I've provided snippets that explain the jist of thing.

PDF Studio XSLT ClientObjects

In the image above, you can (hopefully) see how I iterate all child objects, rendering the JavaScript object implementation code. I've shortened the example for brevity, omitting most of the variable declarations, but if you really want to see the whole shabang, get in touch, and maybe I'll share :). There are two more parts, the jQuery preview code, and the editor control code, but we'll get to those soon enough. Maybe you're wondering why the hell I have two JavaScript objects for each region? Well, one, what I've chosen to name the ClientObject, is used as a data carrier in communication with the server, and the jQuery object is used in the editing and previewing on the client. Yes, I could use the jQuery object for both, but this way is faster. Not in terms of performance, but rather in terms of me not having to think or care so much. Although this is another discussion completely, let me just say it. I really want to do the best solution possible, but I have yet to meet the client willing to pay for that, most clients settle for "Does it work?" (in some cases even for "Does it compile?", but let's not go there.)

PDF Studio XSLT Preview

So, in the sample above, I create a DOM element, with a wrapper function called createElement, it has a signature like this: createElement(tagName, id, style, text). What the XSLT template does is, it creates a DOM element, and if the editor has tagged the region as moveable, registers it as draggable (jQueryUI), it also retains its original position as data on the DOM element, so that it can easily be reset. The example above is for a text element, either a Formatted or Simple Text. In the case of a text element, the different available font sizes are saved as data on the DOM element as well.

PDF Studio XSLT Editor Controls

Finally, we render the editor controls, enabling the user (if allowed by the editor), to modify different aspects of a region. I've shortened it a bit here as well, but it shows the general idea anyway, in this case, it's a Simple Text Region.

PDF Studio UI Simple Text

And this is what it looks like. On the left are the editor controls, on the right, the preview controls, and in the browser memory, a JavaScript object structure representing what you see, and any changes that you have done. As soon as I can get my son to sleep longer than 45 minutes at a time, I'll try to write the next part, as this post has been written, sporadically, over the course of the past six and a half hours.

Next up: Sending modifications to the server.

Using Umbraco as an application platform: Part 2 - Templates

This post is part of a series, this being the second part, if you're interested, read the first part here.

As in every Umbraco project, the first thing to do is set up the Document Types, as they are the containers for data.

Since Umbraco supports inheritance through Master Document Types, I set mine up so that they reflect the different kinds of content available for users (beside the types needed for the UI). My base type is called ContentRegion, it has properties for size and position. Inheriting from ContentRegion is ColoredRegion, with properties for colors, it then in turn has different regions inheriting from it, like FormattedTextRegion and SimpleTextRegion, where the formatted region is a HTML editor, and the simple one is just a text string.

There's also an ImageRegion, with the derived types Image and Upload, where Image is the templated version used by editors, and Upload enables end-users to upload their own content for inclusion in the final PDF. Finally, I created a SelectiveRegion type, that has no content of its own, but will enable end-users to select a child to use and edit.

PDF Studio DocumentTypes

Editors create "templates" of materials, by specifying the size and position of different regions on a page, the hierarchy determines the order, or z-index, that the regions are rendered, enabling overlapping and covering, if desired.

PDF Studio Structured Content

This makes it fairly easy to create and edit templates, enabling editors to create multiple types of content that end-users can edit and output as pdf's.

Next up: Getting the data to the end-user

Using Umbraco as an application platform: Part 1 - Background

This is the first post in a series elaborating on my presentation at the Umbraco 5th birthday event in Stockholm, excellently arranged by Milagro.

Through Milagro, I was tasked with developing a PDF Creation Tool, the project brief was something along the lines of the following:

"Editors should be able to create campaign materials, in the form of posters, folders and flyers, in sizes ranging from A5 to A3. End users should then be able to modify these materials according to parameters set by the editors. The output should be a high resolution PDF, ready for printing."

Time was short, and the whole time allotted, from our initial meeting, to launch day, was just under six weeks. At the time of the meeting, nothing had been done. No pre-studies, no proof of concept, no design, no nothing. You could think this is unusual, but unfortunately, it's quite common. As this project had come to them as a last-minute thing, all of their developers were busy in other projects, I was tasked with doing a short pre-study to select a PDF creation component, while Åsa, their designer at the time, did the design and started on the front-end development.

I began by looking at ABCpdf, ITextSharp and DynamicPDF. A funny thing about the PDF format, is that it's drawn from the bottom left corner and diagonally up to the right, instead of, as everything else is, from the top left and down to the bottom right. I ran into all sorts of issues because of this, and as DynamicPDF is the only component that encapsulates this behavior, I went with that one. I did some quick proof-of-concept, just to see if the component was able to do what I wanted it to. Obviously, it did.

Very early in the project, I mentioned Umbraco to the project manager, as I have been working with the CMS since version 2.1 (that's 2006, if you didn't know), and to me, it all sounded like shuffling data between the client and the server (isn't everything?), and Umbraco is an excellent tool to do just that, in addition to create and store information. If you have no idea what Umbraco is, I suggest you look it up, you won't regret it. Anyway, no one at Milagro had worked with Umbraco, so I started evangelizing it from the get go (if I got a penny every time I said how good Umbraco is, I'd be filthy rich). Since I was the only developer on the project, I got to choose, but that was the only perk.

So, there we had it. UmbracoDynamicPDF, a half-finished UI, and five weeks 'til deadline.

Next up: Creating the PDF Templates in Umbraco