In this tutorial, you will learn how to apply a custom validator to a content area within an Episerver CMS powered website. Before handing over your new build to a content editor, you may want to restrict what blocks an editor can add to a page within the editor. As every project is different, it is likely you will want to apply some bespoke restrictions to the page based on the business needs. For example, you may only want to allow 5 carousel item blocks into a carousel 🚫🚫🚫
In Episerver, there is no easy way to apply these types of restrictions from within the UI itself. It would be possible to create a custom editor rendering for the property. This would involve writing some HTML and JS using Dojo.js. Writing custom editor renderings is painful to debug, it also involves understanding Dojo. Instead, you can create a custom validation attribute using C# alone. This approach is much quicker to build and easier to debug, and it is the approach I recommend you follow.
To create an attribute, you will need to create a class that implements from
ValidationAttribute. Next, override a method called
IsValid() and then create some custom logic. If the validation fails, you return
IsValid(). Doing this will tell the CMS to not save the page. Instead, an error message can be displayed back to the user. Finally, you simply decorate your attribute onto the property you want to add the restrictions to. Simples 🔥🔥🔥
The code to create this attribute can be seen below:
As shown above, the class inherits from
ValidationAttribute and overrides two
IsValid() methods. On Line20, I check the passed-in property type to ensure it is of type
ContentArea, if it is, then the code checks that the
Items collection is not greater than 5.
To apply this attribute to a content area is simple:
Simply decorate the
MaxItemsAllowed attribute within the page or block type property you want to restrict. For most use cases this is the approach I would recommend that you use. There is an alternative way of doing this, which I will cover next.
Validating using IValidate
As of Episerver 7, there is also another way to validate a content area. This approach uses the
IValidate interface. On application start, using reflection Episerver will scan the solutions bin folder for any classes that implements
EPiServer.Validation.IValidate. If it finds any, Episerver will automatically register this validation on a global basis. Whenever a page is saved, Episerver will run all registered global validators any time a page is saved. This approach using reflection works in a similar way as the Episerver code-first content modelling. Registering a new page or block is done in code by decorating a class with the
ContentType attribute. This is all that you need to do in order to register the new type on the CMS. Using reflection on start-up, Episerver will do the rest!
IValidate method will mean that your validation will be called any time a content editor tries to save a page or block. I am not too keen on this approach for two reasons. First, adding too many validators can make debugging a problem. If you have lots, how do you easily tell which validator has prevented the page from saving? The second is around god classes and code smells. If you mix too many validation rules within a single validator, it is likely you will create bugs and maintenance issues for yourself later on.
To build a validator is simple enough. In your validate method, you simply specify the page type you want to filter by and then put your custom code, like this:
This is all you need to do, as the validator runs globally 🔥🔥🔥
As mentioned, I prefer the attribute approach to validation. I find being specific on validation tends to be easier. I recommend you do whatever makes you happy. Happy Coding 🤘