Thursday, 25 August 2016

Validating for uniqueness with EPiServer

This is just a short post describing a method found for validating that the value provided for field within a page or block is unique across other instances of that content type. The specific need was for a poll block that provided a question and set of answers for users to pick from, with the results being saved to the dynamic data store. I had an "identifier" field that the editors had to complete, the value of which being unique across all polls. And rather than relying on them to remember that, it's obviously better to validate it.

Here was the solution. Firstly I created an extension method that gets a list of all blocks of a given type other than the current block, looking like this:

    public static IEnumerable<T> GetOtherContentData<T>(this T instance) where T : IContentData
    {
        var contentTypeRepository = ServiceLocator.Current.GetInstance<IContentTypeRepository>();
        var contentModelUsage = ServiceLocator.Current.GetInstance<IContentModelUsage>();
        var contentLoader = ServiceLocator.Current.GetInstance<IContentLoader>();
        var blockType = contentTypeRepository.Load<T>();
        var existingBlocks = contentModelUsage.ListContentOfContentType(blockType);
        return existingBlocks
            .Where(x => contentLoader.Get<IContent>(x.ContentLink).ContentGuid != ((IContent)instance).ContentGuid)
            .Select(x => contentLoader.Get<T>(x.ContentLink));
    }

With that available validation can be wired up for the block like this:

    public class PollBlock : BlockBase, IValidate<PollBlock>
    {
        ...
        
        [Required]
        [Display(
            Name = "Identifier",
            Description = "This value should be unique across all polls to ensure recorded data is correctly stored",
            Order = 10)]
        [StringLength(10)]
        public virtual string Identifier { get; set; }
        
        ...

        public IEnumerable<ValidationError> Validate(PollBlock instance)
        {
            var errors = new List<ValidationError>();

            // Check whether the identifier is unique across all instances of the PollBlock
            if (AreThereOtherBlocksWithSameIdentifier(instance))
            {
                errors.Add(new ValidationError
                {
                    ErrorMessage = "The identifier provided has been used on another poll block instance.  Please choose a unique one.",
                    PropertyName = instance.GetPropertyName(x => x.Identifier),
                    Severity = ValidationErrorSeverity.Error,
                    ValidationType = ValidationErrorType.StorageValidation,
                });
            }

            return errors.AsEnumerable();
        }

        private static bool AreThereOtherBlocksWithSameIdentifier(PollBlock instance)
        {
            var otherBlockInstances = instance.GetOtherContentData();
            return otherBlockInstances
                .Any(x => x.Identifier == instance.Identifier);
        }
    }

No comments:

Post a Comment