Validation of string lists
Episerver allows you to create string lists - but what happens when you want to add regular expression validation to these? In this blog I'll go through the pitfalls of the built in functionality as well as showing how we can get this working by creating a custom attribute.
I recently had the need to create a list of dates. This is of course easy to do in Episerver – but if the dates needs to be time zones agnostic, this is a bit more challenging. After spending some time trying to solve this with a custom editor, I thought that I’d go for another approach and create a list of strings containing dates in standard ISO format (YYYY-MM-DD) to make it easy to enter a list of dates in a simple and controlled way.
Using RegularExpressionAttribute on a IList<string>
First I tried using a standard .Net RegularExpressionAttribute on the list of strings to see how it would behave. Would it validate for each instance, treat the list as a whole? At first it looked good, it seemed with validation working when I type something that not valid:
However, when the property value is sent to the server, the server validation starts and this seems to be done on the entire property value:
Creating a custom validation attribute
Generally, having validation on both the client and server is a good thing that we want. However, in this case – we can see validation on the client as something that helps us ensure data consistency, but there’s no real security thread if someone forges an incorrect string that’s sent to the server. Therefore, the simplest thing to do here is to create a custom attribute that just turns off the server side validation.
using System.ComponentModel.DataAnnotations;
namespace Episervercom.Site.Areas.Shared.Validation
{
/// <summary>
/// This attribute can be used when only client validation is wanted. The primary use case is for string lists that will do server validation on the entire value which is undesired.
/// </summary>
public class ClientSideOnlyRegularExpressionAttribute : RegularExpressionAttribute
{
public ClientSideOnlyRegularExpressionAttribute(string pattern)
: base(pattern)
{
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
return ValidationResult.Success;
}
}
}
Now - assign this to your property:
[ClientSideOnlyRegularExpressionAttribute("(\\d{4})-(\\d{2})-(\\d{2})", ErrorMessage = "Dates must be entered in the format YYYY-MM-DD")]
public virtual IList<string> OccurrencesAsDateStrings { get; set; }
And let's try again. Now everything works as expected and we can publish the page:
Of course, you could implement server side validation as well in the custom attribute, instead of just turning off server side validation, but that would require some more time which was not needed in this case.