Hide menu Last updated: Mar 31 2014

Table of contents

Introduction

Properties is a central concept in EPiServer CMS. Properties are used to store and present data for pages and blocks, and properties can either be stored for a single content item or as a dynamic property that can be inherited for pages.

In EPiServer CMS, when a property is defined on a content type it is stored as a PropertyDefinition class.  Runtime instances of the property type is backed by types inheriting from  PropertyData, the primary purpose of these classes is dealing with  the data inside the property such as protecting read-only state, preparing data from saving and loading, declaring value type etc. PropertyData classes can also provide a default user interface.

Accessing a property in different modes

A page in read-only mode

All content items delivered from CMS is in read-only mode when returned from the API. The normal way to access a property that resides on for example the CurrentPage property on PageBase through code is like this:

C#
Object propertyValue = CurrentPage["PropertyName"];

The first thing that will happen is that the accessor will see if the property with the name “propertyname” is a property on the page by checking Property defined on IContentData implemented by PageData. If it exists and have a value the property value is returned. If the property is not on the page then a delegate will be called to see if the property can be found elsewhere. The default delegate will first of all look for the property from the “fetch data from” function if that has been activated on the current page. Last of all the delegate will check the dynamic properties for the page. It is possible to write your own delegate and change this behavior.

A page in write mode

If the page you are working with is in write enabled mode the Property accessor will only return properties that are defined on the page. This means that you will never get dynamic properties or fetch data from properties when the page is in write mode.

Accessing properties on a strongly typed content

When accessing properties on a strongly typed page you will work with that page as you work with an ordinary .NET object.

Given a strongly typed page with this signature:

C#
[ContentType]
public class NewsPageModel : PageData
{
    public virtual XhtmlString MainBody { get; set; }
}

If you are using the generic EPiServer.TemplatePage on your page type, you can access the MainBody property like this:

C#
public class NewsPage : TemplatePage<NewsPageModel>
{
    protected override void OnLoad(System.EventArgs e)
    {
        string mainBody = CurrentPage.MainBody.ToHtmlString();
    }
}

Extension methods for strongly typed content

Using the GetPropertyValue and GetPropertyValue extension methods you can take advantages of strongly typed models and at the same time override the get and set behavior for the property. Add a using statement referencing the EPiServer.Core namespace to your class to use these extension methods.

The example below shows a strongly typed content model which has a fallback behavior for its PageHeading property. If the PageHeading page property is set by the editor, the PageHeading property on the model will return the set value. If it is not set by the editor, the property on the model will return the PageName property instead:

C#
[ContentType]
public class ContentPageModel : PageData
{
    public virtual string PageHeading
    {
        get
        {
            var heading = this.GetPropertyValue(p => p.PageHeading);

            // If heading is not set, fall back to PageName
            return String.IsNullOrWhiteSpace(heading) ? PageName : heading;
        }
        set { this.SetPropertyValue(p => p.PageHeading, value); }
    }
}

Accessing properties on non-strongly typed content

When accessing a property’s value there are some different ways to do this depending on what you know about the actual property. If you have no knowledge about the property or if you want to access several properties, for instance in a loop, you can access the value directly through its object representation.

C#
Object propertyValue = CurrentPage["PropertyName"];
If you know the type of your value you can cast it directly
C#
string propertyValueString = (string)CurrentPage["PropertyName"];
If you are not sure of the actual type and want to avoid an exception being thrown you might want to assign the property value with the “as” key word:
C#
string propertyValueAsString = CurrentPage["PropertyName"] as string;
if (!String.IsNullOrEmpty(propertyValueAsString))
{
    DoSomething();
}
Be careful when assuming the value type for a property type so you do not get it wrong. For example, values of PropertyXhtmlString will be of type XhtmlString, not string. So casting the value of a PropertyXhtmlString to string would cause an exception, and using the as string operation would always yield null.

The GetPropertyValue extension method for non-strongly typed content

The EPiServer.Core namespace has some extension methods for ContentData. If you import this namespace (for example with a using statement in codebehind or @import directive in WebForms codefront), ContentData is extended with the GetPropertyValue method. It can simplify some property access by reducing the amount of code needed. For example, you can use it to get the string representation of a property without first checking against null, and/or to provide a default value if the property is null.

Here are some commented usage examples of different overloads of GetPropertyValue:

C#
// 1. Get as string, defaults to null and otherwise calls ToString for the value
string mainBody = CurrentPage.GetPropertyValue("MainBody");

// 2. Specify a fallback value
string mainBodyFallback = CurrentPage.GetPropertyValue("MainBody", String.Empty);

// 3. Which is equivalent to
string mainBodyFallback2 = CurrentPage.GetPropertyValue("MainBody") ?? String.Empty;

// 4. So a common usage is probably
string pageHeading = CurrentPage.GetPropertyValue("PageHeading", CurrentPage.PageName);

// 5. Get typed value, defaults to null if property is not set or defined
XhtmlString xhtml = CurrentPage.GetPropertyValue<XhtmlString>("MainBody");

// 6. Which supports fallback in the same way as the "ToString" overload
XhtmlString xhtmlWithFallback =
    CurrentPage.GetPropertyValue<XhtmlString>("MainBody", new XhtmlString());

// 7. Advanced: Specify a conversion for the value
// Note: this example is very similar to 1. since we just call ToString, EXCEPT
// if MainBody is something else than an Xhtml property in which case 1. would still
// return the ToString representation while this would throw an exception since
// it tries to cast the value to an XhtmlString before handing it over to the
// conversion lambda
string convertedXhtml =
    CurrentPage.GetPropertyValue<XhtmlString, string>("MainBody", x => x.ToString());

// 8. This is equivalent to 1. since it treats the property value as object
string mainBody2 =
    CurrentPage.GetPropertyValue<object, string>("MainBody", x => x.ToString());

Examples – DOs and DON’Ts

If you are accessing a property and you want to use the property several times in your code we recommend you to save a reference to the property as we need to fetch it from the internal collection for each call otherwise. It may also result in several unnecessary calls to the delegate if the property is not native for the page. For instance, use:

C#
PropertyData property = CurrentPage.Property["PropertyName"];
if (property != null && !property.IsNull)
{
    DoSomething();
}

instead of:

C#
if (CurrentPage.Property["PropertyName"] != null && !CurrentPage.Property["PropertyName"].IsNull)
{
    DoSomething();
}

Null values

EPiServer properties with an empty value are never stored in the database. If you access it from code, it will always be null – not an empty string, 0 or false as you maybe expected. Why null? It is by design and is very convenient if you want to check if something is not set by an editor or does not exist on this page. You just have to compare with null regardless of data type.

The following will throw NullReferenceException if value is empty or missing:

C#
StringBuilder sb = new StringBuilder();
sb.Append(CurrentPage["PropertyName"].ToString());

StringBuilder.Append accepts null objects so this is better:

C#
StringBuilder sb = new StringBuilder();
sb.Append(CurrentPage["PropertyName"]);

The following will throw NullReferenceException if value is empty or missing:

C#
<%= CurrentPage.Property["PropertyName"].Value.ToString()%>

Markup will accept any type and convert to string so cast is not needed:

C#
<%= CurrentPage["PropertyName"] %>

An example of fallback for src attributes:

C#
<img src='<%= CurrentPage["ImageUrl"] ?? "/Missing.png" %>' />

Other examples with fallback

If a string must be returned use the ?? operator as follows:

C#
string s = CurrentPage["StringProperty"] as string ?? string.Empty;

And for Value Type it is written as follows:

C#
DateTime date = (DateTime)(CurrentPage["DateProperty"] ?? DateTime.Now);
int i = (int)(CurrentPage["IntegerProperty"] ?? 0);

Another fallback in the markup using the ?? Operator as follows:

C#
<%= CurrentPage["Heading"] ?? CurrentPage.PageName %>

Updating values for a page

If you want to update properties for an existing page you need to make sure that you have a writable version of the page. This can be done in the following way:

C#
PageData writablePage = CurrentPage.CreateWritableClone();
To set new values you just need to assign them directly to the writablePage object. This can be done either by working against the properties for the most common page properties or by accessing the values directly:
C#
writablePage.PageName = "somevalue";
is the same as
C#
writablePage["Pagename"] = "somevalue";
When we are done with the page we simply save it by using DataFactory.Instance:
C#
EPiServer.DataFactory.Instance.Save(writablePage, EPiServer.DataAccess.SaveAction.Publish);
Note that it is not possible to save dynamic properties or properties that reside on other pages when you are working against DataFactory.Save.

HTML encoding and EPiServer page properties

HTML has a special handling for characters such as < > and symbols ? & / etc. Spaces for example may be truncated or corrupted by some browsers, problems can arise when displaying these types of characters in various browsers. For your website to be XHTML valid, use the HtmlEncode method – the HttpUtility.HtmlEncode method – which is part of the .NET framework. The HtmlEncode method encodes a string that is to be displayed in a web browser.

When rendering EPiServer page properties it is often recommended that this function is used – particularly when rendering inline. Calling the HttpUtility.HtmlEncode method on strings that you inject with inline expressions is recommended.

Example

If you want to display the EPiServer pagename property (for example) it is often a good idea to use the the new HTML Encoding syntax introduced in ASP.NET 4.0 to safe guard the output when rendering inline:

C#
<%: CurrentPage.PageName %>

See also

Comments