One thing i miss in EPiServer is the ability to add custom validation on each page template. You can always listen to the GlobalPageValidation.Validators event, but the PageData returned is not typed and if the validation logic is not divided the end result can turn into one big ugly validation method. This blog entry demonstrates how you can infer custom validation logic using the GlobalPageValidation together with the PageTypeBuilder to validate typed instances of the PageData.
Creating the foundations
The first thing step is to simply create a base implemetation that inherit from the PageTypeData that contains the basic set with properties needed. In this case the famous "MainBody". The base class also contains a IsValid method that creates a new ValidationResult (which is a simple class that contains a list of errormessages). The method also validates that the name "Smith" is not entered into the MainBody.
public abstract class BasePageData : PageTypeBuilder.TypedPageData
{
[PageTypeProperty(Required = true)]
public virtual string MainBody { get; set; }
public virtual ValidationResult IsValid()
{
var result = new ValidationResult();
if (!string.IsNullOrEmpty(MainBody) && MainBody.Contains("Smith"))
{
result.AddError("The MainBody is invalid");
}
return result;
}
}
Your implemations of the TypedPageData will inherit this and override the IsValid method to add their own validation.
Inherit and add more validation
Each inherit instances of BasePageData can override the IsValid method and add their validation error. Here i have added a ActiclePageData type with a Ingress and validation logic to ensure value of the Ingress is at least 100 characters long.
[PageTypeBuilder.PageType("DB0867BB-84BB-432B-A3A5-569DE5B76527",
Name = "[Standard] Acticle page",
Filename = "~/Templates/Test.aspx")]
public class ActicePageData : BasePageData
{
[PageTypeProperty(Required=true)]
public virtual string Ingress { get; set; }
public override ValidationResult IsValid()
{
var result = base.IsValid();
if (string.IsNullOrEmpty(Ingress) || Ingress.Length < 100)
{
result.AddError("You got to write some more in the Ingress");
}
return result;
}
}
Intercept and run the validation
To be able to validate the page data you have to simply subscribe to the GlobalPageValidation.Validators event like this:
EPiServer.GlobalPageValidation.Validators += GlobalPageValidation_Validators;
Then add some code that fetches the PageData from the event, identifies the correct PageData type and runs the validation against using a typed instance
static void GlobalPageValidation_Validators(object sender, EPiServer.PageValidateEventArgs e)
{
// Don't validate if the page is not valid for some other reason
if (!e.IsValid)
{
return;
}
Type type = PageTypeResolver.Instance.GetPageTypeType(e.Page.PageTypeID);
// Current page is not a typed page -> don't validate
if (type == null)
{
return;
}
var activator = new TypedPageActivator();
var typedPageData = activator.CreateAndPopulateTypedInstance(e.Page, type) as BasePageData;
// Current page is not a typed page of type BasePageData -> don't validate
if(typedPageData == null)
{
return;
}
// Validate the type instance
var validationResult = typedPageData.IsValid();
if (!validationResult.IsValid)
{
e.IsValid = false;
e.ErrorMessage = FormatErrorMessages(validationResult.ErrorMessages);
}
If the validation identifies any problems the IsValid property is set to false and a formatted error message is displayed to the web editor like this
