<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>Reflection for tag c</title><link>http://blog.bigfinger.se</link><pubDate>2012-02-07T22:58:54</pubDate><generator>umbraco</generator><description>Thoughts on life: Umbraco, EPiServer, .NET and Fatherhood.</description><language>en</language><copyright>Copyright 2009-2012 Stephan Kvart</copyright><webMaster>stephan@bigfinger.se</webMaster><item><title>SwedeGarden is born.</title><link>http://blog.bigfinger.se/2011/4/6/swedegarden-is-born.aspx</link><pubDate>Wed, 06 Apr 2011 12:30:27 GMT</pubDate><guid>http://blog.bigfinger.se/2011/4/6/swedegarden-is-born.aspx</guid><description>
Yesterday I was talking to some people on Twitter, about meeting
up in Copenhagen the evening before Umbraco CodeGarden '11 in June.
And it hit me, that we should invite all swedes that are attending.
And to simplify organizing that, I decided to start
SwedeGarden.

SwedeGarden is aimed at swedes going to CodeGarden, but all
attendees are of course welcome to join in.

You can read more over at SwedeGarden.

Please note, that this is a social event, no 'puters allowed.
Leave your geeky stuff...</description><content:encoded><![CDATA[ 
<p>Yesterday I was talking to some people on Twitter, about meeting
up in Copenhagen the evening before Umbraco CodeGarden '11 in June.
And it hit me, that we should invite all swedes that are attending.
And to simplify organizing that, I decided to start
SwedeGarden.</p>

<p>SwedeGarden is aimed at swedes going to CodeGarden, but all
attendees are of course welcome to join in.</p>

<p>You can read more over at SwedeGarden.</p>

<p>Please note, that this is a social event, no 'puters allowed.
Leave your geeky stuff at the hotel, and just bring your geeky
self. We'll have a few beers, network, and be merry. Also note,
that SwedeGarden is in no way affiliated with Umbraco or
CodeGarden.</p>

<p>See you there!</p>
]]></content:encoded></item><item><title>An EPiServer developer's introduction to the Umbraco Document API</title><link>http://blog.bigfinger.se/2011/3/11/an-episerver-developers-introduction-to-the-umbraco-document-api.aspx</link><pubDate>Fri, 11 Mar 2011 08:29:15 GMT</pubDate><guid>http://blog.bigfinger.se/2011/3/11/an-episerver-developers-introduction-to-the-umbraco-document-api.aspx</guid><description>
When working with EPiServer we're used to having a single class
to work with (if not using PageTypeBuilder), the PageData class. At
first glance it's equivalent in Umbraco is the Document class, but
after looking closer you'll see that there is one enormously
important difference, caching.

In EPiServer, we get all PageData objects from the DataFactory,
since EPiServer implements a factory
pattern. It's also implemented as a singleton, making it
very simple to interact with. We get the page ...</description><content:encoded><![CDATA[ 
<p>When working with EPiServer we're used to having a single class
to work with (if not using PageTypeBuilder), the PageData class. At
first glance it's equivalent in Umbraco is the Document class, but
after looking closer you'll see that there is one enormously
important difference, caching.</p>

<p>In EPiServer, we get all PageData objects from the DataFactory,
since EPiServer implements a <a
href="http://en.wikipedia.org/wiki/Factory_method_pattern"
target="_blank" title="Factory method pattern on Wikipedia">factory
pattern</a>. It's also implemented as a <a
href="http://en.wikipedia.org/wiki/Singleton_pattern"
target="_blank"
title="Singleton pattern on Wikipedia">singleton</a>, making it
very simple to interact with. We get the page by passing a
PageReference to the factory, getting the page we want. By default
the DataFactory returns the currently published version of a page.
In Umbraco, we instead call the constructor on the Document object,
by passing it an ID of the page we want. A big difference here is
that the Document API <strong>by default returns the latest version
of that page</strong>, regardless if it's published or not, if a
certain version is required, specify it by passing the version
Guid.</p>

<p>Another difference between the PageData and Document objects, is
caching. The PageData object you get from the DataFactory is always
cached (except when getting pages with FindPagesWithCriteria, but
more on that in another post), whereas the Document object is never
cached. For this reason, we only work with the Document API when we
want to programatically change data. For a cached page in Umbraco,
we use the Node API.</p>

<p>In EPiServer, <strong>the PageData object is read-only</strong>,
when we want to change a page, we call
<em>CreateWritableClone()</em> on the PageData object, getting a
writeable copy of our object, that we can change all we want. When
we're done, we pass it back to the DataFactory for saving and/or
publishing. In Umbraco, this is not as straight-forward. The
<strong>Document is always open for changes</strong>, and changing
a property will persist that change to the database immediately.
Properties for an EPiServer PageData object is accessed throught
its index property, by property name, like
<em>MyPageData["MyProperty"]</em>. Getting a property on the
Document object is done with a call to
<em>MyDocument.getProperties("MyProperty")</em>, however, this
performs a call to the database as soon as you access the
<em>Property.Value</em> property. What this essentially means, is
that each proeprty is saved as soon as you set its value, calling
<em>Document.Save()</em> fires the <em>BeforeSave</em> and
<em>AfterSave</em> events, updates the <em>UpdateDate</em>
property, and the preview XML. This is important to know. Calling
<em>Document.Publish()</em> performs different task related to
publishing, <strong>but it doesn't push your data to the content
cache</strong>, for this you need to call
<em>umbraco.library.UpdateDocumentCache(int)</em> passing it the ID
of the Document. This also ensures that any other servers, if your
site uses load balancing, also performs the cache update.</p>

<p>There are a number of methods to get cached content in Umbraco,
the old-school way is to use the Node API, most commonly used via
XSLT in Macros, but it's also available from code. Another way is
to use Linq2Umbraco, that gets cached, typed, instances of your
content. It has excellent performance, and if you're more
comfortable with using C#/VB for your coding, this is probably the
way for you. As I write there is also support for using Razor in
Umbraco, and I dare say that it may make XSLT in Umbraco obsolete.
It's the new black, and it's friggin' awesome :)</p>

<p>There's a great set of wiki-articles called <a
href="http://our.umbraco.org/wiki/reference/api-cheatsheet"
target="_blank">The Umbraco API Cheat-sheet</a>. Amongst others, it
clearly describes the <a
href="http://our.umbraco.org/wiki/reference/api-cheatsheet/difference-between-a-node-and-a-document"
 target="_blank">difference between a Node and a Document</a>.</p>

<p>As usual, all and any comments, suggestions and additions are
more than welcome.</p>
]]></content:encoded></item><item><title>An EPiServer developer's introduction to the Umbraco UI</title><link>http://blog.bigfinger.se/2011/3/6/an-episerver-developers-introduction-to-the-umbraco-ui.aspx</link><pubDate>Sun, 06 Mar 2011 21:39:34 GMT</pubDate><guid>http://blog.bigfinger.se/2011/3/6/an-episerver-developers-introduction-to-the-umbraco-ui.aspx</guid><description>

Both CMS's, of course, comes with an administration
interface. I'll assume that you are familliar with the EPiServer
OnlineCenter Dashboard, and the EPiServer CMS Edit- and
Admin-modes. However, if you're an Umbracian, I suppose you can
imagine, and get the general idea of how EPiServer is laid out.
Again, this comparison is not intended to establish which CMS is
better, but to serve as a translation of sorts, between the two
systems, to get you, as an EPiServer developer, started with
Umbr...</description><content:encoded><![CDATA[ 
<p
style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica;">
<span>Both CMS's, of course, comes with an administration
interface. I'll assume that you are familliar with the EPiServer
OnlineCenter Dashboard, and the EPiServer CMS Edit- and
Admin-modes. However, if you're an Umbracian, I suppose you can
imagine, and get the general idea of how EPiServer is laid out.
Again, this comparison is not intended to establish which CMS is
better, but to serve as a translation of sorts, between the two
systems, to get you, as an EPiServer developer, started with
Umbraco. This part is intended to give a brief orientation about
the tool, and I'll go into greater detail about the various
concepts as I get there throughout the series.</span></p>

<p
style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px;">
<span></span></p>

<p
style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica;">
<span>The default sections of Umbraco are Content, Media, Users,
Members, Settings, and Developer. When you first log in to Umbraco,
what you see is normally the "Content" "section", this roughly
translates to the EPiServer CMS Edit-mode, and it features the
functionality needed to edit, save, publish and work with
permissions for content. WHen you have a clean install of Umbraco,
there won't be anything here, since, just as in EPiServer, you need
DocumentTypes (PageTypes) in order to have Documents
(Pages).</span></p>

<p
style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px;">
<span></span></p>

<p
style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica;">
<span>The Media section is an ordered structure for Media, i.e.
files and folders, that can be used , and re-used, from Documents.
It's the equivalent of the file browser in EPiServer, although, not
implemented in the same way.</span></p>

<p
style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px;">
<span></span></p>

<p
style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica;">
<span>The Users section is where Users for the Umbraco UI are
managed, and their respective access rights.</span></p>

<p
style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px;">
<span></span></p>

<p
style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica;">
<span>The Members section is where Users for the website are
managed. In Umbraco, this is the MembershipProvider that you
configure. The Members section is used to manage Members, and it
can be used to edit both the User, called a Member, and the Profile
for that User.</span></p>

<p
style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px;">
<span></span></p>

<p
style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica;">
<span>The Settings section is where you edit the base for your
website, such as Document Types, Media Types, Languages and
Globalization and Templates. It can also be used to manage
Stylesheets and Scripts for your website.</span></p>

<p
style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px;">
<span></span></p>

<p
style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica;">
<span>The Developer section is used to manage the most technical
parts of the website, such as Data Types and Macros.</span></p>

<p
style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px;">
<span></span></p>

<p
style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica;">
<span>The rationale behind the decision to divide the building
blocks for your site in Settings and Developer, can be discussed,
in fact I can imagine it has been on several occasions. One could
argue that Macros are on par with Templates in technicality, but I
suppose there had to be a line drawn somewhere, and here it
is.</span></p>

<p
style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px;">
<span></span></p>

<p
style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica;">
<span>There is also a dashboard, that roughly corresponds to the
EPiServer OnlineCenter Dashboard, where you can load custom
controls and functionality for each section, however, it doesn't
have the same granular security features that EPiServer has, nor
does it rely or ASP.NET MVC to build these "gadgets", they are
simple (or, in some cases, not so simple) UserControls, but they
can be used for really powerful stuff. Your imagination sets the
limits here.</span></p>

<p
style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px;">
<span></span></p>

<p
style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica;">
<span>To sum it all up, coming from EPiServer, the Content- and
Media sections corresponds to the EPiServer CMS Edit-mode, and
Users, Members, Settings and Developer correspond to the
Admin-mode. Also note, that some tasks that are handled in
EPiServer configuration, are done from the UI in Umbraco, and
vice-versa. I'll try to amek sure to point these out as I get
there.</span></p>
]]></content:encoded></item><item><title>An introduction to Umbraco for EPiServer-developers. Or vice-versa.</title><link>http://blog.bigfinger.se/2011/3/1/an-introduction-to-umbraco-for-episerver-developers-or-vice-versa.aspx</link><pubDate>Tue, 01 Mar 2011 14:58:34 GMT</pubDate><guid>http://blog.bigfinger.se/2011/3/1/an-introduction-to-umbraco-for-episerver-developers-or-vice-versa.aspx</guid><description>
This is the
first part in a series introducing Umbraco to EPiServer developers,
however, it can also be seen as an introduction to EPiServer for
Umbraco developers. It all depends on your perspective. Please keep
in mind that this is not an attempt at comparing the two for the
sake of which is better, and I do not make the argument for either
platform. Both have their pro's and con's, but I leave it up to you
to select the platform that best suits your needs and
requirements.




In my
exper...</description><content:encoded><![CDATA[ 
<p style="margin: 0px; font: 12px Helvetica;"><span>This is the
first part in a series introducing Umbraco to EPiServer developers,
however, it can also be seen as an introduction to EPiServer for
Umbraco developers. It all depends on your perspective. Please keep
in mind that this is not an attempt at comparing the two for the
sake of which is better, and I do not make the argument for either
platform. Both have their pro's and con's, but I leave it up to you
to select the platform that best suits your needs and
requirements.</span></p>

<p style="margin: 0px; font: 12px Helvetica; min-height: 14px;">
<span></span></p>

<p style="margin: 0px; font: 12px Helvetica;"><span>In my
experience Umbraco is seen as a competent OSS alternative to
EPiServer. In my opinion, EPiServer is a very competent product,
although, the license costs often excludes it from consideration by
many organizations. Umbraco, too, is very competent. They employ
similar patterns for some of their functionality, and completely
different approaches for some.</span></p>

<p style="margin: 0px; font: 12px Helvetica; min-height: 14px;">
<span></span></p>

<p style="margin: 0px; font: 12px Helvetica;"><span>I've planned
the disposition for the series according to the list below, but it
may change as I write. I'll update this post as the series
progresses.</span></p>

<p style="margin: 0px; font: 12px Helvetica; min-height: 14px;">
<span></span></p>

<p style="margin: 0px; font: 12px Helvetica;"><a
href="/2011/3/6/an-episerver-developers-introduction-to-the-umbraco-ui.aspx"
title="An EPiServer developer introduction to the Umbraco UI">Part
1. The administration user interfaces.</a></p>

<p style="margin: 0px; font: 12px Helvetica;"><a
href="/2011/3/11/an-episerver-developers-introduction-to-the-umbraco-document-api.aspx"
title="An EPiServer developers's introduction to the Umbraco Document API">
<span>Part 2. Document vs. PageData</span></a></p>

<p style="margin: 0px; font: 12px Helvetica;"><span>Part 3.
DocumentType vs. PageType</span></p>

<p style="margin: 0px; font: 12px Helvetica;"><span>Part 4.
DataType vs. PropertyType</span></p>

<p style="margin: 0px; font: 12px Helvetica;"><span>Part 5.
Property vs. PropertyData</span></p>

<p style="margin: 0px; font: 12px Helvetica;"><span>Part 6. Media
vs. the VPP</span></p>

<p style="margin: 0px; font: 12px Helvetica;"><span>Part 7. Members
vs. Users</span></p>

<p style="margin: 0px; font: 12px Helvetica;"><span>Part 8. Event
hooking</span></p>

<p style="margin: 0px; font: 12px Helvetica;"><span>Part 9.
Scheduled tasks</span></p>

<p style="margin: 0px; font: 12px Helvetica;"><span>Part 10.
Building a Custom DataType, vs. Building a Custom
PropertyType</span></p>

<p style="margin: 0px; font: 12px Helvetica;"><span>Part 11.
Extending and customizing the UI.</span></p>

<p style="margin: 0px; font: 12px Helvetica;"><span>Part 12.
Template vs. PageTemplate</span></p>

<p style="margin: 0px; font: 12px Helvetica;"><span>Part 13. Macros
vs. DynamicContent</span></p>

<p style="margin: 0px; font: 12px Helvetica;"><span>Part 14. Macros
(XSLT/Razor/UserControl/Python) vs.
WebControls/UserControls</span></p>

<p style="margin: 0px; font: 12px Helvetica;"><span>Part 15.
Searching with Examine vs. FindPagesWithCriteria</span></p>

<p style="margin: 0px; font: 12px Helvetica; min-height: 14px;">
<span></span></p>

<p style="margin: 0px; font: 12px Helvetica;"><span>I have been
working with both platforms for many years, and I think both offer
excellent performance and functionality. However, regardless of
that experience, I may have gotten some things wrong, and I hereby
invite anyone to correct me, add information, or otherwise express
their opinions.</span></p>
]]></content:encoded></item><item><title>A list of things not cached, and sometimes cached in umbraco.</title><link>http://blog.bigfinger.se/2011/2/8/a-list-of-things-not-cached-and-sometimes-cached-in-umbraco.aspx</link><pubDate>Tue, 08 Feb 2011 12:07:40 GMT</pubDate><guid>http://blog.bigfinger.se/2011/2/8/a-list-of-things-not-cached-and-sometimes-cached-in-umbraco.aspx</guid><description>
When working with umbraco, keeping in mind what is, and what
isn't cached, is crucial for performance. I keep forgetting, so I
thought I might put a list of the things you need to keep track of
here, please help me out if (and I have), I've missed anything, or
am wrong.


The base object for Umbraco content is CMSNode, it is
constructed with an ID, and that goes to the database.

Content is derived from CMSNode

The Content.getProperty methods goes round-trip to the
database. All derivatives...</description><content:encoded><![CDATA[ 
<p>When working with umbraco, keeping in mind what is, and what
isn't cached, is crucial for performance. I keep forgetting, so I
thought I might put a list of the things you need to keep track of
here, please help me out if (and I have), I've missed anything, or
am wrong.</p>

<ul>
<li>The base object for Umbraco content is CMSNode, it is
constructed with an ID, and that goes to the database.</li>

<li>Content is derived from CMSNode</li>

<li>The Content.getProperty methods goes round-trip to the
database. All derivatives of the Content class (e.g. Document,
Media, Member),and thus behave the same way.</li>

<li>Members. The Member object itself can be cached, but getting
property values is just the same as for any Content.</li>

<li>Media is also a derivative of Content. (As Jeroen Breuer
mentioned in his comment, when working with Media in XSLT (via the
umbraco.library.GetMedia method), the returned XPathNodeIterator is
cached).</li>

<li>Document is Content. But it can be published, and thus pushed
to the Node API, which is cached.</li>

<li>Templates. Programmatic access to the templates always result
in a round trip to the database.</li>

<li>ContentType.GetByAlias and GetAll goes to the database, getting
it by ID via ContentType.GetContentType&nbsp;is cached.</li>

<li>PropertyType.GetPropertyType is cached, but all other ways of
instantiation goes to the database.</li>
</ul>

<p>I'll edit this list as needed, I haven't worked wnough with
4.6.1 to know what's changed, so this applies to 4.5.2, at
least.</p>

<p>As Jeroen Breuer accurately pointed out, there's a big <a
href="http://our.umbraco.org/wiki/reference/api-cheatsheet/difference-between-a-node-and-a-document"
 target="_blank">difference between a Node and a Document</a></p>
]]></content:encoded></item><item><title>Adding icons to the PageTree in EPiServer CMS 6.</title><link>http://blog.bigfinger.se/2010/5/10/adding-icons-to-the-pagetree-in-episerver-cms-6.aspx</link><pubDate>Mon, 10 May 2010 18:27:09 GMT</pubDate><guid>http://blog.bigfinger.se/2010/5/10/adding-icons-to-the-pagetree-in-episerver-cms-6.aspx</guid><description>
A feature I use heavily in Umbraco, and one I've missed in
EPiServer CMS, is the use of icons for different page types in the
tree. Although this functionality has been around for a while using
PageTreeIcons, when using PageTypeBuilder it can be quite cumbersome to
maintain a configuration with PageTypeId's, when we want to move
away from that.

Heavily inspired (and with some borrowing), I've converted the
PageTreeIcons project to a collection of attributes that you can
use to alter the ico...</description><content:encoded><![CDATA[ 
<p>A feature I use heavily in Umbraco, and one I've missed in
EPiServer CMS, is the use of icons for different page types in the
tree. Although this functionality has been around for a while using
<a href="https://www.coderesort.com/p/epicode/wiki/PageTreeIcons"
target="_blank">PageTreeIcons</a>, when using <a
href="http://pagetypebuilder.codeplex.com/"
target="_blank">PageTypeBuilder</a> it can be quite cumbersome to
maintain a configuration with PageTypeId's, when we want to move
away from that.</p>

<p>Heavily inspired (and with some borrowing), I've converted the
PageTreeIcons project to a collection of attributes that you can
use to alter the icons for page types and properties. It's still an
early draft, but it works.</p>

<p>This way, it's really easy to keep track of the icons for your
properties, and there's no need to keep an extra section in your
web.config. Some features have been removed, since EPiServer CMS 6
already contains some of the functionality (i.e the
PageLinkTypeHandler).</p>

<p>It's applied like this, on page types</p>

<pre class="brush: csharp">
[PageTypeIcon("~/UI/Images/PageTreeIcons/page.png", typeof(ContentPage))]
[PageType(AvailablePageTypes = new[] { typeof(ContentPage) },
   Filename = "~/UI/Pages/ContentPage.aspx",
   SortOrder = 20,
   Name = "[Public] ContentPage",
   DefaultSortIndex = 100,
   Description = "An ordinary content page.")]
public class ContentPage : PageTypeBuilder.TypedPageData { ... }
</pre>

<p>and like this, on a property</p>

<pre class="brush: csharp">
[PropertyEmptyIcon("~/UI/Images/PageTreeIcons/warning.png", 
   "/pagetreeicons/property/missingkeywords", 
   "MetaKeywords", 
   new [] { typeof(BaseModule), typeof(ModuleContainer), typeof(Contact) })]
[PageTypeProperty(EditCaption = "Keywords",
   HelpText = "A comma-separated string containing keywords used for this page.",
   Searchable = true,
   UniqueValuePerLanguage = true,
   Type = typeof(PropertyString),
   SortOrder = 10)]
public virtual string MetaKeywords {
   get;
   set;
}
</pre>

<p>Again, kudos to Henrik Nyström, <a
href="http://thisisnothing.wordpress.com/"
target="_blank">http://thisisnothing.wordpress.com/</a>, for
writing this in the first place.</p>

<p>Please let me know if you have any comments, improvements, or
questions.</p>

<p><a href="/media/1891/pagetypebuilderadditions.zip"
target="_blank" title="PageTreeIconAttributes">Download the code
here.</a></p>

<p>Don't have any icons? Try <a
href="http://www.famfamfam.com/lab/icons/silk/" target="_blank"
title="Silk Icons">FamFamFam Silk</a>!</p>
]]></content:encoded></item><item><title>Simple validation of property values, redux.</title><link>http://blog.bigfinger.se/2010/5/3/simple-validation-of-property-values-redux.aspx</link><pubDate>Mon, 03 May 2010 08:49:40 GMT</pubDate><guid>http://blog.bigfinger.se/2010/5/3/simple-validation-of-property-values-redux.aspx</guid><description>
Stefan Forsberg wrote an excellent post
on validating page data with Data Annotations, his solution is
by far a more elegant way of validating data on a property than my
ugly hack. So I rewrote my PageType validation hack to fit into his
model instead. I converted my very specific code into a more
generic ValidationAttribute. Works like a charm, and makes sure
that the PageReference actually points to a page of the type you
want, or nothing at all.


using System;
using System.Collections.Ge...</description><content:encoded><![CDATA[ 
<p>Stefan Forsberg wrote an <a
href="http://world.episerver.com/Blogs/Stefan-Forsberg/Dates/2010/5/Validating-page-data-with-Data-Annotations/"
 target="_blank"
title="Validating page data with Data Annotations">excellent post
on validating page data with Data Annotations</a>, his solution is
by far a more elegant way of validating data on a property than my
ugly hack. So I rewrote my PageType validation hack to fit into his
model instead. I converted my very specific code into a more
generic ValidationAttribute. Works like a charm, and makes sure
that the PageReference actually points to a page of the type you
want, or nothing at all.</p>

<pre>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using EPiServer.Core;
using PageTypeBuilder;

namespace Development {

    ///
    /// Specifies the allowed type of pages selected in the property.
    ///
    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
    public sealed class AllowedPageTypeAttribute : ValidationAttribute {

        ///
        /// The allowed types of pages.
        ///
        public Type[] AllowedPageTypes {
            get;
            set;
        }

        public AllowedPageTypeAttribute(Type[] allowedPageTypes)
            : base() {
            this.AllowedPageTypes = allowedPageTypes;
        }

        public override bool IsValid(object value) {
            var reference = value as PageReference;
            // Check if the property ReferenceContainer has a value
            if (PageReference.IsNullOrEmpty(reference))
                return true;

            var page = reference.GetPage();
            if (page == null)
                return false;

            var pageType = page.GetType();

            foreach (Type t in AllowedPageTypes) {
                if (pageType.IsAssignableFrom(t) || t.IsAssignableFrom(pageType) )
                    return true;
            }
            return false;
        }
    }
}
</pre>

<p>And it's simply implemented on the Page property thus:</p>

<pre>
///
/// Name: Office
/// Description: The office associated with this container.
///
[AllowedPageType(new[] { typeof(OfficePage) }, ErrorMessage = "/errors/OfficePagePageType")]
[PageTypeProperty(
EditCaption = "Office",
HelpText = "The office associated with this container.",
Searchable = false,
UniqueValuePerLanguage = true,
Type = typeof(PropertyPageReference),
SortOrder = 15,
Required=true)]
public virtual PageReference OfficePage {
        get {
                var value = this.GetPropertyValue(page =&gt; page.OfficePage);
                return value ?? PageReference.EmptyReference;
            }
        }
}
</pre>

<p>It's also very easy to do e-mail validation etc. on properties.
Like this for example.</p>

<pre>
[RegularExpression(@"^\b[\w\.-]+@[\w\.-]+\.\w{2,4}\b$", ErrorMessage = "/errors/EmailFormat")]
</pre>

<p>It's so simple it almost hurts.</p>
]]></content:encoded></item><item><title>SEO lowercase urls, in EPiServer CMS 6, that actually work.</title><link>http://blog.bigfinger.se/2010/5/2/seo-lowercase-urls-in-episerver-cms-6-that-actually-work.aspx</link><pubDate>Sun, 02 May 2010 08:34:59 GMT</pubDate><guid>http://blog.bigfinger.se/2010/5/2/seo-lowercase-urls-in-episerver-cms-6-that-actually-work.aspx</guid><description>
Last week I wrote a short blog post
about how to create consistent, lowercase, URLs for your EPiServer
CMS 6 site. While there has been some discussion wether or not
the casing of the URLs affect indexing, this post is more of a
correction on the code in the last post.

I did what I've been telling people not to do. I copied code,
and I expected it to work as advertised. Needless to say, it
didn't. The general idea was to hook into the
UrlSegment.CreatedUrlSegment event, and make sure that t...</description><content:encoded><![CDATA[ 
<p>Last week I wrote <a href="/2010/4/22/seo-lowercase-urls-in-episerver-cms-6.aspx"
title="SEO lowercase urls, in EPiServer CMS 6">a short blog post
about how to create consistent, lowercase, URLs for your EPiServer
CMS 6</a> site. While there has been some discussion wether or not
the casing of the URLs affect indexing, this post is more of a
correction on the code in the last post.</p>

<p>I did what I've been telling people not to do. I copied code,
and I expected it to work as advertised. Needless to say, it
didn't. The general idea was to hook into the
UrlSegment.CreatedUrlSegment event, and make sure that the URL was
lowercase. It works fine every time you edit a page, and alter the
URLSegment property. However, if you go into admin mode, and decide
to rebuild all URLs, you're in for a treat. The Rebuilding of URLs
doesn't fire the UrlSegment.CreatedUrlSegment event, since it just
alters the property on the PageData object, and creates a new
version of the page. This circumvents the event model for
URLSegements, I'd call it a bug, others might call it a feature,
but I leave it up to more intelligent people than me to decide what
to do. In the meantime, I've moved my logic to the
DataFactory.Instance.SavingPage event, since that is fired every
time the page is saved, no matter where you alter the page from.
It's in the DataFactory, it's "unfuckwithable".</p>

<p>I copied code, I'm sorry. I will never do it again. Never. At
least not without testing the results throughly first :)</p>
]]></content:encoded></item><item><title>Simple validation of propertyvalues in EPiServer CMS 6</title><link>http://blog.bigfinger.se/2010/4/26/simple-validation-of-propertyvalues-in-episerver-cms-6.aspx</link><pubDate>Mon, 26 Apr 2010 13:11:06 GMT</pubDate><guid>http://blog.bigfinger.se/2010/4/26/simple-validation-of-propertyvalues-in-episerver-cms-6.aspx</guid><description>
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 ...</description><content:encoded><![CDATA[ 
<p>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 <a href="/2010/4/22/seo-lowercase-urls-in-episerver-cms-6.aspx"
title="SEO lowercase urls, in EPiServer CMS 6">the code for hooking
into events</a>, so I suggest you get it from there if you have no
idea where to put this.</p>

<p>First, we hook into the event
<strong>DataFactory.Instance.SavingPage.</strong></p>

<p><strong><br />
</strong></p>

<pre>
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");
            }
        }
    }
}
</pre>

<p>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 <a href="http://pagetypebuilder.codeplex.com/"
target="_blank">PageTypeBuilder</a>. <a
href="http://pagetypebuilder.codeplex.com/"
target="_blank">PageTypeBuilder</a>, I love you.</p>

<p>As always, comments are welcome, maybe I've tried to solve this
whole issue the wrong way. Please let me know if I did :)</p>
]]></content:encoded></item><item><title>SEO lowercase urls, in EPiServer CMS 6</title><link>http://blog.bigfinger.se/2010/4/22/seo-lowercase-urls-in-episerver-cms-6.aspx</link><pubDate>Thu, 22 Apr 2010 07:15:41 GMT</pubDate><guid>http://blog.bigfinger.se/2010/4/22/seo-lowercase-urls-in-episerver-cms-6.aspx</guid><description>
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. ...</description><content:encoded><![CDATA[ 
<p>Yesterday I read a blog post by <a
href="http://www.epinova.no/blog/lars-timenes/" target="_blank"
title="Lars Timenes blogg">Lars Timenes</a>, describing how one
could easily <a
href="http://www.epinova.no/blog/lars-timenes/dates/2010/4/SEO-Lower-case-URLs/"
 target="_blank" title="Lower case URLs in EPiServer">generate a
bit more friendly URL Segments in EPiServer</a>. (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 <a
href="http://googlewebmastercentral.blogspot.com/2009/02/specify-your-canonical.html"
 target="_blank" title="Specify your canonical">&lt;link
rel="canonical" /&gt;</a> tag to your markup, I like to have more
than one solution to things.</p>

<p>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.</p>

<p>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.</p>

<p><strong>Edit: After reading Magnus's comment, I added the simple
code to detach the event.</strong></p>

<p><strong>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.</strong></p>

<pre>
using System;
using EPiServer;
using EPiServer.Framework;
using EPiServer.Framework.Initialization;
using EPiServer.Web;

namespace Development {

/// &lt;summary&gt;
/// An &lt;see cref="EPiServer.Framework.IInitializableModule" /&gt; enabling hooking into EPiServer events.
/// &lt;/summary&gt;
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public class ModuleInitializer : IInitializableModule {


#region IInitializableModule Members
/// &lt;summary&gt;
/// &lt;para&gt;Initializes the Module and attaches custom eventhandlers.&lt;/para&gt;
/// &lt;para&gt;Attaches a &lt;see cref="System.EventHandler" /&gt; for the EPiServer.Web.UrlSegment.
/// CreatedUrlSegment event.&lt;/para&gt;
/// &lt;/summary&gt;
/// &lt;param name="context"&gt;The current 
/// &lt;see cref="EPiServer.Framework.Initialization.InitializationEngine"/&gt;&lt;/param&gt;
public void Initialize(InitializationEngine context) {

UrlSegment.CreatedUrlSegment += 
new EventHandler&lt;UrlSegmentEventArgs&gt;(UrlSegment_CreatedUrlSegment);
}

/// &lt;summary&gt;
/// Makes sure that all URL Segments are always lowercase, for increased SEO performance.
/// &lt;/summary&gt;
void UrlSegment_CreatedUrlSegment(object sender, UrlSegmentEventArgs e) {

e.PageData.URLSegment = e.PageData.URLSegment.ToLowerInvariant();
}

/// &lt;summary&gt;
/// Perform pre-loading tasks.
/// &lt;/summary&gt;
public void Preload(string[] parameters) {

}

/// &lt;summary&gt;
/// &lt;para&gt;Uninitializes the Module.&lt;/para&gt;
/// &lt;para&gt;Detaches the &lt;see cref="System.EventHandler" /&gt; for the EPiServer.Web.UrlSegment.
/// CreatedUrlSegment event added during Initialization.&lt;/para&gt;
/// &lt;/summary&gt;
/// &lt;param name="context"&gt;The current 
/// &lt;see cref="EPiServer.Framework.Initialization.InitializationEngine"/&gt;&lt;/param&gt;
public void Uninitialize(InitializationEngine context) {
UrlSegment.CreatedUrlSegment -= 
new EventHandler&lt;UrlSegmentEventArgs&gt;(UrlSegment_CreatedUrlSegment);
}
#endregion
}
}
</pre>
]]></content:encoded></item></channel></rss>

