Hide menu Last updated: Oct 26 2016
Area: Episerver CMS Applies to versions: 10 and higher
Other versions:

Properties

This topic explains how to access and use properties in Episerver. Properties store and present data for content such as pages and blocks. You can store properties for a single content item or as a dynamic property that can be inherited.

How it works

Properties are the fields in content types such as pages and blocks, where editors enter information. When you define a property on a content type, Episerver stores the property as a PropertyDefinition class and backs runtime instances of the property type by types inheriting from PropertyData. These classes deal with the data inside the property, such as protecting read-only state, preparing data from saving and loading, declaring value type, and so on. PropertyData classes also can provide a default user interface.

Accessing a property on a read-only page

Episerver returns content items in read-only mode from the API. The following code shows how to access a property that resides on the CurrentPage property on PageBase:

Object propertyValue = CurrentPage["PropertyName"];

The accessor determines whether the property with the name PropertyName is a property on the page by checking Property defined on IContentData implemented by PageData. It returns the property value, if one exists. If the property is not on the page, a delegate is called to see if the property is found elsewhere. The default delegate looks for the property from the fetch data from function (if activated on the current page). The delegate checks the dynamic properties for the page. You can write your own delegate and change this behavior.

Accessing a property on a write-enabled page

If the page you are working with is write-enabled, the Property accessor returns properties that are defined on the page; you never get dynamic properties or fetch data from properties when the page is in write mode.

Accessing properties on strongly typed content

When you access properties on a strongly typed page, work with that page as you work with an ordinary .NET object. Given a strongly typed page with the following signature:

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

Note: Why is the property declared as virtual ? In the background, a proxy class is created for the page type, and data is loaded from the database to a property carrier (Property), receiving the data. Through Castle (Inversion of Control tool), the properties in the proxy page type are set, and this only works if properties are declared as virtual. If the properties are not declared virtual, you need to implement get/set so they read/write data to the underlying property collection instead.

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

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

Extension methods for strongly typed content

Use the GetPropertyValue and GetPropertyValue extension methods to take advantages of strongly typed models and also 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 following example shows a strongly typed content model that has a fallback behavior for its PageHeading property. If the editor sets the PageHeading page property, the PageHeading property on the model returns the set value. If the editor does not set it, the property on the model returns the PageName property instead:

[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

If a property is unknown or if you want to access several properties (for example in a loop), you can access the value directly through its object representation.

Object propertyValue = CurrentPage["PropertyName"];

If you know the type of your value, you can cast it directly.

string propertyValueString = (string)CurrentPage["PropertyName"];

If you are unsure of the actual type and want to avoid an exception, assign the property value with the as keyword:

string propertyValueAsString = CurrentPage["PropertyName"] as string;
if (!String.IsNullOrEmpty(propertyValueAsString))
{
    DoSomething();
}

Do not assume the value type for a property type. For example, values of PropertyXhtmlString are of type XhtmlString, not string. So casting the value of a PropertyXhtmlString to string causes an exception, and using the as string operation yields null.

Using the GetPropertyValue extension method for non-strongly typed content

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

The following usage examples show different overloads of GetPropertyValue:

// 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());

Using a property multiple times

If you access a property used multiple times in your code, you can save a reference to the property. Otherwise, the property is fetched from the internal collection for each call, which also may result in several unnecessary calls to the delegate if the property is not native for the page.

For example, use:

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

Instead of:

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

Checking null values in properties

Episerver does not store properties with an empty value in the database. If you access a property from code, it is always null—not an empty string, 0, or false. This is because null is a very convenient way 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 example throws a NullReferenceException if the value is empty or missing:

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

StringBuilder.Append accepts null objects so this example is better than the previous example:

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

The following example throws a NullReferenceException if the value is empty or missing:

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


Markup accepts any type and converts to string, so you do not need cast:

<%= CurrentPage["PropertyName"] %>


The following example shows fallback for src attributes:

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


To return a string, use the ?? operator as follows:

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


The following example returns a value type:

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


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

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

Updating values for a page

If you want to update properties for an existing page, make sure that you have a writable version of the page, as shown in the following example.

PageData writablePage = CurrentPage.CreateWritableClone();

To set new values, assign them directly to the writablePage object by working against the properties for the most common page properties or by accessing the values directly:

writablePage.PageName = "somevalue";

This is the same as:

writablePage["Pagename"] = "somevalue";

When you are done with the page, save it by using DataFactory.Instance:

EPiServer.DataFactory.Instance.Save(writablePage, EPiServer.DataAccess.SaveAction.Publish);

Note: You cannot 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 ? & /. Some browsers may truncate or corrupt spaces, or problems arise when the browser displays these types of characters. For your website to be XHTML valid, use the HttpUtility.HtmlEncode method on strings that you inject with inline expressions. HttpUtility.HtmlEncode is part of the .NET framework. The HtmlEncode method encodes a string that is displayed in a web browser.

The following example shows how to display the Episerver pagename property with the new HTML Encoding syntax introduced in ASP.NET 4.0 to safeguard the output when rendering inline:

<%: CurrentPage.PageName %>

Related topics

Comments