Skip to content
Erik W edited this page Mar 16, 2016 · 4 revisions

Vault is built for extensibility. It's built such that additional TypeHandlers can be easily added, and additional libraries can be included alongside it. With these techniques, you can create additional custom classes and libraries to extend Vault's capabilities for handling types.

Vault's Mapping Process

This diagram overviews what happens when Vault decides that an umbraco property field needs to be mapped to an object property.

Property Mapping

Extending Vault

When you wish to map to a data type that isn't an Umbraco object but has a specific class, these primary tasks needed to be performed:

  1. Create a class that implements UmbracoVault.TypeHandlers.ITypeHandler
  2. Register the TypeHandler with the UmbracoVault.TypeHandlers.TypeHandlerFactory.
  3. (Optional) Extend UmbracoPropertyAttribute to declare a specific type handler to an existing type

UmbracoVault.TypeHandlers.ITypeHandler

Type Handlers have 1 job: Take an Umbraco property value, and map it to a specified object type. Each type handler does this, by implementing this interface:

public interface ITypeHandler
{
    object GetAsType<T>(object input);
    System.Type TypeSupported { get; }
}

A simple Type Handler that maps a property to a string will look like this:

public class StringTypeHandler : ITypeHandler
{
    public object GetAsType<T>(object input)
    {
        return Get(input.ToString());
    }

    public Type TypeSupported
    {
        get { return typeof (string); }
    }
}

Lastly, register the type handler with the UmbracoVault.TypeHandlers.TypeHandlerFactory. This can be done in two ways.

  1. Explicitly register the type on your application init methods.
  2. Add the assembly attribute UmbracoVault.Attributes.ContainsVaultTypeHandlers to your C# project for auto-registration.

Manual Registration

//Global.asax.cs or equivalent
public class Global : UmbracoApplication
{
    protected override void OnApplicationStarting(object sender, System.EventArgs e)
    {
        DefaultRenderMvcControllerResolver
            .Current
            .SetDefaultControllerType(typeof(VaultDefaultGenericController)); //optional

        Vault.RegisterViewModelNamespace("ReferenceWebsite.Models", "ReferenceWebsite");
        UmbracoVault.TypeHandlers.TypeHandlerFactory..RegisterTypeHandler<CustomTypeHandler>();
    }
}

Auto Registration

Vault, on initialization, will automatically search for type handlers to register such that manual registration is not needed. To do this, simply qualify your assembly by putting the assembly attribute somewhere in your class files (Properties/AssemblyInfo.cs is a great place for this)

//Properties/AssemblyInfo.cs

[assembly: AssemblyTitle("UmbracoVault.Tests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
...
[assembly: ContainsUmbracoVaultTypeHandlers]
...

All types within your assembly that implement UmbracoVault.TypeHandlers.ITypeHandler will be auto loaded. It is possible to exclude specific type handlers from being auto loaded by decorating with the property UmbracoVault.Attributes.IgnoreTypeHandlerAutoRegistration. In order to properly use these type handlers, you will need to extend UmbracoProperty and explicitly set the TypeHandler with an instance of your type handler within the attribute. See below for more on this.

//Will not be auto loaded by Vault.
[IgnoreTypeHandlerAutoRegistration]
public class AutoRegisteredTypeHandler : ITypeHandler
{
    public object GetAsType<T>(object input)
    {
        throw new NotImplementedException();
    }

    public Type TypeSupported { get { return typeof (AutoRegisteredType); } }
}

public class AutoRegisteredType { }

UmbracoVault.Attributes.UmbracoPropertyAttribute

The [UmbracoProperty] attribute denotes that a property should be mapped from an Umbraco document. it also can contain metadata on the property alias to bring in and also the type handler that should be used to map it.


In some instances, having a type mapper alone won't be enough for Vault to map your property. For example, if you need a special type handler for a common C# type. Let's say you map to an int value but the data is stored as XML.

Consider this Umbraco Document:

 <Person id="1077" parentID="1054" level="2" creatorID="0" sortOrder="7" createDate="2014-12-05T15:14:45" updateDate="2014-12-18T14:03:01" nodeName="Ken Sykora" urlName="ken-sykora" path="-1,1054,1077" isDoc="" nodeType="1071" creatorName="admin" writerName="admin" writerID="0" template="0" nodeTypeAlias="Person">
    <name>Ken Sykora</name>
    <primaryLocation><location><id>1073</id><name<Minneapolis, MN</name></location></primaryLocation>
    <secondaryLocation><![CDATA[1074]]></secondaryLocation>
    <favoriteLocations><![CDATA[1073,1076]]></favoriteLocations>
    <photo>/media/1001/headshot.jpg</photo>
</Person>

and this Object we wish to map to:

public class Person {
    public string Name { get; set; }
    public int LocationId { get; set; }
}

For the sake of example, let's say we want to mape the Person/primayLocation/location/id field to the LocationId property of the C# object. We will need a custom TypeHandler for this, but since there already exists a type handler for int values, we need to explicitly state that we want this type handler to be used.

public class LocationIdTypeHandler : ITypeHandler
{
    public object GetAsType<T>(object input)
    {
        var value = input.ToString();
        int result = 0;
            
        if (!string.IsNullOrEmpty(value))
        {
            var doc = XDocument.Parse(value);
            int.TryParse( doc.Element("location").Element("id").Value, out result);
        }

        return result;
    }

    public Type TypeSupported { get { return typeof(int); } }
}

Additionally, we need to create an UmbracoProperty attribute to explicilty indicate this type.

public class LocationIdUmbracoPropertyAttribute : UmbracoPropertyAttribute
{
    public LocationIdUmbracoPropertyAttribute()
    {
        TypeHandler = new LocationIdTypeHandler();
    }
}

And finally decorate our object with it.

public class Person {

    public string Name { get; set; }
    
    [LocationIdUmbracoProperty]
    public int LocationId { get; set; }

}

Of course, you will need to register the type handler as described above.

uComponents

For a great, simple example of how to extend Vault, check out the UmbracoVault.uComponents project.