Jul 30, 2010
visibility 7643
star star star star star
(0 votes)

Why you have to mark your properties as virtual when using PTB

A colleague asked me why all the properties that are to be mapped with PageTypeBuilder has to be virtual. This is sort of interesting and everyone that’s using PTB might not be aware of the reason so I thought that that merits a quick post about it.

 

Interceptors

PTB uses something called Interceptors which are used to (wait for it) intercept calls. The framework PTB uses for this is called DynamicProxy and is part of the Castle fame. The reason the properties have to be virtual is that the DynamicProxy needs to override (in the case of PTB) your properties to be able to run the code you (or Joel in this case) specify in the interception.

Why intercept?

A standard property using PTB looks something like this

   1: [PageTypeProperty(Type = typeof(PropertyString))]
   2: public virtual string Heading { get; set; }

and yet when calling CurrentPage.Heading it automagically has the value of the property CurrentPage[“Heading”]. This is due to the interception of the property Heading. Since the logic of how to handle the getting and setting of properties is the same for all properties you can use the above code instead of what’s actually happening under the covers which is something like this

   1: public virtual string Heading
   2: {
   3:     get
   4:     {
   5:         return this["Heading"] as string;
   6:     }
   7:     set
   8:     {
   9:         this.SetValue("Heading", value);
  10:     }
  11: }

So PTB uses interception both to be able to infer which property you’re getting/setting as well as handle the actually getting/setting which stays the same for all properties.

 

How the magic happens

PTB first does some wiring so that the interception is activated for the TypedPageData (see the class TypedPageActivator). Since we’re only interested in intercepting those properties we talked about above PTB uses a generation hook for this

   1: public bool ShouldInterceptMethod(Type type, MethodInfo memberInfo)
   2: {
   3:     return (memberInfo.IsGetterOrSetterForPropertyWithAttribute(typeof(PageTypePropertyAttribute)) && memberInfo.IsCompilerGenerated());
   4: }

So when you access one of the properties the generated proxy intercepts the call. The actual getting and setting of values is handled by the Intercept method in the class PageTypePropertyInterceptor.

   1: public void Intercept(IInvocation invocation)
   2: {
   3:     TypedPageData invocationTarget = (TypedPageData) invocation.InvocationTarget;
   4:     string propertyName = invocation.Method.GetPropertyName();
   5:     if (invocation.Method.IsGetter())
   6:     {
   7:         invocation.ReturnValue = invocationTarget[propertyName];
   8:         if ((invocation.ReturnValue == null) && (invocation.Method.ReturnType == typeof(bool)))
   9:         {
  10:             invocation.ReturnValue = false;
  11:         }
  12:     }
  13:     else
  14:     {
  15:         invocationTarget.SetValue(propertyName, invocation.Arguments[0]);
  16:     }
  17: }

As you can see on line 4 it uses the name of the property to avoid having magic string. It then basically does what the code above that explicitly handled the getting and setting does so that you won’t have to.

Jul 30, 2010

Comments

error Please login to comment.
Latest blogs
Parallel Development in Optimizely CMS SaaS: A Smarter Way to Register Components

📌 A note before you read: The approach described in this article is not a replacement for Optimizely’s recommended out-of-the-box component...

Vipin Banka | Jul 21, 2026

How I Deployed My Optimizely Content JS SDK Next.js App on Vercel (Hello Opti World)

📌 Scope: This post covers Optimizely CMS (SaaS) only, using the official content-js-sdk with Next.js 15 deployed to Vercel. This is a practitioner...

Kiran Patil | Jul 21, 2026 |

Finding Thomas Part 5 - The Closed Loop

Five weeks. Five layers. One Thomas. If you've followed this series from the start — thank you. If you're just landing here, the short version:...

Ritu Madan | Jul 20, 2026

Extending the Optimizely Product Recommendations Feed to Include Custom Product Types

A practical way to extend the Optimizely Product Recommendations catalog feed so the export scheduled job also includes custom catalog types, like...

Wojciech Seweryn | Jul 20, 2026 |