Tuesday, 11 April 2017

Machine learning with F#

Another cross-post to something I've put together on my company's Medium site - in this article I'm discussing working with F# and decision trees (both new to me), in a what was an enjoyable, but futile, attempt to draw some insights from a data set of horse racing results.

You can read the article here.

Friday, 7 April 2017

Umbraco Show & Tell London

Recently had the pleasure of speaking with my colleague Ben Pilgrim at the Umbraco "Show & Tell" event in London. The theme of the day was the "great Umbraco editorial experience". There's a nice write-up of the day up on the Umbraco blog and we've made the slides available here.

Wednesday, 11 January 2017

Building an Alexa Skill with ASP.Net Web API

Another cross post of a piece written for my company blog, on building an Alexa skill. To read, click here.

Friday, 25 November 2016

Umbraco Mapper redux and reviewed

Cross posting a piece written for the Zone blog, introducing a sample site written using Umbraco Mapper and other techniques for site building in Umbraco. Read more here or review the code here.

Thursday, 22 September 2016

To do: write “to do” app with ASP.Net Core

Cross posting a piece written for my company blog going over some code and patterns for a first-look, ASP.Net Core website. Whilst building something simple, I've also looked to use some patterns of DDD and CQRS that I make use of on current ASP.Net MVC projects.

Click to read over on Medium here.

Thursday, 1 September 2016

Using FormFlow with the Microsoft Bot Framework

Again cross-posting a piece written for Zone on their medium site. I'm extending a bot built for internal agency use with features for room booking, using LUIS and FormFlow with the Microsoft Bot Framework.

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);
        }
    }