<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Blog posts by Ram Kumar K</title><link href="http://world.optimizely.com" /><updated>2020-12-23T21:01:12.0000000Z</updated><id>https://world.optimizely.com/blogs/ram-kumar-k/</id> <generator uri="http://world.optimizely.com" version="2.0">Optimizely World</generator> <entry><title>Guided Journey – Developing a Wizard Component using EPiServer CMS</title><link href="https://world.optimizely.com/blogs/ram-kumar-k/dates/2020/12/guided-journey--developing-a-wizard-component-using-episerver-cms/" /><id>&lt;h1&gt;Guided Journey &amp;ndash; Developing a Wizard Component using EpiServer CMS&lt;/h1&gt;
&lt;h2&gt;&amp;nbsp;&lt;strong&gt;Requirement:&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The purpose of the online guided journey is to showcase all programs or services offered by MEDC and its partners in the state of Michigan. By self-identifying, a user will be able to quickly get to a listing of resources available along with a link to where more information can be found on each of the programs or services.&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Functional Prototype Design:&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;img src=&quot;https://rkepiserverblob.blob.core.windows.net/wizardblob/Guided_Journey_Requirement.gif&quot; alt=&quot;Guided&amp;#32;Journey&amp;#32;Requirements&quot; /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Development Approach:&lt;/h2&gt;
&lt;p&gt;The user must choose a path to go down to.&lt;/p&gt;
&lt;p&gt;We would like to build ourselves a cool, simple, and flexible wizard component block using Episerver CMS, Bootstrap, and frontend JavaScript framework.&lt;/p&gt;
&lt;p&gt;We would like to make this component as simple and user friendly as possible for content authors to create Guided Journeys.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When the user clicks on Path 1,&amp;nbsp; we provide them with options to choose from Path 1.1, path 1.2, and Path 1.3, and if they click on Path 1.1, they will be given options to choose Path 1.1.1, Path 1.1.2, Path 1.1.3, and so on.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;strong&gt;The following illustrates the requirement from the Architect&#39;s point of view.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This can be achieved in different ways, using nested blocks (performance and maintenance nightmare?), or link list (maybe). I choose my new fascination &amp;ldquo;Generic Property List&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;img src=&quot;/link/a358d3a7f36f4bac820ec54c5a08a96f.aspx&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Based on the prototype, the guided Journey requires the following&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;Step Image &amp;ndash; Contentreference/URL&lt;/li&gt;
&lt;li&gt;Step Title- String&lt;/li&gt;
&lt;li&gt;Path Data - &lt;a href=&quot;/link/5639beae3dc9454cbe72a4a3106de560.aspx&quot;&gt;Custom PropertyList&lt;/a&gt;
&lt;ol&gt;
&lt;li&gt;Path Title - String&lt;/li&gt;
&lt;li&gt;Path Description (Needed for end of Journey modal) - XHTMLString&lt;/li&gt;
&lt;li&gt;Path Resource Link (Needed for end of Journey modal) - URL&lt;/li&gt;
&lt;li&gt;Step Image - Contentreference/URL&lt;/li&gt;
&lt;li&gt;Step Title - String&lt;/li&gt;
&lt;li&gt;Path Data - &lt;a href=&quot;/link/5639beae3dc9454cbe72a4a3106de560.aspx&quot;&gt;Custom PropertyList&lt;/a&gt;
&lt;ol&gt;
&lt;li&gt;Path Title&lt;/li&gt;
&lt;li&gt;Path Description (Needed for end of Journey modal)&lt;/li&gt;
&lt;li&gt;Path Resource Link (Needed for end of Journey modal)&lt;/li&gt;
&lt;li&gt;Step Image&lt;/li&gt;
&lt;li&gt;Step Title&lt;/li&gt;
&lt;li&gt;Path Data&lt;/li&gt;
&lt;li&gt;Not sure Text&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Not Sure Text - XHTMLString&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Not sure text - XHTMLString&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Each step is a JSON object, the Path data property from the step object is an array of more steps (nested JSON object).&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;CMS Generic property list used in Block:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/b72bd8dd9c2c4ab0abc8fedac0984631.aspx&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;img src=&quot;https://rkepiserverblob.blob.core.windows.net/wizardblob/Guided_Journey_CMS_Block.gif&quot; width=&quot;1292&quot; alt=&quot;Guided&amp;#32;Journey&amp;#32;CMS&amp;#32;Block&quot; height=&quot;812&quot; /&gt;&lt;/p&gt;
&lt;p&gt;JSON Output:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;img src=&quot;/link/eb76f5af270748f0ab7c0add94574598.aspx&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Wizard component block on a page:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://rkepiserverblob.blob.core.windows.net/wizardblob/Guided_Journey_Wizard_Final.gif&quot; width=&quot;1292&quot; alt=&quot;Guided&amp;#32;Journey&amp;#32;Wizard&quot; height=&quot;812&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&quot;A successful application never really is complete but is constantly being improved, hopefully based around users needs.&quot;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Please share your comments if you would like to approach it differently.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;ldquo;Wishing you a season that&amp;rsquo;s merry and bright with the light of God&amp;rsquo;s love.&amp;rdquo;&amp;nbsp;&lt;/p&gt;</id><updated>2020-12-23T21:01:12.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Required Field Validation for Category</title><link href="https://world.optimizely.com/blogs/ram-kumar-k/dates/2018/10/required-field-validation-for-category/" /><id>&lt;p&gt;We all have come across specific requirements for CMS Content authors.&amp;nbsp;One of such requirement for our news sections is, &quot;Every news article belongs to one or more categories&quot;. We must force user to select a category before publish it. We have used a Custom validation rule to fulfill this requirement.&lt;/p&gt;
&lt;p&gt;Episerver Documentation:&amp;nbsp;https://world.episerver.com/documentation/developer-guides/CMS/Content/Properties/built-in-property-types/Writing-custom-attributes/&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;  /// &amp;lt;summary&amp;gt;
     /// Required field validation for Category.
    ///Reference: https://world.episerver.com/documentation/developer-guides/CMS/Content/Properties/built-in-property-types/Writing-custom-attributes/
    /// &amp;lt;/summary&amp;gt;

  [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
    public class FieldRequiredForPublishAttribute : ValidationAttribute
    {
        public bool IsRequired { get; set; }
        public FieldRequiredForPublishAttribute() : this(true) { }
        public FieldRequiredForPublishAttribute(bool isRequired)
        {
            IsRequired = isRequired;
        }

        public override bool IsValid(object value)
        {
            if (value == null) return false;        
            if (value is CategoryList cat) return cat?.Any() == true;          
            return false;
        }

        public override string FormatErrorMessage(string name)
        {
                return $&quot;{name} cannot be empty&quot;;
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Set RequiredFieldAttribute for News Pages.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;        [Display(
              Name = &quot;News Category (*)&quot;,
              Description = &quot;Select News Category&quot;,
              GroupName = SystemTabNames.Content,
              Order = 3)]
          [FieldRequiredForPublish]
        public override CategoryList Category { get; set; }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;The code is generic enough that you can extend to make any field requied.&lt;/p&gt;
&lt;p&gt;Thank you&amp;nbsp; &amp;amp; happy coding!&lt;/p&gt;</id><updated>2018-10-07T14:49:02.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Using Azure Cloud for Storing Episerver CMS Blobs</title><link href="https://world.optimizely.com/blogs/ram-kumar-k/dates/2018/3/using-azure-cloud-for-storing-episerver-cms-blobs/" /><id>&lt;!DOCTYPE html&gt;
 
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Using Azure Cloud for Storing Episerver CMS Blobs - &lt;/title&gt;
&lt;meta name=&quot;author&quot; content=&quot;Ram Kumar K&quot; /&gt;
&lt;meta name=&quot;keywords&quot; content=&quot;Episerver CMS Blob Storage&quot; /&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;p&gt;Working with multiple developers in the Episerver Environment requires sharing&amp;nbsp;Blobs.&amp;nbsp; One of the best options&amp;nbsp;our team agreed on&amp;nbsp;was using &lt;a href=&quot;https://azure.microsoft.com/en-us/pricing/member-offers/credit-for-visual-studio-subscribers/&quot;&gt;Free Azure&lt;/a&gt; account to do a POC.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The following would help you to set-up storage account in Azure and use that as a default blob provider for your Episerver project.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a storage account by using the Azure portal&lt;/li&gt;
&lt;li&gt;Create a Resource, Resource Group &amp;amp; Storage Account&lt;/li&gt;
&lt;li&gt;Create Container and Get&amp;nbsp;Access keys&lt;/li&gt;
&lt;li&gt;Install Azure Packages in Episerver&lt;/li&gt;
&lt;li&gt;Transfer files&amp;nbsp;using&amp;nbsp; AzCopy&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;1) Create a storage account by using the Azure portal&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Login to Azure Site using the following Link&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://portal.azure.com/&quot;&gt;https://portal.azure.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/4dd05b6b77654fc38eae1148566d2576.aspx&quot; alt=&quot;Image Azure_1.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2)&amp;nbsp;Create a Resource, Resource Group &amp;amp; Storage Account&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Resource&lt;/strong&gt;: &amp;nbsp;A manageable item that is available through Azure.&amp;nbsp; EX: Storage account, Web app, Database, VM&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Resource Group&lt;/strong&gt;: A container that holds related resources for an Azure solution.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Storage Account&lt;/strong&gt;: A general-purpose storage account provides access to all of the Azure Storage services: blobs, files, queues, and tables.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/5b02df9334fb46c28e89467f16dc0c84.aspx&quot; alt=&quot;Image Azure_2.PNG&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2) Resource Group:&lt;/strong&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;img src=&quot;/link/a767d97a4d2d4c69b13ce4768148cfb1.aspx&quot; alt=&quot;Image Azure_REsource_Group2.png&quot; /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2) Storage Account&lt;/strong&gt;&lt;strong&gt;&amp;nbsp;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;img src=&quot;/link/7a3e58fc202e49c9b81a3366bb1435ac.aspx&quot; alt=&quot;Image Azure_Storage_Account2.png&quot; /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3)Create Container and Get&amp;nbsp;Access keys&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;After creating the storage account, you can add a container and get keys for&amp;nbsp;the storage account to access them in Episerver CMS. The connectionstring info is used to connect the Azure storage.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;img src=&quot;/link/83ac3f6cb74041a9a07da0cad74583f3.aspx&quot; alt=&quot;Image Azure_Storage_Container2.png&quot; /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/8f1ef5671c4d46c996e51405afde2d3d.aspx&quot; alt=&quot;Image Azure_Storage_Container_Access2.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4) Install Azure Packages in Episerver CMS Project.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Add &lt;a href=&quot;http://nuget.episerver.com/package-details/?packageId=EPiServer.Azure&quot;&gt;EPiServer Azure Nuget&lt;/a&gt; Package&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/b69939c1b8e94e939a7a59c852252652.aspx&quot; alt=&quot;Image Episerver_Azure_Nuget.PNG&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4) Add&amp;nbsp; the following in in web.config&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Change Blob provider&amp;nbsp;: &quot;&lt;strong&gt;mycontainer&lt;/strong&gt;&quot; is name of your Azure Blob Storage Container&lt;/p&gt;
&lt;pre class=&quot;language-xml&quot;&gt;&lt;code&gt; &amp;lt;blob defaultProvider=&quot;azureblobs&quot;&amp;gt;
      &amp;lt;providers&amp;gt;
        &amp;lt;add name=&quot;azureblobs&quot; type=&quot;EPiServer.Azure.Blobs.AzureBlobProvider,EPiServer.Azure&quot;
              connectionStringName=&quot;EPiServerAzureBlobs&quot; container=&quot;mycontainer&quot;/&amp;gt;
      &amp;lt;/providers&amp;gt;
    &amp;lt;/blob&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-xml&quot;&gt;&lt;code&gt;&lt;br /&gt;Add connection string&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-xml&quot;&gt;&lt;code&gt;&amp;lt;connectionStrings&amp;gt;
    &amp;lt;add name=&quot;EPiServerAzureBlobs&quot; connectionString=&quot;DefaultEndpointsProtocol=https;AccountName=myaccount;AccountKey=abcdefghij&quot; /&amp;gt;
  &amp;lt;/connectionStrings&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-xml&quot;&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;5) Upload/Transfer blobs using &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/storage/common/storage-use-azcopy&quot;&gt;AzCopy&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://aka.ms/downloadazcopy&quot;&gt;AzCopy&lt;/a&gt; is a command-line utility designed for copying data to/from Microsoft Azure Blob&lt;/li&gt;
&lt;li&gt;AzCopy /Source:C:\myfolder /Dest:https://myaccount.blob.core.windows.net/mycontainer /DestKey:key /S&lt;/li&gt;
&lt;li&gt;&lt;img src=&quot;/link/4b3763e5d750444ca4b3f6a52c80de53.aspx&quot; alt=&quot;Image AZure_copy.png&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That&#39;s it. Run the website and You are using Azure storage for blobs. This would help&amp;nbsp;your team in the multi-developer environment and remote development as well.&lt;/p&gt;
&lt;p&gt;This POC was done using free VS subscription and we have moved to Gov Cloud now.&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Reference:&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/storage/common/storage-create-storage-account?toc=%2fazure%2fstorage%2fblobs%2ftoc.json&quot;&gt;Azure Quick Start&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;</id><updated>2018-03-24T15:27:36.0000000Z</updated><summary type="html">Blog post</summary></entry></feed>