<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Blog posts by Andy Butland</title><link href="http://world.optimizely.com" /><updated>2016-08-25T21:27:00.0000000Z</updated><id>https://world.optimizely.com/blogs/andy-butland/</id> <generator uri="http://world.optimizely.com" version="2.0">Optimizely World</generator> <entry><title>Validating for uniqueness with EPiServer</title><link href="http://web-matters.blogspot.com/2016/08/validating-for-uniqueness-with-episerver.html" /><id>&lt;p&gt;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 &quot;identifier&quot; 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&#39;s obviously better to validate it.&lt;/p&gt; &lt;p&gt;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:&lt;/p&gt; &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&lt;br /&gt;    public static IEnumerable&amp;lt;T&amp;gt; GetOtherContentData&amp;lt;T&amp;gt;(this T instance) where T : IContentData&lt;br /&gt;    {&lt;br /&gt;        var contentTypeRepository = ServiceLocator.Current.GetInstance&amp;lt;IContentTypeRepository&amp;gt;();&lt;br /&gt;        var contentModelUsage = ServiceLocator.Current.GetInstance&amp;lt;IContentModelUsage&amp;gt;();&lt;br /&gt;        var contentLoader = ServiceLocator.Current.GetInstance&amp;lt;IContentLoader&amp;gt;();&lt;br /&gt;        var blockType = contentTypeRepository.Load&amp;lt;T&amp;gt;();&lt;br /&gt;        var existingBlocks = contentModelUsage.ListContentOfContentType(blockType);&lt;br /&gt;        return existingBlocks&lt;br /&gt;            .Where(x =&amp;gt; contentLoader.Get&amp;lt;IContent&amp;gt;(x.ContentLink).ContentGuid != ((IContent)instance).ContentGuid)&lt;br /&gt;            .Select(x =&amp;gt; contentLoader.Get&amp;lt;T&amp;gt;(x.ContentLink));&lt;br /&gt;    }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;With that available validation can be wired up for the block like this:   &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&lt;br /&gt;    public class PollBlock : BlockBase, IValidate&amp;lt;PollBlock&amp;gt;&lt;br /&gt;    {&lt;br /&gt;        ...&lt;br /&gt;        &lt;br /&gt;        [Required]&lt;br /&gt;        [Display(&lt;br /&gt;            Name = &quot;Identifier&quot;,&lt;br /&gt;            Description = &quot;This value should be unique across all polls to ensure recorded data is correctly stored&quot;,&lt;br /&gt;            Order = 10)]&lt;br /&gt;        [StringLength(10)]&lt;br /&gt;        public virtual string Identifier { get; set; }&lt;br /&gt;        &lt;br /&gt;        ...&lt;br /&gt;&lt;br /&gt;        public IEnumerable&amp;lt;ValidationError&amp;gt; Validate(PollBlock instance)&lt;br /&gt;        {&lt;br /&gt;            var errors = new List&amp;lt;ValidationError&amp;gt;();&lt;br /&gt;&lt;br /&gt;            // Check whether the identifier is unique across all instances of the PollBlock&lt;br /&gt;            if (AreThereOtherBlocksWithSameIdentifier(instance))&lt;br /&gt;            {&lt;br /&gt;                errors.Add(new ValidationError&lt;br /&gt;                {&lt;br /&gt;                    ErrorMessage = &quot;The identifier provided has been used on another poll block instance.  Please choose a unique one.&quot;,&lt;br /&gt;                    PropertyName = instance.GetPropertyName(x =&amp;gt; x.Identifier),&lt;br /&gt;                    Severity = ValidationErrorSeverity.Error,&lt;br /&gt;                    ValidationType = ValidationErrorType.StorageValidation,&lt;br /&gt;                });&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            return errors.AsEnumerable();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private static bool AreThereOtherBlocksWithSameIdentifier(PollBlock instance)&lt;br /&gt;        {&lt;br /&gt;            var otherBlockInstances = instance.GetOtherContentData();&lt;br /&gt;            return otherBlockInstances&lt;br /&gt;                .Any(x =&amp;gt; x.Identifier == instance.Identifier);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;</id><updated>2016-08-25T21:27:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Validating for uniqueness with EPiServer</title><link href="https://web-matters.blogspot.com/2016/08/validating-for-uniqueness-with-episerver.html" /><id>&lt;p&gt;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 &quot;identifier&quot; 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&#39;s obviously better to validate it.&lt;/p&gt; &lt;p&gt;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:&lt;/p&gt; &lt;pre class=&quot;brush: csharp&quot;&gt;&lt;br /&gt;    public static IEnumerable&amp;lt;T&amp;gt; GetOtherContentData&amp;lt;T&amp;gt;(this T instance) where T : IContentData&lt;br /&gt;    {&lt;br /&gt;        var contentTypeRepository = ServiceLocator.Current.GetInstance&amp;lt;IContentTypeRepository&amp;gt;();&lt;br /&gt;        var contentModelUsage = ServiceLocator.Current.GetInstance&amp;lt;IContentModelUsage&amp;gt;();&lt;br /&gt;        var contentLoader = ServiceLocator.Current.GetInstance&amp;lt;IContentLoader&amp;gt;();&lt;br /&gt;        var blockType = contentTypeRepository.Load&amp;lt;T&amp;gt;();&lt;br /&gt;        var existingBlocks = contentModelUsage.ListContentOfContentType(blockType);&lt;br /&gt;        return existingBlocks&lt;br /&gt;            .Where(x =&amp;gt; contentLoader.Get&amp;lt;IContent&amp;gt;(x.ContentLink).ContentGuid != ((IContent)instance).ContentGuid)&lt;br /&gt;            .Select(x =&amp;gt; contentLoader.Get&amp;lt;T&amp;gt;(x.ContentLink));&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt; &lt;p&gt;With that available validation can be wired up for the block like this:   &lt;pre class=&quot;brush: csharp&quot;&gt;&lt;br /&gt;    public class PollBlock : BlockBase, IValidate&amp;lt;PollBlock&amp;gt;&lt;br /&gt;    {&lt;br /&gt;        ...&lt;br /&gt;        &lt;br /&gt;        [Required]&lt;br /&gt;        [Display(&lt;br /&gt;            Name = &quot;Identifier&quot;,&lt;br /&gt;            Description = &quot;This value should be unique across all polls to ensure recorded data is correctly stored&quot;,&lt;br /&gt;            Order = 10)]&lt;br /&gt;        [StringLength(10)]&lt;br /&gt;        public virtual string Identifier { get; set; }&lt;br /&gt;        &lt;br /&gt;        ...&lt;br /&gt;&lt;br /&gt;        public IEnumerable&amp;lt;ValidationError&amp;gt; Validate(PollBlock instance)&lt;br /&gt;        {&lt;br /&gt;            var errors = new List&amp;lt;ValidationError&amp;gt;();&lt;br /&gt;&lt;br /&gt;            // Check whether the identifier is unique across all instances of the PollBlock&lt;br /&gt;            if (AreThereOtherBlocksWithSameIdentifier(instance))&lt;br /&gt;            {&lt;br /&gt;                errors.Add(new ValidationError&lt;br /&gt;                {&lt;br /&gt;                    ErrorMessage = &quot;The identifier provided has been used on another poll block instance.  Please choose a unique one.&quot;,&lt;br /&gt;                    PropertyName = instance.GetPropertyName(x =&amp;gt; x.Identifier),&lt;br /&gt;                    Severity = ValidationErrorSeverity.Error,&lt;br /&gt;                    ValidationType = ValidationErrorType.StorageValidation,&lt;br /&gt;                });&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            return errors.AsEnumerable();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private static bool AreThereOtherBlocksWithSameIdentifier(PollBlock instance)&lt;br /&gt;        {&lt;br /&gt;            var otherBlockInstances = instance.GetOtherContentData();&lt;br /&gt;            return otherBlockInstances&lt;br /&gt;                .Any(x =&amp;gt; x.Identifier == instance.Identifier);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;/p&gt;</id><updated>2016-08-25T21:27:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Creating a Confirmation Email With EPiServer Forms</title><link href="http://web-matters.blogspot.com/2016/06/creating-confirmation-email-with-episerver-forms.html" /><id>&lt;p&gt;Had what probably seemed quite a straightforward request for an EPiServer site in development that&#39;s using &lt;a href=&quot;/link/1c63c14e3ef148fb8080b50b09dfeabd.aspx&quot;&gt;EPiServer Forms&lt;/a&gt; - an add-on that allows editors to create their own forms to receive input from the site visitors and review the submissions in the back-office. &amp;nbsp;They wanted a confirmation email to go to the recipient.&lt;/p&gt; &lt;p&gt;Of course though, we don&#39;t know what fields the editors are going to create. There may not be one for the visitor&#39;s email address. nd even if there were, how can we know which field is the one to use?&lt;/p&gt; &lt;p&gt;I came up with a solution to this that requires some simple conventions for the editor to follow but is quite straightforward for them to set up.&lt;/p&gt; &lt;p&gt;The first step was to create a new model for the form, inheriting from the base one provided but adding additional properties for the confirmation email details:&lt;/p&gt; &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&lt;br /&gt;    public class FormContainerWithConfirmationEmailBlock : FormContainerBlock, IHasConfirmationEmail&lt;br /&gt;    {&lt;br /&gt;        [Display(&lt;br /&gt;            Name = &quot;Tick to send a confirmation message to the user following sign-up&quot;,&lt;br /&gt;            Order = 40)]&lt;br /&gt;        public virtual bool SendConfirmationEmail { get; set; }&lt;br /&gt;&lt;br /&gt;        [Display(&lt;br /&gt;            Name = &quot;Confirmation email subject&quot;,&lt;br /&gt;            GroupName = ContentGroupNames.Content,&lt;br /&gt;            Order = 45)]&lt;br /&gt;        [StringLength(200)]&lt;br /&gt;        public virtual string ConfirmationEmailSubject { get; set; }&lt;br /&gt;&lt;br /&gt;        [Display(&lt;br /&gt;            Name = &quot;Confirmation email copy&quot;,&lt;br /&gt;            Order = 50)]&lt;br /&gt;        [PropertySettings(typeof(BasicTinyMceSettings))]&lt;br /&gt;        public virtual XhtmlString ConfirmationEmailCopy { get; set; }&lt;br /&gt;&lt;br /&gt;        public override void SetDefaultValues(ContentType contentType)&lt;br /&gt;        {&lt;br /&gt;            base.SetDefaultValues(contentType);&lt;br /&gt;            AllowAnonymousSubmission = true;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Then to allow for that model to be rendered, I similarly created a controller delegating to the provided base controller:&lt;/p&gt; &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&lt;br /&gt;    public class FormContainerWithConfirmationEmailBlockController : FormContainerBlockController&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;And a view delegating to the user control that provides the front-end and back-office rendering functionality.&lt;/p&gt; &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&lt;br /&gt;    @model FormContainerWithConfirmationEmailBlock&lt;br /&gt;&lt;br /&gt;    @Html.Partial(&quot;~/modules/_protected/EPiServer.Forms/Views/ElementBlocks/FormContainerBlock.ascx&quot;, Model)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Secondly I created a new field element type, that behaves just like a text box (I copied the user control TextboxElementBlock.ascx and saved it under a new name), but is a &quot;special&quot; one that the editors will need to use if they want the confirmation email to function. &amp;nbsp;This is added to the form for the collection of the visitor&#39;s email address.&lt;/p&gt; &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&lt;br /&gt;    public class VisitorsEmailAddressElementBlock : TextboxElementBlock&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Finally I needed to hook into the form submission event to process the confirmation email. The following code:&lt;/p&gt; &lt;ul&gt;&lt;li&gt;Checks to see if the form submission comes from a form block type that can be configured with a confirmation email&lt;/li&gt;&lt;li&gt;Checks to see if the confirmation email has been configured&lt;/li&gt;&lt;li&gt;Checks that the &quot;special&quot; field holding the visitor&#39;s email address is present and has been completed&lt;/li&gt;&lt;li&gt;And if all those are the case, sends the email&lt;/li&gt;&lt;/ul&gt; &lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&lt;br /&gt;    [ModuleDependency(typeof(EPiServer.Web.InitializationModule))]&lt;br /&gt;    public class FormSubmissionInitialization : IInitializableModule&lt;br /&gt;    {&lt;br /&gt;        public void Initialize(InitializationEngine context)&lt;br /&gt;        {&lt;br /&gt;            var eventRegistry = ServiceLocator.Current.GetInstance&amp;lt;FormsEvents&amp;gt;();&lt;br /&gt;            eventRegistry.FormsSubmissionFinalized += OnFormsSubmissionFinalized;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void Preload(string[] parameters)&lt;br /&gt;        {&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void Uninitialize(InitializationEngine context)&lt;br /&gt;        {&lt;br /&gt;            var eventRegistry = ServiceLocator.Current.GetInstance&amp;lt;FormsEvents&amp;gt;();&lt;br /&gt;            eventRegistry.FormsSubmissionFinalized += OnFormsSubmissionFinalized;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private static void OnFormsSubmissionFinalized(object sender, FormsEventArgs e)&lt;br /&gt;        {&lt;br /&gt;            HandleConfirmationEmail((FormsSubmittedEventArgs)e);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private static void HandleConfirmationEmail(FormsSubmittedEventArgs eventArgs)&lt;br /&gt;        {&lt;br /&gt;            // Even though we get back the full form block details later, do a quick cast based check here&lt;br /&gt;            // to see if we are working with a form that could have confirmation emails configured&lt;br /&gt;            var formContent = eventArgs.FormsContent as FormContainerWithConfirmationEmailBlock;&lt;br /&gt;            if (IsConfirmationEmailConfigured(formContent))&lt;br /&gt;            {&lt;br /&gt;                int fieldIdForVisitorsEmailAddress;&lt;br /&gt;                if (TryGetFieldIdForVisitorsEmailAddress(formContent, out fieldIdForVisitorsEmailAddress))&lt;br /&gt;                {&lt;br /&gt;                    string recipientEmail;&lt;br /&gt;                    if (TryExtractVisitorsEmailAddress(eventArgs, fieldIdForVisitorsEmailAddress, out recipientEmail))&lt;br /&gt;                    {&lt;br /&gt;                        // Send the email (the component called below is a simple wrapper for populating an email sending via SMTP)&lt;br /&gt;                        var confirmationEmailSender = ServiceLocator.Current.GetInstance&amp;lt;IConfirmationEmailSender&amp;gt;();&lt;br /&gt;                        confirmationEmailSender.SendConfirmationEmail(&quot;editable-form-confirmation.txt&quot;,&lt;br /&gt;                            formContent.ConfirmationEmailSubject,&lt;br /&gt;                            formContent.ConfirmationEmailCopy, recipientEmail);&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private static bool IsConfirmationEmailConfigured(FormContainerWithConfirmationEmailBlock formContent)&lt;br /&gt;        {&lt;br /&gt;            return formContent != null &amp;&amp; formContent.SendConfirmationEmail;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private static bool TryGetFieldIdForVisitorsEmailAddress(FormContainerWithConfirmationEmailBlock formContent, out int fieldId)&lt;br /&gt;        {&lt;br /&gt;            fieldId = 0;&lt;br /&gt;            var contentLoader = ServiceLocator.Current.GetInstance&amp;lt;IContentLoader&amp;gt;();&lt;br /&gt;            foreach (var element in formContent.ElementsArea.Items)&lt;br /&gt;            {&lt;br /&gt;                VisitorsEmailAddressElementBlock visitorsEmailAddressElementBlock;&lt;br /&gt;                if (contentLoader.TryGet&amp;lt;VisitorsEmailAddressElementBlock&amp;gt;(element.ContentLink,&lt;br /&gt;                    out visitorsEmailAddressElementBlock))&lt;br /&gt;                {&lt;br /&gt;                    fieldId = element.ContentLink.ID;&lt;br /&gt;                    return true;&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            return false;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private static bool TryExtractVisitorsEmailAddress(FormsSubmittedEventArgs eventArgs, int fieldIdForVisitorsEmailAddress, out string recipientEmailAddress)&lt;br /&gt;        {&lt;br /&gt;            var formData = eventArgs.SubmissionData.Data;&lt;br /&gt;            recipientEmailAddress = formData[&quot;__field_&quot; + fieldIdForVisitorsEmailAddress]?.ToString();&lt;br /&gt;            return recipientEmailAddress.IsValidEmailAddress();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;</id><updated>2016-06-24T17:21:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Working with View Models in Umbraco and EPiServer</title><link href="http://web-matters.blogspot.com/2015/12/working-with-view-models-in-umbraco-and.html" /><id>&lt;p&gt;Cross-posting an article I&#39;ve written for my company Zone&#39;s Medium blog.  I&#39;ve written about techniques for using strongly typed view models with Umbraco here before - in this article I recap some of that and extend the discussion to EPiServer CMS too.&lt;/p&gt;&lt;p&gt;You can read and comment on the article &lt;a href=&quot;https://medium.com/@ThisisZone/working-with-view-models-in-umbraco-and-episerver-7ab1b01668df&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;</id><updated>2015-12-31T16:58:00.0000000Z</updated><summary type="html">Blog post</summary></entry></feed>