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.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;
}
}
}
And it's simply implemented on the Page property thus:
///
/// 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 => page.OfficePage);
return value ?? PageReference.EmptyReference;
}
}
}
It's also very easy to do e-mail validation etc. on properties.
Like this for example.
[RegularExpression(@"^\b[\w\.-]+@[\w\.-]+\.\w{2,4}\b$", ErrorMessage = "/errors/EmailFormat")]
It's so simple it almost hurts.