Monday, February 7, 2011

Writing custom properties: #1 Custom value type

This is first post from series showing how to implement custom property in EPiServer in "proper" way without unnecessary hacking.
  1. Writing custom properties: #1 Custom value type
  2. Writing custom properties: #2 Default value
  3. Writing custom properties: #3 Edit control

Introduction
In EPiServer all custom properties must inherit from abstract base class PropertyData.  It’s value can be stored using one of following underlying types:
•    Boolean
•    Category
•    Date
•    FloatNumber
•    LinkCollection
•    LongString
•    Number
•    PageReference
•    PageType
•    String

Those types are defined in enumeration EPiServer.Core.PropertyDataType and when creating custom property you have to decide which storage type is closest to your requirements. From my experience you will usually use number or variations of string storage. The easiest way to start is to use one of default property type defined in EPiServer as your base class.

Guid Property
In this tutorial series I will show how to create complete custom property used for storing and editing Guid value. Using Guid as example will be easy to understand but still possible to show many features available for custom properties.

As usage example you may consider integrating with external system where product identifiers are stored as Guids and editor is responsible for providing them to our CMS.

Analysis

Guid are easily stored in string using different formats (the most popular is “{96C7DFDF-668C-4A71-AA79-1E8898B1A0E4}”), therefore as base type I will use PropertyString – originally used for storing up to 255 characters.

If we would leave property unchanged, editor could easily mistype value, which may cause system failure when application will be parsing invalid string. Creating custom property can prevent human error.

It’s also crucial to return proper object type, so developer can avoid parsing and, what is even worse, invalid format error handling in every place value is used.

//bad – requires parsing and error handling
Guid value=new Guid(CurrentPage[“GuidProperty”].Value); 

//good – returned value is System.Guid
Guid value= (Guid) CurrentPage[“GuidProperty”].Value; 

 Implementation

[PageDefinitionTypePlugIn]
public class GuidProperty : PropertyString
{
    private Guid value;

    public override Type PropertyValueType
    {
        get { return typeof(Guid); }
    }

    public override object Value
    {
        get { return this.value; }
        set
        {
            this.SetPropertyValue(value, delegate
            {
                //currenty we don't have custom editor control for guid, 
                //therefore if standard string control value sets value from editor
                //we try to parse it. Throwing exception in this place will show nice
                //message that provided value "is not valid value for property 
                //'YourPropertyName'"
                this.value = value is string? new Guid((string)value) : (Guid)value;

                if (Equals(value, Guid.Empty))
                    this.Clear();
                else
                    this.Modified();
            });
        }
    }

    public override void LoadData(object newValue)
    {
        this.Value = this.DeserializeValue(newValue as string);
    }

    public override object SaveData(PropertyDataCollection properties)
    {
        return this.SerializeValue(this.value);
    }

    protected string SerializeValue(Guid value)
    {
        return value.ToString();
    }
    protected Guid DeserializeValue(string value)
    {
        if (string.IsNullOrEmpty(value))
        {
            return Guid.Empty;
        }        
        return new Guid(value);        
    }
}

 Usage

var value = CurrentPage["Guid"]; // e.g. c75dfcdb-258c-47a0-a2ea-81f0b92341e4
var type = CurrentPage["Guid"].GetType(); //System.Guid (not System.String!)

1 comment:

Alexander Haneng said...

Nice post. Looking forward to the rest.

And congrats on your first post on EPiServer World, I hope there are many more to come :-)