Allowed Types By Interface

Sometimes, you will have a flexible content area where you will be able to add a large number of blocks. In this blog post, I will show you how you can replace a large list of allowed types in a property by using an interface.

First, let’s go with a real scenario, where we have a standard page which has a generic content area that will host several blocks. In order to handle that approach, we need to create a property and decorating it with [AllowedTypes] that specifies which blocks are allowed or restricted in the content area. You can either pass types as parameters or an array of types. AllowedTypes implicitly restricts every other type.

The recommended practice is to name parameters for clearness:

[AllowedTypes(AllowedTypes = new[] { typeof(BlockData1), typeof(BlockData2) },
RestrictedTypes = new[] { typeof(BlockData3) })]

And here is how the definition of a content area property that will support a large number of blocks could look

[AllowedTypes(AllowedType = new[] { typeof(BlockData1), typeof(BlockData2), typeof(BlockData3), typeof(BlockData4), typeof(BlockData5), typeof(BlockData6), typeof(BlockData7), typeof(BlockData8), typeof(BlockData9), typeof(BlockData10) })]
[Display(Name = "Flexible Content", Description = "Manage additional components for the main area", GroupName = SystemTabNames.Content, Order = 100)]
public virtual ContentArea FlexibleContentArea { get; set; }

If you see, the list of allowed types can grow depending on the number of blocks you want to support.

In order to simplify the definition of this kind of properties, we could use an Interface class and a UIDescriptor that will make this type assignable on allowed types annotations.

  1. Create an interface class
public interface IFlexible
{
}

2. Create a UIDescriptor

[UIDescriptorRegistration]
public class FlexibleUIDescriptor : UIDescriptor<IFlexible>
{
}

3. Create an Initialization Module that will register our Descriptor and let the interface to be referenced as part of the AllowedTypes definition.

[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public class FlexibleTypeInitialization : IInitializableModule
{
	public void Initialize(InitializationEngine context)
	{
		var uiDescriptorRegistry = context.Locate.Advanced.GetInstance<UIDescriptorRegistry>();
		var descriptors = uiDescriptorRegistry.UIDescriptors;
		
		var flexibleType = typeof(IFlexible);
		if (flexibleType.FullName == null) return;

		foreach (UIDescriptor descriptor in descriptors)
		{
			if (flexibleType.IsAssignableFrom(descriptor.ForType))
			{
				descriptor.DndTypes.Add(flexibleType.FullName.ToLowerInvariant());
			}
		}
	}

	public void Uninitialize(InitializationEngine context)
	{
		//do nothing
	}
}

4. Inherit the IFlexible interface into the blocks you want to be allowed in these flexible content areas.

public class BlockData1 : BlockData, IFlexible
{
....
}
public class BlockData2 : BlockData, IFlexible
{
....
}
public class BlockData3 : BlockData, IFlexible
{
....
}

5. Finally, update the definition of the content area by adding the IFlexible interface class as part of the allowed types.

[AllowedTypes(typeof(IFlexible))]
[Display(Name = "Flexible Content", Description = "Manage additional components for the main area", GroupName = SystemTabNames.Content, Order = 100)]
public virtual ContentArea FlexibleContentArea { get; set; }

Now, you have a clean definition of a content area that will host a large number of blocks. Don’t forget to inherit the IFlexible class in all blocks that you want to support flexible content. This can also be applied to PageData types.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: