<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Akshay Sura</title>
    <link>https://akshaysura.com/</link>
    <description>Practical, first-person notes on Sitecore, .NET, and the web from Akshay Sura.</description>
    <language>en-US</language>
    <item>
      <title>Sitecore Precision Scheduling with SiteCron 3.0.4 released in powerful ways!</title>
      <link>https://akshaysura.com/blog/sitecore-precision-scheduling-with-sitecron-3-0-4-released-in-powerful-ways/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/sitecore-precision-scheduling-with-sitecron-3-0-4-released-in-powerful-ways/</guid>
      <pubDate>Thu, 19 Apr 2018 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[SiteCron 3.0.4 has been released.]]></description>
      <content:encoded><![CDATA[<p>SiteCron 3.0.4 has been released.</p>
<p><strong>SiteCron NuGet Link:</strong> <a href="https://www.nuget.org/packages/SiteCron" target="_blank" rel="noopener">https://www.nuget.org/packages/SiteCron</a></p>
<p><strong>SiteCron GitHub Link:</strong> <a href="https://github.com/akshaysura/Sitecron" target="_blank" rel="noopener">https://github.com/akshaysura/Sitecron</a></p>
<p><strong>SiteCron Marketplace Link:</strong> <a href="https://marketplace.sitecore.net/Modules/S/Sitecron.aspx?sc_lang=en" target="_blank" rel="noopener">https://marketplace.sitecore.net/Modules/S/Sitecron.aspx?sc_lang=en</a></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2018/04/cron34.jpg"><img loading="lazy" class="alignnone wp-image-3211 size-full" src="https://akshaysura.com/wp-content/uploads/2018/04/cron34.jpg" alt="" width="1117" height="1188" /></a></p>
<p>&nbsp;</p>
<h2>Credit where its due!</h2>
<p>Credit for this release goes to <a href="https://twitter.com/BenGGolden" target="_blank" rel="noopener">Ben Golden</a>.</p>
<p>&nbsp;</p>
<h2>What&#8217;s New?</h2>
<p>Lets look at what was added. Please remember to Merge &#8211; Append when installing the package if you are upgrading.</p>
<p>1. Add SiteCron jobs via config files, that&#8217;t right a config file!</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2018/04/cron-config-34.jpg"><img loading="lazy" class="alignnone size-full wp-image-3212" src="https://akshaysura.com/wp-content/uploads/2018/04/cron-config-34.jpg" alt="" width="882" height="739" /></a></p>
<p>2. Switch between DB mode, config mode or a mixed mode to load your SiteCron jobs.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2018/04/job-provider-cron34.jpg"><img loading="lazy" class="alignnone size-full wp-image-3213" src="https://akshaysura.com/wp-content/uploads/2018/04/job-provider-cron34.jpg" alt="" width="1177" height="254" /></a></p>
<p>&nbsp;</p>
<p>If you have any questions or concerns, please get in touch with me. (<a href="https://twitter.com/akshaysura13" target="_blank" rel="noopener">@akshaysura13</a> on twitter or on Slack).</p>
<p>&nbsp;</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/12/a5ba19c52eabda5b504fa11d37ff2653.gif"><img loading="lazy" class="alignnone size-full wp-image-3174" src="https://akshaysura.com/wp-content/uploads/2017/12/a5ba19c52eabda5b504fa11d37ff2653.gif" alt="" width="224" height="144" /></a></p>
<p>&nbsp;</p>
]]></content:encoded>
    </item>
    <item>
      <title>Sitecore Precision Scheduling with SiteCron 3.0.2 released in powerful ways!</title>
      <link>https://akshaysura.com/blog/sitecore-precision-scheduling-with-sitecron-3-0-2-released-in-powerful-ways/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/sitecore-precision-scheduling-with-sitecron-3-0-2-released-in-powerful-ways/</guid>
      <pubDate>Tue, 10 Apr 2018 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[SiteCron 3.0.2 has been released.]]></description>
      <content:encoded><![CDATA[<p>SiteCron 3.0.2 has been released.</p>
<p><strong>SiteCron NuGet Link:</strong> <a href="https://www.nuget.org/packages/SiteCron" target="_blank" rel="noopener">https://www.nuget.org/packages/SiteCron</a></p>
<p><strong>SiteCron GitHub Link:</strong> <a href="https://github.com/akshaysura/Sitecron" target="_blank" rel="noopener">https://github.com/akshaysura/Sitecron</a></p>
<p><strong>SiteCron Marketplace Link:</strong> <a href="https://marketplace.sitecore.net/Modules/S/Sitecron.aspx?sc_lang=en" target="_blank" rel="noopener">https://marketplace.sitecore.net/Modules/S/Sitecron.aspx?sc_lang=en</a></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2018/04/302.jpg"><img loading="lazy" class="alignnone wp-image-3207 size-full" src="https://akshaysura.com/wp-content/uploads/2018/04/302.jpg" alt="" width="1123" height="1021" /></a></p>
<p>&nbsp;</p>
<h2>Credit where its due!</h2>
<p>Credit for this release goes to <a href="https://twitter.com/BenGGolden" target="_blank" rel="noopener">Ben Golden</a> and <a href="https://twitter.com/sitecorey" target="_blank" rel="noopener">Corey Smith</a>. <a href="https://twitter.com/mike_i_reynolds" target="_blank" rel="noopener">Mike Goldsuit Reynolds</a> also chimed in with some help.</p>
<p>&nbsp;</p>
<h2>What&#8217;s New?</h2>
<p>Lets look at what was added. Please remember to Merge &#8211; Append when installing the package if you are upgrading.</p>
<p>1. Added a check to add CRON Expression validation.</p>
<p>2. Added a check for Standard Values updates.</p>
<p>3. Added an IJob type that will let you run a SiteCron job as a Sitecore Job. You can now run a parameterless method from any of the loaded libraries.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2018/04/sitecron302.jpg"><img loading="lazy" class="alignnone size-full wp-image-3204" src="https://akshaysura.com/wp-content/uploads/2018/04/sitecron302.jpg" alt="" width="591" height="616" /></a></p>
<p>4. Added an IJob type to help you run the Sitecore Command assigned to a Sitecore Scheduled Job item.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2018/04/sitecron302sitecorejob.jpg"><img loading="lazy" class="alignnone size-full wp-image-3205" src="https://akshaysura.com/wp-content/uploads/2018/04/sitecron302sitecorejob.jpg" alt="" width="715" height="554" /></a></p>
<p>&nbsp;</p>
<p>If you have any questions or concerns, please get in touch with me. (<a href="https://twitter.com/akshaysura13" target="_blank" rel="noopener">@akshaysura13</a> on twitter or on Slack).</p>
<p>&nbsp;</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/12/a5ba19c52eabda5b504fa11d37ff2653.gif"><img loading="lazy" class="alignnone size-full wp-image-3174" src="https://akshaysura.com/wp-content/uploads/2017/12/a5ba19c52eabda5b504fa11d37ff2653.gif" alt="" width="224" height="144" /></a></p>
<p>&nbsp;</p>
]]></content:encoded>
    </item>
    <item>
      <title>Sitecore Precision Scheduling with SiteCron 3.0 released in powerful ways!</title>
      <link>https://akshaysura.com/blog/sitecore-precision-scheduling-with-sitecron-3-0-released-in-powerful-ways/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/sitecore-precision-scheduling-with-sitecron-3-0-released-in-powerful-ways/</guid>
      <pubDate>Thu, 29 Mar 2018 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[SiteCron 3.0 has been released and I cannot believe there are 7,237 downloads. I never ever thought that it will be used by this many people.]]></description>
      <content:encoded><![CDATA[<p>SiteCron 3.0 has been released and I cannot believe there are <strong>7,237</strong> downloads. I never ever thought that it will be used by this many people.</p>
<p><strong>SiteCron NuGet Link:</strong> <a href="https://www.nuget.org/packages/SiteCron" target="_blank" rel="noopener">https://www.nuget.org/packages/SiteCron</a></p>
<p><strong>SiteCron GitHub Link:</strong> <a href="https://github.com/akshaysura/Sitecron" target="_blank" rel="noopener">https://github.com/akshaysura/Sitecron</a></p>
<p><strong>SiteCron Marketplace Link:</strong> <a href="https://marketplace.sitecore.net/Modules/S/Sitecron.aspx?sc_lang=en" target="_blank" rel="noopener">https://marketplace.sitecore.net/Modules/S/Sitecron.aspx?sc_lang=en</a></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2018/03/sitecron3.jpg"><img loading="lazy" class="alignnone size-full wp-image-3189" src="https://akshaysura.com/wp-content/uploads/2018/03/sitecron3.jpg" alt="" width="1128" height="783" /></a></p>
<p>&nbsp;</p>
<h2>Credit where its due!</h2>
<p>As you know I use SiteCron every day. Often the new features are based on the current needs of the project I am working on but lately it has been the developers who have been using the module. It was truly humbling to see my small module being used by huge organizations at a great scale. I never imagined that this would be the case.</p>
<p>This release was primarily fueled by the pull request by <a href="https://twitter.com/BenGGolden" target="_blank" rel="noopener">Ben Golden</a>. Ben refactored majority of the codebase in an effort to add in Dependency Injection and also add the ability to have template inheritance for SiteCron jobs. This along with bug reports by <a href="https://github.com/Trisco" target="_blank" rel="noopener">Trisco</a> &amp; functionality requests I needed for my projects made the bulk of this release.</p>
<p>I always say that the Sitecore community is unique because of its Community. Like always I had <a href="https://twitter.com/mike_i_reynolds" target="_blank" rel="noopener">Mike Goldsuit Reynolds</a> &amp; <a href="https://twitter.com/jammykam" target="_blank" rel="noopener">Kamruz RealKAM Jaman</a> whom I was able to use as a sounding board and get advice.</p>
<p>&nbsp;</p>
<h2>What&#8217;s New?</h2>
<p>Lets look at what was added. Please remember to Merge &#8211; Append when installing the package if you are upgrading.<br />
1. New Icon for the SiteCron node 😉</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2018/03/newsitecronitems.jpg"><img loading="lazy" src="https://akshaysura.com/wp-content/uploads/2018/03/newsitecronitems.jpg" alt="" width="307" height="153" /></a></p>
<p>2. <a href="https://github.com/akshaysura/Sitecron/issues/4" target="_blank" rel="noopener">Fixed ExecuteExactlyAtDateTime past bug</a><br />
3. Code refactoring and introduced DI<br />
4. Ability to run jobs which inherit from the SiteCronJob template (this is very helpful to customize)<br />
5. Ability to provide Script log so that Execution Reports can be stored (more on this later)</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2018/03/spescript.jpg"><img loading="lazy" class="alignnone size-full wp-image-3193" src="https://akshaysura.com/wp-content/uploads/2018/03/spescript.jpg" alt="" width="933" height="326" /></a></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2018/03/executionreportspe.jpg"><img loading="lazy" class="alignnone size-full wp-image-3194" src="https://akshaysura.com/wp-content/uploads/2018/03/executionreportspe.jpg" alt="" width="1017" height="339" /></a></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2018/03/ijob.jpg"><img loading="lazy" class="alignnone size-full wp-image-3195" src="https://akshaysura.com/wp-content/uploads/2018/03/ijob.jpg" alt="" width="1457" height="659" /></a></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2018/03/ijobexecution.jpg"><img loading="lazy" class="alignnone size-full wp-image-3196" src="https://akshaysura.com/wp-content/uploads/2018/03/ijobexecution.jpg" alt="" width="978" height="347" /></a></p>
<p>6. New Log4net appender to store logs outside of the log.txt files</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2018/03/sitecron-log.jpg"><img loading="lazy" src="https://akshaysura.com/wp-content/uploads/2018/03/sitecron-log.jpg" alt="" width="1236" height="221" /></a></p>
<p>7. Configuration was modified to add a few more settings and also modified a couple</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2018/03/sitecron3config.jpg"><img loading="lazy" class="alignnone wp-image-3190 size-full" src="https://akshaysura.com/wp-content/uploads/2018/03/sitecron3config.jpg" alt="" width="1166" height="959" /></a></p>
<p>8.The SiteCron Execution Reports item bucket is set to Never Publish so that it does not slow down your publishing.</p>
<p>&nbsp;</p>
<p>If you have any questions or concerns, please get in touch with me. (<a href="https://twitter.com/akshaysura13" target="_blank" rel="noopener">@akshaysura13</a> on twitter or on Slack).</p>
<p>&nbsp;</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/12/a5ba19c52eabda5b504fa11d37ff2653.gif"><img loading="lazy" class="alignnone size-full wp-image-3174" src="https://akshaysura.com/wp-content/uploads/2017/12/a5ba19c52eabda5b504fa11d37ff2653.gif" alt="" width="224" height="144" /></a></p>
<p>&nbsp;</p>
]]></content:encoded>
    </item>
    <item>
      <title>Sitecore Precision Scheduling with SiteCron 2.1.8 released in powerful ways!</title>
      <link>https://akshaysura.com/blog/sitecore-precision-scheduling-with-sitecron-2-1-8-released-in-powerful-ways/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/sitecore-precision-scheduling-with-sitecron-2-1-8-released-in-powerful-ways/</guid>
      <pubDate>Mon, 04 Dec 2017 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[SiteCron 2.1.8 has been released and I cannot believe there are 3,682 downloads.]]></description>
      <content:encoded><![CDATA[<p>SiteCron 2.1.8 has been released and I cannot believe there are <strong>3,682</strong> downloads.</p>
<p><strong>SiteCron NuGet Link:</strong> <a href="https://www.nuget.org/packages/SiteCron" target="_blank" rel="noopener">https://www.nuget.org/packages/SiteCron</a></p>
<p><strong>SiteCron GitHub Link:</strong> <a href="https://github.com/akshaysura/Sitecron" target="_blank" rel="noopener">https://github.com/akshaysura/Sitecron</a></p>
<p><strong>SiteCron Marketplace Link:</strong> <a href="https://marketplace.sitecore.net/Modules/S/Sitecron.aspx?sc_lang=en" target="_blank" rel="noopener">https://marketplace.sitecore.net/Modules/S/Sitecron.aspx?sc_lang=en</a></p>
<p>&nbsp;</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/12/sitecron218.jpg"><img loading="lazy" class="alignnone size-full wp-image-3163" src="https://akshaysura.com/wp-content/uploads/2017/12/sitecron218.jpg" alt="" width="1129" height="1022" /></a></p>
<h2>What&#8217;s New?</h2>
<p>I use SiteCron every day and based on my project needs, I evolve it. Please remember to Merge &#8211; Append when installing the package if you are upgrading.</p>
<ol>
<li>Modify Icon when the SiteCron scheduling item is disabled</li>
<li>Modify SiteCron scheduling item Display Name when the job is disabled</li>
<li>Ability to Execute Now! on any SiteCron job.<br />
<a href="https://akshaysura.com/wp-content/uploads/2017/12/execute-now.jpg"><img loading="lazy" class="alignnone size-full wp-image-3164" src="https://akshaysura.com/wp-content/uploads/2017/12/execute-now.jpg" alt="" width="925" height="450" /></a></li>
<li>New Stats section to log, LastRun, NextRun, Execution Time and Last Run Log.<br />
<a href="https://akshaysura.com/wp-content/uploads/2017/12/stats.jpg"><img loading="lazy" class="alignnone size-full wp-image-3166" src="https://akshaysura.com/wp-content/uploads/2017/12/stats.jpg" alt="" width="486" height="446" /></a></li>
<li>Schedule helping passing in the current scheduling SiteCron ItemID as zSiteCronItemID to all jobs<br />
<a href="https://akshaysura.com/wp-content/uploads/2017/12/params.jpg"><img loading="lazy" class="alignnone size-full wp-image-3167" src="https://akshaysura.com/wp-content/uploads/2017/12/params.jpg" alt="" width="754" height="138" /></a></li>
<li>Configuration was modified to add a few more settings<br />
<a href="https://akshaysura.com/wp-content/uploads/2017/12/config.jpg"><img loading="lazy" class="alignnone size-full wp-image-3168" src="https://akshaysura.com/wp-content/uploads/2017/12/config.jpg" alt="" width="1147" height="626" /></a></li>
<li><strong>HIGHLY EXPERIMENTAL</strong>: Added the ability to extend the Save Item Handler inside of SiteCron. With this you could do several things, one which comes to mind is the ability to schedule item publishes based on Publish Restrictions.<br />
<a href="https://akshaysura.com/wp-content/uploads/2017/12/highgly.jpg"><img loading="lazy" class="alignnone size-full wp-image-3169" src="https://akshaysura.com/wp-content/uploads/2017/12/highgly.jpg" alt="" width="1177" height="204" /></a><br />
<a href="https://akshaysura.com/wp-content/uploads/2017/12/publish1.jpg"><img loading="lazy" class="alignnone size-full wp-image-3170" src="https://akshaysura.com/wp-content/uploads/2017/12/publish1.jpg" alt="" width="998" height="618" /></a><br />
<a href="https://akshaysura.com/wp-content/uploads/2017/12/publish2.jpg"><img loading="lazy" class="alignnone size-full wp-image-3171" src="https://akshaysura.com/wp-content/uploads/2017/12/publish2.jpg" alt="" width="1001" height="611" /></a></li>
<li>Finally added both item only package and a full install Sitecore package with items and files to avoid code deployment. I requested an update on the marketplace but not sure how long the approval process will take.</li>
<li>Execute Exactly At a Specific Date Time was added. Using this field you can trigger a job at a specific date time. Why is it so different than a Cron Expression you ask, well Cron Expression based scheduling is typically recurring. You can execute a one time job but if I were to schedule publishing restrictions based item publishes, this field was necessary to facilitate that.</li>
</ol>
<p>&nbsp;</p>
<p>If you have any questions or concerns, please get in touch with me. (<a href="https://twitter.com/akshaysura13" target="_blank" rel="noopener">@akshaysura13</a> on twitter or on Slack).</p>
<p>&nbsp;</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/12/a5ba19c52eabda5b504fa11d37ff2653.gif"><img loading="lazy" class="alignnone size-full wp-image-3174" src="https://akshaysura.com/wp-content/uploads/2017/12/a5ba19c52eabda5b504fa11d37ff2653.gif" alt="" width="224" height="144" /></a></p>
<p>&nbsp;</p>
]]></content:encoded>
    </item>
    <item>
      <title>TIHIDI: Sitecore Scheduling with SiteCron 2.1.8 in powerful ways!</title>
      <link>https://akshaysura.com/blog/tihidi-sitecore-scheduling-with-sitecron-2-1-8-in-powerful-ways/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/tihidi-sitecore-scheduling-with-sitecron-2-1-8-in-powerful-ways/</guid>
      <pubDate>Mon, 04 Dec 2017 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[I have been using SiteCron for a while now and I get a steady stream of questions about the module. I thought its time I documented how I use SiteCron.]]></description>
      <content:encoded><![CDATA[<p>I have been using SiteCron for a while now and I get a steady stream of questions about the module. I thought its time I documented how I use SiteCron.</p>
<p>I do have some custom implementations of the IJob interface but I use PowerShell based jobs predominantly.</p>
<p>First go through some of my <a href="https://akshaysura.com/?s=sitecron" target="_blank" rel="noopener">previous posts about SiteCron</a>. Once SiteCron is installed and you are ready to rock, there is no better place to start than Sitecore PowerShell.</p>
<p>I get most of my work done via PowerShell scripts and this should not be any different.</p>
<p>SiteCron by default comes with a PowerShell Job which you can use.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/12/powershellsample.jpg"><img loading="lazy" class="alignnone size-full wp-image-3181" src="https://akshaysura.com/wp-content/uploads/2017/12/powershellsample.jpg" alt="" width="928" height="845" /></a></p>
<p>Here are a few tips which help me:</p>
<ul>
<li>Create a new SiteCron job and update the Type using the sample Execute PowerShell Script job.</li>
<li>Remember the Default PowerShell Job included out of the box only uses the first item in the Items field. This is to make sure that there is no recurrence, which means that you can only run one PowerShell script item at once. If you have a different need, utilize the code in the default PowerShell Job.</li>
<li>All of my jobs are automated and run at odd times. Make sure your Sitecore Instance running the jobs is up and running. I usually do this by running a Windows scheduler to call the instance url based on the needs.</li>
<li>Add the context db in your scripts.<br />
<em>&lt;# Set DB Context as Master #&gt;</em><br />
<em> Set-Location master:</em></li>
<li>Non-console based output might cause issues so use SilentlyContinue.<br />
<em>$ProgressPreference = &#8216;SilentlyContinue&#8217;</em></li>
<li>Run in admin context when you can.<br />
<em>$admin = [Sitecore.Security.Accounts.User]::FromName(&#8220;sitecore\admin&#8221;, $false)</em><br />
<em> [Sitecore.Security.Accounts.UserSwitcher]::Enter($admin)</em></li>
<li>Use the zSiteCronItemID which gets passed in by SiteCron and write the LastRunLog in the Scheduled Item Job.
<ul>
<li><em>$script:logEntries = &#8220;&#8221;</em></li>
<li><em>function WriteToLog($message)</em><br />
<em> {</em><br />
<em> Write-Log $message</em><br />
<em> $script:logEntries += $(Get-Date –f o) + &#8220; &#8221; + $message + &#8220;`n&#8221;</em><br />
<em> }</em></li>
<li><em>finally</em><em> {</em><br />
<em> if($zSiteCronItemID) {</em><br />
<em> $scheduleItem = Get-Item master: -ID $zSiteCronItemID</em><br />
<em> if($scheduleItem)</em><br />
<em> {</em><br />
<em> $scheduleItem.Editing.BeginEdit()</em><br />
<em> $scheduleItem[&#8220;LastRunLog&#8221;]=$script:logEntries</em><br />
<em> $scheduleItem=$scheduleItem.Editing.EndEdit()</em><br />
<em> }</em><br />
<em> }</em></li>
</ul>
</li>
</ul>
<p><em> </em></p>
<p><strong>TIHIDI: Stands for This Is How I Do It. I am going to write a series of blog posts going through how I do Sitecore related work. Hope it helps you!</strong></p>
<p>If you have any questions or concerns, please get in touch with me. (<a href="https://twitter.com/akshaysura13" target="_blank" rel="noopener">@akshaysura13</a> on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>Sitecore 9 Config Layers - Load Sequence</title>
      <link>https://akshaysura.com/blog/sitecore-9-config-layers-load-sequence/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/sitecore-9-config-layers-load-sequence/</guid>
      <pubDate>Tue, 17 Oct 2017 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Most of you are at the Sitecore Symposium 2017 in Vegas with me to witness the launch of Sitecore 9.]]></description>
      <content:encoded><![CDATA[<p>Most of you are at the Sitecore Symposium 2017 in Vegas with me to witness the launch of Sitecore 9.</p>
<p>One feature which has been refined in this release is the loading of the Configuration files. We can find a ton of code and modules for this specific section to control what gets loaded first etc.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/10/Sitecore-9-Is-here.png"><img loading="lazy" class="alignnone size-full wp-image-3157" src="https://akshaysura.com/wp-content/uploads/2017/10/Sitecore-9-Is-here.png" alt="" width="440" height="440" /></a></p>
<p><em>Not the official logo. Credit goes to <a href="https://twitter.com/jammykam" target="_blank" rel="noopener">Kamruz Jaman</a> for creating it.</em></p>
<p>&nbsp;</p>
<p>With Sitecore 9 the configuration loading is organized in the layers. With the introduction of layers, we have a new config file in App_Config called Layers.config. The following is an example:</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/10/layers.png"><img loading="lazy" class="alignnone size-full wp-image-3153" src="https://akshaysura.com/wp-content/uploads/2017/10/layers.png" alt="" width="659" height="1004" /></a></p>
<h3>Load Order</h3>
<p>First Sitecore reads Web.Config, App_Config\ConnectionStrings.config and App_Config\Layers.config.</p>
<p>As you can see from the screenshot above, Layers.config by default contains 4 layers and they are loaded in the sequence as defined in the Layers.config file.</p>
<ol>
<li>Sitecore configs</li>
<li>Module configs (modules such as SPE, Publishing service etc)</li>
<li>Custom configs (all your customizations to Sitecore)</li>
<li>and lastly Environment configs (Environment specific configs)</li>
</ol>
<p>You can customize the config load order and create additional config layers to suite your development needs.</p>
<p><span style="text-decoration: underline;"><strong>By default: With in each Layer, configuration files are loaded Alphabetically first from the base folder and then the sub-folders.</strong></span></p>
<p>You can alter this behavior by specifying a specific folder load order as shown in the Sitecore layer in the above screenshot. You can also disable a layer by adding mode=&#8221;off&#8221; for that specific layer in the Layers.config file. This is a neat way to disable all custom configs to work on a bug.</p>
<p>As always, please please please use Patch configs to modify Sitecore functionality.</p>
<p>You can always check your configuration using the Showconfig.aspx file.</p>
<p>If you have any questions or concerns, please get in touch with me. (<a href="https://twitter.com/akshaysura13" target="_blank" rel="noopener">@akshaysura13</a> on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>Sitecore Experience Platform - Sitecore 9 released!</title>
      <link>https://akshaysura.com/blog/sitecore-experience-platform-sitecore-9-released/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/sitecore-experience-platform-sitecore-9-released/</guid>
      <pubDate>Tue, 17 Oct 2017 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Sitecore just released Sitecore 9 at the 2017 Sitecore Symposium here at the Mirage in Vegas.]]></description>
      <content:encoded><![CDATA[<p>Sitecore just released Sitecore 9 at the 2017 Sitecore Symposium here at the Mirage in Vegas.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/10/Sitecore-9-Is-here.png"><img loading="lazy" class="alignnone size-full wp-image-3157" src="https://akshaysura.com/wp-content/uploads/2017/10/Sitecore-9-Is-here.png" alt="" width="440" height="440" /></a></p>
<p><em>Not the official logo. Credit goes to <a href="https://twitter.com/jammykam" target="_blank" rel="noopener">Kamruz Jaman</a> for creating it.</em></p>
<p>Sitecore Experience Platform (Sitecore XP) consists on three major foundation pillars. Sitecore XP combines Experience Management (xManagement) with features of xConnect to get marketing and customer intelligence information stored in the Experience Database (xDB).</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/10/sitecorexp.png"><img loading="lazy" class="alignnone size-full wp-image-3138" src="https://akshaysura.com/wp-content/uploads/2017/10/sitecorexp.png" alt="" width="1850" height="187" /></a></p>
<h3>Experience Management (xManagement)</h3>
<p>xManagement is the Content Management part of Sitecore which lets you create, manage, personalize and publish content. It comprises of three sections:</p>
<p><strong>Data Definition</strong>: This is the part of Sitecore which we use to define the data using Templates. Templates contain fields and the template standard values can define the presentation of that specific template item.</p>
<p><strong>Content</strong>: The content in Sitecore is based on templates. Either templates which you created or system templates. This content also includes media items in the Media Library.</p>
<p><strong>Presentation</strong>: The presentation layer in Sitecore is where the items are combines with the presentation to render items on your website. Presentation is primarily built using ASP.NET MVC, although there are some who still use WebForms.</p>
<h3>xDB</h3>
<p>The Experience Database (xDB) provides data storage for all contact interactions across all data channels. This enables xDB to provide valuable information on marketing and analytical capabilities in Sitecore.</p>
<h3>xConnect</h3>
<p>xConnect provides services to get data from xDB. This information can be used on the Sitecore back-end or on your user facing website. xConnect enabled xDB to be decoupled from Sitecore.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/10/xdbxconnect.png"><img loading="lazy" class="alignnone size-full wp-image-3145" src="https://akshaysura.com/wp-content/uploads/2017/10/xdbxconnect.png" alt="" width="1791" height="939" /></a></p>
<h3>Notable features in Sitecore 9</h3>
<p><strong>xConnect</strong><br />
The introduction of xConnect enables native omni-channel collection and segmentation at scale. This includes upgraded features for modeling your data, marketing automation, a unified view of the customer, as well as major architectural improvements including updating contacts from any channel at any time, automatic indexing of your data and built-in PII compliance support.</p>
<p><strong>New Forms module</strong><br />
The Sitecore 9.0 release sees the introduction of a new Forms module, including:<br />
&#8211; A completely redesigned UX with strong focus on business user<br />
&#8211; A ’drag and drop’ form builder<br />
&#8211; Form and field metrics showing the form and field performance<br />
&#8211; Multi-page forms<br />
&#8211; A Clean MVC (only) approach<br />
&#8211; The ability to create form templates</p>
<p>Be sure to attend the Introduction to Sitecore Forms session by <a href="https://twitter.com/pieterbrink123" target="_blank" rel="noopener">Pieter Brinkman</a> and Hylke Heidstra on Webnesday October 18, 2017 at 3:15PM.</p>
<p><strong>New Marketing Automation module</strong><br />
Marketing Automation provides a new way to create automated online campaigns in Sitecore. With a user friendly drag-and-drop interface, Marketing Automation provides an extendible set of tools.</p>
<p><strong>Dynamic Placeholders</strong><br />
Sitecore MVC now supports Dynamic Placeholders allowing the use of the same placeholder key multiple times in the same rendering and across multiple renderings in the same placeholder</p>
<p>If you have any questions or concerns, please get in touch with me. (<a href="https://twitter.com/akshaysura13" target="_blank" rel="noopener">@akshaysura13</a> on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>Sitecore Multi-Site custom 500 error page</title>
      <link>https://akshaysura.com/blog/sitecore-multi-site-custom-500-error-page/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/sitecore-multi-site-custom-500-error-page/</guid>
      <pubDate>Thu, 07 Sep 2017 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[This post is an add on to my previous post Secure Sitecore : Why use a custom 500 error page? In this post I will go through how you can get a multi-site custom 500 error page in a Sitecore solution.]]></description>
      <content:encoded><![CDATA[<p>This post is an add on to my previous post <a href="https://akshaysura.com/2016/08/02/secure-sitecore-why-use-a-custom-500-error-page/" target="_blank" rel="noopener">Secure Sitecore : Why use a custom 500 error page?</a> In this post I will go through how you can get a multi-site custom 500 error page in a Sitecore solution.</p>
<p>This would mean that each site in your Sitecore instance can have it&#8217;s individualized custom 500 error page. As I mentioned before, I truly believe it makes absolute sense to have a static 500 error page rather than on inside of Sitecore for obvious reasons.</p>
<p>A version of this code exists in production environments and has been working like a charm.</p>
<p>First, we need to add Global.asax because we need to process Application_Error event. Second, try not to use any Sitecore API in this file.</p>
<p>We added an AppSettings config flag to control the processing. In your web.config add the following to the AppSettings section:</p>
<pre><code class="language-xml">
&lt;add key="Show500PagePerSite" value="true" /&gt;
</code></pre>
<p>You would also need to make a few changes in the Web.config. First add in the httpErrors node in <system.webServer>:</p>
<pre><code class="language-xml">
&lt;httpErrors existingResponse="PassThrough" /&gt;
</code></pre>
<p>Also set the customErrors mode as On.</p>
<p>Next we need to add the Application_Error event in the global.asax.cs file. Here is a sample below:</p>
<pre><code class="language-csharp">
using System;
using System.Configuration;
using System.Web;

namespace YOURNAMESPACE
{
    public class Global : Sitecore.Web.Application
    {

        protected void Application_Error(object sender, EventArgs e)
        {
            var lastException = Server.GetLastError();

            bool show500page = !string.IsNullOrEmpty(ConfigurationManager.AppSettings["Show500PagePerSite"]) && ConfigurationManager.AppSettings["Show500PagePerSite"].ToLower().Equals("true") ? true : false;

            if (show500page)
            {
                HttpContext.Current.Server.ClearError();
                HttpContext.Current.Response.Clear();
                HttpContext.Current.Response.TrySkipIisCustomErrors = true;
                HttpContext.Current.Response.StatusCode = 500;
                HttpContext.Current.Response.StatusDescription = "500 Internal Server Error";
                Server.Transfer(GetSitePath(HttpContext.Current.Request.Url.GetComponents(UriComponents.Host, UriFormat.Unescaped))); // set the redirect location
            }
        }

        private string GetSitePath(string hostname)
        {
            if (hostname.Contains("FIRSTSITEHOST")) return "/errors/FIRSTSITEERRORPAGENAME.html";
            if (hostname.Contains("SECONDSITEHOST")) return "/errors/SECONDSITEERRORPAGENAME.html";

            return "/";
        }
    }
}
</code></pre>
<p>Hope this helps you out with your solution.</p>
<p>If you have any questions or concerns, please get in touch with me. (<a href="https://twitter.com/akshaysura13" target="_blank" rel="noopener">@akshaysura13</a> on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>Sitecore Scheduling with SiteCron 2.1.6</title>
      <link>https://akshaysura.com/blog/sitecore-scheduling-with-sitecron-2-1-6/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/sitecore-scheduling-with-sitecron-2-1-6/</guid>
      <pubDate>Thu, 07 Sep 2017 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[SiteCron has been around for a while now and I have used it on production systems for the past two years. I use it for triggering Sitemap file generation, PowerShell scripts for data syncs with external API and maintenance tasks. Shout out to Mike Edwards for fixing the OnItemSaved handler.]]></description>
      <content:encoded><![CDATA[<p>SiteCron has been around for a while now and I have used it on production systems for the past two years. I use it for triggering Sitemap file generation, PowerShell scripts for data syncs with external API and maintenance tasks. Shout out to <a href="https://twitter.com/mikeedwards83" target="_blank" rel="noopener">Mike Edwards</a> for fixing the OnItemSaved handler.</p>
<p><strong>SiteCron NuGet Link:</strong> <a href="https://www.nuget.org/packages/SiteCron" target="_blank" rel="noopener">https://www.nuget.org/packages/SiteCron</a></p>
<p><strong>SiteCron GitHub Link:</strong> <a href="https://github.com/akshaysura/Sitecron" target="_blank" rel="noopener">https://github.com/akshaysura/Sitecron</a></p>
<p><strong>SiteCron Marketplace Link:</strong> <a href="https://marketplace.sitecore.net/Modules/S/Sitecron.aspx?sc_lang=en" target="_blank" rel="noopener">https://marketplace.sitecore.net/Modules/S/Sitecron.aspx?sc_lang=en</a></p>
<p>&nbsp;</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/09/Sitecron.png"><img loading="lazy" class="alignnone size-full wp-image-3109" src="https://akshaysura.com/wp-content/uploads/2017/09/Sitecron.png" alt="" width="864" height="709" /></a></p>
<h2>What&#8217;s New?</h2>
<p>I use this module in every project I build. One of the things which bugged me the most was that it needed the Context DB to run in. For instance, on production CD&#8217;s we need it to run in the context of the Web or a custom db name like prod etc. Unfortunately, with the previous versions this was not possible.</p>
<ol>
<li>Ability to auto Archive the item after it executes once. This will be useful for those one time jobs. More exciting things to come off of this.</li>
<li>Ability to run in a different context db than Master. This will allow you to use publish restrictions to run Jobs only on CM, CM &amp; CD.</li>
</ol>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/09/dcontaxt.png"><img loading="lazy" class="alignnone size-full wp-image-3124" src="https://akshaysura.com/wp-content/uploads/2017/09/dcontaxt.png" alt="" width="683" height="434" /></a></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/09/blanksitecron.png"><img loading="lazy" class="alignnone size-full wp-image-3125" src="https://akshaysura.com/wp-content/uploads/2017/09/blanksitecron.png" alt="" width="961" height="968" /></a></p>
<p>&nbsp;</p>
<h2>Installing SiteCron</h2>
<p>To Install SiteCron, run the following command in your Visual Studio solution&#8217;s Package Manager Console.</p>
<p><strong>Install-Package SiteCron</strong></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/09/sitecron1.png"><img loading="lazy" class="alignnone size-large wp-image-3110" src="https://akshaysura.com/wp-content/uploads/2017/09/sitecron1-1024x665.png" alt="" width="900" height="584" /></a></p>
<p>Once installed the NuGet package will add a few files to your solution.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/09/sitecron2.png"><img loading="lazy" class="alignnone size-large wp-image-3112" src="https://akshaysura.com/wp-content/uploads/2017/09/sitecron2-1024x665.png" alt="" width="900" height="584" /></a></p>
<p>Once the NuGet package is installed. Use the <strong>SiteCron Items Only Sitecore Package.zip</strong> file and install the package on your Sitecore instance via the Installation Wizard.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/09/sitecron3.png"><img loading="lazy" class="alignnone size-large wp-image-3114" src="https://akshaysura.com/wp-content/uploads/2017/09/sitecron3.png" alt="" width="547" height="547" /></a></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/09/sitecron4.png"><img loading="lazy" class="alignnone size-full wp-image-3113" src="https://akshaysura.com/wp-content/uploads/2017/09/sitecron4.png" alt="" width="548" height="547" /></a></p>
<p>Once installed you can publish your code and you are good to go.</p>
<p>&nbsp;</p>
<h2>Using SiteCron</h2>
<p>Now for the fun part. Using SiteCron truly depends on your needs. Out of the box, it can handle a Smart Publish and running a Sitecore PowerShell script. Apart from these two, you are free to implement your own code as long as you inherit from the IJob interface.</p>
<p>I personally use the PowerShell job to run custom PowerShell scripts for API Sync and Sitemap generation.</p>
<p>Let&#8217;s look at the Smart Publish job and see if we can figure out the mechanics of the Quartz jobs.</p>
<h3>Smart Publish</h3>
<p>Smart Publish job is a custom job I wrote to take care of smart publishing in Sitecore and be able to specify the target db. Here is how the Sitecore Item is setup:</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/09/smartpublish.png"><img loading="lazy" class="alignnone size-full wp-image-3119" src="https://akshaysura.com/wp-content/uploads/2017/09/smartpublish.png" alt="" width="938" height="967" /></a></p>
<p>Notice that the type filed has been set to a specific class in the SiteCron library. You could easily point this to your own library and write your custom Job. As long as you inherit from IJob interface and implement the Execute method you are golden. You can choose to use the Parameters AND/OR the Items field in your Job as needed. In this case I am only using the Parameters field.</p>
<p>Here is the code for this call:</p>
<p>&nbsp;</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/09/sitepublishjob.png"><img loading="lazy" class="alignnone size-full wp-image-3120" src="https://akshaysura.com/wp-content/uploads/2017/09/sitepublishjob.png" alt="" width="1428" height="651" /></a></p>
<p>Please review the comments to understand how we are leveraging Quartz to get our work done.</p>
<p>&nbsp;</p>
<h3>PowerShell</h3>
<p>This by far is the most powerful Job in SiteCron. Sitecore PowerShell is a wonderful module and I do not know how I can get my work done without it. <a href="https://twitter.com/adamnaj" target="_blank" rel="noopener">Adam Najmanowicz</a> and <a href="https://twitter.com/MichaelWest101" target="_blank" rel="noopener">Michael West</a> have done such a wonderful job.</p>
<p>I use this Job to execute custom PowerShell scripts to run API syncs on the CM, Sitemap generation on the CD&#8217;s and nightly cleanup tasks.</p>
<p>I will go through this job code as well. First the Sitecore Item:</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/09/sitepowershell.png"><img loading="lazy" class="alignnone size-full wp-image-3121" src="https://akshaysura.com/wp-content/uploads/2017/09/sitepowershell.png" alt="" width="949" height="970" /></a></p>
<p>Notice that this job code exists in the SiteCron library as well. The code to this library is available in GitHub.</p>
<p>Essentially the Job is capable of running ONE Sitecore PowerShell script. Why ONE you ask? Well because there could be inter-dependencies among scripts, long running scripts and complications arising from it. I do however have commented code in the Powershell Execute Script Job which can tackle more than one PowerShell script at a time.</p>
<p>Please be sure that if you are scheduling PowerShell scripts, no client interaction commands exist in your script. Otherwise you will be hit by &#8220;Non interactive session cannot perform an interactive &#8216;WriteProgress&#8217; operation&#8221;. I was able to clean up my PowerShell script and silence it by using the $ProgressPreference = &#8216;SilentlyContinue&#8217;.</p>
<p>Future versions of the Sitecore PowerShell module 4.7 and above might not need this.</p>
<p>Here is the code for this Job:</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/09/powershelljob.png"><img loading="lazy" class="alignnone size-full wp-image-3122" src="https://akshaysura.com/wp-content/uploads/2017/09/powershelljob.png" alt="" width="1642" height="1199" /></a></p>
<p>&nbsp;</p>
<h4>Custom Job</h4>
<p>Now if you were to get started with a Custom Job. Here is what you need to do:</p>
<ol>
<li>Install Quartz from NuGet</li>
<li>Create a new class lets call it HelloWorld.cs</li>
<li>Inherit from IJob interface</li>
<li>Implement Execute method</li>
<li>Place your code inside of the Job</li>
<li>Go to Sitecore admin and navigate to /sitecore/system/Modules/Sitecron</li>
<li>Insert a new Sitecron Job</li>
<li>Add in your library and class information for example: Sitecron.Jobs.PowerShell.ExecuteScript, Sitecron</li>
<li>Setup the Cron Expression &#8211; use the link on the field name or <a href="http://www.cronmaker.com/" target="_blank" rel="noopener">http://www.cronmaker.com/</a></li>
<li>Specify any Parameters or Items based on your Job needs</li>
</ol>
<p>That is it!</p>
<p>If you have any questions or concerns, please get in touch with me. (<a href="https://twitter.com/akshaysura13" target="_blank" rel="noopener">@akshaysura13</a> on twitter or on Slack).</p>
<p>&nbsp;</p>
]]></content:encoded>
    </item>
    <item>
      <title>Sitecore 8.2+ Multi-site Shared Placeholders and Cascade Renderings</title>
      <link>https://akshaysura.com/blog/sitecore-8-2-multi-site-shared-placeholders-and-cascade-renderings/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/sitecore-8-2-multi-site-shared-placeholders-and-cascade-renderings/</guid>
      <pubDate>Mon, 04 Sep 2017 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[This post is based on setting up the home item (or another item) with the needed presentation and letting it cascade to all the pages under it in a multi-site Sitecore solution. At first, we tried using the cascade renderings which works great but at some point it becomes hard to manage with each rendering having the cascade flag.]]></description>
      <content:encoded><![CDATA[<p>This post is based on setting up the home item (or another item) with the needed presentation and letting it cascade to all the pages under it in a multi-site Sitecore solution. At first, we tried using the cascade renderings which works great but at some point it becomes hard to manage with each rendering having the cascade flag.</p>
<p>What if, we setup the Home item with the presentation we need cascaded in a specific placeholders and the code takes care of the rest. <a href="https://twitter.com/tbraga01" target="_blank" rel="noopener">Tim Braga</a> at SUGCON Europe 2016 had a talk about Atomic Design which led to a conversation with <a href="https://twitter.com/kamsar" target="_blank" rel="noopener">Kam Figy</a> (the fake Kam). I looked for code and my good friend Google got me to a blog post by <a href="https://twitter.com/TomDudfield" target="_blank" rel="noopener">Tom Dudfield</a>.</p>
<p>Following which we came up with the requirements:</p>
<ol>
<li>Setup one or more placeholders where we can set the presentation on the home item of a multi-site Sitecore solution.</li>
<li>Add or remove placeholders as we wish</li>
<li>Execute it in the context on specific databases (master, web, prod, etc)</li>
<li>Execute this on specific item templates</li>
<li>Exclude certain renderings from certain pages</li>
</ol>
<p>Once we had the requirements we went to code. Having existing code helped a ton but making it generic and to be able to control as per the requirements needed some work.</p>
<p>Currently we use it for cascading the header and footer sections on our sites.  A version of this code currently is running on our production systems and has not given us any issue.</p>
<p>Please be ware that modules such as Sitecore.Boost rely on the same processors as this code does. I would suggest coordinating with the module creators and wrapping their code as part of yours.</p>
<p><script src="https://gist.github.com/akshaysura/fca500bacc71a29e7079c1d55b7955d9.js"></script></p>
<p>If you have any questions or concerns, please get in touch with me. (<a href="https://twitter.com/akshaysura13" target="_blank" rel="noopener">@akshaysura13</a> on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>TIHIDI: Deploy a Sitecore application via Octopus Deploy</title>
      <link>https://akshaysura.com/blog/tihidi-deploy-a-sitecore-application-via-octopus-deploy/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/tihidi-deploy-a-sitecore-application-via-octopus-deploy/</guid>
      <pubDate>Fri, 01 Sep 2017 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[I have only been working with Octopus Deploy for a year but its one of my favorite tools. We depend on it for our end to end 100% automated deployments to all of our environments. The trick is to set it up properly in the first place. I was able to get some guidance from Kamruz Jaman when I got started and that helped me immensely to understand Octopus Deploy.]]></description>
      <content:encoded><![CDATA[<p>I have only been working with <a href="https://octopus.com/" target="_blank" rel="noopener">Octopus Deploy</a> for a year but its one of my favorite tools. We depend on it for our end to end 100% automated deployments to all of our environments. The trick is to set it up properly in the first place. I was able to get some guidance from <a href="https://twitter.com/jammykam" target="_blank" rel="noopener">Kamruz Jaman</a> when I got started and that helped me immensely to understand Octopus Deploy.</p>
<p>The deployment I am going to describe is how I set it up, it might not be right for all situations but hoping that it will provide some insight into how you would want to set it up for your own environment.</p>
<p>First, we use Slow Cheetah to do config transforms for local deploys on dev machines. This is important, because our main configs (not the transforms) will host Octopus variables, which is a huge part of this process.</p>
<p><strong>TIHIDI: Stands for This Is How I Do It. I am going to write a series of blog posts going through how I do Sitecore related work. Hope it helps you!</strong></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/06/Well-Armed-Octopus.jpg"><img loading="lazy" class="alignnone size-large wp-image-3082" src="https://akshaysura.com/wp-content/uploads/2017/06/Well-Armed-Octopus.jpg" alt="" width="640" height="635" /></a></p>
<p>Octopus Deploy is free for small teams and its an efficient and powerful deployment tool. Octopus has several process step templates ranging from a PowerShell step to a SQL backup step. For more information visit: <a href="https://octopus.com/" target="_blank" rel="noopener">https://octopus.com/</a></p>
<h2>Setup</h2>
<p>Here are the steps for the deployment server:</p>
<ol>
<li>Create a local system admin account &#8211; call it OctoAdmin for example. This account will be used by the Octopus windows services to carry out your tasks.</li>
<li>Install Octopus Deploy on the deployment server.</li>
<li>Change the Logon user for the OctopusDeploy windows service to the local system admin account, which is OctoAdmin in our example.</li>
<li>Add any additional URL bindings you need to access Octopus Deploy in your environment.</li>
</ol>
<p>&nbsp;</p>
<h2>Configuration</h2>
<p>Configuration is where the Magic is for Octopus Deploy.</p>
<h4>Environments</h4>
<p>In the Environments section, setup your overall environment structure: Dev, QA, Stage, Prod, etc.</p>
<h4>Lifecycles</h4>
<p>Lifecycles are how you control the flow of releases between environments. If you wish to auto deploy to the first environment, like dev for instance and then promote it to the upper environments.</p>
<h4><img loading="lazy" class="alignnone size-full wp-image-3078" src="https://akshaysura.com/wp-content/uploads/2017/06/sometimes-i-wish-i-was-an-octopus-so-i-could-11139805.png" alt="" width="500" height="522" /></h4>
<h4>Variable Sets</h4>
<p>This is where the gravy is. Set this up properly and you can do a ton of things. The idea is that the variable hold substitution values which you can replace at a machine level, environment level, role level, etc. You define your variables for debug mode, connection strings, etc. Anything which needs changing.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/06/variables.png"><img loading="lazy" class="alignnone size-large wp-image-3097" src="https://akshaysura.com/wp-content/uploads/2017/06/variables-1024x175.png" alt="" width="900" height="154" /></a></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/06/variablescope.png"><img loading="lazy" class="alignnone size-full wp-image-3098" src="https://akshaysura.com/wp-content/uploads/2017/06/variablescope.png" alt="" width="478" height="293" /></a></p>
<p>Once you defined your variables you simple substitute it in your configs using this syntax:  &lt;add name=&#8221;core&#8221; connectionString=&#8221;#{connectionstrings.core}&#8221; /&gt;</p>
<p>Octopus has a ton of documentation here: <a href="https://octopus.com/docs" target="_blank" rel="noopener">https://octopus.com/docs</a></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/06/tumblr_nszafnFVyT1uap0hno1_500.jpg"><img loading="lazy" class="alignnone size-large wp-image-3084" src="https://akshaysura.com/wp-content/uploads/2017/06/tumblr_nszafnFVyT1uap0hno1_500.jpg" alt="" width="500" height="488" /></a></p>
<h4>Project</h4>
<p>The project setup relies on all the setup we have done so far. Octopus gives you a ton of step templates which will let you deploy packages, run PowerShell, backup SQL Server db&#8217;s, etc. There are a ton of community templates which you can use as well. Below is a sample from one of our projects:</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/06/projectstep11.png"><img loading="lazy" class="alignnone size-full wp-image-3099" src="https://akshaysura.com/wp-content/uploads/2017/06/projectstep11.png" alt="" width="291" height="796" /></a></p>
<p>This combined with <a href="https://akshaysura.com/2017/06/13/tihidi-continuous-integration-for-a-sitecore-solution-engage/" target="_blank" rel="noopener">TIHIDI: Continuous Integration for a Sitecore solution</a> – Engage! will get you going.</p>
<p>&nbsp;</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/06/Lonely-Octopus.jpg"><img loading="lazy" class="alignnone size-large wp-image-3083" src="https://akshaysura.com/wp-content/uploads/2017/06/Lonely-Octopus.jpg" alt="" width="471" height="313" /></a></p>
<p>The key is to start small but have the right structure and you can build upon that.</p>
<p>If you have any questions or concerns, please get in touch with me. (<a href="https://twitter.com/akshaysura13" target="_blank" rel="noopener">@akshaysura13</a> on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>SiteCron 2.1.3 Released!</title>
      <link>https://akshaysura.com/blog/sitecron-2-1-3-released/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/sitecron-2-1-3-released/</guid>
      <pubDate>Sun, 18 Jun 2017 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[SiteCron 2.1.3 has been released to GitHub & NuGet. I use this module on my projects quite a bit and I have been meaning to release an upgrade for the longest time.]]></description>
      <content:encoded><![CDATA[<p>SiteCron 2.1.3 has been released to <a href="https://github.com/akshaysura/Sitecron" target="_blank" rel="noopener">GitHub</a> &amp; <a href="https://www.nuget.org/packages/SiteCron/" target="_blank" rel="noopener">NuGet</a>. I use this module on my projects quite a bit and I have been meaning to release an upgrade for the longest time.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/06/sitecron213.png"><img loading="lazy" class="alignnone size-full wp-image-3089" src="https://akshaysura.com/wp-content/uploads/2017/06/sitecron213.png" alt="" width="741" height="250" /></a></p>
<p>Whats new?</p>
<p>Well, here is a short list:</p>
<ul>
<li>Upgrade of Quartz.net</li>
<li>Included a Disabled Flag</li>
<li>Included an ArchiveOnExecution Flag</li>
<li>Upgrade references for Sitecore 8.2</li>
<li>Upgrade references for PowerShell 4.5</li>
<li>Fixed PowerShell execute code</li>
<li>Out of The Box (OOTB) plugins for Site Smart Publish and PowerShell execute</li>
</ul>
<p>I will be posting some blog posts about the new features shortly.</p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>TIHIDI: Continuous Integration for a Sitecore solution - Engage!</title>
      <link>https://akshaysura.com/blog/tihidi-continuous-integration-for-a-sitecore-solution-engage/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/tihidi-continuous-integration-for-a-sitecore-solution-engage/</guid>
      <pubDate>Tue, 13 Jun 2017 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[This blog post will go through how I setup my solution in a Continuous Integration environment. A true Continuous Integration and Delivery environment would need very little human intervention.]]></description>
      <content:encoded><![CDATA[<p>This blog post will go through how I setup my solution in a Continuous Integration environment. A true Continuous Integration and Delivery environment would need very little human intervention.</p>
<p>The Continuous Integration setup should trigger a build for each check-in and deployed to the Dev environment by default. Deployment to other environments should be on demand and controlled.</p>
<p>Previously I have used Team City and Jenkins to do automated builds. In this blog post we will only talk about the Build process using VSTS (Visual Studio Team Services).</p>
<p>Although I have only been using it for a year, I love VSTS. It has a lot of integrations and is very flexible.</p>
<p><strong>TIHIDI: Stands for This Is How I Do It. I am going to write a series of blog posts going through how I do Sitecore related work. Hope it helps you!</strong></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/06/picard-make-it-so-continuous-integration-engage.jpg"><img loading="lazy" class="alignnone size-full wp-image-3073" src="https://akshaysura.com/wp-content/uploads/2017/06/picard-make-it-so-continuous-integration-engage.jpg" alt="" width="500" height="381" /></a></p>
<p>A vent about source control: We have all used Team Foundation Server (TFS). It used to be a great tool back in the day but with the amount of collaboration of teams across time zones, Git is where its at. Git wont bite you.</p>
<p>Once you get used to using Git, its fairly simple. With tools like SourceTree, Git Extensions and more, its very convenient.</p>
<p>First, get to <a href="https://www.visualstudio.com/team-services/" target="_blank" rel="noopener">https://www.visualstudio.com/team-services/</a> and get yourself an account if you do not already have one. Its free! You can host your Git repo to play with VSTS. There are a few restrictions but none that will block you for trying it out and even use it on your projects.</p>
<p>Once you have the account, create a project with a Git repo. Clone the repo and add your solution.</p>
<p>In your Sample solution, install the following on your .Web.csproj and .Serialization.csproj:</p>
<p><em><strong>Install-Package OctoPack -Version 3.6.1</strong></em></p>
<p>Once that is done, you would need to add a .nuspec file to define what gets packaged when OctoPack runs.</p>
<p>Here is the sample from my web project:</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/06/ci5.png"><img loading="lazy" class="alignnone size-full wp-image-3062" src="https://akshaysura.com/wp-content/uploads/2017/06/ci5.png" alt="" width="904" height="451" /></a></p>
<p>Here is he sample from my serialization project:</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/06/Ci4.png"><img loading="lazy" class="alignnone size-full wp-image-3063" src="https://akshaysura.com/wp-content/uploads/2017/06/Ci4.png" alt="" width="905" height="488" /></a></p>
<p>Notice in the serialization nuspec, we are specifying the exact files we need packaged up, where as in the web, we want it to capture the output.</p>
<p>Next, get to VSTS and create a build project for a Visual Studio Project. Here are the trigger settings so an automated build triggers on check-in. Be sure to check the &#8220;Batch changes while a build is in progress&#8221;.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/06/ci6-1.png"><img loading="lazy" class="alignnone size-full wp-image-3071" src="https://akshaysura.com/wp-content/uploads/2017/06/ci6-1.png" alt="" width="621" height="550" /></a></p>
<p>Here are the steps in my definition:</p>
<p>Add a Get sources task and specify the repo and the branch. In this case I am pulling from the dev branch.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/06/ci1.png"><img loading="lazy" class="alignnone size-large wp-image-3066" src="https://akshaysura.com/wp-content/uploads/2017/06/ci1-1024x483.png" alt="" width="900" height="425" /></a></p>
<p>Add a NuGet restore step to restore the NuGet packages for your solution. Previously the NuGet restore was part of the Build Solution step but that is now deprecated.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/06/ci2.png"><img loading="lazy" class="alignnone size-large wp-image-3065" src="https://akshaysura.com/wp-content/uploads/2017/06/ci2-1024x561.png" alt="" width="900" height="493" /></a></p>
<p>Also I do some name attribute manipulation in the Nuspec file on the build server based on the environment we run on to generate NuGet packages with different names. This step has some PowerShell to replace content in the Nuspec files.</p>
<p>Add a Build Solution step to compile your solution and run OctoPack to push your generated NuGet packages to your Octopus server.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/06/ci3.png"><img loading="lazy" class="alignnone size-large wp-image-3064" src="https://akshaysura.com/wp-content/uploads/2017/06/ci3-1024x393.png" alt="" width="900" height="345" /></a></p>
<p>That is it. Our builds are done in less than 1 minute. The majority of time goes into uploading the NuGet packages to the Octopus server.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/06/build-blue.jpg"><img loading="lazy" class="alignnone size-full wp-image-3074" src="https://akshaysura.com/wp-content/uploads/2017/06/build-blue.jpg" alt="" width="500" height="375" /></a></p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>It’s going to be a rainbow and unicorns kind of day - Ride the Sitecore Unicorn on a rainbow!</title>
      <link>https://akshaysura.com/blog/its-going-to-be-a-rainbow-and-unicorns-kind-of-day-ride-the-sitecore-unicorn-on-a-rainbow/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/its-going-to-be-a-rainbow-and-unicorns-kind-of-day-ride-the-sitecore-unicorn-on-a-rainbow/</guid>
      <pubDate>Mon, 12 Jun 2017 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Alright let’s address the elephant in the room! Kam Figy is not the creator of Unicorn, Kamruz Jaman is. This post is not mean to sing praises of Unicon or the Kams as we callz it. It is mainly to show how we use Unicorn to build our end to end deployment from a dev machine to the production CD’s using Unicorn for serialization.]]></description>
      <content:encoded><![CDATA[<p>Alright let&#8217;s address the elephant in the room! <a href="https://twitter.com/kamsar" target="_blank" rel="noopener">Kam Figy</a> is not the creator of Unicorn, <a href="https://twitter.com/jammykam" target="_blank" rel="noopener">Kamruz Jaman</a> is. This post is not mean to sing praises of Unicon or the Kams as we callz it. It is mainly to show how we use Unicorn to build our end to end deployment from a dev machine to the production CD&#8217;s using Unicorn for serialization.<br />
<a href="https://akshaysura.com/wp-content/uploads/2017/06/badass.jpg"><img loading="lazy" src="https://akshaysura.com/wp-content/uploads/2017/06/badass.jpg" alt="" width="448" height="584" class="alignnone size-large wp-image-3052" /></a></p>
<p>If I have not said so before, I love VSTS and Octopus Deploy. I am not a master of either but I got a great deal of experience in the past year setting them up. I will follow up this blog post with Octopus posts but this one is reserved for Unicorn.</p>
<p>Unicorn != TDS &amp;&amp; TDS != Unicorn. This has been said multiple times. Each has a few features which are common but they have their own set of features. TDS being that its a paid product has a lot of great features especially to do with deployment, builds etc.</p>
<p>So lets start. First you install Unicorn from NuGet:</p>
<p><em>Install-Package Unicorn -Version 3.3.2</em></p>
<p>This installs a set of configs and adds appropriate references to your project.  If you plan on serializing roles, you would also need Unicorn.Roles:</p>
<p><em>Install-Package Unicorn.Roles -Version 3.3.2</em></p>
<p>By default, Unicorn provides sample configurations.  Here are some I use:</p>
<pre><code class="language-xml">
&lt;configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"&gt;
  &lt;sitecore&gt;
    &lt;!-- A source folder param to be used later to specify folders where serialization will store files --&gt;
    &lt;sc.variable name="sourceFolder"&gt;
      &lt;patch:attribute name="value"&gt;#{sitecore.sourcefolder}&lt;/patch:attribute&gt;
    &lt;/sc.variable&gt;
  &lt;/sitecore&gt;
&lt;/configuration&gt;

</code></pre>
<pre><code class="language-xml">
&lt;!--
	This is an example of how to configure a basic Unicorn configuration using your own config patch file.
	Copy this file to use as a basis for your own configuration definitions.

	Enabled configuration definition patches should be present on all environments Unicorn is present on.

	See Unicorn.config for commentary on how configurations operate, or https://github.com/kamsar/Unicorn/blob/master/README.md
--&gt;
&lt;configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"&gt;
	&lt;sitecore&gt;
		&lt;unicorn&gt;
			&lt;configurations&gt;
				&lt;!--
					The default configuration is an example to start making other configurations from.

					WHAT SHOULD I INCLUDE?
					In general, include the fewest items possible. This both makes things faster and reduces the amount of things kept in source control.
					The most common candidates for serialization are layout items and template items, but Unicorn can serialize any type of item or field including media.
					
					BEHAVIORS
					Configurations can override the default dependencies defined in Unicorn.config's &lt;defaults&gt; to apply
					custom behaviors to specific configurations. They behave like an inherited IoC container.
					
					DEPENDENCIES
					Configurations may also depend on each other. Add a comma-delimited list of configuration names to depend on to the 'dependencies' attribute on the configuration.
					Dependent configurations do not force dependencies to sync if not selected, but syncs will always occur in dependency order if multiple dependent configurations sync at once.
					Transitive dependency and multiple dependency (comma delimited) are supported.
					
					TIPS
					Favor using several configurations over a single monolithic one.
					Favor using more includes and fewer excludes in your predicates.
          
          
				
          
					Start with minimal configurations and add includes as you need to serialize new things.

					Set the Project folder under the sourceFolder.
				--&gt;
				&lt;configuration name="Project.PROJECTNAME"&gt;
          &lt;targetDataStore physicalRootPath="$(sourceFolder)\PROJECTNAME" useDataCache="false" type="Rainbow.Storage.SerializationFileSystemDataStore, Rainbow" singleInstance="true"/&gt;
          &lt;predicate type="Unicorn.Predicates.SerializationPresetPredicate, Unicorn" singleInstance="true"&gt;
					
            &lt;!-- Layouts - Simple content items, specify a unique name, database name and the path --&gt;
            &lt;include name="Layouts_PROJECT" database="master" path="/sitecore/layout/Layouts/PROJECTNAME" /&gt;
            
            &lt;!-- using the right predicate is very important. Here we want Unicorn to take the parent node, exclude all children except the ones named.--&gt;
            &lt;include name="FBPowershellScripts" database="master" path="/sitecore/system/Modules/PowerShell/Script Library"&gt;
              &lt;exclude children="true"&gt;
                &lt;except name="Why Cant you be my friend" /&gt;
                &lt;except name="What did I ever do to you" /&gt;
                &lt;except name="All I wanted is to be your friend" /&gt;
                &lt;except name="Kamruz is the only Coveo MVP in the world" /&gt;
              &lt;/exclude&gt;
            &lt;/include&gt;

            &lt;!-- Core Settings - Notice the database value as core--&gt;
            &lt;include database="core" path="/sitecore/system/Settings/Html Editor Profiles" /&gt;
          &lt;/predicate&gt;
          &lt;!-- As per the roles, as long as you have Unicron.Roles installed and you specify the following predicates you can sync roles across all environments --&gt;
          &lt;roleDataStore type="Unicorn.Roles.Data.FilesystemRoleDataStore, Unicorn.Roles" physicalRootPath="$(sourceFolder)\Roles" singleInstance="true"/&gt;
          &lt;rolePredicate type="Unicorn.Roles.RolePredicates.ConfigurationRolePredicate, Unicorn.Roles" singleInstance="true"&gt;
            &lt;include domain="sitecore"  pattern="^ProjectName.*$" /&gt;
          &lt;/rolePredicate&gt;

          &lt;!--
						SYNC TYPE
						
						Traditional Sync (the default) updates the state of the database only when a sync operation is run. It supports additional operations but can be more of a chore to remember to sync.
						Transparent Sync (preferred) updates the state of Sitecore instantly as soon as changes to files occur. It is optimal for development purposes, but has a few limitations.
						See the guide to help decide: https://github.com/kamsar/Unicorn/wiki/The-Transparent-Sync-Guide
					--&gt;
					&lt;dataProviderConfiguration enableTransparentSync="false" type="Unicorn.Data.DataProvider.DefaultUnicornDataProviderConfiguration, Unicorn" singleInstance="true" /&gt;

					&lt;!-- 
						SYNC CONFIGURATION
					
						UpdateLinkDatabase: If true, the links will be updated for synced items after the sync has completed. If false (default) links are not updated for performance.
							Updating links is important if you are syncing user-facing content where link tracking is important. It is not very important for system items (templates/renderings).
						
						UpdateSearchIndex: If true, the search index(es) containing the item will be updated with item changes after the sync has completed. If false, indexing will not be updated for performance.
							Updating the index is important for content that relies on indexing, which may include most user-facing content items. Most of the time templates and renderings don't need indexing.
						
						MaxConcurrency: Controls how many threads Unicorn can use when syncing this configuration. Concurrency can usually increase sync speed 30-50% over single threading.
							IF YOUR CONFIGURATION INCLUDES TEMPLATES YOU MUST SET THIS TO 1 OR YOUR SYNC WILL HANG INDEFINITELY DUE TO A SITECORE ISSUE
							IF YOU ARE ON SITECORE 8.0 U2 OR EARLIER, YOU MUST SET THIS TO 1 DUE TO A SITECORE ISSUE
						
							This value can be set to significantly higher than the number of CPU cores, as these are largely I/O bound.
							Use fewer threads for HDDs or slow SQL servers, and more threads for SSDs.
							For a SSD workload on a quad-core CPU 16 seems to be a decent number.
						
						NOTE: UpdateLinkDatabase and UpdateSearchIndex also apply to items that are reloaded from disk when using Transparent Sync, as well as normal Sync.
					--&gt;
					&lt;syncConfiguration updateLinkDatabase="false" updateSearchIndex="false" maxConcurrency="1" type="Unicorn.Loader.DefaultSyncConfiguration, Unicorn" singleInstance="true" /&gt;
				&lt;/configuration&gt;
			&lt;/configurations&gt;
		&lt;/unicorn&gt;
	&lt;/sitecore&gt;
&lt;/configuration&gt;

</code></pre>
<pre><code class="language-xml">
&lt;!--
SHARED SECRET CONFIGURATION EXAMPLE
This is a config file that can be used as a basis to set the Unicorn PowerShell remote API's shared secret 
without altering the stock config file. Duplicate this file and set a long, 32+ character secret to enable
invoking Unicorn with the PowerShell API, e.g. for CI.

IMPORTANT: THIS CONFIG PATCH *MUST* RUN AFTER Unicorn.UI.config, or you will receive an error:
"Unable to cast object of type 'System.String' to type 'Unicorn.ControlPanel.Security.IUnicornAuthenticationProvider'."

See the README here for more on setting up remote API: https://github.com/kamsar/Unicorn

Need some randomness? Try here: https://www.random.org/passwords/?num=5&amp;len=24&amp;format=html&amp;rnd=new
--&gt;
&lt;configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"&gt;
	&lt;sitecore&gt;
		&lt;unicorn&gt;
			&lt;authenticationProvider&gt;
				&lt;SharedSecret&gt;YOURSECREDKEYPLEASEUSEALONGONEANDBEMEEEFRIEND&lt;/SharedSecret&gt;
				&lt;!-- 
					Writes the reason why failed automated tool authentications failed to the Sitecore logs.
					Will result in writing your shared secret to the logs as part of the signature base,
					so disable it unless you're debugging failed authentications.
				--&gt;
				&lt;WriteAuthFailuresToLog&gt;true&lt;/WriteAuthFailuresToLog&gt;
			&lt;/authenticationProvider&gt;
		&lt;/unicorn&gt;
	&lt;/sitecore&gt;
&lt;/configuration&gt;
</code></pre>
<p>I make sure that the config transforms locally point to the local serialization folder outside of the wwwroot on my dev box. This helps a lot in structuring your configs on all the environments. Using Octopus, we set the path for the serialization folder dynamically.</p>
<p>For your deployment:</p>
<ol>
<li>Package code and serialization separately in to different Nuget Packages. I use Nuspec files with Octopus Deploy.</li>
<li>Once code is deployed, make sure you remove the Unicorn.DataProvider.config file from the destination CD/CM so that Unicorn does not serialize on those servers.</li>
<li>Make sure the serialization folder on the destination system is wiped before your add it via Octopus or any other deployment tool.</li>
<li>Deploy the serialization Nuget package.</li>
<li>Use PowerShell to sync Unicorn serialized files automatically as part of your deployment process on the CM instances.</li>
<li>On CD&#8217;s remove the Rainbow.config and Project.Unicron.Serialization.config files.</li>
</ol>
<p>Here is a sample of the Octopus step of sync Unicorn via PowerShell:</p>
<pre><code>
$apppath = $OctopusParameters["sitecore.powershellfolder"]
$siteHostName = $OctopusParameters["website.url"]
$siteUrl = "$siteHostName/unicorn.aspx"

Import-Module $apppath\Unicorn.psm1
Sync-Unicorn -ControlPanelUrl $siteUrl -SharedSecret 'YOURSECREDKEYPLEASEUSEALONGONEANDBEMEEEFRIEND'
</code></pre>
<p>&nbsp;</p>
<p>Since we deployed this 5 months ago, we have not touched it. We run through a few hundred deploys per week.</p>
<p>From dev to prod, we do not do any manual steps, everything is handled by Octopus and so far we have not yet gotten any Unicorn issues. If you do end up with an odd situation, Kam is reachable on the Sitecore Slack and he is very responsive.<br />
<a href="https://akshaysura.com/wp-content/uploads/2017/06/31347086131d1ff3ae0ae850864f9aea.jpg"><img loading="lazy" src="https://akshaysura.com/wp-content/uploads/2017/06/31347086131d1ff3ae0ae850864f9aea.jpg" alt="" width="236" height="295" class="alignnone size-full wp-image-3051" /></a></p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>Sitecore Multi-site Multi-CDN implementation</title>
      <link>https://akshaysura.com/blog/sitecore-multi-site-multi-cdn-implementation/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/sitecore-multi-site-multi-cdn-implementation/</guid>
      <pubDate>Mon, 12 Jun 2017 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Recently we have been going through a series of SEO tweaks based on recommendations from our SEO Expert. Several of them are very interesting to look into and the reasoning and how search engines rank sites based on that is amazing.]]></description>
      <content:encoded><![CDATA[<p>Recently we have been going through a series of SEO tweaks based on recommendations from our SEO Expert. Several of them are very interesting to look into and the reasoning and how search engines rank sites based on that is amazing.</p>
<p>One of those happens to be how we use a CDN. CDN stands for Content Delivery Network. A CDN helps deliver anything from web page assets to the page itself to the end users browser. In our case we use a CDN for our website assets like CSS, java-script and media library items.</p>
<p>Traditionally we set the following configuration in Sitecore:</p>
<pre><code class="language-xml">     
    &lt;settings&gt;
      &lt;setting name="MediaResponse.Cacheability"&gt;
        &lt;patch:attribute name="value"&gt;public&lt;/patch:attribute&gt;
      &lt;/setting&gt;
      &lt;setting name="Media.AlwaysIncludeServerUrl"&gt;
        &lt;patch:attribute name="value"&gt;false&lt;/patch:attribute&gt;
      &lt;/setting&gt;
      &lt;setting name="Media.MediaLinkServerUrl"&gt;
        &lt;patch:attribute name="value"&gt;https://SOMENAME.azureedge.net/&lt;/patch:attribute&gt;
      &lt;/setting&gt;
    &lt;/settings&gt;
    
</code></pre>
<p>This works fine as the server url is added to all the media library links. Now, if we have multiple sites, we would want to control the CDN accordingly. Also based on the SEO guidelines its better to do cdn.SiteA.com or anysubdomain.SiteA.com for the CDN name.</p>
<p>So now we need to use cdn.SiteA.com and cdn.SiteB.com on the same instance of Sitecore where we have only one setting which is Media.MediaLinkServerUrl. To get around this we turn to the MediaProvider. We would need to override the GetMediaUrl function to append the appropriate CDN host based on the website.</p>
<p>There are a few CDN modules on the Sitecore marketplace but we wanted something simple. We want it to just modify the Media Library links and append the url of the CDN per site. To do this, we add an additional attribute to the site node of your website to store the CDN hostname.</p>
<pre><code class="language-xml">     
&lt;configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"&gt;
  &lt;sitecore&gt;
    &lt;sites&gt;
      &lt;site name="firstsite" patch:before="site[@name='website']"
           virtualFolder="/"
           physicalFolder="/"
           rootPath="/sitecore/content/firstsite"
           startItem="/Home"
           database="web"
           domain="extranet"
           allowDebug="true"
           cacheHtml="true"
           htmlCacheSize="5000MB"
           xslCacheSize="10MB"
           filteredItemsCacheSize="20MB"
           enablePreview="true"
           enableWebEdit="true"
           enableDebugger="true"
           disableClientData="false"
           hostName="firstsitedomain*"
           cdnHostname="cdn.firstsitedomain.com"
            /&gt;
      &lt;site name="secondsite" patch:before="site[@name='website']"
           virtualFolder="/"
           physicalFolder="/"
           rootPath="/sitecore/content/secondsite"
           startItem="/Home"
           database="web"
           domain="extranet"
           allowDebug="true"
           cacheHtml="true"
           htmlCacheSize="5000MB"
           xslCacheSize="10MB"
           filteredItemsCacheSize="20MB"
           enablePreview="true"
           enableWebEdit="true"
           enableDebugger="true"
           disableClientData="false"
           hostName="secondsitedomain*"
           cdnHostname="cdn.secondsitedomain.com"
            /&gt;
      &lt;!-- Third site does not use a CDN --&gt;
      &lt;site name="thirdsite" patch:before="site[@name='website']"
           virtualFolder="/"
           physicalFolder="/"
           rootPath="/sitecore/content/thirdsite"
           startItem="/Home"
           database="web"
           domain="extranet"
           allowDebug="true"
           cacheHtml="true"
           htmlCacheSize="5000MB"
           xslCacheSize="10MB"
           filteredItemsCacheSize="20MB"
           enablePreview="true"
           enableWebEdit="true"
           enableDebugger="true"
           disableClientData="false"
           hostName="thirdsitedomain*"
           cdnHostname=""
            /&gt;
    &lt;/sites&gt;
  &lt;/sitecore&gt;
&lt;/configuration&gt;
    
</code></pre>
<p>Once that is done you would need to create the following class called CDNMediaProvider inheriting from the MediaProvider class.</p>
<pre><code class="language-csharp">  
using Sitecore.Data.Items;
using Sitecore.Resources.Media;
using System;
using Microsoft.Extensions.DependencyInjection;
using Sitecore.DependencyInjection;
using Sitecore;
using Sitecore.Sites;
using Sitecore.Text;
using Sitecore.Web;
using YOURSOLUTION.Business.Caching;
using YOURSOLUTION.SCExtensions.Settings;

namespace YOURSOLUTIONNAMESPACE.Business.SC.Providers
{
    public class CDNMediaProvider : MediaProvider
    {
        string CDNHostnamePropertyKey = "";

        public override string GetMediaUrl(MediaItem item, MediaUrlOptions options)
        {
            string baseMediaUrl = base.GetMediaUrl(item, options);
            IGeneralSettings settings = GeneralSettings.Current;
            CDNHostnamePropertyKey = settings.CDNHostnameKey;

            if (HasCDN(Sitecore.Context.Site))
            {
                string cacheKey = string.Concat(Sitecore.Context.Site.Name, baseMediaUrl);

                var cache = ServiceLocator.ServiceProvider.GetService&lt;ICacheLogic&gt;();
                if (cache != null)
                {
                    baseMediaUrl = cache.GetOrCreateItem(cacheKey, () =&gt; GetMediaUrl(item, baseMediaUrl),
                        new TimeSpan(6, 0, 0));
                }
            }
            return baseMediaUrl;
        }

        private string GetMediaUrl(MediaItem item, string baseMediaUrl)
        {
            UrlString url = new UrlString(baseMediaUrl);

            if (baseMediaUrl.Contains(Sitecore.Configuration.Settings.Media.MediaLinkPrefix))
            {
                var version = item.InnerItem.Version.Number.ToString();
                var updated = DateUtil.ToIsoDate(item.InnerItem.Statistics.Updated);

                url.HostName = Sitecore.Context.Site.Properties[CDNHostnamePropertyKey];
                url.Protocol = WebUtil.GetScheme();
                url.Add("v", version);
                url.Add("d", updated);
                baseMediaUrl = url.ToString();
            }
            return LinkHelper.RemoveSslPort(baseMediaUrl);
        }

        private bool HasCDN(SiteContext siteContext)
        {
            return !string.IsNullOrEmpty(siteContext.Properties[CDNHostnamePropertyKey]);
        }
    }
}

</code></pre>
<p>The code above can serve requests as they come and cache them for a speedy retrieval. As you can see I am adding in the version and the updated date so that published changes will get reflected. To get this code executing we need to register our CDNMediaProvider class using the following patch config.</p>
<pre><code class="language-xml">     
&lt;configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"&gt;
  &lt;sitecore&gt;
    &lt;mediaLibrary&gt;
      &lt;mediaProvider&gt;
        &lt;patch:attribute name="type"&gt;YOURSOLUTIONNAMESPACE.Business.SC.Providers.CDNMediaProvider, YOURSOLUTIONNAMESPACE.Business&lt;/patch:attribute&gt;
      &lt;/mediaProvider&gt;
    &lt;/mediaLibrary&gt;
  &lt;/sitecore&gt;
&lt;/configuration&gt;
</code></pre>
<p>That is it. Once the code is published with the right settings, you will see your media urls come up with the cdn host appended.<br />
https://cdn.firstsitedomain.com/-/media/hero/blackboard.png?v=1&#038;d=20170322T200703Z</p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>Don't speak I know just what you're saying - Sitecore SPEAK - Customize General Link with NoFollow Checkbox</title>
      <link>https://akshaysura.com/blog/dont-speak-i-know-just-what-youre-saying-sitecore-speak-customize-general-link-with-nofollow-checkbox/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/dont-speak-i-know-just-what-youre-saying-sitecore-speak-customize-general-link-with-nofollow-checkbox/</guid>
      <pubDate>Fri, 07 Apr 2017 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[I recently had to customize a General Link SPEAK dialog to add a NoFollow checkbox so that we can add a rel=”nofollow” on certain links on the site. At first, I was scared of SPEAK and I did not SPEAK yet! 😉]]></description>
      <content:encoded><![CDATA[<p>I recently had to customize a General Link SPEAK dialog to add a NoFollow checkbox so that we can add a rel=&#8221;nofollow&#8221; on certain links on the site. At first, I was scared of SPEAK and I did not SPEAK yet! 😉</p>
<p>I will say that SPEAK could be easier thank it is and it would help if it didn&#8217;t change for every release. Saying that, my hope is that SPEAK will either evolve or Sitecore will end up changing it entirely. I implemented it in Sitecore 8.2 Update 2 rev.161221.</p>
<p>I started searching on this topic and I did not get many hits on customizing an existing field like General Link. The ones I found useful are listed at the bottom of this post. It was made difficult by the changes to Sitecore in each release. Finally I was able to get a working solution. So here goes.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/04/hFE406D6A.jpg"><img loading="lazy" class="alignnone size-full wp-image-3025" src="https://akshaysura.com/wp-content/uploads/2017/04/hFE406D6A.jpg" alt="" width="500" height="357" /></a></p>
<p>First and foremost, install <a href="https://marketplace.visualstudio.com/items?itemName=JakobChristensen.SitecoreRocks" target="_blank">Sitecore Rocks Visual Studio Plugin</a>, it will make your life easy.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/04/speak1.png"><img loading="lazy" class="alignnone size-full wp-image-3009" src="https://akshaysura.com/wp-content/uploads/2017/04/speak1.png" alt="" width="1009" height="948" /></a></p>
<p>Connect Sitecore Rocks to your local Sitecore Site. Make sure you test the connection so that Sitecore Rocks can update the server components for its interaction.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/04/speak2.png"><img loading="lazy" class="alignnone size-full wp-image-3010" src="https://akshaysura.com/wp-content/uploads/2017/04/speak2.png" alt="" width="647" height="347" /></a></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/04/speak3.png"><img loading="lazy" class="alignnone size-full wp-image-3011" src="https://akshaysura.com/wp-content/uploads/2017/04/speak3.png" alt="" width="464" height="281" /></a></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/04/speak4.png"><img loading="lazy" class="alignnone size-full wp-image-3012" src="https://akshaysura.com/wp-content/uploads/2017/04/speak4.png" alt="" width="485" height="367" /></a></p>
<p>Once connected, traverse through the tree to /sitecore/client/Applications/Dialogs/InsertLinkViaTreeDialog.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/04/speak5.png"><img loading="lazy" class="alignnone size-full wp-image-3013" src="https://akshaysura.com/wp-content/uploads/2017/04/speak5.png" alt="" width="407" height="811" /></a></p>
<p>Open the Design Layout for that Dialog.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/04/speak6.png"><img loading="lazy" class="alignnone size-full wp-image-3014" src="https://akshaysura.com/wp-content/uploads/2017/04/speak6.png" alt="" width="834" height="506" /></a></p>
<p>Once open you can see the different renderings which make up the Dialog.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/04/speak7.png"><img loading="lazy" class="alignnone size-large wp-image-3015" src="https://akshaysura.com/wp-content/uploads/2017/04/speak7-1024x864.png" alt="" width="900" height="759" /></a></p>
<p><span style="text-decoration: underline;"><strong>WORD OF CAUTION: I hosed my install when I added SPEAK 2 renderings in this dialog. The Dialog displayed and acted differently. So the best way to make sure it will work is to duplicate the renderings currently in the Dialog and set the properties.</strong></span></p>
<p>Open the properties of the PageCode rendering and note the location for the PageCodeScriptFileName attribute and the value for the PageCodeTypeName. Later on we will be modifying these to get our functionality working.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/04/speak8.png"><img loading="lazy" class="alignnone size-large wp-image-3016" src="https://akshaysura.com/wp-content/uploads/2017/04/speak8-1024x441.png" alt="" width="900" height="388" /></a></p>
<p>Next, lets duplicate one of the existing items like Anchor. Each of the fields usually comes with three renderings, one for Row, one for label and field. Lets call them, NoFollowRow, NoFollowTextLbl and NoFollowText.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/04/speak9.png"><img loading="lazy" class="alignnone size-full wp-image-3017" src="https://akshaysura.com/wp-content/uploads/2017/04/speak9.png" alt="" width="805" height="62" /></a></p>
<p>Since we want a checkbox, we will add a new SPEAK version 1 checkbox by clicking on the Add rendering button up top. Lets call it NoFollowChk.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/04/speak11.png"><img loading="lazy" class="alignnone size-large wp-image-3019" src="https://akshaysura.com/wp-content/uploads/2017/04/speak11-1024x817.png" alt="" width="900" height="718" /></a></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/04/speak12.png"><img loading="lazy" class="alignnone size-full wp-image-3020" src="https://akshaysura.com/wp-content/uploads/2017/04/speak12.png" alt="" width="813" height="74" /></a><a href="https://akshaysura.com/wp-content/uploads/2017/04/speak10.png"><br />
</a></p>
<p>On NoFollowRow properties lets make sure the PlaceholderKey is set to NameContainer.Content and for the other three renderings, lets set the PlaceholderKey to NoFollowRow.Content.</p>
<p><span style="text-decoration: underline;"><strong>Now please don&#8217;t be that fruit who complains about too much detail. I figured that there are a few steps which seem simple enough but difficult to find/perform if you are not a SPEAK expert.</strong></span></p>
<p>Here are the property values for each of the renderings.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/04/speak13.png"><img loading="lazy" class="alignnone size-full wp-image-3021" src="https://akshaysura.com/wp-content/uploads/2017/04/speak13.png" alt="" width="1006" height="536" /></a></p>
<p>For Text&#8217;s you can either specify on the rendering or provide a datasource to where the text is stored.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/04/speak14.png"><img loading="lazy" class="alignnone size-large wp-image-3022" src="https://akshaysura.com/wp-content/uploads/2017/04/speak14-1024x569.png" alt="" width="900" height="500" /></a></p>
<p>Leave the text field for Checkbox empty as we want to use the pretty label in NoFollowTextLbl.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/04/speak15.png"><img loading="lazy" class="alignnone size-large wp-image-3023" src="https://akshaysura.com/wp-content/uploads/2017/04/speak15-1024x548.png" alt="" width="900" height="482" /></a></p>
<p>We are going to set the text box to be invisible. We will use it for storage of the checked value.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/04/speak16.png"><img loading="lazy" class="alignnone size-full wp-image-3024" src="https://akshaysura.com/wp-content/uploads/2017/04/speak16.png" alt="" width="1004" height="562" /></a></p>
<p>Now that we have everything setup on the dialog, save the InsertLinkViaTreeDialog.layout item.</p>
<p>Ok now for the dirty part. We need to replace Sitecore.Speak.Applications.InsertLinkDialogTree, Sitecore.Speak.Applications with our custom implementation. Unfortunately we have to go down this route ad the code in Sitecore.Speak.Applications.InsertLinkDialogTree, Sitecore.Speak.Applications cannot be extended or overwritten. Lets get to it.</p>
<p>Use your favorite decompiler to get the output for Sitecore.Speak.Applications.InsertLinkDialogTree, Sitecore.Speak.Applications and create a new class InsertLinkDialogTreeCustom. Here is the complete class from ReSharper (Modified lines are highlighted):</p>
<pre><code class="language-csharp">using Sitecore;
using Sitecore.Configuration;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.Shell;
using Sitecore.Speak.Applications;
using Sitecore.Web;
using Sitecore.Web.PageCodes;
using System;
using System.Net;
using System.Xml.Linq;

namespace CustomSpeak
{
    public class InsertLinkDialogTreeCustom : PageCodeBase
    {
        private string targetActiveBrowserItemId = "{C5FA4571-37B3-472C-BDA1-0FADC2D2EFA7}";
        private string targetNewBrowserItemId = "{02A6C72E-17BB-48C5-8D35-AF9C494ED6BA}";
        private string targetCustomItemId = "{07CF2A84-9C22-4E85-8F3F-C301AADF5218}";

        public Sitecore.Mvc.Presentation.Rendering TreeView { get; set; }

        public Sitecore.Mvc.Presentation.Rendering ListViewToggleButton { get; set; }

        public Sitecore.Mvc.Presentation.Rendering TreeViewToggleButton { get; set; }

        public Sitecore.Mvc.Presentation.Rendering InsertEmailButton { get; set; }

        public Sitecore.Mvc.Presentation.Rendering InsertAnchorButton { get; set; }

        public Sitecore.Mvc.Presentation.Rendering TextDescription { get; set; }

        public Sitecore.Mvc.Presentation.Rendering AnchorText { get; set; }

        public Sitecore.Mvc.Presentation.Rendering Target { get; set; }

        public Sitecore.Mvc.Presentation.Rendering AltText { get; set; }

        public Sitecore.Mvc.Presentation.Rendering QueryString { get; set; }

        public Sitecore.Mvc.Presentation.Rendering StyleClass { get; set; }

        public Sitecore.Mvc.Presentation.Rendering CustomUrl { get; set; }

        public Sitecore.Mvc.Presentation.Rendering TargetLoadedValue { get; set; }

        public Sitecore.Mvc.Presentation.Rendering NoFollowChk { get; set; }

        public Sitecore.Mvc.Presentation.Rendering NoFollowText { get; set; }

        public string TargetActiveBrowserItemId
        {
            get
            {
                return this.targetActiveBrowserItemId;
            }
            set
            {
                Assert.ArgumentNotNull((object)value, "value");
                this.targetActiveBrowserItemId = value;
            }
        }

        public string TargetNewBrowserItemId
        {
            get
            {
                return this.targetNewBrowserItemId;
            }
            set
            {
                Assert.ArgumentNotNull((object)value, "value");
                this.targetNewBrowserItemId = value;
            }
        }

        public string TargetCustomItemId
        {
            get
            {
                return this.targetCustomItemId;
            }
            set
            {
                Assert.ArgumentNotNull((object)value, "value");
                this.targetCustomItemId = value;
            }
        }

        public override void Initialize()
        {
            string setting = Settings.GetSetting("BucketConfiguration.ItemBucketsEnabled");
            this.ListViewToggleButton.Parameters["IsVisible"] = setting;
            this.TreeViewToggleButton.Parameters["IsVisible"] = setting;
            this.TreeView.Parameters["ShowHiddenItems"] = UserOptions.View.ShowHiddenItems.ToString();
            this.TreeView.Parameters["ContentLanguage"] = WebUtil.GetQueryString("la");
            this.ReadQueryParamsAndUpdatePlaceholders();
        }

        private static string GetXmlAttributeValue(XElement element, string attrName)
        {
            if (element.Attribute((XName)attrName) == null)
                return string.Empty;
            return element.Attribute((XName)attrName).Value;
        }

        private void ReadQueryParamsAndUpdatePlaceholders()
        {
            string queryString1 = WebUtil.GetQueryString("ro");
            string queryString2 = WebUtil.GetQueryString("hdl");
            if (!string.IsNullOrEmpty(queryString1) && queryString1 != "{0}")
                this.TreeView.Parameters["RootItem"] = queryString1;
            this.InsertAnchorButton.Parameters["Click"] = string.Format(this.InsertAnchorButton.Parameters["Click"], (object)WebUtility.UrlEncode(queryString1), (object)WebUtility.UrlEncode(queryString2));
            this.InsertEmailButton.Parameters["Click"] = string.Format(this.InsertEmailButton.Parameters["Click"], (object)WebUtility.UrlEncode(queryString1), (object)WebUtility.UrlEncode(queryString2));
            this.ListViewToggleButton.Parameters["Click"] = string.Format(this.ListViewToggleButton.Parameters["Click"], (object)WebUtility.UrlEncode(queryString1), (object)WebUtility.UrlEncode(queryString2));
            int num = queryString2 != string.Empty ? 1 : 0;
            string empty = string.Empty;
            if (num != 0)
                empty = UrlHandle.Get()["va"];
            if (!(empty != string.Empty))
                return;
            XElement xelement = XElement.Parse(empty);
            if (!(InsertLinkDialogTreeCustom.GetXmlAttributeValue(xelement, "linktype") == "internal"))
                return;
            string xmlAttributeValue = InsertLinkDialogTreeCustom.GetXmlAttributeValue(xelement, "id");
            if (string.IsNullOrWhiteSpace(xmlAttributeValue))
                return;
            Item obj = (string.IsNullOrEmpty(queryString1) ? (Item)null : ClientHost.Databases.ContentDatabase.GetItem(queryString1)) ?? ClientHost.Databases.ContentDatabase.GetRootItem();
            Item itemFromQueryString = SelectMediaDialog.GetMediaItemFromQueryString(xmlAttributeValue);
            if (obj != null && itemFromQueryString != null && itemFromQueryString.Paths.LongID.StartsWith(obj.Paths.LongID))
                this.TreeView.Parameters["PreLoadPath"] = obj.ID.ToString() + itemFromQueryString.Paths.LongID.Substring(obj.Paths.LongID.Length);
            this.TextDescription.Parameters["Text"] = InsertLinkDialogTreeCustom.GetXmlAttributeValue(xelement, "text");
            this.AltText.Parameters["Text"] = InsertLinkDialogTreeCustom.GetXmlAttributeValue(xelement, "title");
            this.StyleClass.Parameters["Text"] = InsertLinkDialogTreeCustom.GetXmlAttributeValue(xelement, "class");
            this.QueryString.Parameters["Text"] = InsertLinkDialogTreeCustom.GetXmlAttributeValue(xelement, "querystring");
            this.AnchorText.Parameters["Text"] = InsertLinkDialogTreeCustom.GetXmlAttributeValue(xelement, "anchor");
            this.NoFollowChk.Parameters["Text"] = InsertLinkDialogTreeCustom.GetXmlAttributeValue(xelement, "nofollowchk");

            this.NoFollowText.Parameters["Text"] = InsertLinkDialogTreeCustom.GetXmlAttributeValue(xelement, "nofollowtext");

            this.SetupTargetDropbox(xelement);
        }

        private void SetupTargetDropbox(XElement fieldContent)
        {
            string xmlAttributeValue = InsertLinkDialogTreeCustom.GetXmlAttributeValue(fieldContent, "target");
            string str;
            if (xmlAttributeValue.Equals("_blank", StringComparison.OrdinalIgnoreCase))
                str = this.TargetNewBrowserItemId;
            else if (string.IsNullOrWhiteSpace(xmlAttributeValue))
            {
                str = this.TargetActiveBrowserItemId;
            }
            else
            {
                str = this.TargetCustomItemId;
                this.CustomUrl.Parameters["Text"] = xmlAttributeValue;
            }
            this.TargetLoadedValue.Parameters["Text"] = str;
        }
    }
}

</code></pre>
<p>Add the two properties we need.</p>
<pre><code class="language-csharp">public Sitecore.Mvc.Presentation.Rendering NoFollowChk { get; set; }
public Sitecore.Mvc.Presentation.Rendering NoFollowText { get; set; }
</code></pre>
<p>In the ReadQueryParamsAndUpdatePlaceholders function add the following to send back information stored to the SPEAK component.</p>
<pre><code class="language-csharp">this.NoFollowChk.Parameters["Text"] = InsertLinkDialogTreeCustom.GetXmlAttributeValue(xelement, "nofollowchk");
this.NoFollowText.Parameters["Text"] = InsertLinkDialogTreeCustom.GetXmlAttributeValue(xelement, "nofollowtext");
</code></pre>
<p>The next part is to modify how the fields interact. Open Website\sitecore\shell\client\Applications\Dialogs\InsertLinkViaTreeDialog.js file.</p>
<p>Modify the initialized function to check for the text value in the text field and set the checkbox based on that. Here is the entire file with modifications.</p>
<pre><code class="language-javascript">define(["sitecore"], function(Sitecore) {
  var InsertLinkViaTreeDialog = Sitecore.Definitions.App.extend({
    initialized: function () {

      this.updateCustomUrl();

      if (this.NoFollowText.get("text") == "true")
      {
	      this.NoFollowChk.set("isChecked", true);
      }
	  
      this.Target.on("change", function () {
        this.updateCustomUrl();
      }, this);

      // work around an issue in combobox
      this.TargetsDataSource.on("change:items", function () {
        if (this.__firstTime) {
          this.__firstTime = false;
          this.Target.set("selectedValue", this.TargetLoadedValue.get("text"));
        }
      }, this);
    },
      
    updateCustomUrl: function () {

      var emptyOptionID = "{A3C9DB39-1D1B-4AA1-8C68-7B9674D055EE}";
      var customUrlOptionID = "{07CF2A84-9C22-4E85-8F3F-C301AADF5218}";

      var targetWindowValue = this.Target.get("selectedItem");

      if (!targetWindowValue || targetWindowValue.itemId === emptyOptionID) {
        this.CustomUrl.set("isEnabled", false);
        return;
      }

      if (targetWindowValue.itemId === customUrlOptionID) {
        this.CustomUrl.set("isEnabled", true);
      } else {
        this.CustomUrl.set("isEnabled", false);
      }
    },

    insertInternalLinkResult: function () {
      var targetDisplayTextID = this.TextDescription,
      targetPathID = this.TreeView,
      targetPathProperty = "$path",
      targetQueryID = this.QueryString,
      targetAltTextID = this.AltText,
      targetStyleID = this.StyleClass,
      targetWindowID = this.Target,
      customUrlID = this.CustomUrl,
      targetControlID = this.TreeView,
      anchor = this.AnchorText,
      nofollowtext = this.NoFollowText,

      nofollowchk = this.NoFollowChk,
      selectedItemsPropertyName = "selectedNode",
      template = '&lt;link text="&lt;%=displayText%&gt;" anchor="&lt;%=anchor%&gt;" linktype="internal" class="&lt;%=styleClass%&gt;" title="&lt;%=alternateText%&gt;" &lt;%=target%&gt; querystring="&lt;%=queryString%&gt;" id="&lt;%=itemId%&gt;" nofollowtext="&lt;%=nofollowtext%&gt;" nofollowchk="&lt;%=nofollowchk%&gt;" /&gt;',
      targetWindowValue,
      path,
      emptyOptionID = "{A3C9DB39-1D1B-4AA1-8C68-7B9674D055EE}",
      htmlEncode = function (str) {
        return str.toString().replace(/&amp;/g, '&amp;amp;').replace(/&lt;/g, '&amp;lt;').replace(/&gt;/g, '&amp;gt;').replace(/"/g, '&amp;quot;');
      };

      if (!targetDisplayTextID) {
        console.log("Provide at least display text for your link");
        return false;
      }

      targetWindowValue = targetWindowID.get("selectedItem");

      if (!targetWindowValue || targetWindowValue.itemId === emptyOptionID) {
        targetWindowValue = "";
      } else {
        var targetWindow = targetWindowValue.$displayName.trim();

        switch (targetWindow) {
          case 'Active Browser':
            targetWindow = "";
            break;
          case 'New Browser':
            targetWindow = "_blank";
            break;
          case "Custom":
            targetWindow = customUrlID.get("text");
            break;
          default:
            targetWindow = "";
        }

        targetWindowValue = "target=\"" + targetWindow + "\"";
      }

      if (targetPathID.get(selectedItemsPropertyName) &amp;&amp;
        "rawItem" in targetPathID.get(selectedItemsPropertyName) &amp;&amp;
        targetPathID.get(selectedItemsPropertyName).rawItem[targetPathProperty]) {
        path = targetPathID.get(selectedItemsPropertyName).rawItem[targetPathProperty];
      }

      var itemLink = _.template(template, {
        displayText: htmlEncode(targetDisplayTextID.get("text")),
        alternateText: htmlEncode(targetAltTextID.get("text")),
        itemId: targetControlID.get("selectedItemId"),
        queryString: htmlEncode(targetQueryID.get("text")),
        target: targetWindowValue,
        styleClass: htmlEncode(targetStyleID.get("text")),
        path: path,
        
        nofollowtext: nofollowchk.get("isChecked"),

        nofollowchk: htmlEncode(nofollowchk.get("text")),
        anchor: htmlEncode(anchor.get("text"))
      });

      return this.closeDialog(itemLink);
    },
        
    __firstTime: true

  });

  return InsertLinkViaTreeDialog;
});
</code></pre>
<p>In the insertInternalLinkResult function, add in the mapping from the Class to the variables UI will write as raw value of the General Link field. Also modify the template variable to add in the markup used to generate the output to be stored in the General Link field. Last but not the least is to store the correct Checkbox value in the text field. Boom, this concludes the customization. Now to check out the output.</p>
<pre><code class="language-javascript">
if (this.NoFollowText.get("text") == "true")
{
      this.NoFollowChk.set("isChecked", true);
}
</code></pre>
<pre><code class="language-javascript">
nofollowtext = this.NoFollowText,
nofollowchk = this.NoFollowChk,
selectedItemsPropertyName = "selectedNode",
template = '&lt;link text="&lt;%=displayText%&gt;" anchor="&lt;%=anchor%&gt;" linktype="internal" class="&lt;%=styleClass%&gt;" title="&lt;%=alternateText%&gt;" &lt;%=target%&gt; querystring="&lt;%=queryString%&gt;" id="&lt;%=itemId%&gt;" nofollowtext="&lt;%=nofollowtext%&gt;" nofollowchk="&lt;%=nofollowchk%&gt;" /&gt;',
</code></pre>
<pre><code class="language-javascript">
nofollowtext: nofollowchk.get("isChecked"),
nofollowchk: htmlEncode(nofollowchk.get("text")),
</code></pre>
<p>This only solves half the problem which is how do we get Sitecore backend to show and process the Checkbox for NoFollow. In the next blog post we will look at how to render it using GlassMapper. Here is a video of the functionality.</p>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/FO0mGYdb2Sk" frameborder="0" allowfullscreen></iframe></p>
<p><iframe width="480" height="293.8775510204082" allowfullscreen="allowfullscreen" class="giphy-embed" frameborder="0" src="//giphy.com/embed/vgOJdBUmdySf6"></iframe><br />
<a href="https://giphy.com/gifs/gwen-stefani-divorce-gavin-rossdale-vgOJdBUmdySf6">via GIPHY</a></p>
<p>&nbsp;</p>
<p>References:<br />
<a href="http://sitecore.stackexchange.com/questions/3781/general-link-dialog-insertlinkviatreedialog-misses-insertlinkrules-after-upgra" target="_blank">General Link Dialog InsertLinkViaTreeDialog misses InsertLinkRules after Upgrade to 8.2u2</a><br />
<a href="http://sitecore.stackexchange.com/questions/571/extending-internal-general-link-dialog-with-checkbox-in-speak" target="_blank">Extending internal General Link dialog with Checkbox in SPEAK</a><br />
<a href="https://drazenjanjicek.com/2016/03/18/extending-sitecore-8-1-adding-support-for-anchors-in-internal-links/" target="_blank">Extending Sitecore 8.1 – Adding support for anchors in internal links</a></p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>Habi what-a-tat ? Create a Sitecore Helix solution from scratch using PowerShell</title>
      <link>https://akshaysura.com/blog/habi-what-a-tat-create-a-sitecore-helix-solution-from-scratch-using-powershell/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/habi-what-a-tat-create-a-sitecore-helix-solution-from-scratch-using-powershell/</guid>
      <pubDate>Sat, 21 Jan 2017 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[This post is all about creating a Helix based solution from scratch. Please watch the video for additional information and a demo of the script. I really discourage people from using Habitat as the base to create new solutions. Hopefully this script will help.]]></description>
      <content:encoded><![CDATA[<p>This post is all about creating a Helix based solution from scratch. Please watch the video for additional information and a demo of the script. I really discourage people from using Habitat as the base to create new solutions. Hopefully this script will help.</p>
<p>Also refer to Marc Duiker&#8217;s <a href="http://blog.marcduiker.nl/2016/12/29/hands-on-with-sitecore-helix-anatomy-add-helix-powershell-script.html" target="_blank">Hands-on with Sitecore Helix: Anatomy of the Add-HelixModule.ps1 PowerShell script</a>.</p>
<p>So in order to create a Helix solution from scratch, we do not have any tool at this moment. We either manually build it or use Habitat as a base. I do not recommend using Habitat and modifying that solution to fit your needs.</p>
<p>To start of with, the best way to automate this is to use PowerShell scripts inside of the Visual Studio IDE via the Package Manager Console. We need to use <a href="https://msdn.microsoft.com/en-us/library/mt452175.aspx" target="_blank">DTE (EnvDTE)</a>.</p>
<p>Download the HabitatSolutionScript.ps1 from <a href="https://gist.github.com/akshaysura/184132f67decb749ae235b602351832c" target="_blank">https://gist.github.com/akshaysura/184132f67decb749ae235b602351832c</a></p>
<p>Open Visual Studio IDE</p>
<p>Open Package Manager Console</p>
<p>Type in $profile</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/01/habiwhat1.png"><img loading="lazy" class="alignnone size-full wp-image-2975" src="https://akshaysura.com/wp-content/uploads/2017/01/habiwhat1.png" alt="" width="752" height="149" /></a></p>
<p>Open that location in Windows explorer. You might not have NuGet_profile.ps1 at that location. Create one.</p>
<p>Open the NuGet_profile.ps1 and insert the following line and modify the path to your HabitatSolutionScript.ps1</p>
<p>. &#8220;D:\Projects\PowerShell\HabitatSolutionScript.ps1&#8221;</p>
<p>Save and close NuGet_profile.ps1</p>
<p>Restart your Visual Studio IDE and open Package Manager Console</p>
<p>Type in let and tab or you could type in the whole command Lets-Rumble</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/01/habitwhat2.png"><img loading="lazy" class="alignnone size-full wp-image-2976" src="https://akshaysura.com/wp-content/uploads/2017/01/habitwhat2.png" alt="" width="642" height="256" /></a></p>
<p>Follow the on screen prompts and enjoy your solution. I would recommend watching the video for additional information.</p>
<p>The script is not tested so please use it at your own risk. Since it required an empty folder, it won&#8217;t affect your existing code/solutions.</p>
<p>&nbsp;</p>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/zvEI437nMH8" frameborder="0" allowfullscreen="allowfullscreen"></iframe></p>
<p>&nbsp;</p>
<p>Please contribute to this script and hopefully we can make it better for the entire community.</p>
<pre><code class="language-csharp">#paths to the project templates on your system
$global:classTemplate = "D:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\ProjectTemplatesCache\CSharp\Windows Root\Windows\1033\ClassLibrary\csClassLibrary.vstemplate"
$global:webTemplate = "D:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\ProjectTemplatesCache\CSharp\Web\1033\WebApplicationProject40\EmptyWebApplicationProject40.vstemplate"

#variable used to store the path for the empty Habitat folder
$global:helixPath =""

#empty variable used to store the solution name
$global:solutionName = ""

#empty variable used to store the project names like Habitat to which we will add .Website
$global:projectNames = New-Object System.Collections.ArrayList

#empty variable used to store the feature name prefix like Sitecore.Foundation to which we will add foundation projects
$global:foundationNamePrefix = ""

#list of foundation projects to create
$global:foundationNames = New-Object System.Collections.ArrayList


#empty variable used to store the feature name prefix like Sitecore.Feature to which we will add feature projects
$global:featureNamePrefix = ""

#list of features to create
$global:featureNames = New-Object System.Collections.ArrayList


#Setup the folders to create
$global:folderPaths = @("\etc","\lib","\scripts","\specs","\src\Feature","\src\Foundation","\src\Project","\src\Project\Common\code","\src\Project","\src\Project\Common\code","\src\Project\Common\serialization")

$global:projectPath = "\src\Project\"
$global:foundationPath = "\src\Foundation\"
$global:featurePath = "\src\Feature\"
$global:srcFolder = "\src"
$global:codeFolder = "\code"
$global:rolesFolder = "\roles"
$global:serializationFolder = "\serialization"
$global:testsFolder = "\Tests"


$global:testProjectName = "Tests"
$global:websiteName = "Website"

$global:ConfigFolderName = "Configuration"
$global:FeatureFolderName = "Feature"
$global:FoundationFolderName = "Foundation"
$global:ProjectFolderName = "Project"


$global:solution = $null

&lt;# Prompt to confirm solution creation. #&gt;
function Confirm-Creation
{
     param (
           [string]$Title = 'Create Helix Solution?'
     )

     Write-Host "================ $Title ================"
     
     Write-Host "1: Continue"
     Write-Host "q: Press 'q' to Quit"
}

&lt;# Prompt to accept Projects #&gt;
function Accept-Projects
{
     param (
           [string]$Title = 'Enter Project Names/Tenants/Sites - Site1 etc'
     )

cls
     Write-Host "================ $Title ================"
     
     Write-Host "1: Create a Project."
     Write-Host "q: Press 'q' to exit this prompt and continue to create Foundation projects."
}

&lt;# Prompt to accept Foundation projects #&gt;
function Accept-FoundationProjects
{
     param (
           [string]$Title = 'Enter Foundation Project Name(s)'
     )

cls     
     Write-Host "================ $Title ================"
     
     Write-Host "1: Create a Foundation Project."
     Write-Host "q: Press 'q' to exit this prompt and continue to create Feature projects."
}

&lt;# Prompt to accept Feature projects #&gt;
function Accept-FeatureProjects
{
     param (
           [string]$Title = 'Enter Feature Project Name(s)'
     )
     cls
     Write-Host "================ $Title ================"
     
     Write-Host "1: Create a Feature Project."
     Write-Host "q: Press 'q' to exit this prompt and continue."
}

&lt;# Purpose is get the information for the folder in which we are going to create the folder structure #&gt;
function Get-HabitatFoundationFolder
{
    #Get path and validate the path
    $global:helixPath = $input = Read-Host "Please specify the path to an empty folder"

    if($global:helixPath -eq "")
    {
        Write-Host "Select a valid folder path."
        exit
    }

    if ( -not (Test-Path $global:helixPath -PathType Container) ) 
    { 
        Write-Host "Select a valid folder."
        exit
    }

    $directoryInfo = Get-ChildItem $global:helixPath | Measure-Object
    if ($directoryInfo.count -gt 0)
    {
        Write-Host "Folder is not empty."
        exit
    }
}

&lt;# Purpose is to create the base folder structure of the Habitat solution. Step 1. #&gt;
function Create-HabitatFoundationFolders
{

    foreach ($path in $global:folderPaths)
    {
        $newFolder = $global:helixPath + $path
        New-Item -ItemType Directory -Path $newFolder -Force    
    }

    $solution = Get-Interface $dte.Solution ([EnvDTE80.Solution2])
    $parentProject = $solution.AddSolutionFolder($global:FoundationFolderName)
    $parentSolutionFolder = Get-Interface $parentProject.Object ([EnvDTE80.SolutionFolder])

    foreach ($foundation in $global:foundationNames)
    {
    
        $newFolder = $global:helixPath + $global:foundationPath + $foundation + $global:codeFolder
        $projectName = $global:foundationNamePrefix + "." + $foundation
        $testsProjectName = $global:foundationNamePrefix + "." + $foundation + "." + $global:testProjectName

        $childProject = $parentSolutionFolder.AddSolutionFolder($foundation)
        $childSolutionFolder = Get-Interface $childProject.Object ([EnvDTE80.SolutionFolder])

        $projectFile = $childSolutionFolder.AddFromTemplate($global:webTemplate,$newFolder, $projectName);

        $newFolder = $global:helixPath + $global:foundationPath + $foundation + $global:rolesFolder
        New-Item -ItemType Directory -Path $newFolder -Force    

        $newFolder = $global:helixPath + $global:foundationPath + $foundation + $global:serializationFolder
        New-Item -ItemType Directory -Path $newFolder -Force    

        $newFolder = $global:helixPath + $global:foundationPath + $foundation + $global:testsFolder
        $projectFile = $childSolutionFolder.AddFromTemplate($global:classTemplate,$newFolder, $testsProjectName);
    }

    $solution = Get-Interface $dte.Solution ([EnvDTE80.Solution2])
    $parentProject = $solution.AddSolutionFolder($global:FeatureFolderName)
    $parentSolutionFolder = Get-Interface $parentProject.Object ([EnvDTE80.SolutionFolder])

    foreach ($feature in $global:featureNames)
    {
        $newFolder = $global:helixPath + $global:featurePath + $feature + $global:codeFolder
        $projectName = $global:featureNamePrefix + "." + $feature
        $testsProjectName = $global:featureNamePrefix + "." + $feature + "." + $global:testProjectName

        $childProject = $parentSolutionFolder.AddSolutionFolder($feature)
        $childSolutionFolder = Get-Interface $childProject.Object ([EnvDTE80.SolutionFolder])

        $projectFile = $childSolutionFolder.AddFromTemplate($global:webTemplate,$newFolder, $projectName);

        $newFolder = $global:helixPath + $global:featurePath + $feature + $global:rolesFolder
        New-Item -ItemType Directory -Path $newFolder -Force    

        $newFolder = $global:helixPath + $global:featurePath + $feature + $global:serializationFolder
        New-Item -ItemType Directory -Path $newFolder -Force    

        $newFolder = $global:helixPath + $global:featurePath + $feature + $global:testsFolder
        $projectFile = $childSolutionFolder.AddFromTemplate($global:classTemplate,$newFolder, $testsProjectName);
    }

    $solution = Get-Interface $dte.Solution ([EnvDTE80.Solution2])
    $parentProject = $solution.AddSolutionFolder($global:ProjectFolderName)
    $parentSolutionFolder = Get-Interface $parentProject.Object ([EnvDTE80.SolutionFolder])

    foreach ($project in $global:projectNames)
    {
        $newFolder = $global:helixPath + $global:projectPath + $project + $global:codeFolder
        $projectName = $global:solutionName + "." + $project + "." + $global:websiteName

        $parentSolutionFolder = Get-Interface $parentProject.Object ([EnvDTE80.SolutionFolder])
        $childProject = $parentSolutionFolder.AddSolutionFolder($project)
        $childSolutionFolder = Get-Interface $childProject.Object ([EnvDTE80.SolutionFolder])

        $projectFile = $childSolutionFolder.AddFromTemplate($global:webTemplate,$newFolder, $projectName);

        $newFolder = $global:helixPath + $global:projectPath + $project + $global:rolesFolder
        New-Item -ItemType Directory -Path $newFolder -Force    

        $newFolder = $global:helixPath + $global:projectPath + $project + $global:serializationFolder
        New-Item -ItemType Directory -Path $newFolder -Force    
    }

    Write-Host "Done creating Habitat Foundation Structure."
}

&lt;# Purpose is to accept inputs #&gt;
function Accept-VSSolutionNames
{
    do
    {
        cls
        $input = Read-Host "Please specify you solution name. This could be the company name or overall solution name. e.g. Acme or MSFT "

        if([string]::IsNullOrWhiteSpace($input))
        {
            Write-Host "Empty solution name. Try again."
        }
        else
        {
            $global:solutionName = $input
        }
    }
    until (-not([string]::IsNullOrWhiteSpace($global:solutionName)))

    do
    {
        $global:foundationNamePrefix = Read-Host "Please specify you foundation name prefix. e.g."$global:solutionName".Foundation"

        if([string]::IsNullOrWhiteSpace($global:foundationNamePrefix))
        {
            Write-Host "Empty foundation name prefix. Try again."
        }
    }
    until (-not([string]::IsNullOrWhiteSpace($global:foundationNamePrefix)))

    do
    {
        $global:featureNamePrefix = Read-Host "Please specify you feature name prefix. e.g."$global:solutionName".Feature"

        if([string]::IsNullOrWhiteSpace($global:featureNamePrefix))
        {
            Write-Host "Empty feature name prefix. Try again."
        }
    }
    until (-not([string]::IsNullOrWhiteSpace($global:featureNamePrefix)))

    do
    {
         Accept-Projects
         $input = Read-Host "Enter your Project name/Tenant/Site name or q to continue. (Habitat or Site1)"
         if ($input -eq 'q')
         {
            break         
         }
         elseif (-not([string]::IsNullOrWhiteSpace($input)))
         {
               $global:projectNames.Add($input)
               #create foundation project          
         }
    }
    until ($input -eq 'q')

    do
    {
         Accept-FoundationProjects
         $input = Read-Host "Enter your Foundation project name or q to continue."
         if ($input -eq 'q')
         {
            break         
         }
         elseif (-not([string]::IsNullOrWhiteSpace($input)))
         {
               $global:foundationNames.Add($input)
               #create foundation project          
         }
    }
    until ($input -eq 'q')

    do
    {
         Accept-FeatureProjects
         $input = Read-Host "Enter your Feature project name or q to continue."
         if ($input -eq 'q')
         {
            break         
         }
         elseif (-not([string]::IsNullOrWhiteSpace($input)))
         {
               $global:featureNames.Add($input)
               #create feature project          
         }
    }
    until ($input -eq 'q')
}

&lt;# Confirm selections/input #&gt;
function Confirm-VSSolutionNames
{
    cls
    Write-Host "Solution Name:" $global:solutionName
    Write-Host "Project Names:" $global:projectNames
    Write-Host "Foundation Name Prefix:" $global:foundationNamePrefix
    Write-Host "Feature Name Prefix:" $global:featureNamePrefix
    Write-Host "Foundation Projects:" $global:foundationNames
    Write-Host "Feature Projects:" $global:featureNames

    Confirm-Creation

    $input = Read-Host "Enter 1 to continue or q to exit."
    if ($input -eq 'q')
    {
        exit
    }
    elseif ($input -eq '1')
    {
        $dte.Solution.Create($global:helixPath, $global:solutionName)
        $global:solution = $dte.Solution
        $dte.ExecuteCommand("File.SaveAll")

        Create-HabitatFoundationFolders

        $solution = Get-Interface $dte.Solution ([EnvDTE80.Solution2])
        $parentFolder = $solution.AddSolutionFolder($global:ConfigFolderName)
        $dte.ExecuteCommand("File.SaveAll")
    }
}

&lt;# Start function #&gt;
function Lets-Rumble
{
    Write-Host "    )                 (                                  (                         "
    Write-Host " ( /(     (           )\ )     (         )               )\ )                   )  "
    Write-Host " )\())  ( )\(     )  (()/(     )\  (  ( /((             (()/(    (  (        ( /(  "
    Write-Host "((_)\  ))((_)\ ( /(   /(_)) ( ((_)))\ )\())\  (   (      /(_)) ( )( )\ `  )  )\()) "
    Write-Host " _((_)/((_)((_))\()) (_))   )\ _ /((_|_))((_) )\  )\ )  (_))   )(()((_)/(/( (_))/  "
    Write-Host "| || (_))| |(_|(_)\  / __| ((_) (_))(| |_ (_)((_)_(_/(  / __| ((_|(_|_|(_)_\| |_   "
    Write-Host "| __ / -_) || \ \ /  \__ \/ _ \ | || |  _|| / _ \ ' \)) \__ \/ _| '_| | '_ \)  _|  "
    Write-Host "|_||_\___|_||_/_\_\  |___/\___/_|\_,_|\__||_\___/_||_|  |___/\__|_| |_| .__/ \__|  "
    Write-Host "                                                                      |_|          "

    Get-HabitatFoundationFolder
    Accept-VSSolutionNames
    Confirm-VSSolutionNames
}

</code></pre>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>Is Boost the secret of Sitecore performance?</title>
      <link>https://akshaysura.com/blog/is-boost-the-secret-of-sitecore-performance/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/is-boost-the-secret-of-sitecore-performance/</guid>
      <pubDate>Thu, 05 Jan 2017 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[I have been doing quite a bit of performance testing lately. I promised Nathaneal Mann a while back that I would include Sitecore Boost while testing performance. Nat has done a lot of work around performance and he has put together Sitecore Boost. Its fairly simple to install and you can find all the information on his GitHub page: https://github.com/cardinal252/Sitecore.Boost]]></description>
      <content:encoded><![CDATA[<p>I have been doing quite a bit of performance testing lately. I promised <a href="https://twitter.com/cardinal252" target="_blank">Nathaneal Mann</a> a while back that I would include Sitecore Boost while testing performance. Nat has done a lot of work around performance and he has put together Sitecore Boost. Its fairly simple to install and you can find all the information on his GitHub page: <a href="https://github.com/cardinal252/Sitecore.Boost" target="_blank">https://github.com/cardinal252/Sitecore.Boost</a></p>
<p>I did not did not modify any configuration after installation. I pushed the production code to the VM and ran the tests.</p>
<p>The code is based on the information provided in <a href="https://akshaysura.com/2016/12/29/bring-it-on-the-battle-rages-between-simple-injector-and-microsoft-di-in-sitecore-performance-testing-land-far-far-away/" target="_blank">Bring it on! – The battle rages between Simple Injector and Microsoft DI in Sitecore Performance Testing land far far away!</a> . It currently runs on Microsoft DI, Glass 4.3.</p>
<p>I ran a test as is and a test with just Boost installed on top of it.</p>
<h2>Test Setup</h2>
<p><strong><em><span style="text-decoration: underline;">The following test was run twice for Non-Boost and twice for Boost.</span></em></strong></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/01/2.png"><img loading="lazy" class="alignnone size-full wp-image-2959" src="https://akshaysura.com/wp-content/uploads/2017/01/2.png" alt="" width="957" height="770" /></a></p>
<p>&nbsp;</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/01/1.png"><img loading="lazy" class="alignnone size-full wp-image-2958" src="https://akshaysura.com/wp-content/uploads/2017/01/1.png" alt="" width="770" height="635" /></a></p>
<p>&nbsp;</p>
<h2>Performance</h2>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/01/r1.png"><img loading="lazy" class="alignnone size-large wp-image-2966" src="https://akshaysura.com/wp-content/uploads/2017/01/r1-1024x453.png" alt="" width="900" height="398" /></a></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/01/r2.png"><img loading="lazy" class="alignnone size-large wp-image-2967" src="https://akshaysura.com/wp-content/uploads/2017/01/r2-1024x448.png" alt="" width="900" height="394" /></a></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/01/3.png"><img loading="lazy" class="alignnone size-large wp-image-2965" src="https://akshaysura.com/wp-content/uploads/2017/01/3-1024x450.png" alt="" width="900" height="396" /></a></p>
<h2>Page Timing Results</h2>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/01/TimeComparison.png"><img loading="lazy" class="alignnone size-full wp-image-2963" src="https://akshaysura.com/wp-content/uploads/2017/01/TimeComparison.png" alt="" width="1105" height="134" /></a></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/01/compare2.png"><img loading="lazy" class="alignnone size-full wp-image-2962" src="https://akshaysura.com/wp-content/uploads/2017/01/compare2.png" alt="" width="896" height="202" /></a></p>
<h2>Final Result</h2>
<p>Overall Boost did show performance improvement especially with processor time and queued requests. I have posted the comparisons for your review. As I mentioned, I did not make any config changes or code changes, just installed Boost. I will be doing some more performance tests to see if it stays consistent. Depending on your page and its renderings it will help a great deal.</p>
<p>If you have any questions about Boost, please be sure to reach out to <a href="https://twitter.com/cardinal252" target="_blank">Nathanael Mann</a>.</p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>SQL Server PowerShell to Backup or Run Jobs using Octopus Deploy</title>
      <link>https://akshaysura.com/blog/sql-server-powershell-to-backup-or-run-jobs-using-octopus-deploy/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/sql-server-powershell-to-backup-or-run-jobs-using-octopus-deploy/</guid>
      <pubDate>Thu, 05 Jan 2017 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Recently I had to re-tool our Continuous Integration and Deployment environments due to a Sitecore Helix based solution. As part of that process I ended up using Octopus Deploy for the first time and I love it. I do not know how I did not use it before. I will have an upcoming blog post on how I setup our Octopus Deploy environment.]]></description>
      <content:encoded><![CDATA[<p>Recently I had to re-tool our Continuous Integration and Deployment environments due to a Sitecore Helix based solution. As part of that process I ended up using Octopus Deploy for the first time and I love it. I do not know how I did not use it before. I will have an upcoming blog post on how I setup our Octopus Deploy environment.</p>
<p>As part of the Continuous Deployment using Octopus Deploy, I needed the production databases backed up before we pushed the code &amp; items to the Production CM servers. Octopus gives you a lot of step template to do various tasks and some of them are related to the SQL Server.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/01/step-templates.png"><img loading="lazy" class="alignnone size-large wp-image-2947" src="https://akshaysura.com/wp-content/uploads/2017/01/step-templates-957x1024.png" alt="" width="900" height="963" /></a></p>
<p>There are a few specific to Sitecore as-well, one in particular by my Guitar friend <a href="https://twitter.com/rich_seal" target="_blank">Richard Seal</a>.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/01/Guitar.png"><img loading="lazy" class="alignnone size-full wp-image-2948" src="https://akshaysura.com/wp-content/uploads/2017/01/Guitar.png" alt="" width="568" height="291" /></a></p>
<p>The SQL templates rely on SQL Server PowerShell commandlets to run. Here is the process to install it and it has to be done in a specific sequence, unless you want to install everything. In my case, I wanted this to run in the context of the Production CM&#8217;s, so I kept it to what is necessary. Go to <a href="https://www.microsoft.com/en-us/download/confirmation.aspx?id=29065" target="_blank">https://www.microsoft.com/en-us/download/confirmation.aspx?id=29065</a> and download &amp; install the following in the order given below:</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/01/clr.png"><img loading="lazy" class="alignnone size-full wp-image-2951" src="https://akshaysura.com/wp-content/uploads/2017/01/clr.png" alt="" width="684" height="188" /></a></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/01/Shared-management.png"><img loading="lazy" class="alignnone size-full wp-image-2950" src="https://akshaysura.com/wp-content/uploads/2017/01/Shared-management.png" alt="" width="699" height="182" /></a></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2017/01/sql-powershell.png"><img loading="lazy" class="alignnone size-full wp-image-2949" src="https://akshaysura.com/wp-content/uploads/2017/01/sql-powershell.png" alt="" width="689" height="221" /></a></p>
<p>Once all three are installed you can use one of the SQL Server templates in Octopus and run it on that box.</p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>Bring it on! - The battle rages between Simple Injector and Microsoft DI in Sitecore Performance Testing land far far away!</title>
      <link>https://akshaysura.com/blog/bring-it-on-the-battle-rages-between-simple-injector-and-microsoft-di-in-sitecore-performance-testing-land-far-far-away/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/bring-it-on-the-battle-rages-between-simple-injector-and-microsoft-di-in-sitecore-performance-testing-land-far-far-away/</guid>
      <pubDate>Thu, 29 Dec 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Sitecore 8.2 was released with Microsoft Dependency Injection and with the recent release of Sitecore 8.2.1 it was finally time for me to do what I have been promising. I wanted to take an existing solution which was on production using Simple Injector (My Favorite framework), test it again the same solution but with Microsoft DI.]]></description>
      <content:encoded><![CDATA[<p>Sitecore 8.2 was released with <a href="https://www.nuget.org/packages/Microsoft.Extensions.DependencyInjection/" target="_blank">Microsoft Dependency Injection</a> and with the recent release of Sitecore 8.2.1 it was finally time for me to do what I have been promising. I wanted to take an existing solution which was on production using Simple Injector (My Favorite framework), test it again the same solution but with Microsoft DI.</p>
<p>So here is some information:</p>
<ol>
<li>Two sites were setup, one for Simple Injector and one for Microsoft DI</li>
<li>The code is exactly the same, except the DI framework has been swapped out</li>
<li>No other code changes were made to the code base</li>
<li>The solution runs on 8.2 rev. 161115 (8.2 Update-1)</li>
<li>The solution uses Web API calls as well and so the Web API controllers were also registered</li>
<li>I used <a href="https://twitter.com/kamsar" target="_blank">Kam</a>&#8216;s <a href="https://gist.github.com/kamsar/460528edc3043b16bdccfdbd0ea0c552#file-servicecollectionextensions-cs" target="_blank">ServiceCollectionExtensions</a> and made a change to include Web API controllers with the help of one Mr. <a href="https://twitter.com/seanholmesby" target="_blank">Sean Holmesby</a>. The modification is added as a comment on Kam&#8217;s Git.</li>
<li>Each site was isolated to an identical environment</li>
</ol>
<p>You can refer to my previous blog post to implement Microsoft DI: <a href="https://akshaysura.com/2016/09/15/microsoft-extensions-dependency-injection-di-with-sitecore-8-2-sample-project/" target="_blank">Microsoft Extensions Dependency Injection (DI) with Sitecore 8.2 Sample Project</a></p>
<p>I ran the following two tests on both the sites:</p>
<h3>Test 1</h3>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/oldnew-2.png"><img loading="lazy" class="alignnone wp-image-2908 size-full" src="https://akshaysura.com/wp-content/uploads/2016/12/oldnew-2.png" width="771" height="676" /></a></p>
<h3>Test 2</h3>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/round2-1.png"><img loading="lazy" class="alignnone wp-image-2907 size-full" src="https://akshaysura.com/wp-content/uploads/2016/12/round2-1.png" width="770" height="634" /></a></p>
<p>&nbsp;</p>
<p>While the both tests were running, I took some sample screenshots of the server performance and the current load. I also compared page load times for specific pages. Here are some screenshots.</p>
<p>&nbsp;</p>
<h2>Results of Test 1</h2>
<h3>Test 1 &#8211; Page Load Times &#8211; Simple Injector</h3>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/old6-1.png"><img loading="lazy" class="alignnone size-full wp-image-2923" src="https://akshaysura.com/wp-content/uploads/2016/12/old6-1.png" alt="" width="961" height="447" /></a></p>
<h3>Test 1 &#8211; Page Load Times &#8211; Microsoft DI</h3>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/new5-1.png"><img loading="lazy" class="alignnone size-full wp-image-2924" src="https://akshaysura.com/wp-content/uploads/2016/12/new5-1.png" alt="" width="962" height="450" /></a></p>
<p>&nbsp;</p>
<h3>Test 1 &#8211; Server Performance &#8211; Simple Injector</h3>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/simple-stats.png"><img loading="lazy" class="alignnone size-full wp-image-2926" src="https://akshaysura.com/wp-content/uploads/2016/12/simple-stats.png" alt="" width="1000" height="1402" /></a></p>
<h3>Test 1 &#8211; Server Performance &#8211; Microsoft DI</h3>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/msdi-stats.png"><img loading="lazy" class="alignnone size-full wp-image-2927" src="https://akshaysura.com/wp-content/uploads/2016/12/msdi-stats.png" alt="" width="1000" height="1238" /></a></p>
<h3>Test 1 &#8211; Winner &#8211; Microsoft DI</h3>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/Test-1-Results.png"><img loading="lazy" class="alignnone size-full wp-image-2921" src="https://akshaysura.com/wp-content/uploads/2016/12/Test-1-Results.png" alt="" width="876" height="201" /></a></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/giphy.gif"><img loading="lazy" class="alignnone size-full wp-image-2928" src="https://akshaysura.com/wp-content/uploads/2016/12/giphy.gif" alt="" width="245" height="245" /></a></p>
<p>Now for test 2!</p>
<h2>Results of Test 2</h2>
<h3>Test 2 &#8211; Page Load Times &#8211; Simple Injector</h3>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/round-2-old-7-1.png"><img loading="lazy" class="alignnone size-full wp-image-2930" src="https://akshaysura.com/wp-content/uploads/2016/12/round-2-old-7-1.png" alt="" width="962" height="590" /></a></p>
<p>&nbsp;</p>
<h3>Test 2 &#8211; Page Load Times &#8211; Microsoft DI</h3>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/round-2-new-7-1.png"><img loading="lazy" class="alignnone size-full wp-image-2931" src="https://akshaysura.com/wp-content/uploads/2016/12/round-2-new-7-1.png" alt="" width="957" height="588" /></a></p>
<p>&nbsp;</p>
<h3>Test 2 &#8211; Server Performance &#8211; Simple Injector</h3>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/test2-si.png"><img loading="lazy" class="alignnone size-full wp-image-2938" src="https://akshaysura.com/wp-content/uploads/2016/12/test2-si.png" alt="" width="1000" height="1383" /></a></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/test2simple2.png"><img loading="lazy" class="alignnone wp-image-2934 size-full" src="https://akshaysura.com/wp-content/uploads/2016/12/test2simple2.png" width="1000" height="1350" /></a></p>
<h3>Test 2 &#8211; Server Performance &#8211; Microsoft DI</h3>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/test2-di-1.png"><img loading="lazy" class="alignnone size-full wp-image-2942" src="https://akshaysura.com/wp-content/uploads/2016/12/test2-di-1.png" alt="" width="1000" height="1383" /></a></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/test-2-di-2.png"><img loading="lazy" class="alignnone size-full wp-image-2941" src="https://akshaysura.com/wp-content/uploads/2016/12/test-2-di-2.png" alt="" width="1000" height="1346" /></a></p>
<h3>Test 2 &#8211; Winner &#8211; Microsoft DI</h3>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/round-2-new-8-1.png"><img loading="lazy" class="alignnone size-full wp-image-2936" src="https://akshaysura.com/wp-content/uploads/2016/12/round-2-new-8-1.png" alt="" width="905" height="200" /></a></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/giphy-1.gif"><img loading="lazy" class="alignnone wp-image-2939 size-full" src="https://akshaysura.com/wp-content/uploads/2016/12/giphy-1.gif" width="300" height="172" /></a></p>
<p>Over all with Microsoft DI, the server performance was much better. Needless to say that I will be using Microsoft DI. Hope Sitecore can update the Microsoft DI version in the upcoming versions.</p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
<p>&nbsp;</p>
]]></content:encoded>
    </item>
    <item>
      <title>Helix and the re-tooling of your Continuous Integration and Deployments</title>
      <link>https://akshaysura.com/blog/helix-and-the-re-tooling-of-your-continuous-integration-and-deployments/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/helix-and-the-re-tooling-of-your-continuous-integration-and-deployments/</guid>
      <pubDate>Wed, 28 Dec 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[“Helix is a set of overall design principles and conventions for Sitecore development.” Like other architectures and design principles, Helix also has pros and cons. You might hear “saves the developer from having to create these modules from scratch” or “improve the efficiency of your projects, reduce costs and time to market”. Great right? Not so fast!]]></description>
      <content:encoded><![CDATA[<p><em>“Helix</em> is a set of overall design principles and conventions for Sitecore development.&#8221; Like other architectures and design principles, Helix also has pros and cons. You might hear &#8220;saves the developer from having to create these modules from scratch&#8221; or &#8220;improve the efficiency of your projects, reduce costs and time to market&#8221;. Great right? Not so fast!</p>
<p>The concept of Helix and the Habitat implementation are great. When you get behind a set of design principles, its easier to follow them and also easier to overlook/overcome the cons. The intent of Helix is great but the long term goal of saving time or money is yet to be seen in real life implementations.</p>
<p>I personally can share my journey when we complete 6 &#8211; 9 sites on our Helix bases solution by next year. Until then lets talk about tooling or re-tooling.</p>
<p><span style="text-decoration: underline;"><strong>In my opinion, Helix = Tooling, there is nothing else to it.</strong></span> By adopting Helix, you are committing to its architecture which WILL disrupt your current CI and CD processes. But since we are committed to Helix, its our job to re-tool and get back on track.</p>
<p>A lot of people choose to start off with Habitat instead of starting from scratch using Helix principles, because they do not understand how to start from scratch or how to convert an existing solution to a Helix based solution.</p>
<p>Now back to re-tooling. We started off with Gulp in my blog post yesterday: <a href="https://akshaysura.com/2016/12/27/finally-with-one-great-big-gulp-i-conquered-sitecore-helix/" target="_blank">Finally, with one great big Gulp, I conquered Sitecore Helix!</a></p>
<p>Today we will take a look at:</p>
<ol>
<li>VSTS builds</li>
<li>Tweak Gulp to do builds the way we want it to</li>
<li>OctoPack</li>
<li>Octopus Deploy</li>
</ol>
<h2>VSTS</h2>
<p>First lets check out the .gitignore file to make sure that node_modules/ is un-commented. Just like Nuget packages being stored in the packages folder, all the Node.js plugins are stored in the node_modules folder. You do not want these checked into the source control for several reasons. You want the build server to download both the Nuget packages and the Node.js plugins while doing the build.</p>
<p>Add the npm step to install Node.js packages and specify the working folder:</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/npminstll.png"><img loading="lazy" class="alignnone size-large wp-image-2879" src="https://akshaysura.com/wp-content/uploads/2016/12/npminstll-1024x321.png" alt="" width="900" height="282" /></a></p>
<p>Add the Gulp step and specify the location for the gulpfile.js:</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/gulpstep.png"><img loading="lazy" class="alignnone size-large wp-image-2880" src="https://akshaysura.com/wp-content/uploads/2016/12/gulpstep-1024x440.png" alt="" width="900" height="387" /></a></p>
<p>Notice that we are passing in some Arguments. Yeap, here I am sending in some information which could be used in the gulpfile.js. I am mainly interested in the BuildNumber, so that I can send the NuGet packages to my Octopus server with the version needed. Since we did not specify the Gulp Task(s), VSTS will run the default task.</p>
<p>Now that I am passing in the parameters, I need a way to consume it in my gulpfile.js.</p>
<h2>Back to Gulp</h2>
<p>To consume the parameters passed through VSTS, I use minimist (<a href="https://www.npmjs.com/package/minimist" target="_blank">https://www.npmjs.com/package/minimist</a>).</p>
<p>Install minimist: <em>npm install minimist</em></p>
<p>Then add the following to the top of your gulpfile.js:</p>
<p><em>var minimist = require(&#8216;minimist&#8217;);</em></p>
<p>Once that is done, add the following under the require statements:</p>
<p><em>var knownOptions = {</em><br />
<em> string: &#8216;buildNumber&#8217;,</em><br />
<em> default: { buildNumber: &#8216;unversioned&#8217; }</em><br />
<em>}</em><br />
<em>var options = minimist(process.argv.slice(2), knownOptions);</em></p>
<p>The above basically gives us access to the BuildNumber paraments from VSTS.</p>
<p>Now its next for OctoPack.</p>
<p>&nbsp;</p>
<h2>OctoPack</h2>
<p>I love OctoPack because its so simple and just gets the job done.</p>
<p>To start, simply install OctoPack on the project you want to generate the NuGet package on by running the following in the Package Manager Console:</p>
<p><em>Install-Package OctoPack</em></p>
<p>Once installed, you need to create a nuspec file for that project with the same name as the project with a nuspec extension. For example, if you project name is Company.Project.Website, you need  a nuspec file at the root of that project called Company.Project.Website.nuspec. Here is a sample nuspec file:</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/nuspec.png"><img loading="lazy" class="alignnone size-full wp-image-2882" src="https://akshaysura.com/wp-content/uploads/2016/12/nuspec.png" alt="" width="885" height="549" /></a></p>
<p>In the nuspec file, be sure to give a value in all the attributes including iconUrl. The main section however is the &lt;files&gt;. Specify the files which will be part of the NuGet package.</p>
<p>Once all of this is configured, you need a couple of things from your Octopus Server.</p>
<p>&nbsp;</p>
<h2>Octopus Server</h2>
<p>I recently started used Octopus Deploy. I learned it by bothering two of my friends, the REAL <a href="https://twitter.com/jammykam" target="_blank">Kam(ruz)</a> and Google. I setup the environment and the deployments on Octopus are so easy. Some day soon I will do a session on Octopus deploy. Back to the topic of re-tooling.</p>
<p>We need to setup an API key in order to push our NuGet packages. Here is an article on <a href="http://docs.octopusdeploy.com/display/OD/How+to+create+an+API+key" target="_blank">How to create an API key</a>. Also make sure that your Octopus admin URL is available to your build system, in this case VSTS.</p>
<p>&nbsp;</p>
<h2>Back to Gulp</h2>
<p>Back in gulpfile.js, I tweaked the Build task to add additional parameters to execute the OctoPack. Here is a sample of that code:</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/octopacksolu-1.png"><img loading="lazy" class="alignnone size-medium wp-image-2887" src="https://akshaysura.com/wp-content/uploads/2016/12/octopacksolu-1-300x171.png" alt="" width="300" height="171" /></a></p>
<p>Notice that we are specifying the Octopus Server URL with /nuget/packages, this is the destination for the NuGet packages we generate. Second, we are specifying the API key we generated, this is the means to authenticate, so please keep this key safely. Third, is the version number of the NuGet package, which plays a big role in Octopus deploys and we get that through the BuildNumber parameter processes using minimist NPM package.</p>
<p>I run a few other scripts in my Gulp to make sure all my dll&#8217;s from features and foundation projects are copied over to the project, minify css and js etc.</p>
<p>Once all of this is said and done, we should have a working Continuous Integration environment for a Helix based solution. My Octopus Deploy configuration, automatically deploys the new NuGet package to the dev environment.</p>
<p>The NuGet restore, NPM package install, Gulp build and OctoPack NuGet push is taking about 3.9 minutes on average and the auto deploy to development environment is taking about 5 minutes.</p>
<p><strong>Setting up your local and a Continuous Integration/Deployment environments for Helix takes longer than your traditional Web solution but once you set it up properly you are good since you follow the FOLDER STRUCTURE. All scripts for building features, foundation projects and tenants are all dynamic.</strong></p>
<p>I encourage you to discuss Helix/Habitat based conversations in the Sitecore Slack Helix-Habitat channel – <a href="https://sitecorechat.slack.com/" target="_blank">https://sitecorechat.slack.com</a> .</p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>Finally, with one great big Gulp, I conquered Sitecore Helix!</title>
      <link>https://akshaysura.com/blog/finally-with-one-great-big-gulp-i-conquered-sitecore-helix/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/finally-with-one-great-big-gulp-i-conquered-sitecore-helix/</guid>
      <pubDate>Tue, 27 Dec 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[“Helix is a set of overall design principles and conventions for Sitecore development. Habitat is a real Sitecore project implemented on the Sitecore Experience Platform using Helix.” – Please ingrain this in your brain. It helps to download the source for Habitat as a reference, because you are going to need it and need it you shall!]]></description>
      <content:encoded><![CDATA[<p><em>&#8220;Helix</em> is a set of overall design principles and conventions for Sitecore development. <em>Habitat</em> is a real Sitecore project implemented on the Sitecore Experience Platform using Helix.&#8221; &#8211; Please ingrain this in your brain. It helps to download the source for Habitat as a reference, because you are going to need it and need it you shall!</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/brainingraingiphy.gif"><img loading="lazy" class="alignnone size-full wp-image-2859" src="https://akshaysura.com/wp-content/uploads/2016/12/brainingraingiphy.gif" alt="" width="500" height="381" /></a></p>
<p>You can download Habitat from: <a href="https://github.com/sitecore/habitat" target="_blank">https://github.com/sitecore/habitat</a></p>
<p>You could read more about Helix here: <a href="http://helix.sitecore.net/" target="_blank">http://helix.sitecore.net/</a></p>
<p><strong>I did not choose Helix, Helix chose me.</strong> Based on conversations with Helix folks, it was apparent that Sitecore will push its partners and customers to get behind Helix. Although I am not sure when everyone or the majority will be on board with this. I was thrown into a project where they were trying to implement Helix but unfortunately it fell short in a few areas.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/throwngiphy.gif"><img loading="lazy" class="alignnone size-full wp-image-2860" src="https://akshaysura.com/wp-content/uploads/2016/12/throwngiphy.gif" alt="" width="637" height="358" /></a></p>
<p>This was very apparent when I tried to get Gulp working.</p>
<p>One of the biggest issues is that devs fallback on others cleaning up their mess. In this case they fell back on TDS cleaning it up. TDS did a great job of packaging up the code and content, config transforms, etc. Since the code is packaged in an update package, custom post installation steps were needed to push them to the web root.</p>
<p>You can use the Multi-Project Package Bundling to easily package up Helix projects. Unfortunately this also meant that Helix principles were not followed to the T.</p>
<p>Earlier this month, HedgeHog posted FxCop rules for Sitecore Helix which should help a lot (<a href="http://www.hhog.com/blog/sitecore-helix-fxcop-rules/" target="_blank">http://www.hhog.com/blog/sitecore-helix-fxcop-rules/</a>). At the end of the day it truly comes down to what technologies you want to use for your development &amp; deployments.</p>
<p>FOLDER STRUCTURE, FOLDER STRUCTURE, FOLDER STRUCTURE is key. You enforce that, and you got some Structure 😉 and are part way into implementing a Helix solution.</p>
<p>Do not get me wrong, <strong>I am not a Helix expert nor am I a TDS expert</strong>. I learn as I go but this time I had no choice. I do not like to depending on third party technology for deployment. I like to streamline it as much as possible.</p>
<p>In this struggle/journey, I had to tackle the following:</p>
<ol>
<li>VSTS &#8211; Visual Studio Team Services with a Git repo &#8211; <a href="https://www.visualstudio.com/team-services/git/" target="_blank">https://www.visualstudio.com/team-services/git/</a></li>
<li>OctoPack &#8211; Create Nuget packages from your builds &#8211; <a href="http://docs.octopusdeploy.com/display/OD/Using+OctoPack" target="_blank">http://docs.octopusdeploy.com/display/OD/Using+OctoPack</a></li>
<li>Gulp &#8211; Gulpjs is a task/build runner &#8211; <a href="http://gulpjs.com/" target="_blank">http://gulpjs.com/</a></li>
<li>Octopus Deploy &#8211; Octopus is a deployment automation tool &#8211; <a href="https://octopus.com/" target="_blank">https://octopus.com/</a></li>
</ol>
<p>Now, bare in mind that I have not used any of the above except VSTS for source control before this. I hope to document in detail what you need to do to get this working. If you are one of the fruits who knows all of some of these technologies, don&#8217;t hate yo!, share..</p>
<p>I have been using VSTS for a while for only source control and nothing else. When I tried to set it up for builds, I was pleasantly surprised as to how easy it was. We will come to this later.</p>
<h2>Gulp</h2>
<p>Now as for Gulp, I knew what it could be used for but had no clue how to use it or even how to get started. In order to get Gulp working, we needed Node.js running as well. In Visual Studio 2015, Node.js and Gulp are automatically installed so I did not have to do much.</p>
<p>Next, I looked at the Habitat source and copied the gulpfile.js, package.json and gulp-config.js files to the same location as the solution file. Deployments are specific to your company or team and cater to your individual needs. My script probably wont suffice for you but all I am trying to do here is to give you an example. Once I copied the three files, I included them in my solution.</p>
<ol>
<li>gulp-config.js contains configuration strings with paths etc &#8211; Optional</li>
<li>gulpfile.js contains all the tasks you might end up using. Default task is executed if no startup task is specified.</li>
<li>package.json file contains the references to all the plugins which are installed and could be used by your gulpfile.js</li>
</ol>
<p>Once that is done, open the Task Runner Explorer by going to View &gt; Other Windows &gt; Task Runner Explorer in your Visual Studio solution.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/taskrunner.png"><img loading="lazy" class="alignnone wp-image-2864 size-full" src="https://akshaysura.com/wp-content/uploads/2016/12/taskrunner.png" width="755" height="898" /></a></p>
<p>This will open the Task Runner Explorer window. This window is your best friend for Gulp tasks. You can run any and all tasks in your Gulpfile.js file.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/taskrunnerwindow.png"><img loading="lazy" class="alignnone size-large wp-image-2863" src="https://akshaysura.com/wp-content/uploads/2016/12/taskrunnerwindow-1024x187.png" alt="" width="900" height="164" /></a></p>
<p>Even though the gulpfile.js from the Habitat solution has a bunch of code, you might need to add/modify part of it. At first I played around with the tasks and found that the solution folder structure was not right. Please refer to <a href="http://helix.sitecore.net/principles/file-structure/index.html" target="_blank">http://helix.sitecore.net/principles/file-structure/index.html</a></p>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/solutionstructure.png"><img loading="lazy" class="alignnone size-large wp-image-2869" src="https://akshaysura.com/wp-content/uploads/2016/12/solutionstructure-1024x260.png" alt="" width="900" height="229" /></a><br />
<a href="https://akshaysura.com/wp-content/uploads/2016/12/module-structure.png"><img loading="lazy" class="alignnone size-full wp-image-2868" src="https://akshaysura.com/wp-content/uploads/2016/12/module-structure.png" alt="" width="971" height="831" /></a></p>
<p>In my case, the default scripts did not suffice as I was using TDS for item deployment and not Unicorn. Gulp is very well documented and so all you need to do is google what you are looking for.</p>
<p>Most likely you will be asked to install Gulp plugins or end up on <a href="http://gulpjs.com/plugins/" target="_blank">http://gulpjs.com/plugins/</a> .</p>
<p>When you encounter commands such as these <em>npm install &#8211;save gulp-uglifycss</em> , all you need to do is to open a command window or a windows PowerShell window and navigate to the location of the gulpfile.js. You would run the npm command at that location. By running the Node.js command, it will install the plugin and make an entry in the package.json file.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/packagejson.png"><img loading="lazy" class="alignnone size-full wp-image-2870" src="https://akshaysura.com/wp-content/uploads/2016/12/packagejson.png" alt="" width="433" height="641" /></a></p>
<p>Once that is complete you would need to modify your gulpfile.js to add a required statement like the one shown below:</p>
<p><em>var concat = require(&#8216;gulp-concat&#8217;);</em><br />
<em>var uglify = require(&#8216;gulp-uglify&#8217;);</em><br />
<em>var zip = require(&#8216;gulp-zip&#8217;);</em><br />
<em>var minimist = require(&#8216;minimist&#8217;);</em></p>
<p>This would give you access to using a specific plugin in Gulp. From here on, its tweaking tasks, calling one task from the other and getting Gulp to do what you need it to do, all the while running it from the Task Runner window to make sure its working the way you need it to.</p>
<p>Here is my default task:</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/12/defaultgulp.png"><img loading="lazy" class="alignnone wp-image-2871 size-full" src="https://akshaysura.com/wp-content/uploads/2016/12/defaultgulp.png" width="447" height="629" /></a></p>
<p>Once you have your Gulp task running and you are happy with it, we need to deal with automated builds. We will tackle VSTS and OctoPack in the next blog entry.</p>
<p>I encourage you to discuss Helix/Habitat based conversations in the Sitecore Slack Helix-Habitat channel &#8211; <a href="https://sitecorechat.slack.com" target="_blank">https://sitecorechat.slack.com</a> .</p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>Unofficial Sitecore 8 Training Webinar Series – Session 9</title>
      <link>https://akshaysura.com/blog/unofficial-sitecore-8-training-webinar-series-session-9/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/unofficial-sitecore-8-training-webinar-series-session-9/</guid>
      <pubDate>Thu, 17 Nov 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[https://attendee.gotowebinar.com/register/2535764463444191236]]></description>
      <content:encoded><![CDATA[<h3><u>Agenda &#8211; Presented by <a href="https://twitter.com/AmandaShiga" target="_blank">Amanda Shiga</a></u></h3>
<ol>
<li><strong>Data enrichment and personalization</strong>
<ol>
<li>Getting started: the importance of xDB data enrichment</li>
<li>Building your strategy: types of personalization in Sitecore and how/when to apply them</li>
<li>Keeping personalization manageable for marketing ops and website performance</li>
<li>Measuring success: how to determine if personalization is making a difference</li>
<li>Useful extensions: some helpful approaches to extend Sitecore’s personalization capabilities</li>
</ol>
</li>
</ol>
<h4><del>Please register for Unofficial Sitecore 8 Training Webinar Series &#8211; Session 9 on January 12th, 2017 1:00 PM &#8211; 2:00 PM PST at:</del></h4>
<p><a href="https://attendee.gotowebinar.com/register/2535764463444191236" target="_blank"><del>https://attendee.gotowebinar.com/register/2535764463444191236</del></a></p>
<p><del>After registering, you will receive a confirmation email containing information about joining the webinar.</del></p>
<h3>Video</h3>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/6gknSbKg7Pw" frameborder="0" allowfullscreen="allowfullscreen"></iframe></p>
<h3>Links from the Presentation</h3>
<ol>
<li><a href="https://doc.sitecore.net/sitecore_experience_platform/digital_marketing/personalization/walkthrough_personalizing_components" target="_blank">https://doc.sitecore.net/sitecore_experience_platform/digital_marketing/personalization/walkthrough_personalizing_components</a></li>
<li><a href="https://doc.sitecore.net/sitecore_experience_platform/81/setting_up__maintaining/experience_management/configuring/the_experience_management_personalization_rules" target="_blank">https://doc.sitecore.net/sitecore_experience_platform/81/setting_up__maintaining/experience_management/configuring/the_experience_management_personalization_rules</a></li>
<li><a href="http://www.nonlinearcreations.com/Digital/how-we-think/articles/2016/05/Testing-scenarios-for-Sitecore-XP-readiness.aspx" target="_blank">http://www.nonlinearcreations.com/Digital/how-we-think/articles/2016/05/Testing-scenarios-for-Sitecore-XP-readiness.aspx</a></li>
<li><a href="http://www.nonlinearcreations.com/Digital/how-we-think/articles/2016/10/Tips-for-using-Sitecore-profile-cards-effectively.aspx" target="_blank">http://www.nonlinearcreations.com/Digital/how-we-think/articles/2016/10/Tips-for-using-Sitecore-profile-cards-effectively.aspx</a></li>
<li><a href="https://marketplace.sitecore.net/Modules/S/SBOS_XCCELLERATORS.aspx?sc_lang=en" target="_blank">https://marketplace.sitecore.net/Modules/S/SBOS_XCCELLERATORS.aspx?sc_lang=en</a></li>
</ol>
<p>If you need more information get in touch with Akshay Sura or Mike Reynolds.</p>
<p>@akshaysura13 or @mike_i_reynolds on twitter or on Slack.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Unofficial Sitecore 8 Training Webinar Series – Session 8</title>
      <link>https://akshaysura.com/blog/unofficial-sitecore-8-training-webinar-series-session-8/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/unofficial-sitecore-8-training-webinar-series-session-8/</guid>
      <pubDate>Thu, 03 Nov 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[]]></description>
      <content:encoded><![CDATA[<h3><u>Agenda &#8211; Presented by <strong><a href="https://twitter.com/AgileStCyr" target="_blank">Jason St-Cyr</a></strong></u></h3>
<ol>
<li><strong>Continuous Integration and Deployment </strong>
<ol>
<li>Continuous Everything: Improvement, Integration, Testing, Delivery, Deployment</li>
<li>Continuous Integration: The Dirty Details</li>
<li>Continuous Testing: The test team in the deployment pipeline</li>
<li>Production Deployments: The Big Bad Wolf</li>
<li>Demo on setting up a simple CI setup (participants are encouraged to follow along with the demo on their machines)</li>
</ol>
</li>
</ol>
<h4>Video</h4>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/1Rk6svwF9FE" frameborder="0" allowfullscreen></iframe></p>
<h4><del>Please register for Unofficial Sitecore 8 Training Webinar Series &#8211; Session 8 on November 30th, 2016 1:00 PM &#8211; 2:00 PM PST at:</del></h4>
<p><del><a href="https://attendee.gotowebinar.com/register/4352811881652099330" target="_blank">https://attendee.gotowebinar.com/register/4352811881652099330</a></del></p>
<p><del>After registering, you will receive a confirmation email containing information about joining the webinar.</del></p>
<p>If you need more information get in touch with Akshay Sura or Mike Reynolds.</p>
<p>@akshaysura13 or @mike_i_reynolds on twitter or on Slack.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Unofficial Sitecore 8 Training Webinar Series – Session 6</title>
      <link>https://akshaysura.com/blog/unofficial-sitecore-8-training-webinar-series-session-6/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/unofficial-sitecore-8-training-webinar-series-session-6/</guid>
      <pubDate>Sat, 29 Oct 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Link to GitHub source.]]></description>
      <content:encoded><![CDATA[<h3><u>Agenda for the sixth Unofficial Sitecore training session</u></h3>
<ol>
<li><strong>Customizations</strong>
<ol>
<li>Pipelines &amp; Processors
<ol>
<li>What is a pipeline?</li>
<li>What is a processor?</li>
<li>Existing Pipelines in Sitecore</li>
<li>Implement custom functionality in a pipeline</li>
<li>Demo on customizing httpRequestBegin pipeline (participants are encouraged to follow along with the demo on their machines)</li>
<li>Can I create my own pipeline?</li>
</ol>
</li>
<li>Events &amp; Commands
<ol>
<li>Customizing Events</li>
<li>Demo on adding custom item:saved event handler</li>
<li>Create Custom commands</li>
</ol>
</li>
</ol>
</li>
</ol>
<h4>Source Code</h4>
<p><a href="https://github.com/akshaysura/UnofficialTraining.Session6" target="_blank">Link to GitHub source</a>.</p>
<h4>Video</h4>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/_T6ApKnPpQg" frameborder="0" allowfullscreen></iframe></p>
<h4><del>Please register for Unofficial Sitecore 8 Training Webinar Series &#8211; Session 6 on November 10th, 2016 1:00 PM &#8211; 2:00 PM PST at:</del></h4>
<p><del><a href="https://attendee.gotowebinar.com/register/890111116093814531" target="_blank">https://attendee.gotowebinar.com/register/890111116093814531</a></del></p>
<p><del>After registering, you will receive a confirmation email containing information about joining the webinar.</del></p>
<p>If you need more information get in touch with Akshay Sura or Mike Reynolds.</p>
<p>@akshaysura13 or @mike_i_reynolds on twitter or on Slack.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Unofficial Sitecore 8 Training Webinar Series – Session 7</title>
      <link>https://akshaysura.com/blog/unofficial-sitecore-8-training-webinar-series-session-7/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/unofficial-sitecore-8-training-webinar-series-session-7/</guid>
      <pubDate>Sat, 29 Oct 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[https://attendee.gotowebinar.com/register/8760359272621483523]]></description>
      <content:encoded><![CDATA[<h3><u>Agenda &#8211; Presented by <a href="https://twitter.com/VasiliyFomichev" target="_blank">Vasiliy Fomichev</a></u></h3>
<ol>
<li><strong>Best Practices</strong>
<ul>
<li>Naming conventions</li>
<li>Provide help to content authors</li>
<li>Validation</li>
<li>Datasources</li>
<li>Scaling</li>
<li>CD CM configs</li>
<li>Media handling</li>
<li>Caching</li>
<li>Workflow</li>
</ul>
</li>
</ol>
<h4>Please register for Unofficial Sitecore 8 Training Webinar Series &#8211; Session 7 on December 8th, 2016 1:00 PM &#8211; 2:00 PM PST at:</h4>
<p><a href="https://attendee.gotowebinar.com/register/8760359272621483523" target="_blank">https://attendee.gotowebinar.com/register/8760359272621483523</a></p>
<p>After registering, you will receive a confirmation email containing information about joining the webinar.</p>
<p>If you need more information get in touch with Akshay Sura or Mike Reynolds.</p>
<p>@akshaysura13 or @mike_i_reynolds on twitter or on Slack.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Unofficial Sitecore 8 Training Webinar Series – Session 5</title>
      <link>https://akshaysura.com/blog/unofficial-sitecore-8-training-webinar-series-session-5/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/unofficial-sitecore-8-training-webinar-series-session-5/</guid>
      <pubDate>Fri, 28 Oct 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[]]></description>
      <content:encoded><![CDATA[<h3><u>Agenda &#8211; Presented by <a href="https://twitter.com/MichaelWest101" target="_blank">Michael West</a></u></h3>
<ol>
<li><strong>Introduction to Sitecore PowerShell Extensions</strong>
<ol>
<li>Intro to SPE</li>
<li>No Coding Required</li>
<li>Nuts &amp; Bolts</li>
<li>Advanced Capabilities</li>
</ol>
</li>
<li><strong>Out of the Box</strong>
<ol>
<li>Bundled Tools</li>
<li>Audit Reports</li>
</ol>
</li>
<li><strong>Meat &amp; Potatoes</strong>
<ol>
<li>Windows PowerShell for Beginners</li>
<li>Console and ISE</li>
<li>Scripts, Libraries, and Modules</li>
<li>Integration Points</li>
</ol>
</li>
<li><strong>Remoting</strong>
<ol>
<li>Setup</li>
<li>Remote Code Execution</li>
<li>Best Practices</li>
</ol>
</li>
</ol>
<h4>Video</h4>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/6n7pShsFHLY" frameborder="0" allowfullscreen></iframe></p>
<h4><del>Please register for Unofficial Sitecore 8 Training Webinar Series &#8211; Session 5 on November 16th 17th, 2016 8:00 PM (20:00) &#8211; 9:00 PM (21:00) PST at:</del></h4>
<p><del><a href="https://attendee.gotowebinar.com/register/7488577262485271297" target="_blank">https://attendee.gotowebinar.com/register/7488577262485271297</a></del></p>
<p><del>After registering, you will receive a confirmation email containing information about joining the webinar.</del></p>
<p>If you need more information get in touch with Akshay Sura or Mike Reynolds.</p>
<p>@akshaysura13 or @mike_i_reynolds on twitter or on Slack.</p>
]]></content:encoded>
    </item>
    <item>
      <title>How can you help the Stack Exchange Beta site for Sitecore</title>
      <link>https://akshaysura.com/blog/how-can-you-help-the-stack-exchange-beta-site-for-sitecore/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/how-can-you-help-the-stack-exchange-beta-site-for-sitecore/</guid>
      <pubDate>Mon, 19 Sep 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[A month ago Mark Cassidy took the initiative to start a Stack Exchange beta site. In doing so we got the community together and got them to commit to the cause. The community rose to the occasion was were quickly in beta. It was the fastest path to beta and other users were questioning how we got here. See the screenshot at the bottom of this post.]]></description>
      <content:encoded><![CDATA[<p>A month ago <a href="https://twitter.com/cassidydotdk" target="_blank">Mark Cassidy</a> took the initiative to start a Stack Exchange beta site. In doing so we got the community together and got them to commit to the cause. The community rose to the occasion was were quickly in beta. It was the fastest path to beta and other users were questioning how we got here. See the screenshot at the bottom of this post.</p>
<p><a href="http://area51.stackexchange.com/proposals/101710" target="_blank">http://area51.stackexchange.com/proposals/101710</a></p>
<p>Stack Exchange is a perfect searchable platform for Sitecore Q &amp; A. Even with other tools out there, we noticed fragmentation of Q &amp; A on all the tools. We are hoping to centralize that.</p>
<p>&nbsp;</p>
<p><strong>What can you do to help?</strong></p>
<p>Well for one, you need to get on to the beta site at <a href="http://sitecore.stackexchange.com/" target="_blank">http://sitecore.stackexchange.com/</a>.</p>
<p>If you do not have a beta invite, get in touch with any of the prominent Sitecore guys on LinkedIn, Twitter or Slack and get an invite. You can also <a href="https://goo.gl/WgjXRP" target="_blank">fill in this form</a>.</p>
<p>If you are already on it, here is what we need:</p>
<ul>
<li>Ask Sitecore and Sitecore module related questions on Sitecore.StackExchange.com.</li>
<li>Tag your questions with appropriate tags.</li>
<li>Use the tags already on <a href="http://sitecore.stackexchange.com/tags" target="_blank">http://sitecore.stackexchange.com/tags</a> or add new ones which you do not see.</li>
<li>Comment, answer and up vote as necessary.</li>
<li>Build your rep on the beta site, we need people with more than 200 rep</li>
<li>Remember, even if you do not know the answer, you could point the person to the right direction by suggesting appropriate resource(s).</li>
<li>If you have questions about the beta Stack Exchange site itself, post questions at <a href="http://meta.sitecore.stackexchange.com/" target="_blank">http://meta.sitecore.stackexchange.com/</a></li>
</ul>
<p>&nbsp;</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/09/1aw4mr.jpg"><img loading="lazy" class="alignnone size-full wp-image-2749" src="http://akshaysura.com/wp-content/uploads/2016/09/1aw4mr.jpg" alt="1aw4mr" width="500" height="264" /></a></p>
<p>Lets put some effort and make this beta count. Lets show the strength of the Sitecore community.</p>
<p>&nbsp;</p>
<p>We need to satisfy the following criteria to get out of beta.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/09/se1.png"><img loading="lazy" class="alignnone size-large wp-image-2748" src="http://akshaysura.com/wp-content/uploads/2016/09/se1.png" alt="se1" width="900" height="733" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/09/se2.png"><img loading="lazy" class="alignnone size-large wp-image-2747" src="http://akshaysura.com/wp-content/uploads/2016/09/se2-1024x837.png" alt="se2" width="900" height="736" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/09/communityKey_design_SE.png"><img loading="lazy" class="alignnone size-large wp-image-2760" src="http://akshaysura.com/wp-content/uploads/2016/09/communityKey_design_SE-802x1024.png" alt="communitykey_design_se" width="802" height="1024" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/09/How-did-this-proposal-advance-so-fast-Area-51-Discussions.png"><img loading="lazy" class="alignnone size-large wp-image-2746" src="http://akshaysura.com/wp-content/uploads/2016/09/How-did-this-proposal-advance-so-fast-Area-51-Discussions-727x1024.png" alt="how-did-this-proposal-advance-so-fast-area-51-discussions" width="727" height="1024" /></a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Microsoft Extensions Dependency Injection (DI) with Sitecore 8.2 Sample Project</title>
      <link>https://akshaysura.com/blog/microsoft-extensions-dependency-injection-di-with-sitecore-8-2-sample-project/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/microsoft-extensions-dependency-injection-di-with-sitecore-8-2-sample-project/</guid>
      <pubDate>Thu, 15 Sep 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Sitecore 8.2 was released with Microsoft Dependency Injection. I wanted to try to setup a sample project which utilizes the DI.]]></description>
      <content:encoded><![CDATA[<p>Sitecore 8.2 was released with <a href="https://www.nuget.org/packages/Microsoft.Extensions.DependencyInjection/" target="_blank">Microsoft Dependency Injection</a>. I wanted to try to setup a sample project which utilizes the DI.</p>
<p>First and foremost, I thank <a href="https://twitter.com/kamsar" target="_blank">Kam</a> for writing the <a href="https://gist.github.com/kamsar/460528edc3043b16bdccfdbd0ea0c552#file-servicecollectionextensions-cs" target="_blank">ServiceCollectionExtensions</a> and making my life easier.</p>
<p>As with everything we start with a fresh install of Sitecore 8.2 (sc82rev160729). Following which setup a base visual studio project. I setup a very basic controller rendering to test this out. Here is the setup for the functionality of the TextBlock. The code necessary for Glass can be found in my previous blog posts. Later on I will get into the config.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/09/di1.png"><img loading="lazy" class="alignnone size-full wp-image-2725" src="http://akshaysura.com/wp-content/uploads/2016/09/di1.png" alt="di1" width="850" height="432" /></a><br />
<a href="http://akshaysura.com/wp-content/uploads/2016/09/di2.png"><img loading="lazy" class="alignnone size-large wp-image-2724" src="http://akshaysura.com/wp-content/uploads/2016/09/di2-1024x284.png" alt="di2" width="900" height="250" /></a></p>
<p>Here is a simple Business Interface and class implementations:</p>
<pre><code class="language-csharp">
using SC82.Models.Templates.Content;

namespace SC82.Business.Content
{
    public interface IContentLogic
    {
        ITextBlock GetTextBlock();
    }
}

</code></pre>
<pre><code class="language-csharp">
using SC82.Business.GlassSC;
using SC82.Models.Templates.Content;

namespace SC82.Business.Content
{
    public class ContentLogic : IContentLogic
    {
        private readonly IControllerSCContext _currentContext;

        public ContentLogic(IControllerSCContext currentContext)
        {
            _currentContext = currentContext;
        }

        public ITextBlock GetTextBlock()
        {
            return _currentContext.GetDataSource&lt;ITextBlock&gt;();
        }
    }
}

</code></pre>
<p>Lets go ahead and define Controller and the View:</p>
<pre><code class="language-csharp">
using SC82.Business.Content;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace SC82.Controllers
{
    public class ContentController : Controller
    {
        private readonly IContentLogic _contentLogic;

        public ContentController(IContentLogic contentLogic)
        {
            _contentLogic = contentLogic;
        }

        public ActionResult RenderTextBlock()
        {
            return View(_contentLogic.GetTextBlock());
        }
    }
}
</code></pre>
<pre><code class="language-csharp">
@inherits Glass.Mapper.Sc.Web.Mvc.GlassView&lt;SC82.Models.Templates.Content.ITextBlock&gt;
@using Sitecore.Mvc

@if (Model != null)
{
    &lt;h3&gt;@Editable(Model, y =&gt; y.Heading)&lt;/h3&gt;
    &lt;h4&gt;@Editable(Model, y =&gt; y.SubHeading)&lt;/h4&gt;
    &lt;div class="content"&gt;@Editable(Model, y =&gt; y.Content)&lt;/div&gt;
}

</code></pre>
<p>Now that we have everything set in terms of functionality. We need plumbing (funnel connector) to register with the DI. We do this by implementing an IServicesConfigurator and later on we will add the config to get this working.</p>
<pre><code class="language-csharp">
using Glass.Mapper.Sc;
using Microsoft.Extensions.DependencyInjection;
using SC82.Business.Content;
using SC82.Business.GlassSC;
using Sitecore.DependencyInjection;
using Sitecore.Foundation.DependencyInjection;

namespace SC82.Business.DI
{
    public class RegisterDI : IServicesConfigurator
    {
        public void Configure(IServiceCollection serviceCollection)
        {

            var serviceProvider =  serviceCollection.BuildServiceProvider();
            
            serviceCollection.AddTransient&lt;ISitecoreContext&gt;(provider =&gt; new SitecoreContext());
            serviceCollection.AddTransient&lt;IGlassHtml&gt;(provider =&gt; new GlassHtml(serviceProvider.GetService&lt;ISitecoreContext&gt;()));
            serviceCollection.AddTransient&lt;IControllerSCContext&gt;(provider =&gt; new ControllerSCContext(serviceProvider.GetService&lt;IGlassHtml&gt;()));
            serviceCollection.AddTransient&lt;IContentLogic, ContentLogic&gt;();

            serviceCollection.AddMvcControllers(
                "SC82*");
        }
    }
}

</code></pre>
<p>Now that we registered all the items we need, next is the config (which is one of a few ways) to let Sitecore know:</p>
<pre><code class="language-xml">
&lt;?xml version="1.0"?&gt;
&lt;configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"&gt;
    &lt;sitecore&gt;
        &lt;services&gt;
            &lt;configurator type="SC82.Business.DI.RegisterDI, SC82.Business" /&gt;
        &lt;/services&gt;
    &lt;/sitecore&gt;
&lt;/configuration&gt;
</code></pre>
<p>That is it. I could not believe how simple this was. If you have more registrations, simple add it to the Configure method. When its all said and done, here is the output.<br />
<a href="http://akshaysura.com/wp-content/uploads/2016/09/di3.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/09/di3-1024x146.png" alt="di3" width="900" height="128" class="alignnone size-large wp-image-2723" /></a><br />
&nbsp;<br />
Make sure all the interfaces you need are registered. Check the /sitecore/admin/ShowServicesConfig.aspx page for registrations via the Microsoft DI in Sitecore ONLY. If you use a different DI framework, it will not show your registrations on this page.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/09/di5-1.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/09/di5-1-1024x139.png" alt="di5" width="900" height="122" class="alignnone size-large wp-image-2739" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/09/di8.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/09/di8-1024x565.png" alt="di8" width="900" height="497" class="alignnone size-large wp-image-2742" /></a><br />
<a href="http://akshaysura.com/wp-content/uploads/2016/09/di9.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/09/di9-1024x564.png" alt="di9" width="900" height="496" class="alignnone size-large wp-image-2741" /></a><br />
<a href="http://akshaysura.com/wp-content/uploads/2016/09/di10.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/09/di10-1024x128.png" alt="di10" width="900" height="113" class="alignnone size-large wp-image-2740" /></a></p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
<p>Documentation on Microsoft DI: <a href="https://docs.asp.net/en/latest/fundamentals/dependency-injection.html" target="_blank">https://docs.asp.net/en/latest/fundamentals/dependency-injection.html</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>IoC Container Benchmark comparison 2016 including Microsoft.Extensions.DependencyInjection</title>
      <link>https://akshaysura.com/blog/ioc-container-benchmark-comparison-2016-including-microsoft-extensions-dependencyinjection/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/ioc-container-benchmark-comparison-2016-including-microsoft-extensions-dependencyinjection/</guid>
      <pubDate>Wed, 31 Aug 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[As most of you know, my favorite is SimpleInjector. I use it in all my projects. Since Sitecore 8.2 was released yesterday (August 30th 2016), I decided to do a performance benchmark against Microsoft Extensions DependencyInjection which is used as part of Sitecore to provide DependencyInjection.]]></description>
      <content:encoded><![CDATA[<p>As most of you know, my favorite is SimpleInjector. I use it in all my projects. Since Sitecore 8.2 was released yesterday (August 30th 2016), I decided to do a performance benchmark against Microsoft Extensions DependencyInjection which is used as part of Sitecore to provide DependencyInjection.</p>
<p><a href="https://twitter.com/kamsar" target="_blank">Kam</a> has written a blog post: <a href="http://kamsar.net/index.php/2016/08/Dependency-Injection-in-Sitecore-8-2/" target="_blank">Dependency Injection in Sitecore 8.2</a> which talks about the Sitecore integration.</p>
<p>I ran these tests on a virtual with Intel(R) Core(TM) i7-4870HQ CPU @ 2.50GHz with 8GB memory.</p>
<p>My source is available on GitHub: <a href="https://github.com/akshaysura/IoCPerformance" target="_blank">IoC Performance</a></p>
<p>In order to do this I have taken two approaches. First, I used the repo from <a href="https://github.com/danielpalme/IocPerformance" target="_blank">Daniel Palme</a> and his blog post: <a href="http://www.palmmedia.de/blog/2011/8/30/ioc-container-benchmark-performance-comparison" target="_blank">IoC Container Benchmark &#8211; Performance comparison</a> and I updated the NuGet packages. Here is a blurb from Daniels post about the setup:</p>
<h3>The test setup</h3>
<p>Several benchmarks are executed to test the performance of the containers in different scenarios. Every container is initialized with a couple of interfaces and their corresponding implementations. The types are registered with different lifetimes to support the various benchmarks.</p>
<p>Every interface is resolved 500.000 times during the benchmark and the time is measured in milliseconds. Each test is executed single threaded and multi threaded.</p>
<p>The benchmarks:</p>
<ul>
<li>Singleton: Objects with is singleton lifetime are resolved</li>
<li>Transient: Objects with is transient lifetime are resolved</li>
<li>Combined: Objects with two dependencies (singleton and transient lifetime) are resolved</li>
<li>Complex: Objects with several nested dependencies are resolved</li>
<li>Property: Objects which require property injection are resolved</li>
<li>Generics: Objects with a generic dependency are resolved</li>
<li>IEnumerable: Several objects that implement the same interface are resolved</li>
<li>Conditional: Objects with a conditional dependency are resolved</li>
<li>Child Container: Objects are resolved trough a child container</li>
<li>Interception With Proxy: Objects with a dynamically generated wrapper are resolved</li>
<li>Prepare And Register: Initializes container and registers some basic elements (executed 3.000 times)</li>
<li>Prepare And Register And Simple Resolve: Initializes container and registers some basic elements. The resolves two objects (executed 3.000 times)</li>
</ul>
<p><strong>First value</strong>: Time of single-threaded execution in [ms]<br />
<strong>Second value</strong>: Time of multi-threaded execution in [ms]</p>
<p>That produced the following results:</p>
<table class="table table-striped">
<thead>
<tr>
<th></th>
<th>Version</th>
<th>Singleton</th>
<th>Transient</th>
<th>Combined</th>
<th>Complex</th>
<th>Property</th>
<th>Generics</th>
<th>IEnumerable</th>
<th>Conditional</th>
<th>Child Container</th>
<th>Interception With Proxy</th>
<th>Prepare And Register</th>
<th>Prepare And Register And Simple Resolve</th>
</tr>
</thead>
<tbody>
<tr>
<td>No</td>
<td style="text-align: center;"></td>
<td style="text-align: center;">
<p style="text-align: center;"> 56</p>
<p style="text-align: center;">89</p>
</td>
<td style="text-align: center;"> 72</p>
<p>104</td>
<td style="text-align: center;">105</p>
<p>124</td>
<td style="text-align: center;">134</p>
<p>134</td>
<td style="text-align: center;"> 148</p>
<p>146</td>
<td style="text-align: center;">96</p>
<p>110</td>
<td style="text-align: center;">305</p>
<p>231</td>
<td style="text-align: center;">98</p>
<p>118</td>
<td style="text-align: center;">606</p>
<p>391</td>
<td style="text-align: center;">72</p>
<p>105</td>
<td style="text-align: center;">2</td>
<td style="text-align: center;"> 3</td>
<td></td>
</tr>
<tr>
<td><a href="https://www.nuget.org/packages/Autofac/" target="_blank">AutoFac</a></td>
<th style="text-align: center;">4.1.0.0</th>
<td style="text-align: center;"> 602</p>
<p>508</td>
<td style="text-align: center;"> 1240</p>
<p>785</td>
<td style="text-align: center;">3760</p>
<p>2108</td>
<td style="text-align: center;">10242</p>
<p>6385</td>
<td style="text-align: center;">18682</p>
<p>10466</td>
<td style="text-align: center;">2632</p>
<p>1592</td>
<td style="text-align: center;">10363</p>
<p>5634</td>
<td style="text-align: center;"></td>
<td style="text-align: center;"> 37968</p>
<p>20398</td>
<td style="text-align: center;"></td>
<td style="text-align: center;"></td>
<td></td>
</tr>
<tr>
<td><a href="https://www.nuget.org/packages/Microsoft.Extensions.DependencyInjection/" target="_blank">Microsoft<br />
Extensions<br />
DependencyInjection</a></td>
<th style="text-align: center;">1.0.0.20622</th>
<td style="text-align: center;">156</p>
<p>220</td>
<td style="text-align: center;">140</p>
<p>144</td>
<td style="text-align: center;">320</p>
<p>318</td>
<td style="text-align: center;">729</p>
<p>830</td>
<td style="text-align: center;"></td>
<td style="text-align: center;">198</p>
<p>186</td>
<td style="text-align: center;">738</p>
<p>448</td>
<td style="text-align: center;"></td>
<td style="text-align: center;"></td>
<td style="text-align: center;"></td>
<td style="text-align: center;">18</td>
<td style="text-align: center;"> 25</td>
</tr>
<tr>
<td><a href="https://www.nuget.org/packages/Ninject/4.0.0-beta-0134" target="_blank">Ninject</a></td>
<th style="text-align: center;">3.2.2.0</th>
<td style="text-align: center;"> 3932</p>
<p>2588</td>
<td style="text-align: center;"> 13965</p>
<p>11564</td>
<td style="text-align: center;"> 37197</p>
<p>25070</td>
<td style="text-align: center;"> 103800</p>
<p>64927</td>
<td style="text-align: center;">93449</p>
<p>69829</td>
<td style="text-align: center;">37011</p>
<p>26061</td>
<td style="text-align: center;">91829</p>
<p>68581</td>
<td style="text-align: center;">34162</p>
<p>23586</td>
<td style="text-align: center;">62954750*</p>
<p>75133444*</td>
<td style="text-align: center;"> 102117</p>
<p>99437</td>
<td style="text-align: center;"> 129042</td>
<td style="text-align: center;"> 115231</td>
</tr>
<tr>
<td><a href="https://www.nuget.org/packages/SimpleInjector/" target="_blank">SimpleInjector</a></td>
<th style="text-align: center;"> 3.2.2.0</th>
<td style="text-align: center;"> 66</p>
<p>101</td>
<td style="text-align: center;">87</p>
<p>120</td>
<td style="text-align: center;"> 151</p>
<p>159</td>
<td style="text-align: center;">188</p>
<p>176</td>
<td style="text-align: center;"> 270</p>
<p>218</td>
<td style="text-align: center;">100</p>
<p>131</td>
<td style="text-align: center;">854<br />
520</td>
<td style="text-align: center;">121</p>
<p>144</td>
<td style="text-align: center;"></td>
<td style="text-align: center;"> 28926</p>
<p>30097</td>
<td style="text-align: center;"> 419</td>
<td style="text-align: center;"> 3359</td>
</tr>
</tbody>
</table>
<p>Second, I took the repos from:</p>
<p><a href="https://github.com/MartinF/IOCBattle" target="_blank">IOCBattle</a> by Martin From<br />
<a href="https://github.com/cardinal252/IOCBattle" target="_blank">IOCBattle</a> by Nathanael Mann</p>
<p>To get the following results:</p>
<table class="table table-striped">
<thead>
<tr>
<th></th>
<th>Version</th>
<th>Singleton Reg. (ms)</th>
<th>Singleton Resolve (1,000,000) (ms)</th>
<th>Transient Reg. (ms)</th>
<th>Transient Resolve (1,000,000) (ms)</th>
</tr>
</thead>
<tbody>
<tr>
<td>new ()</td>
<th></th>
<td style="text-align: center;">0.0726</td>
<td style="text-align: center;">57.6387</td>
<td style="text-align: center;">0.0683</td>
<td style="text-align: center;">200.6526</td>
</tr>
<tr>
<td><a href="https://www.nuget.org/packages/Autofac/" target="_blank">AutoFac</a> Lambda</td>
<th style="text-align: center;">4.1.0.0</th>
<td style="text-align: center;">54.8336</td>
<td style="text-align: center;">453.2864</td>
<td style="text-align: center;">2.1957</td>
<td style="text-align: center;">6569.4292</td>
</tr>
<tr>
<td><a href="https://www.nuget.org/packages/Autofac/" target="_blank">AutoFac</a></td>
<th style="text-align: center;">4.1.0.0</th>
<td style="text-align: center;">4.8632</td>
<td style="text-align: center;">464.7712</td>
<td style="text-align: center;">0.7575</td>
<td style="text-align: center;">16183.6045</td>
</tr>
<tr>
<td><a href="https://www.nuget.org/packages/Microsoft.Extensions.DependencyInjection/" target="_blank">Microsoft<br />
Extensions<br />
DependencyInjection</a></td>
<th style="text-align: center;">1.0.0.20622</th>
<td style="text-align: center;">0.5311</td>
<td style="text-align: center;">66.0343</td>
<td style="text-align: center;">0.4936</td>
<td style="text-align: center;">198.7997</td>
</tr>
<tr>
<td><a href="https://www.nuget.org/packages/Ninject/4.0.0-beta-0134" target="_blank">Ninject</a></td>
<th style="text-align: center;">3.2.2.0</th>
<td style="text-align: center;">34.5873</td>
<td style="text-align: center;">3343.113</td>
<td style="text-align: center;">1.6425</td>
<td style="text-align: center;">186098.403</td>
</tr>
<tr>
<td><a href="https://www.nuget.org/packages/SimpleInjector/" target="_blank">SimpleInjector</a></td>
<th style="text-align: center;"> 3.2.2.0</th>
<td style="text-align: center;">31.0477</td>
<td style="text-align: center;">104.6839</td>
<td style="text-align: center;">2.5184</td>
<td style="text-align: center;">225.4272</td>
</tr>
</tbody>
</table>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
<p><strong>Links</strong>:<br />
<a href="http://www.palmmedia.de/blog/2011/8/30/ioc-container-benchmark-performance-comparison" target="_blank">IoC Container Benchmark &#8211; Performance comparison</a><br />
<a href="https://cardinalcore.co.uk/2015/01/28/ioc-battle-in-2015-results-using-ninject-think-again/" target="_blank">IoC Battle in 2015 results: Using Ninject – think again!</a></p>
<p>&nbsp;</p>
<p>*Due to the updated AutoFac version I was getting some issues with Daniels code. I will resolve it at a later date and retest it.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Secure Sitecore : Secure Headers XSS Protection</title>
      <link>https://akshaysura.com/blog/secure-sitecore-secure-headers-xss-protection/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/secure-sitecore-secure-headers-xss-protection/</guid>
      <pubDate>Fri, 19 Aug 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[We have been going through XSS vulnerability in the past two posts. I am going to end this series with one last post about Secure Headers. We will go through a few headers that we can implement.]]></description>
      <content:encoded><![CDATA[<p>We have been going through XSS vulnerability in the past two posts. I am going to end this series with one last post about Secure Headers. We will go through a few headers that we can implement.</p>
<p>Environment testing was done on two Windows 10 machines with Sitecore 8.1 update 3. Browsers use were Chrome (), Firefox (47.0.1), Microsoft Edge (25.10586.0.0 and Internet Explorer 11 (11.494.10586.0). <strong>Fresh installs on both, no config patches or customizations.</strong></p>
<p>You can protect your self with headers without any need for code. Some of the headers which are recommended are:<br />
<a href="https://www.owasp.org/index.php/HTTP_Strict_Transport_Security_Cheat_Sheet" target="_blank">HTTP Strict Transport Security (HSTS)</a><br />
HSTS informs browsers that the communication should only happen in HTTPS and not in HTTP.</p>
<p><a href="https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning" target="_blank">HTTP Public Key Pinning (HPKP)</a><br />
HPKP informs browsers to associate a specific cryptographic public key with a specific web server to prevent Man-in-the-middle (MITM) attacks with forged certificates.</p>
<p><a href="https://www.owasp.org/index.php/Clickjacking_Defense_Cheat_Sheet" target="_blank">X-Frame-Options</a><br />
The X-Frame-Options header indicates if a browser should allow the render of a page in a frame, iframe or object. By implementing this header a site can avoid clickjacking attacks, by ensuring that the content is not embedded into other sites.</p>
<p><a href="https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#X-XSS-Protection" target="_blank">X-XSS-Protection</a><br />
The X-XSS-Protection informs your browser to enable XSS filter in your browser. Not all browsers support this header.</p>
<p><a href="https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#X-Content-Type-Options" target="_blank">X-Content-Type-Options</a><br />
The X-Content-Type-Options header prevents MIME type confusion attacks by enforcing MIME types on script and style elements.</p>
<p><a href="https://www.owasp.org/index.php/Content_Security_Policy" target="_blank">Content-Security-Policy</a><br />
The Content-Security-Policy header prevents XSS attacks by dictating what kind of resources can be loaded into the browser.</p>
<p><a href="https://twitter.com/BasLijten" target="_blank">Bas Lijten</a> has written a few blog posts to go over some of the above. Here are the links: <a href="http://blog.baslijten.com/sitecore-security-3-prevent-xss-using-content-security-policy/" target="_blank">Sitecore Security #3: Prevent XSS using Content Security Policy</a> &amp; <a href="http://blog.baslijten.com/sitecore-security-2-secure-connections-and-how-to-force-the-browser-to-use-the-secure-connection/" target="_blank">Sitecore Security #2: Secure connections and how to force the browser to use the secure connection</a>.</p>
<p><strong>X-Xss-Protection</strong><br />
This header configures the built in reflective XSS protection found in some modern browsers. Valid settings are:<br />
0 &#8211; disable the protection<br />
1 &#8211; enable the protection. If the browser detects an attack, the browser will sanitize the page<br />
1; mode=block &#8211; enable the protection &amp; block the response. If the browser detects an attack, the page will not be loaded and the browser wont sanitize the page<br />
1; report=http://[YOURDOMAIN]/your_report_URI &#8211; enable the protection. If the browser detects an attack, he browser will sanitize the page and report the violation</p>
<p>By default we do not get many headers from the base install of Sitecore.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/xss31.png"><img loading="lazy" class="alignnone size-large wp-image-2688" src="http://akshaysura.com/wp-content/uploads/2016/08/xss31-1024x845.png" alt="xss31" width="900" height="743" /></a></p>
<p>Lets do some testing.</p>
<p><strong>X-Xss-Protection &#8220;0&#8221; &#8211; Disable</strong></p>
<pre><code class="language-xml">
  &lt;system.webServer&gt;
    &lt;httpProtocol&gt;
      &lt;customHeaders&gt;
	&lt;add name="X-XSS-Protection" value="0" /&gt;
      &lt;/customHeaders&gt;
    &lt;/httpProtocol&gt;
  &lt;/system.webServer&gt;
</code></pre>
<p>Now we load http://local.testsc8.com/?special=%3Cscript%20src=%22https://somedomain.com/somescript.js%22%3E%3C/script%3E on a page which consumes the special query string parameter and renders it on the page causing the script to execute.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/xss32.png"><img loading="lazy" class="alignnone size-large wp-image-2689" src="http://akshaysura.com/wp-content/uploads/2016/08/xss32-1024x768.png" alt="xss32" width="900" height="675" /></a></p>
<p>The header gets loaded as we expected but on closer look on all four browsers, each acts differently. Chrome and FF load the script where as Microsoft Edge and IE11 do not load the script. We also do not see any console output.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/xss33.png"><img loading="lazy" class="alignnone size-large wp-image-2690" src="http://akshaysura.com/wp-content/uploads/2016/08/xss33-1024x550.png" alt="xss33" width="900" height="483" /></a></p>
<p><strong>X-Xss-Protection &#8220;1&#8221; &#8211; Enable &amp; Sanitize</strong></p>
<pre><code class="language-xml">
  &lt;system.webServer&gt;
    &lt;httpProtocol&gt;
      &lt;customHeaders&gt;
	&lt;add name="X-XSS-Protection" value="1" /&gt;
      &lt;/customHeaders&gt;
    &lt;/httpProtocol&gt;
  &lt;/system.webServer&gt;
</code></pre>
<p>Now we load http://local.testsc8.com/?special=%3Cscript%20src=%22https://somedomain.com/somescript.js%22%3E%3C/script%3E . Something very interesting happens:</p>
<ol>
<li>Chrome, Microsoft Edge and IE11 respect the header value of 1 and do not load the script.</li>
<li>Chrome, Microsoft Edge and IE11 show a console message.</li>
<li>Props to IE11 (never thought I would say this about IE), it even shows a very visible notification to the user.</li>
<li>Firefox on the other hand still loads the scripts and completely ignores the header.</li>
</ol>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/xss34.png"><img loading="lazy" class="alignnone size-large wp-image-2692" src="http://akshaysura.com/wp-content/uploads/2016/08/xss34-1024x552.png" alt="xss34" width="900" height="485" /></a><br />
<a href="http://akshaysura.com/wp-content/uploads/2016/08/xss35.png"><img loading="lazy" class="alignnone size-large wp-image-2691" src="http://akshaysura.com/wp-content/uploads/2016/08/xss35-1024x554.png" alt="xss35" width="900" height="487" /></a></p>
<p><strong>X-Xss-Protection &#8220;1; mode=block&#8221; &#8211; Enable &amp; Block</strong></p>
<pre><code class="language-xml">
  &lt;system.webServer&gt;
    &lt;httpProtocol&gt;
      &lt;customHeaders&gt;
	&lt;add name="X-XSS-Protection" value="1; mode=block" /&gt;
      &lt;/customHeaders&gt;
    &lt;/httpProtocol&gt;
  &lt;/system.webServer&gt;
</code></pre>
<ol>
<li>Now we load http://local.testsc8.com/?special=%3Cscript%20src=%22https://somedomain.com/somescript.js%22%3E%3C/script%3E . All browsers behave differently yet again:</li>
<li>Chrome does not load any content. No output in Network or Console tabs.</li>
<li>Firefox loads all the content including the offending script. No output in console.</li>
<li>Microsoft Edge and IE11 do not load any content. The console shows error message and the network tab shows the request.</li>
</ol>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/xss38.png"><img loading="lazy" class="alignnone size-large wp-image-2694" src="http://akshaysura.com/wp-content/uploads/2016/08/xss38-1024x555.png" alt="xss38" width="900" height="488" /></a> <a href="http://akshaysura.com/wp-content/uploads/2016/08/xss37.png"><img loading="lazy" class="alignnone size-large wp-image-2695" src="http://akshaysura.com/wp-content/uploads/2016/08/xss37-1024x553.png" alt="xss37" width="900" height="486" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/xss39.png"><img loading="lazy" class="alignnone size-large wp-image-2696" src="http://akshaysura.com/wp-content/uploads/2016/08/xss39-1024x579.png" alt="xss39" width="900" height="509" /></a></p>
<p>As you can see each browser behaves differently. I would say in this case FireFox is the worst. We are unable to get full protection from all browsers with the X-XSS-Protection. This should show us that there is no silver bullet. We would need to implement multiple protections to remedy the XSS vulnerability.</p>
<p>You can use a third party site like <a href="https://securityheaders.io/?" target="_blank">securityheaders.io</a> to evaluate your site.<br />
<a href="http://akshaysura.com/wp-content/uploads/2016/08/xss40.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/08/xss40-1024x512.png" alt="xss40" width="900" height="450" class="alignnone size-large wp-image-2699" /></a><br />
<a href="http://akshaysura.com/wp-content/uploads/2016/08/xss41.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/08/xss41-1024x657.png" alt="xss41" width="900" height="577" class="alignnone size-large wp-image-2701" /></a></p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>Secure Sitecore : Cross Site Scripting (XSS) Vulnerability Prevention</title>
      <link>https://akshaysura.com/blog/secure-sitecore-cross-site-scripting-xss-vulnerability-prevention/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/secure-sitecore-cross-site-scripting-xss-vulnerability-prevention/</guid>
      <pubDate>Thu, 18 Aug 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[In the last Cross Site Scripting (XSS) post: Secure Sitecore : Cross Site Scripting (XSS) Vulnerability Findings , we looked at how these attacks might look based on the browser the user is using. The interesting factor is that a potential attacker might not use a browser at all. You do not need a browser to initiate requests and process them. Fuzzing is a common technique where an attacker can create potentially invalid requests from scratch to perform testing on applications, to see how they respond.]]></description>
      <content:encoded><![CDATA[<p>In the last Cross Site Scripting (XSS) post: <a href="http://akshaysura.com/2016/08/04/secure-sitecore-cross-site-scripting-xss-vulnerability-findings/" target="_blank">Secure Sitecore : Cross Site Scripting (XSS) Vulnerability Findings</a> , we looked at how these attacks might look based on the browser the user is using. The interesting factor is that a potential attacker might not use a browser at all. You do not need a browser to initiate requests and process them. <a href="https://www.owasp.org/index.php/Fuzzing" target="_blank">Fuzzing</a> is a common technique where an attacker can create potentially invalid requests from scratch to perform testing on applications, to see how they respond.</p>
<p>Environment testing was done on two Windows 10 machines with Sitecore 8.1 update 3. Browsers use were Chrome (), Firefox (47.0.1), Microsoft Edge (25.10586.0.0 and Internet Explorer 11 (11.494.10586.0).</p>
<p>I would also recommend that you go through the post: <a href="http://blog.baslijten.com/sitecore-security-3-prevent-xss-using-content-security-policy/" target="_blank">Sitecore Security #3: Prevent XSS using Content Security Policy</a> by <a href="https://twitter.com/BasLijten" target="_blank">Bas Lijten</a>. Content headers can enforce security on browsers. Remember, each browser acts differently.</p>
<p>Based on the last post, I want to show you how to add in custom validation on requests. Because we are on 4.5, we have the ability to specify a Custom Request Validator. To do this lets do an sample in a true ASP.NET MVC application.</p>
<p>I created a sample MVC application with no custom coding. I added the following class for a custom Request Validator:</p>
<pre><code class="language-csharp">
    public class CustomRequestValidation : RequestValidator
    {
        protected override bool IsValidRequestString(HttpContext context, string value, RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex)
        {
            validationFailureIndex = 0;

            switch (requestValidationSource)
            {
                case RequestValidationSource.QueryString:
                    WriteLog(value, requestValidationSource, collectionKey);
                    return false;

                    break;
            }

            return base.IsValidRequestString(context, value, requestValidationSource, collectionKey, out validationFailureIndex);
        }
}
</code></pre>
<p>Here is are the web.config entries related to compilation and httpRuntime:</p>
<pre><code class="language-xml">
&lt;compilation debug="true" targetFramework="4.5" /&gt;
&lt;httpRuntime requestValidationType="WebApplication2.Code.CustomRequestValidation" /&gt;
</code></pre>
<p>The output is what we expected. Any request with a QueryString will and should result in an error.<br />
<a href="http://akshaysura.com/wp-content/uploads/2016/08/xss21.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/08/xss21-1024x567.png" alt="xss21" width="900" height="498" class="alignnone size-large wp-image-2657" /></a></p>
<p>The default ASP.NET MVC app, hits the return false which causes the invalid value error and stops.</p>
<p>Now lets take the default Sitecore install and make the same change by adding the CustomRequestValidation.</p>
<pre><code class="language-xml">
&lt;compilation defaultLanguage="c#" debug="false" targetFramework="4.5"&gt;
&lt;httpRuntime  requestValidationType="TestXSS.Code.CustomRequestValidation" maxRequestLength="512000" executionTimeout="600" enableKernelOutputCache="false" relaxedUrlToFileSystemMapping="true" enableVersionHeader="false" /&gt;
</code></pre>
<pre><code class="language-csharp">
namespace TestXSS.Code
{
    public class CustomRequestValidation : RequestValidator
    {
        protected override bool IsValidRequestString(HttpContext context, string value, RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex)
        {
            validationFailureIndex = 0;

            switch (requestValidationSource)
            {
                case RequestValidationSource.QueryString:
                    return false;

                    break;
            }

            return base.IsValidRequestString(context, value, requestValidationSource, collectionKey, out validationFailureIndex);
        }
  }
</code></pre>
<p>Lets open the site using some QueryString params and see what happens.<br />
<a href="http://akshaysura.com/wp-content/uploads/2016/08/xss23.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/08/xss23-1024x554.png" alt="xss23" width="900" height="487" class="alignnone size-large wp-image-2663" /></a></p>
<p>As you can see, Sitecore somehow seems to move past it and continues to evaluate the other parameters. My initial thought was to some how detect the additional tags via the CustomRequestValidation but now that doesn&#8217;t look feasible.</p>
<p>There is processor called SupressFormValidation which triggers even before the CustomRequestValidation and here Sitecore basically suppresses the validations for specific urls. In doing so, my previous article show that we are getting inconsistent results. The default SupressFormValidation code is shown below:</p>
<pre><code class="language-csharp">
using Sitecore.Diagnostics;
using Sitecore.Web;
using System;
using System.Collections.Specialized;
using System.Web;

namespace Sitecore.Pipelines.PreprocessRequest
{
    /// &lt;summary&gt;
    /// The suppress form validation.
    /// &lt;/summary&gt;
    public class SuppressFormValidation : PreprocessRequestProcessor
    {
        public SuppressFormValidation()
        {
        }

        /// &lt;summary&gt;
        /// Suppresses the form validation exception that has been introduced in .NET 4.0 for Sitecore backend.
        /// &lt;/summary&gt;
        /// &lt;param name="args"&gt;The pipeline arguments.&lt;/param&gt;
        /// &lt;exception cref="T:System.Web.HttpRequestValidationException"&gt;Indicates that form validation exception occured for frontend.&lt;/exception&gt;
        public override void Process(PreprocessRequestArgs args)
        {
            Assert.ArgumentNotNull(args, "args");
            if (WebUtil.ShouldIgnoreUrl(args.Context.Request.Url.AbsolutePath))
            {
                return;
            }
            try
            {
                NameValueCollection form = args.Context.Request.Form;
            }
            catch (HttpRequestValidationException httpRequestValidationException)
            {
                string rawUrl = args.Context.Request.RawUrl;
                if (!rawUrl.StartsWith("/sitecore/shell/", StringComparison.InvariantCultureIgnoreCase) &amp;&amp; !rawUrl.StartsWith("/sitecore/admin/", StringComparison.InvariantCultureIgnoreCase) &amp;&amp; !rawUrl.StartsWith("/-/speak/request/", StringComparison.InvariantCultureIgnoreCase))
                {
                    throw;
                }
            }
        }
    }
}
</code></pre>
<p>Here is a possible remedy. Get the web.config back to normal without the CustomRequestValidation. We validate our query string parameters against <a href="http://www.rfc-base.org/rfc-3986.html" target="_blank">RFC 3986</a> and if its violated we throw an error. Here is the modified SupressFormValidation:</p>
<pre><code class="language-csharp">
using Sitecore.Diagnostics;
using Sitecore.Pipelines.PreprocessRequest;
using System;
using System.Text.RegularExpressions;
using System.Web;

namespace TestXSS.Code
{
    public class SuppressFormValidation : Sitecore.Pipelines.PreprocessRequest.SuppressFormValidation
    {

        public override void Process(PreprocessRequestArgs args)
        {
            bool isShell = CheckSitecoreUrl(args.Context.Request.RawUrl);

            if (isShell)
            {
                base.Process(args);
            }
            else
            {
                try
                {
                    if (IsSecurePayload())
                        base.Process(args);
                }
                catch (HttpRequestValidationException)
                {
                    throw;
                }
            }
        }

        private bool CheckSitecoreUrl(string url)
        {
            string[] exceptions = new string[]
            {
                "/sitecore/",
                "/WebResource.axd",
                "/ScriptResource.axd",
                "/Telerik.Web.UI.WebResource.axd"
            };
            //"/sitecore/shell/",
            //"/sitecore/admin/",
            //"/sitecore/api/",

            foreach (string e in exceptions)
            {
                if (url.StartsWith(e, StringComparison.InvariantCultureIgnoreCase))
                {
                    return true;
                }
            }
            return false;
        }

        //just processing query string at this moment
        private bool IsSecurePayload()
        {
            bool returnVal = true;

            foreach (String key in HttpContext.Current.Request.QueryString.AllKeys)
            {
                string value = HttpContext.Current.Request.QueryString[key];
                if (!IsSecureParam(value))
                {
                    throw new HttpRequestValidationException("-*-*-*-*A potentially dangerous Request.RawUrl value was detected from the client " + value);
                }
            }

            return returnVal;
        }

        //RFC 3986 for query string - http://www.rfc-base.org/rfc-3986.html
        private bool IsSecureParam(string value)
        {
            if (!string.IsNullOrEmpty(value) && !Regex.IsMatch(value, @"^[a-zA-Z0-9@.' _~-]{1,40}$"))
                return false;
            else
                return true;
        }
    }
}
</code></pre>
<p>Here is the patch config:</p>
<pre><code class="language-xml">
&lt;configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"&gt;
  &lt;sitecore&gt;
    &lt;pipelines&gt;
        preprocessRequest&gt;
            &lt;processor type="Sitecore.Pipelines.PreprocessRequest.SuppressFormValidation, Sitecore.Kernel"&gt;
               &lt;patch:attribute name="type"&gt;TestXSS.Code.SuppressFormValidation, TestXSS&lt;/patch:attribute&gt;
             &lt;/processor&gt;
      &lt;/preprocessRequest&gt;
    &lt;/pipelines&gt;
  &lt;/sitecore&gt;
&lt;/configuration&gt;
</code></pre>
<p>Now if we run the tests using urls regardless of the encoding:</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/xss26.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/08/xss26-1024x553.png" alt="xss26" width="900" height="486" class="alignnone size-large wp-image-2669" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/xss24.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/08/xss24-1024x554.png" alt="xss24" width="900" height="487" class="alignnone size-large wp-image-2670" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/xss25.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/08/xss25-1024x551.png" alt="xss25" width="900" height="484" class="alignnone size-large wp-image-2671" /></a></p>
<p>The system functions the way we expect it to on top of the base validation by ASP.NET. Now if we get in to the Sitecore admin, we have no issues modifying items etc.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/xss27.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/08/xss27-1024x557.png" alt="xss27" width="900" height="490" class="alignnone size-large wp-image-2672" /></a></p>
<p>This is not limited to what I did, you can evaluate Form posts, cookies etc. You can check encoding as well as any custom rules you have for your system to be secure. We no longer have security mishaps when Chrome or FF encode their inputs.</p>
<p>Remember, we did not set the validation mode to 2.0, we left the default web.config and sitecore.config which defaults to framework 4.5.</p>
<p>&nbsp;<br />
If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>Secure Sitecore : Cross Site Scripting (XSS) Vulnerability Findings</title>
      <link>https://akshaysura.com/blog/secure-sitecore-cross-site-scripting-xss-vulnerability-findings/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/secure-sitecore-cross-site-scripting-xss-vulnerability-findings/</guid>
      <pubDate>Thu, 04 Aug 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Lately I have been focussed on OWASP Top 10 security guidelines and locking down sites. The next one on the list is Cross Site Scripting (XSS). According to OWASP:]]></description>
      <content:encoded><![CDATA[<p>Lately I have been focussed on <a href="https://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project" target="_blank">OWASP Top 10 security guidelines</a> and locking down sites. The next one on the list is Cross Site Scripting (XSS). According to OWASP:</p>
<p><em>Cross-Site Scripting (XSS) attacks are a type of injection, in which malicious scripts are injected into otherwise benign and trusted web sites. XSS attacks occur when an attacker uses a web application to send malicious code, generally in the form of a browser side script, to a different end user. Flaws that allow these attacks to succeed are quite widespread and occur anywhere a web application uses input from a user within the output it generates without validating or encoding it.</em></p>
<p>Environment testing was done on two Windows 10 machines with Sitecore 8.1 update 3. Browsers use were Chrome (), Firefox (47.0.1), Microsoft Edge (25.10586.0.0 and Internet Explorer 11 (11.494.10586.0).</p>
<p>These tests were done on a base install of Sitecore where no changes were made to the Web.config and Sitecore.config. As of .NET 4.5 the Request Validation does not trigger until the data is requested. You could always use the Request.Unvalidated to access the potentially unsafe values coming in.</p>
<p>It is important to know that not all browsers are alike. Some are advanced in their implementations and some are not. Your solution has to deter potential risks from any browser.</p>
<p>First, load the site http://local.testsc8.com on all browsers to make sure its loading:</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/xss10.png"><img loading="lazy" class="alignnone size-large wp-image-2637" src="http://akshaysura.com/wp-content/uploads/2016/08/xss10-1024x555.png" alt="xss10" width="900" height="488" /></a></p>
<p>Following that, lets load it with some malicious params, http://local.testsc8.com/?q=&lt;script&gt;</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/xss11.png"><img loading="lazy" class="alignnone size-large wp-image-2638" src="http://akshaysura.com/wp-content/uploads/2016/08/xss11-1024x555.png" alt="xss11" width="900" height="488" /></a></p>
<p>What happened here? Seems like Chrome and Firefox are not even recognizing what the input is, where as IE 11 and MS Edge are. But this is not true. lets inspect the session using Fiddler.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/xss12.png"><img loading="lazy" class="alignnone size-full wp-image-2639" src="http://akshaysura.com/wp-content/uploads/2016/08/xss12.png" alt="xss12" width="835" height="447" /></a></p>
<p>What you can see is that each browser interprets the url differently. We typed in http://local.testsc8.com/?q=&lt;script&gt; but each of the browsers interpreted it differently than what I typed in except IE11. Chrome and Firefox encoded it immediately. Microsoft Edge encoded the ending &gt; but not the beginning &lt;.</p>
<p>What this shows is that even though Chrome and Firefox encoded the input, it did not make the input safe. If we on the code behind did not interpret the incoming parameters incorrectly, we could cause a lot of damage and let a potential hacker get in.</p>
<p>Next, lets put in a simple form in a view on the default install and see how that matches up. Lets input &lt;script&gt; in the text box.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/xss13.png"><img loading="lazy" class="alignnone size-large wp-image-2641" src="http://akshaysura.com/wp-content/uploads/2016/08/xss13-1024x553.png" alt="xss13" width="900" height="486" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/xss15.png"><img loading="lazy" class="alignnone size-large wp-image-2642" src="http://akshaysura.com/wp-content/uploads/2016/08/xss15-1024x554.png" alt="xss15" width="900" height="487" /></a></p>
<p>All browsers transmitted the data and we were able to catch all exceptions. Lets try a few more combinations. (%3Cscript%3E)</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/xss16.png"><img loading="lazy" class="alignnone size-large wp-image-2644" src="http://akshaysura.com/wp-content/uploads/2016/08/xss16-1024x552.png" alt="xss16" width="900" height="485" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/xss17.png"><img loading="lazy" class="alignnone size-large wp-image-2643" src="http://akshaysura.com/wp-content/uploads/2016/08/xss17-1024x556.png" alt="xss17" width="900" height="489" /></a></p>
<p>Now for &lt;script%3E.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/xss18.png"><img loading="lazy" class="alignnone size-large wp-image-2645" src="http://akshaysura.com/wp-content/uploads/2016/08/xss18-1024x553.png" alt="xss18" width="900" height="486" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/xss19.png"><img loading="lazy" class="alignnone size-large wp-image-2646" src="http://akshaysura.com/wp-content/uploads/2016/08/xss19-1024x556.png" alt="xss19" width="900" height="489" /></a></p>
<p>I also want to mention the below setting:</p>
<pre><code class="language-xml">
    &lt;!-- If requestValidationMode attribute of httRuntime node is set to 2.0, 
         Sitecore requires this setting to be set to "false" for Sitecore client to work and it shouldn't be changed.
         You can however set ValidateRequest attribute in the @Page directive to "true" for your layout .aspx files. 
    --&gt;
    &lt;pages validateRequest="true"&gt;
</code></pre>
<p>Setting it to true is not going to do anything unless you want to set the requestValidationMode to 2.0 which I do not intend to. I want the requestValidationMode to 4.5. Also the httpRuntime is misspelled ;).</p>
<p>In all of this even with flag as true for validateRequest, the admin works and is able to save items etc.</p>
<p>In the next post we will see if we can add on more security for Querystring and Form.</p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
<p>&nbsp;</p>
]]></content:encoded>
    </item>
    <item>
      <title>Secure Sitecore : Headers are a headache but nothing we cannot solve!</title>
      <link>https://akshaysura.com/blog/secure-sitecore-headers-are-a-headache-but-nothing-we-cannot-solve/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/secure-sitecore-headers-are-a-headache-but-nothing-we-cannot-solve/</guid>
      <pubDate>Tue, 02 Aug 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Lately I have been focussed on OWASP Top 10 security guidelines and locking down sites. The next one on the list is Response Headers. For reach page request, the server sends over the headers containing information about the server and ASP.NET. Some call it chatty headers and less we send back the better it is to protect ourselves.]]></description>
      <content:encoded><![CDATA[<p>Lately I have been focussed on <a href="https://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project" target="_blank">OWASP Top 10 security guidelines</a> and locking down sites. The next one on the list is Response Headers. For reach page request, the server sends over the headers containing information about the server and ASP.NET. Some call it chatty headers and less we send back the better it is to protect ourselves.</p>
<p>There are several things you could do to secure your Sitecore instance, namely the <a href="https://sdn.sitecore.net/upload/sitecore7/75/sitecore_security_hardening_guide-sc75-usletter.pdf" target="_blank">Sitecore Security Hardening Guide</a>. Along with the documented steps, there are several others you should implement to secure your instances.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/header1.png"><img loading="lazy" class="alignnone size-full wp-image-2603" src="http://akshaysura.com/wp-content/uploads/2016/08/header1.png" alt="header1" width="928" height="319" /></a></p>
<p>Thank goodness in the newer versions of Sitecore they tackled two of these by default, namely the X-Powered-By:</p>
<pre><code class="language-xml">
    &lt;httpProtocol&gt;
      &lt;customHeaders&gt;
        &lt;remove name="X-Powered-By" /&gt;
      &lt;/customHeaders&gt;
    &lt;/httpProtocol&gt;
  &lt;/system.webServer&gt;
</code></pre>
<p>and X-AspNet-Version (enableVersionHeader as false):</p>
<pre><code class="language-xml">
    &lt;httpRuntime maxRequestLength="512000" executionTimeout="600" enableKernelOutputCache="false" relaxedUrlToFileSystemMapping="true" enableVersionHeader="false" /&gt;
  &lt;/system.web&gt;
</code></pre>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/header2.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/08/header2.png" alt="header2" width="891" height="507" class="alignnone size-full wp-image-2605" /></a></p>
<p>Next for the X-AspNetMvc-Version HTTP Header, we need to add the following in the Global.asax:</p>
<pre><code class="language-csharp">
using System;
using System.Web.Mvc;

namespace TIHIDI.Web
{
    public class Global : Sitecore.Web.Application
    {

        protected void Application_Start(object sender, EventArgs e)
        {
            MvcHandler.DisableMvcResponseHeader = true;
        }
</code></pre>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/header4.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/08/header4.png" alt="header4" width="948" height="496" class="alignnone size-full wp-image-2606" /></a></p>
<p>Last but not the least is the Server header. In order to take this guy out we could add on to the Global.asax, here is the sample code:</p>
<pre><code class="language-csharp">

        protected void Application_PreSendRequestHeaders(object sender, EventArgs e)
        {
            HttpApplication app = sender as HttpApplication;
            if (app != null &&
                app.Context != null)
            {
                app.Context.Response.Headers.Remove("Server");

                //Response.Headers.Set("Server", "YoMama!"); // you can modify the headers
                //Response.Headers.Remove("X-AspNet-Version"); //alternate
                //Response.Headers.Remove("X-AspNetMvc-Version"); //alternate
            }
        }
</code></pre>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/header5.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/08/header5.png" alt="header5" width="918" height="449" class="alignnone size-full wp-image-2607" /></a></p>
<p>But where is the fun in that! I usually do not like to fiddle with the Global.asax and so this is an alternate solution to the two fixes above which require Global.asax. This fix relies on defining an Http Module. Lets start by defining a class which inherits IHttpModule:</p>
<pre><code class="language-csharp">
using System;
using System.Web;

namespace TIHIDI.SCExtensions.HTTPModules
{
    public class CustomHeadersModule : IHttpModule
    {
        public void Init(HttpApplication context)
        {
            context.PreSendRequestHeaders += OnPreSendRequestHeaders;
        }
        public void Dispose() { }
        static void OnPreSendRequestHeaders(object sender, EventArgs e)
        {
            // remove the Server Http header
            HttpContext.Current.Response.Headers.Remove("Server");

            //remove the X-AspNetMvc-Version Http header
            HttpContext.Current.Response.Headers.Remove("X-AspNetMvc-Version");

            //no need to fiddle with the Global.asax ;)
        }
    }
}

</code></pre>
<p>Following which lets add it into the Modules section of system.webServer to register the module.</p>
<pre><code class="language-xml">
      &lt;add name="CustomHeadersModule" type="TIHIDI.SCExtensions.HTTPModules.CustomHeadersModule" /&gt;
    &lt;/modules&gt;
</code></pre>
<p>Both yield the same results, one is cleaner than the other.</p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
<p>Http Module inspiration from <a href="https://blogs.technet.microsoft.com/stefan_gossner/2008/03/12/iis-7-how-to-send-a-custom-server-http-header/" target="_blank">IIS 7 – How to send a custom &#8220;Server&#8221; http header</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Secure Sitecore : Why use a custom 500 error page?</title>
      <link>https://akshaysura.com/blog/secure-sitecore-why-use-a-custom-500-error-page/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/secure-sitecore-why-use-a-custom-500-error-page/</guid>
      <pubDate>Tue, 02 Aug 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Enable custom errors to restrict users from seeing sensitive information such as the paths, stack trace and .NET version information. A potential hacker can get a lot of information on your environment just by looking at the default error page.]]></description>
      <content:encoded><![CDATA[<p>Enable custom errors to restrict users from seeing sensitive information such as the paths, stack trace and .NET version information. A potential hacker can get a lot of information on your environment just by looking at the default error page.</p>
<p>There are several things you could do to secure your Sitecore instance, namely the <a href="https://sdn.sitecore.net/upload/sitecore7/75/sitecore_security_hardening_guide-sc75-usletter.pdf" target="_blank">Sitecore Security Hardening Guide</a>. Along with the documented steps, there are several others you should implement to secure your instances.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/error1.png"><img loading="lazy" class="alignnone size-large wp-image-2595" src="http://akshaysura.com/wp-content/uploads/2016/08/error1-1024x590.png" alt="error1" width="900" height="519" /></a></p>
<p>The good thing is that Sitecore by default sets the customErrors to RemoteOnly. This way it shows you the information when you are working locally and will display generic information when accessing the site remotely.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/error2.png"><img loading="lazy" class="alignnone size-large wp-image-2594" src="http://akshaysura.com/wp-content/uploads/2016/08/error2-1024x592.png" alt="error2" width="900" height="520" /></a></p>
<p>Most of us are used to setting up a default 500 and 404 pages but I have seen in some instances that developers forget. The best thing to do is to set the default 500 page. For now I am going to set it to a physical Html file. There are different schools of thought depending on the security team you need to answer to. The ones I have had to deal with argue that if you set it to a Sitecore page /500 for instance, it might cause a recurring loop if Sitecore solution code itself is an issue. Instead if you use a standalone 500.html file, it will render always. The disadvantage is that we are unable to manage content on this file without code change.</p>
<pre><code class="language-html">
&lt;customErrors mode="On" defaultRedirect="~/Error/500.html" /&gt;
</code></pre>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/error3.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/08/error3-1024x590.png" alt="error3" width="900" height="519" class="alignnone size-large wp-image-2597" /></a><br />
This is better but we can do better. By default the redirectMode is ResponseRedirect and it places the path in the url. To overcome that we add in the redirectMode as ResponseRewrite so that the url where the error occurred stays as is but the response will be shown from the custom error page.</p>
<pre><code class="language-html">
&lt;customErrors mode="On" defaultRedirect="~/Error/500.html" redirectMode="ResponseRewrite" /&gt;
</code></pre>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/08/error4.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/08/error4.png" alt="error4" width="966" height="587" class="alignnone size-full wp-image-2598" /></a></p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>TIHIDI: Hardcode Constants vs. Sitecore Configuration Factory</title>
      <link>https://akshaysura.com/blog/tihidi-hardcode-constants-vs-sitecore-configuration-factory/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/tihidi-hardcode-constants-vs-sitecore-configuration-factory/</guid>
      <pubDate>Tue, 02 Aug 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[This blog post will go through how I setup my solution to be able to read everything I need from configuration rather than hardcoding it as part of code.]]></description>
      <content:encoded><![CDATA[<p>This blog post will go through how I setup my solution to be able to read everything I need from configuration rather than hardcoding it as part of code.</p>
<p>During a project, you might have the need to store Id&#8217;s or strings in your project. What ever you do, DONOT store them as part of code or in a constants file. Use Id&#8217;s over paths always.</p>
<p><strong>TIHIDI: Stands for This Is How I Do It. I am going to write a series of blog posts going through how I do Sitecore related work. Hope it helps you!</strong></p>
<p>In the TIHIDI post: <a href="http://akshaysura.com/2016/07/28/tihidi-glass-mapper-with-custom-models-and-mapping-using-fluent-configuration/" target="_blank">TIHIDI: Glass Mapper with Custom Models and Mapping using Fluent Configuration</a>, I ended up adding in the Sitecore configuration factory code to pull in the template Ids.</p>
<p>The concept is very similar to what <a href="https://twitter.com/mike_i_reynolds" target="_blank">Mike GoldSuit Reynolds</a> did in one of his blog posts, which I am unable to find the link.</p>
<p>First lets define the interface with all the config elements we need:</p>
<pre><code class="language-csharp">
using System;

namespace TIHIDI.SCExtensions.Settings
{
    public interface ITIHIDISettings
    {
        Guid CommunityChildrenTemplateId { get;  }
        Guid CommunityTypeTemplateId { get;  }
        Guid SampleCommunityTemplateId { get;  }
        Guid SampleStatusTemplateId { get;  }
    }
}
</code></pre>
<p>Next, lets implement a class inheriting this interface and loading the settings.</p>
<pre><code class="language-csharp">
using Sitecore.Configuration;
using Sitecore.Diagnostics;
using System;

namespace TIHIDI.SCExtensions.Settings
{
    public class TIHIDISettings : ITIHIDISettings
    {
        private static volatile ITIHIDISettings current;

        private static object lockObject = new Object();

        public static ITIHIDISettings Current
        {
            get
            {
                if (current == null)
                {
                    lock (lockObject)
                    {
                        if (current == null)
                        {
                            current = CreateNewBVSettings();
                        }
                    }
                }

                return current;
            }
        }

        public Guid CommunityChildrenTemplateId { get; private set; }
        public Guid CommunityTypeTemplateId { get; private set; }
        public Guid SampleCommunityTemplateId { get; private set; }
        public Guid SampleStatusTemplateId { get; private set; }

        private static ITIHIDISettings CreateNewBVSettings()
        {
            ITIHIDISettings tihidiSettings = Factory.CreateObject("settings/tihidiSettings", true) as ITIHIDISettings;
            Assert.IsNotNull(tihidiSettings, "tihidiSettings must be set in configuration!");
            return tihidiSettings;
        }
    }
}
</code></pre>
<p>Finally create a custom config with the settings you need and specify type to point to the new class.</p>
<pre><code class="language-xml">
&lt;configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"&gt;
  &lt;sitecore&gt;
    &lt;settings&gt;
      &lt;tihidiSettings type="TIHIDI.SCExtensions.Settings.TIHIDISettings, TIHIDI.SCExtensions"&gt;
        &lt;CommunityChildrenTemplateId&gt;{21FA0A73-BAC5-436E-9BBC-4FFCA1C79141}&lt;/CommunityChildrenTemplateId&gt;
        &lt;CommunityTypeTemplateId&gt;{DEA3C5F3-F610-4A10-BD61-79BA92716361}&lt;/CommunityTypeTemplateId&gt;
        &lt;SampleCommunityTemplateId&gt;{4BFC250F-51B0-4BD2-8A88-F6956CD6292C}&lt;/SampleCommunityTemplateId&gt;
        &lt;SampleStatusTemplateId&gt;{6A0338A7-3497-4870-9AE3-9C2CE053A400}&lt;/SampleStatusTemplateId&gt;
      &lt;/tihidiSettings&gt;
    &lt;/settings&gt;
  &lt;/sitecore&gt;
&lt;/configuration&gt;
</code></pre>
<p>Now that we have that all setup, we can use it in code. Here is an example in one of my Model mapping classes.</p>
<pre><code class="language-csharp">
using Glass.Mapper.Sc.Maps;
using TIHIDI.Models;
using TIHIDI.Models.Templates.Data;
using TIHIDI.SCExtensions.Settings;

namespace TIHIDI.Mapping.Templates.Data
{
    public class SampleCommunityMap : SitecoreGlassMap&lt;ISampleCommunity&gt;
    {

        public override void Configure()
        {
            ITIHIDISettings settings = TIHIDISettings.Current;

            Map(x =&gt;
            {
                ImportMap&lt;IGlassBase&gt;(); //import existing maps

                //you can specify the file types so that Glass can interpret them correctly
                x.Field(y =&gt; y.CommunityType).FieldType(Glass.Mapper.Sc.Configuration.SitecoreFieldType.Multilist);

                x.Field(y =&gt; y.CommunityStatus).FieldType(Glass.Mapper.Sc.Configuration.SitecoreFieldType.Droplink);

                //as for the children we can do any of the following, each has its own advantages
                //you do not necessarily have to call the attribute children

                x.Query(y =&gt; y.MyChildren)
                    .Query(string.Format("./*[@@templateid='{0}']", settings.CommunityChildrenTemplateId))
                    .IsRelative();

                x.Children(y =&gt; y.AlsoMyChildren);

                x.TemplateId(settings.SampleCommunityTemplateId); //totally optional but you can use it to enforce template id
                x.AutoMap();
            });
        }
    }
}

</code></pre>
<p>You are not limited to just Ids, you can use this for all your constants needs.</p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>TIHIDI: Implement a simple controller rendering in Sitecore MVC</title>
      <link>https://akshaysura.com/blog/tihidi-implement-a-simple-controller-rendering-in-sitecore-mvc/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/tihidi-implement-a-simple-controller-rendering-in-sitecore-mvc/</guid>
      <pubDate>Mon, 01 Aug 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[This blog post will go through how I setup a basic Controller rendering using Glass Mapper Model.]]></description>
      <content:encoded><![CDATA[<p>This blog post will go through how I setup a basic Controller rendering using Glass Mapper Model.</p>
<p>Visit <a href="http://www.glass.lu/mapper/sc" target="_blank">http://www.glass.lu/mapper/sc</a> for more information on Glass Mapper for Sitecore.</p>
<p><strong>TIHIDI: Stands for This Is How I Do It. I am going to write a series of blog posts going through how I do Sitecore related work. Hope it helps you!</strong></p>
<p>We are going to use the same infrastructure as my previous post <a href="http://akshaysura.com/2016/06/10/tihidi-implement-a-simple-view-rendering-in-sitecore-mvc-and-glass/" target="_blank">TIHIDI: Implement a simple view rendering in Sitecore MVC and Glass</a>.</p>
<p>Keeping the model as is, we need to add the code to render this via a Controller Rendering. This functionality really does not need a controller rendering as we were able to do this in a view rendering but I wanted to give you an example.</p>
<p>Before we get into controllers, we need to setup a couple of things related to Glass and Business Logic.</p>
<p>I setup a ControllerSCContext similar to Nathanael Mann (the Mann). You can read about it further <a href="https://cardinalcore.co.uk/2015/06/04/easy-access-of-datasource-and-rendering-parameters-from-your-controllers-using-glass-mapper-for-sitecore/" target="_blank">here</a>. Why do I do it this way? I do not know, I was taught by the master(s) to do it this way. If there is a more efficient way to do it, please send me links.</p>
<pre><code class="language-csharp">
using Glass.Mapper.Sc;

namespace TIHIDI.Business.GlassSC
{
    public interface IControllerSCContext : ISitecoreContext
    {
        T GetDataSource&lt;T&gt;() where T : class;

        T GetRenderingParameters&lt;T&gt;() where T : class;
    }
}

</code></pre>
<pre><code class="language-csharp">
using Glass.Mapper.Sc;
using Sitecore.Mvc.Presentation;
using System;

namespace TIHIDI.Business.GlassSC
{
    public class ControllerSCContext: SitecoreContext, IControllerSCContext
    {
        private IGlassHtml _glassHtml;

        public ControllerSCContext(IGlassHtml glassHtml)
        {
            _glassHtml = glassHtml;
        }

        public T GetRenderingParameters&lt;T&gt;() where T : class
        {
            if (RenderingContext.CurrentOrNull != null)
            {
                string parameters = RenderingContext.CurrentOrNull.Rendering["Parameters"];
                if (String.IsNullOrEmpty(parameters))
                {
                    return _glassHtml.GetRenderingParameters&lt;T&gt;(parameters);
                }
            }
            return default(T);

        }

        public T GetDataSource&lt;T&gt;() where T : class
        {
            string dataSource = RenderingContext.CurrentOrNull.Rendering.DataSource;

            if (String.IsNullOrEmpty(dataSource))
            {
                return default(T);
            }

            Guid dataSourceId;

            return Guid.TryParse(dataSource, out dataSourceId)

                ? GetItem&lt;T&gt;(dataSourceId)

                : GetItem&lt;T&gt;(dataSource);
        }

        /// &lt;summary&gt;
        /// if the rendering context and data source has been set then returns the data source item, otherwise returns the context item.
        /// &lt;/summary&gt;
        /// &lt;typeparam name="T"&gt;&lt;/typeparam&gt;
        /// &lt;param name="isLazy"&gt;&lt;/param&gt;
        /// &lt;param name="inferType"&gt;&lt;/param&gt;
        /// &lt;returns&gt;&lt;/returns&gt;
        public T GetControllerItem&lt;T&gt;(bool isLazy = false, bool inferType = false)
        where T : class
        {
            T renderingItem;
            if (RenderingContext.Current == null || RenderingContext.Current.Rendering == null || string.IsNullOrEmpty(RenderingContext.Current.Rendering.DataSource))
            {
                return GetCurrentItem&lt;T&gt;(false, false);
            }
            try
            {
                renderingItem = this.GetRenderingItem&lt;T&gt;(isLazy, inferType);
            }
            catch (InvalidOperationException invalidOperationException)
            {
                renderingItem = GetCurrentItem&lt;T&gt;(false, false);
            }
            return renderingItem;
        }

        /// &lt;summary&gt;
        /// Returns the data source item.
        /// &lt;/summary&gt;
        /// &lt;typeparam name="T"&gt;&lt;/typeparam&gt;
        /// &lt;param name="isLazy"&gt;&lt;/param&gt;
        /// &lt;param name="inferType"&gt;&lt;/param&gt;
        /// &lt;returns&gt;&lt;/returns&gt;
        public virtual T GetRenderingItem&lt;T&gt;(bool isLazy = false, bool inferType = false)
        where T : class
        {
            if (RenderingContext.Current == null || RenderingContext.Current.Rendering == null || string.IsNullOrEmpty(RenderingContext.Current.Rendering.DataSource))
            {
                return default(T);
            }
            return GetItem&lt;T&gt;(RenderingContext.Current.Rendering.DataSource, isLazy, inferType);
        }
    }
}

</code></pre>
<p>Once that is done, I setup my business logic code.</p>
<pre><code class="language-csharp">
using TIHIDI.Models.Templates.Content;

namespace TIHIDI.Business.Content
{
    public interface IContentLogic
    {
        ITextBlock GetTextBlock();
    }
}

</code></pre>
<pre><code class="language-csharp">
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TIHIDI.Business.GlassSC;
using TIHIDI.Models.Templates.Content;

namespace TIHIDI.Business.Content
{
    public class ContentLogic : IContentLogic
    {
        private readonly IControllerSCContext _currentContext;

        public ContentLogic(IControllerSCContext currentContext)
        {
            _currentContext = currentContext;
        }

        public ITextBlock GetTextBlock()
        {
            return _currentContext.GetDataSource&lt;ITextBlock&gt;();
        }
    }
}

</code></pre>
<p>I know the code is light but this shows you where the logic part of the code is supposed to be. I like my controllers as lean as possible. The next step is to define a controller.</p>
<pre><code class="language-csharp">
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using TIHIDI.Business.Content;

namespace TIHIDI.Web.Controllers
{
    public class ContentController : Controller
    {
        private readonly IContentLogic _contentLogic;

        public ContentController(IContentLogic contentLogic)
        {
            _contentLogic = contentLogic;
        }

        public ActionResult RenderTextBlock()
        {
            return View(_contentLogic.GetTextBlock());
        }
    }
}
</code></pre>
<p>We also need to register our new interfaces with Simple Injector.</p>
<pre><code class="language-csharp">
            container.Register&lt;IControllerSCContext&gt;(()=&gt; new ControllerSCContext(container.GetInstance&lt;IGlassHtml&gt;()));
            container.Register&lt;IContentLogic, ContentLogic&gt;();
</code></pre>
<p>Once that is done, its time to just copy our view rendering code since its going to be exactly the same. Create a new view under Views\Content.</p>
<pre><code class="language-csharp">
@inherits Glass.Mapper.Sc.Web.Mvc.GlassView&lt;TIHIDI.Models.Templates.Content.ITextBlock&gt;
@using Sitecore.Mvc

@if (Model != null)
{
    &lt;h3&gt;@Editable(Model, y =&gt; y.Heading)&lt;/h3&gt;
    &lt;h4&gt;@Editable(Model, y =&gt; y.SubHeading)&lt;/h4&gt;
    &lt;div class="content"&gt;@Editable(Model, y =&gt; y.Content)&lt;/div&gt;
}

</code></pre>
<p>Now that its all wired up, lets build and publish. </p>
<p>Setup a controller rendering in Sitecore to map this new controller.<br />
<a href="http://akshaysura.com/wp-content/uploads/2016/08/cview1.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/08/cview1.png" alt="cview1" width="560" height="216" class="alignnone size-full wp-image-2584" /></a></p>
<p>Modify your item&#8217;s presentation to include this new rendering and fire it up.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/view5.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/06/view5.png" alt="view5" width="323" height="267" class="alignnone size-full wp-image-2579" /></a><br />
<a href="http://akshaysura.com/wp-content/uploads/2016/06/view3.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/06/view3.png" alt="view3" width="525" height="246" class="alignnone size-full wp-image-2578" /></a></p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>TIHIDI: Glass Mapper with Custom Models and Mapping using Fluent Configuration</title>
      <link>https://akshaysura.com/blog/tihidi-glass-mapper-with-custom-models-and-mapping-using-fluent-configuration/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/tihidi-glass-mapper-with-custom-models-and-mapping-using-fluent-configuration/</guid>
      <pubDate>Thu, 28 Jul 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[This blog post will go through how I setup Glass Mapper Models. I hand code models and also keep them close to a .NET Class/Interface. I setup a mapping project which will do the mapping of the custom model with Glass. I believe a cleaner and smaller View Model is the way to go. Some times you might need the entire template but most of the time its pieces of the template you need.]]></description>
      <content:encoded><![CDATA[<p>This blog post will go through how I setup Glass Mapper Models. I hand code models and also keep them close to a .NET Class/Interface. I setup a mapping project which will do the mapping of the custom model with Glass. I believe a cleaner and smaller View Model is the way to go. Some times you might need the entire template but most of the time its pieces of the template you need.</p>
<p>Visit <a href="http://www.glass.lu/mapper/sc" target="_blank">http://www.glass.lu/mapper/sc</a> for more information on Glass Mapper for Sitecore.</p>
<p><strong>TIHIDI: Stands for This Is How I Do It. I am going to write a series of blog posts going through how I do Sitecore related work. Hope it helps you!</strong></p>
<p>For all the fruit cakes who want to jump all over this, calm down. This is just a sample intended to showcase the mapping portion of it. This is not meant as a Sitecore or best practices example, although I am mindful of that.</p>
<p>Before I setup any models I setup an IGlassBase interface I use based on the need.</p>
<pre><code class="language-csharp">using Sitecore.Globalization;
using System;
using System.Collections.Generic;

namespace TIHIDI.Models
{
    public interface IGlassBase
    {
        Guid Id { get; set; }

        Language Language { get; set; }

        int Version { get; set; }

        IEnumerable BaseTemplateIds { get; set; }

        string TemplateName { get; set; }

        Guid TemplateId { get; set; }

        string Name { get; set; }

        string Url { get; set; }
    }
}

</code></pre>
<pre><code class="language-csharp">using Glass.Mapper.Sc.Configuration;
using Glass.Mapper.Sc.Maps;
using TIHIDI.Models;

namespace TIHIDI.Mapping
{
    public class GlassBaseMap : SitecoreGlassMap&lt;IGlassBase&gt;
    {

        public override void Configure()
        {
            Map(x =&gt;
            {
                x.AutoMap();
                x.Info(y =&gt; y.BaseTemplateIds).InfoType(SitecoreInfoType.BaseTemplateIds);
            });
        }
    }
}


</code></pre>
<p>Lets setup a few models and their mappings. For pure auto maps, I dump all auto maps in one file PureAutoMaps.cs.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/07/custommodel2.png"><img loading="lazy" class="alignnone size-large wp-image-2563" src="http://akshaysura.com/wp-content/uploads/2016/07/custommodel2.png" alt="custommodel2" width="900" height="491" /></a></p>
<pre><code class="language-csharp">namespace TIHIDI.Models.Templates.Data
{
    public interface ISampleStatus
    {
        string Status { get; set; }
        string StatusDescription { get; set; }
    }
}
</code></pre>
<pre><code class="language-csharp">        public class SampleStatusMap : SitecoreGlassMap&lt;ISampleStatus&gt;
    {
        ITIHIDISettings settings = TIHIDISettings.Current;

        public override void Configure()
        {
            Map(x =&gt;
            {
                x.TemplateId(settings.SampleStatusTemplateId); //totally optional but you can use it to enforce template id
                x.AutoMap();
            });
        }
    }
</code></pre>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/07/custommodel1.png"><img loading="lazy" class="alignnone size-large wp-image-2564" src="http://akshaysura.com/wp-content/uploads/2016/07/custommodel1-1024x512.png" alt="custommodel1" width="900" height="450" /></a></p>
<pre><code class="language-csharp">namespace TIHIDI.Models.Templates.Data
{
    public interface ICommunityType
    {
        string CommunityType { get; set; }
        string TypeDescription { get; set; }
        bool Inactive { get; set; }
    }
}

</code></pre>
<pre><code class="language-csharp">            public class CommunityTypeMap : SitecoreGlassMap&lt;ICommunityType&gt;
    {
        ITIHIDISettings settings = TIHIDISettings.Current;

        public override void Configure()
        {
            Map(x =&gt;
            {
                x.TemplateId(settings.CommunityTypeTemplateId); //totally optional but you can use it to enforce template id
                x.AutoMap();
            });
        }
    }
</code></pre>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/07/custommodel4-1.png"><img loading="lazy" class="alignnone size-full wp-image-2568" src="http://akshaysura.com/wp-content/uploads/2016/07/custommodel4-1.png" alt="custommodel4" width="885" height="461" /></a></p>
<pre><code class="language-csharp">namespace TIHIDI.Models.Templates.Data
{
    public interface ICommunityChildren
    {
        string DummyContent { get; set; }
    }
}
</code></pre>
<pre><code class="language-csharp">        public class CommunityChildrenMap : SitecoreGlassMap&lt;ICommunityChildren&gt;
    {
        ITIHIDISettings settings = TIHIDISettings.Current;

        public override void Configure()
        {
            Map(x =&gt;
            {
                x.TemplateId(settings.CommunityChildrenTemplateId); //totally optional but you can use it to enforce template id
                x.AutoMap();
            });
        }
    }
</code></pre>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/07/custommodel3.png"><img loading="lazy" class="alignnone size-large wp-image-2562" src="http://akshaysura.com/wp-content/uploads/2016/07/custommodel3-1024x425.png" alt="custommodel3" width="900" height="374" /></a></p>
<pre><code class="language-csharp">using Glass.Mapper.Sc.Fields;
using System.Collections.Generic;

namespace TIHIDI.Models.Templates.Data
{
    public interface ISampleCommunity:IGlassBase
    {
        string CommunityName { get; set; }
        string CommunityDescription { get; set; }
        IEnumerable&lt;ICommunityType&gt; CommunityType { get; set; }
        Link CommunitySite { get; set; }
        ISampleStatus CommunityStatus { get; set; }

        IEnumerable&lt;ICommunityChildren&gt; MyChildren { get; set; }

        IEnumerable&lt;ICommunityChildren&gt; AlsoMyChildren { get; set; }
    }
}
</code></pre>
<pre><code class="language-csharp">using Glass.Mapper.Sc.Maps;
using TIHIDI.Models;
using TIHIDI.Models.Templates.Data;
using TIHIDI.SCExtensions.Settings;

namespace TIHIDI.Mapping.Templates.Data
{
    public class SampleCommunityMap : SitecoreGlassMap&lt;ISampleCommunity&gt;
    {

        public override void Configure()
        {
            ITIHIDISettings settings = TIHIDISettings.Current;

            Map(x =&gt;
            {
                ImportMap&lt;IGlassBase&gt;(); //import existing maps

                //you can specify the file types so that Glass can interpret them correctly
                x.Field(y =&gt; y.CommunityType).FieldType(Glass.Mapper.Sc.Configuration.SitecoreFieldType.Multilist);

                x.Field(y =&gt; y.CommunityStatus).FieldType(Glass.Mapper.Sc.Configuration.SitecoreFieldType.Droplink);

                //as for the children we can do any of the following, each has its own advantages
                //you do not necessarily have to call the attribute children

                x.Query(y =&gt; y.MyChildren)
                    .Query(string.Format("./*[@@templateid='{0}']", settings.CommunityChildrenTemplateId))
                    .IsRelative();

                x.Children(y =&gt; y.AlsoMyChildren);

                x.TemplateId(settings.SampleCommunityTemplateId); //totally optional but you can use it to enforce template id
                x.AutoMap();
            });
        }
    }
}

</code></pre>
<p>&nbsp;</p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>Sitecore PowerShell Extensions History engine - Improved!</title>
      <link>https://akshaysura.com/blog/sitecore-powershell-extensions-history-engine-improved/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/sitecore-powershell-extensions-history-engine-improved/</guid>
      <pubDate>Sat, 23 Jul 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Yesterday I had written a blog post on Sitecore PowerShell Extensions History engine? As it was pointed out in the blog post and by Mike Reynolds & Kamruz Jaman (who refuse to be my friends). We have to improve the code by adding a pipeline. It bothered me enough all night, that I had to get this out of the way. One its a bit difficult as we are dealing with Windows PowerShell at its code. So post script execution, I decided to add a new pipeline which gets executed along with the commands and the errors reported.]]></description>
      <content:encoded><![CDATA[<p>Yesterday I had written a blog post on <a href="http://akshaysura.com/2016/07/22/sitecore-powershell-extensions-history-engine/" target="_blank">Sitecore PowerShell Extensions History engine?</a> As it was pointed out <strong>in the blog post</strong> and by <a href="https://twitter.com/mike_i_reynolds" target="_blank">Mike Reynolds</a> &amp; <a href="https://twitter.com/jammykam" target="_blank">Kamruz Jaman</a> (who refuse to be my friends). We have to improve the code by adding a pipeline. It bothered me enough all night, that I had to get this out of the way. One its a bit difficult as we are dealing with Windows PowerShell at its code. So post script execution, I decided to add a new pipeline which gets executed along with the commands and the errors reported.</p>
<p>Anyone can tap into this pipeline and add additional processors. Again, I hope this gets integrated into SPE some how, or Adam/Mikey will make this better.</p>
<p>Here goes. First lets setup to have a brand new pipeline but defining the PipelineArgs, here is the sample code:</p>
<pre><code class="language-csharp">using Sitecore.Pipelines;
using System;
using System.Collections.Generic;
using System.Management.Automation;
using System.Management.Automation.Runspaces;

namespace SPE.Logging.Pipelines
{
    public class SPECommandProcessedArgs:PipelineArgs
    {
        public CommandCollection Commands { get; set; }
        public IEnumerable LastErrors { get; set; }

        public string UserName { get; set; }
        public DateTime Date { get; set; }
    }
}
</code></pre>
<p>Once that is done, lets define the interface the pipeline processor will be based on, here is the sample code:</p>
<pre><code class="language-csharp">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SPE.Logging.Pipelines
{
    interface ISPECommandProcessor
    {
        void Process(SPECommandProcessedArgs args);
    }
}

</code></pre>
<p>Next, lets define the processor it self. This processor&#8217;s job is to log the commands into the MongoDb connection we made using the previous blog post. Here we are passing in the MongoDB connection string by config.</p>
<p>Here is the sample code:</p>
<pre><code class="language-csharp">using SPE.Logging.Log;
using System.Configuration;

namespace SPE.Logging.Pipelines
{
    public class SPECommandProcessor:ISPECommandProcessor
    {
        public string MongoConnectionString { get; set; }
        public void Process(SPECommandProcessedArgs args)
        {
            CommandHistoryRepository commandHistoryRepository = new CommandHistoryRepository(ConfigurationManager.ConnectionStrings[MongoConnectionString].ConnectionString);

            foreach (var cmd in args.Commands)
            {
                var logCommand = new SPECommand
                {
                    UserName = args.UserName,
                    Command = cmd.CommandText,
                    Date = args.Date
                };
                commandHistoryRepository.Set(logCommand);
            }
        }
    }
}
</code></pre>
<p>Finally in the Cognifide.PowerShell.Core.Host.ScriptSession class, we will tap directly into the ExecuteCommand method. We are going to add some code right after the command is executed around line 740. We are going to load the Args with the commands and the errors if we see the HadErrors is set true. One thing to notice is, that depending on the command, we might see more than 1 in the commands collection. Here is the sample code:</p>
<pre><code class="language-csharp">LastErrors?.Clear();
// execute the commands in the pipeline now
var execResults = powerShell.Invoke();

if (powerShell.HadErrors)
{
    LastErrors = powerShell.Streams.Error.ToList();
}

if (execResults != null &amp;&amp; execResults.Any())
{
    foreach (var record in execResults.Where(r =&gt; r != null).Select(p =&gt; p.BaseObject).OfType())
    {
        LogUtils.Debug(record + record.InvocationInfo.PositionMessage, this);
    }
}

// START execute Sitecore pipeline speCommandProcessed
SPECommandProcessedArgs pipelineArgs = new SPECommandProcessedArgs();
pipelineArgs.Commands = powerShell.Commands.Commands;
pipelineArgs.LastErrors = LastErrors;
pipelineArgs.Date = DateTime.Now;
pipelineArgs.UserName = Sitecore.Context.GetUserName();

CorePipeline.Run("speCommandProcessed", pipelineArgs);
//END
</code></pre>
<p>Once that is all set, we are ready to create the new config to load the pipeline and the processor. Here is the sample config:</p>
<pre><code class="language-xml"> 
&lt;configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"&gt;
  &lt;sitecore&gt;
    &lt;pipelines&gt;
      &lt;speCommandProcessed&gt;
        &lt;processor type="SPE.Logging.Pipelines.SPECommandProcessor, SPE.Logging"&gt;
          &lt;MongoConnectionString&gt;specommandhistory&lt;/MongoConnectionString&gt;
        &lt;/processor&gt;
      &lt;/speCommandProcessed&gt;
    &lt;/pipelines&gt;
  &lt;/sitecore&gt;
&lt;/configuration&gt;
</code></pre>
<p>Rebuild and run a few commands as two different users. As you can see from the screenshot, it records them in Mongo.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/07/spe21.png"><img loading="lazy" class="alignnone size-full wp-image-2555" src="http://akshaysura.com/wp-content/uploads/2016/07/spe21.png" alt="spe21" width="978" height="658" /></a></p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>Sitecore PowerShell Extensions History engine?</title>
      <link>https://akshaysura.com/blog/sitecore-powershell-extensions-history-engine/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/sitecore-powershell-extensions-history-engine/</guid>
      <pubDate>Fri, 22 Jul 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[As many of your know Sitecore PowerShell Extensions is a valuable tool in the Sitecore ecosystem. I cannot recall how many times SPE has saved me from repeated and tedious tasks.]]></description>
      <content:encoded><![CDATA[<p>As many of your know Sitecore PowerShell Extensions is a valuable tool in the Sitecore ecosystem. I cannot recall how many times SPE has saved me from repeated and tedious tasks.</p>
<p>For the longest time I wanted to store the command history for audit purposes. Finally I got some time to get into some code hacking to get this done.</p>
<p>One, you have to realize that SPE relies on Microsoft PowerShell and so we cannot mold it as we want. Ideally it would be great if we could develop a SPE Command pipeline.</p>
<p>So we start off by setting up MongoDB. Part of this blog post depends on work in <a href="http://akshaysura.com/2015/02/24/use-mongodb-to-store-sitecore-log-entries-centrally/" target="_blank">Use MongoDB to store Sitecore log entries centrally!</a></p>
<p>Lets start by adding a connection string to a new MongoDB collection:</p>
<pre><code class="language-html">&lt;add name="specommandhistory" connectionString="mongodb://localhost:27017/SPE" /&gt;</code></pre>
<p>Setup a class called SPECommand to hold the structure of the record. Here is the sample code:</p>
<pre><code class="language-csharp">using MongoDB.Bson;
using System;

namespace SPE.Logging.Log
{
    public class SPECommand
    {
        public ObjectId Id { get; set; }
        public string UserName { get; set; }
        public string Command { get; set; }
        public DateTime Date { get; set; }
    }
}
</code></pre>
<p>Create a repository to interact with MongoDB, here is the sample code:</p>
<pre><code class="language-csharp">using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Builders;
using MongoDB.Driver.Linq;
using Sitecore.Diagnostics;
using System;
using System.Collections.Generic;
using System.Linq;

namespace SPE.Logging.Log
{
    public class CommandHistoryRepository
    {
        internal const string CollectionName = "specommandhistory";
        private readonly MongoCollection _commandHistoryCollection;

        public CommandHistoryRepository(string connectionString)
        {
            _commandHistoryCollection = GetCollection(connectionString, CollectionName);
            Assert.IsNotNull(_commandHistoryCollection, "commandHistoryCollection");
        }

        public IEnumerable GetAll()
        {
            return _commandHistoryCollection.FindAllAs();
        }

        public SPECommand Get(ObjectId id)
        {
            return _commandHistoryCollection.FindOneAs(GetIDQuery(id));
        }

        public bool Set(SPECommand SPECommand)
        {
            return _commandHistoryCollection.Insert(SPECommand).Ok;
        }

        public IEnumerable GetByDateRange(DateTime startDate, int numberOfDays)
        {
            return _commandHistoryCollection.AsQueryable().Where(c => c.Date &gt;= startDate &amp;&amp; c.Date &lt; startDate.AddDays(numberOfDays)).ToArray();
        }

        protected IMongoQuery GetIDQuery(ObjectId id)
        {
            return Query.EQ(c => c.Id, id);
        }

        private static MongoCollection GetCollection(string connectionString, string collectionName)
        {
            var url = new MongoUrl(connectionString);
            return new MongoClient(url).GetServer().GetDatabase(url.DatabaseName).GetCollection(collectionName);
        }
    }
}

</code></pre>
<p>Now that we have everything setup to write to Mongo, lets get into the depths of the SPE code to find the place where we can log the commands being executed.</p>
<p>In the Cognifide.PowerShell project go into Core &gt; Host &gt; ScriptSession.cs file. In the ExecuteScriptPart function on like 599, you can add the following to log the command being executed. Here is the sample code:</p>
<pre><code class="language-csharp">            LogUtils.Info("Executing a Sitecore PowerShell Extensions script." + script, this);

            CommandHistoryRepository commandHistoryRepository = new CommandHistoryRepository(ConfigurationManager.ConnectionStrings["specommandhistory"].ConnectionString);
            var logCommand = new SPECommand
            {
                UserName = Sitecore.Context.GetUserName(),
                Command = script,
                Date = DateTime.Now
            };
            commandHistoryRepository.Set(logCommand);
</code></pre>
<p>Also in the Measure method we could add additional logging on who executed the command for the log entry.</p>
<pre><code class="language-csharp">            //We need to modify the Measure method
            return SpeTimer.Measure("script execution", () =>
            {
                try
                {
                    using (powerShell = NewPowerShell())
                    {
                        powerShell.Commands.AddScript(script);
                        return ExecuteCommand(stringOutput, marshalResults);
                    }
                }
                finally
                {
                    powerShell = null;
                }
            });
</code></pre>
<p>Add in &#8212; {Sitecore.Context.GetUserName()} to the LogUtile.Info so that we record the user who executed that command.</p>
<pre><code class="language-csharp">    public static class SpeTimer
    {
        public static T Measure(string message, Func action) where T : class
        {
            try
            {
                var stopWatch = new Stopwatch();
                stopWatch.Start();

                var result = action();

                stopWatch.Stop();
                
                LogUtils.Info($"The {message} completed in {stopWatch.ElapsedMilliseconds} ms. -- {Sitecore.Context.GetUserName()}", typeof(SpeTimer));
                return result;
            }
            catch (Exception ex)
            {
                LogUtils.Error(ex.Message, typeof(SpeTimer));
                throw;
            }
        }
</code></pre>
<p>This might not be the best way to add the History Engine to SPE but its a start. We could also have additional features like success of the command, script status monitor and a report pulling all of this Mongo information.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/07/spe3.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/07/spe3.png" alt="spe3" width="644" height="56" class="alignnone size-full wp-image-2549" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/07/spe2.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/07/spe2.png" alt="spe2" width="621" height="34" class="alignnone size-large wp-image-2550" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/07/spe1.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/07/spe1.png" alt="spe1" width="660" height="302" class="alignnone size-large wp-image-2551" /></a></p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>TIHIDI: Install and Configure Glass Mapper 4.x for Sitecore 8.x MVC Solution with Simple Injector 3.x</title>
      <link>https://akshaysura.com/blog/tihidi-install-and-configure-glass-mapper-4-x-for-sitecore-8-x-mvc-solution-with-simple-injector-3-x/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/tihidi-install-and-configure-glass-mapper-4-x-for-sitecore-8-x-mvc-solution-with-simple-injector-3-x/</guid>
      <pubDate>Thu, 21 Jul 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[This blog post will go through how I setup Glass Mapper in a Visual Studio 2015 MVC solution for Sitecore 8.1. I have used other Sitecore ORM solutions but finally ended up liking Glass. Mike Edwards and Nathanael Mann were patient enough to teach me Glass in a short amount of time and the Glass training helped a lot as well.]]></description>
      <content:encoded><![CDATA[<p>This blog post will go through how I setup Glass Mapper in a Visual Studio 2015 MVC solution for Sitecore 8.1. I have used other Sitecore ORM solutions but finally ended up liking Glass. <a href="https://twitter.com/mikeedwards83" target="_blank">Mike Edwards</a> and <a href="https://twitter.com/cardinal252" target="_blank">Nathanael Mann</a> were patient enough to teach me Glass in a short amount of time and the Glass training helped a lot as well.</p>
<p>Visit <a href="http://www.glass.lu/mapper/sc" target="_blank">http://www.glass.lu/mapper/sc</a> for more information on Glass Mapper for Sitecore.</p>
<p><strong>TIHIDI: Stands for This Is How I Do It. I am going to write a series of blog posts going through how I do Sitecore related work. Hope it helps you!</strong></p>
<p>As usual we will be using NuGet to get the current stable version of Glass, which at this moment is 4.1.2.67.</p>
<p>Before we run the install package for Glass, make sure you have Sitecore.Kernel.dll, Sitecore.Mvc.dll and System.Web.Mvc.dll referenced in your project, which I do since I have been using the same solution for my blog posts.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/glass1.png"><img loading="lazy" class="alignnone size-large wp-image-2526" src="http://akshaysura.com/wp-content/uploads/2016/06/glass1-1024x472.png" alt="glass1" width="900" height="415" /></a></p>
<p>Once Glass is installed, create two class library solutions, one called Mapping and one called Models.</p>
<p>I create hand coded (yes hand coded you lazy farts!) Models which are true .NET classes or interfaces. These will use .NET types along with Glass field types.</p>
<p>I do the mapping separately in the Mapping project. If the Model can auto map we can add it to the auto maps. If not, we create a specific mapping class for that Model to tackle the mapping.</p>
<p>Install Glass on these two projects as well.</p>
<p>In the SimpleInjector.cs class we will be registering all business logic functionality along with Glass mapping classes. Here is the sample code for SimpleInjector.cs:</p>
<pre><code class="language-csharp">using SimpleInjector.Packaging;
using System;
using SimpleInjector;
using Glass.Mapper.Sc;
using System.Reflection;
using System.Collections.Generic;
using Glass.Mapper.Maps;
using System.Linq;
using TIHIDI.SCExtensions.DI;
using TIHIDI.Business.GlassSC;
using TIHIDI.Business.Content;

namespace TIHIDI.Web.App_Start
{
    public class SimpleInjector:IPackage
    {
        public void RegisterServices(Container container)
        {
            container.Register(() => new SitecoreContext());
            container.Register(() => new GlassHtml(container.GetInstance()));
            container.Register(()=> new ControllerSCContext(container.GetInstance()));

            //register all Glass mapping classes
            string assemblyName = ".Mapping";

            IEnumerable assemblies = AppDomain.CurrentDomain.GetAssemblies().Where(x => x.FullName.IndexOf(assemblyName, StringComparison.OrdinalIgnoreCase) >= 0);
            Type glassmapType = typeof(IGlassMap);

            List maps = new List();
            foreach (Assembly assembly in assemblies)
            {
                if (maps.Count == 0)
                    maps = assembly.GetTypes().Where(x => glassmapType.IsAssignableFrom(x)).ToList();
                else
                    maps.AddRange(assembly.GetTypes().Where(x => glassmapType.IsAssignableFrom(x)).ToList());
            }
            container.RegisterCollection(maps);
        }
    }
}
</code></pre>
<p>Following this, lets get to the GlassMapperSCCustom.cs file in order to add our maps so that Glass can handle them. Here is the sample code for GlassMapperSCCustom.cs:</p>
<pre><code class="language-csharp">
	public static void AddMaps(IConfigFactory&lt;IGlassMap&gt; mapsConfigFactory)
        {
            // Add maps here
            // mapsConfigFactory.Add(() =&gt; new SeoMap());
            ContainerManager containerManager = new ContainerManager();
            
            foreach (var map in containerManager.Container.GetAllInstances&lt;IGlassMap&gt;())
            {
                mapsConfigFactory.Add(() =&gt; map);
            }
        }
</code></pre>
<p>Once this is done we have to go and modify our App_Config &gt; Include &gt; SimpleInjector &gt; SimpleInjector.config file to load the Initialize of the Simple Injector <strong>before</strong> Glass.  Here is the updated config file:</p>
<pre><code class="language-csharp">
&lt;configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"
               xmlns:set="http://www.sitecore.net/xmlconfig/set/"&gt;
  &lt;sitecore&gt;
    &lt;pipelines&gt;
      &lt;initialize&gt;
        &lt;processor type="Sitecore.Mvc.Pipelines.Loader.InitializeControllerFactory, Sitecore.Mvc"
                   set:type="TIHIDI.SCExtensions.DI.Pipelines.InitializeSimpleInjectorControllerFactory, TIHIDI.SCExtensions"  patch:before="*[@type='TIHIDI.Web.App_Start.GlassMapperSc, TIHIDI.Web']" /&gt;
      &lt;/initialize&gt;
    &lt;/pipelines&gt;
  &lt;/sitecore&gt;
&lt;/configuration&gt;
</code></pre>
<p>Now lets add a simple TextBlock template in Sitecore for demo purposes, here is the sample template:</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/glass5.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/06/glass5-1024x430.png" alt="glass5" width="900" height="378" class="alignnone size-large wp-image-2539" /></a></p>
<p>In the Models project add IGlassBase, here is the sample code for the interface:</p>
<pre><code class="language-csharp">
using Sitecore.Globalization;
using System;
using System.Collections.Generic;

namespace TIHIDI.Models
{
    public interface IGlassBase
    {
        Guid Id { get; set; }

        Language Language { get; set; }

        int Version { get; set; }

        IEnumerable&lt;Guid&gt; BaseTemplateIds { get; set; }

        string TemplateName { get; set; }

        Guid TemplateId { get; set; }

        string Name { get; set; }

        string Url { get; set; }
    }
}

</code></pre>
<p>Lets also add an interface to represent our template called ITextBlock. Here is the sample code for the interface:</p>
<pre><code class="language-csharp">
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TIHIDI.Models.Templates.Content
{
    public interface ITextBlock : IGlassBase
    {
        string Heading { get; set; }
        string SubHeading { get; set; }
        string Content { get; set; }
    }
}

</code></pre>
<p>Next we need a way to inform Glass as to how it needs to map these interfaces. We will begin my adding a GlassBaseMap class, here is the sample code:</p>
<pre><code class="language-csharp">
using Glass.Mapper.Sc.Configuration;
using Glass.Mapper.Sc.Maps;
using TIHIDI.Models;

namespace TIHIDI.Mapping
{
    public class GlassBaseMap : SitecoreGlassMap&lt;IGlassBase&gt;
    {

        public override void Configure()
        {
            Map(x =&gt;
            {
                x.AutoMap();
                x.Info(y =&gt; y.BaseTemplateIds).InfoType(SitecoreInfoType.BaseTemplateIds);
            });
        }
    }
}
</code></pre>
<p>For all simple mappings I dump them into a class called PureAutoMaps, so lets create a class and add that mapping. Here is the sample code:</p>
<pre><code class="language-csharp">
using Glass.Mapper.Sc.Maps;
using TIHIDI.Models;
using TIHIDI.Models.Templates.Content;

namespace TIHIDI.Mapping
{
    public class PureAutoMaps
    {
    }

    public class TextBlockMap : SitecoreGlassMap&lt;ITextBlock&gt;
    {

        public override void Configure()
        {
            Map(x =&gt;
            {
                ImportMap&lt;IGlassBase&gt;();
                x.AutoMap();
            });
        }
    }
}

</code></pre>
<p>There is no reason to inherit the IGlassBase except that it provides some additional attributes. You would need the Id attribute in order for you to make this editable in the Experience editor. Again this is just an example, we can highly simplify this as well.</p>
<p>Notice the way you are able to use ImportMap and pull in inherited classes/interfaces. Also notice how we used Automap and .Info in order to specify what Glass needs to do with the BaseTemplateIds. We will get into this in a lot more detail later.</p>
<p>Rebuild and deploy. Sites come up fine. Let check the ShowConfig.aspx.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/glass4.png"><img loading="lazy" class="alignnone size-large wp-image-2532" src="http://akshaysura.com/wp-content/uploads/2016/06/glass4-1024x64.png" alt="glass4" width="900" height="56" /></a></p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>TIHIDI: Install and configure Simple Injector DI for a Sitecore 8.x Solution</title>
      <link>https://akshaysura.com/blog/tihidi-install-and-configure-simple-injector-di-for-a-sitecore-8-x-solution/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/tihidi-install-and-configure-simple-injector-di-for-a-sitecore-8-x-solution/</guid>
      <pubDate>Tue, 19 Jul 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[This blog post will show you how I setup Simple Injector Dependency Injection in Visual Studio 2015 MVC solution for Sitecore 8.1. I use Simple Injector a lot and is my favorite. I have never had performance issues with it. Hope you enjoy it too.]]></description>
      <content:encoded><![CDATA[<p>This blog post will show you how I setup Simple Injector Dependency Injection in Visual Studio 2015 MVC solution for Sitecore 8.1.  I use Simple Injector a lot and is my favorite. I have never had performance issues with it. Hope you enjoy it too.</p>
<p>You can get more information about <a href="https://simpleinjector.org/" target="_blank">Simple Injector here</a>.</p>
<p><strong>TIHIDI: Stands for This Is How I Do It. I am going to write a series of blog posts going through how I do Sitecore related work. Hope it helps you!</strong></p>
<p>One of the best ways to install any packages in Visual Studio is to use NuGet Package Manager Console available under the Tools &gt; NuGet Package Manager option. There is a UI available but using the console is the best way for me.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/07/simple1.png"><img loading="lazy" class="alignnone size-large wp-image-2517" src="http://akshaysura.com/wp-content/uploads/2016/07/simple1-1024x668.png" alt="simple1" width="900" height="587" /></a></p>
<p>If you are unsure of the command to use, visit <a href="http://www.nuget.org/" target="_blank">www.nuget.org</a> and search for Simple Injector.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/07/simple2.png"><img loading="lazy" class="alignnone size-large wp-image-2516" src="http://akshaysura.com/wp-content/uploads/2016/07/simple2-1024x718.png" alt="simple2" width="900" height="631" /></a></p>
<p>Click on the search result and it will show you information on the package.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/07/simple3.png"><img loading="lazy" class="alignnone size-large wp-image-2515" src="http://akshaysura.com/wp-content/uploads/2016/07/simple3-1024x717.png" alt="simple3" width="900" height="630" /></a></p>
<p>Copy the command, paste it in your Visual Studio Package Manage Console window and hit the Enter key.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/07/simple5.png"><img loading="lazy" class="alignnone size-full wp-image-2513" src="http://akshaysura.com/wp-content/uploads/2016/07/simple5.png" alt="simple5" width="915" height="479" /></a></p>
<p>Now that we have Simple Injector installed, we need to plug it into Sitecore.</p>
<p>In order to help us with Simple Injector you would also need to install SimpleInjector.Integration.Mvc and SimpleInjector.Packing from NuGet.</p>
<p>We will first define the Controller Factory. To do this, we will create a new project in our solution called SCExtensions to house all the Sitecore customizations.</p>
<p>Add a new Class project to your solution and name it TIHIDI.SCExtensions.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/07/simple13.png"><img loading="lazy" class="alignnone size-full wp-image-2535" src="http://akshaysura.com/wp-content/uploads/2016/07/simple13.png" alt="simple13" width="333" height="609" /></a></p>
<p>Create the appropriate folder structure and add a class called SimpleInjectorControllerFactory.</p>
<p>Install Simple Injector using NuGet in this project.</p>
<p>Copy the System.Web.MVC from your website bin folder and dump it in to the Dependencies\Sitecore folder.</p>
<p>Reference the above System.Web.MVC as well as System.Web and System.Routing in the TIHIDI.SCExtensions project.</p>
<p>Also add in Sitecore.Kernel and Sitecore.Mvc references in the SCExtensions project.</p>
<p>Here is the code for the SimpleInjectorControllerFactory class.</p>
<pre><code class="language-csharp">using SimpleInjector;
using System;
using System.Web.Mvc;
using System.Web.Routing;

namespace TIHIDI.SCExtensions.DI
{
    public class SimpleInjectorControllerFactory : DefaultControllerFactory
    {
        private Container _container;

        public SimpleInjectorControllerFactory(Container container)
        {
            _container = container;
        }

        protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        {
            return (IController)_container.GetInstance(controllerType);
        }
    }
}
</code></pre>
<p>Now we need to initialize this. There are several ways to initialize Simple Injector, you could use Global.asax or WeActivator but staying true to Sitecore, the best way to do it is to use the Initialize pipeline.</p>
<p>I also want to have access to the ContainerManager for future registration especially when I add Glass models.</p>
<p>Create a new class in the SCExtensions project called ContainerManager. Here is the code for the class.</p>
<pre><code class="language-csharp">using SimpleInjector;

namespace TIHIDI.SCExtensions.DI
{
    public class ContainerManager
    {
        private static readonly Container container = new Container();

        public Container Container
        {
            get
            {
                return container;
            }
        }
    }
}

</code></pre>
<p>We also want to be able to do Property Injection, create a new class ImportAttributePropertySelectionBehavior in the SCExtensions project. Here is the code for this class.</p>
<pre><code class="language-csharp">using SimpleInjector.Advanced;
using System;
using System.ComponentModel.Composition;
using System.Linq;
using System.Reflection;

namespace TIHIDI.SCExtensions.DI
{
    public class ImportAttributePropertySelectionBehavior : IPropertySelectionBehavior
    {
        public bool SelectProperty(Type serviceType, PropertyInfo propertyInfo)
        {
            return propertyInfo.GetCustomAttributes(typeof(ImportAttribute), true).Any();
        }
    }
}

</code></pre>
<p>Create a new class in the SCExtensions project called InitializeSimpleInjectorControllerFactory. Here is the code to do the initialization:</p>
<pre><code class="language-csharp">using SimpleInjector;
using Sitecore.Pipelines;
using System;
using System.Linq;
using System.Web.Mvc;
using SimpleInjector.Integration.Web.Mvc;
using SimpleInjector.Integration.Web;

namespace TIHIDI.SCExtensions.DI.Pipelines
{
    public class InitializeSimpleInjectorControllerFactory
    {
        public virtual void Process(PipelineArgs args)
        {
            SetControllerFactory(args);
        }

        private void SetControllerFactory(PipelineArgs args)
        {
            ContainerManager containerM = new ContainerManager();
            SetContainerOptions(containerM.Container);

            // you can customize this to what ever you need. This registers all IPackage implementations
            PackageExtensions.RegisterPackages(containerM.Container, AppDomain.CurrentDomain.GetAssemblies().Where(a =&gt; a.FullName.StartsWith("TIHIDI.")));

            DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(containerM.Container));
        }

        private void SetContainerOptions(Container container)
        {
            container.Options.PropertySelectionBehavior = new ImportAttributePropertySelectionBehavior();
            container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
            container.RegisterMvcIntegratedFilterProvider();
            //container.Options.AllowOverridingRegistrations = true; //we do not want overriding registrations but if you do this is the property you set
        }
    }
}

</code></pre>
<p>Since we have the code in place to pick up IPackage implementations, lets create a class called SimpleInjector.cs in the App_Start folder to add our registrations. Here is he sample code:</p>
<pre><code class="language-csharp">using SimpleInjector.Packaging;
using System;
using SimpleInjector;
using Glass.Mapper.Sc;
using System.Reflection;
using System.Collections.Generic;
using Glass.Mapper.Maps;
using System.Linq;
using TIHIDI.SCExtensions.DI;
using TIHIDI.Business.GlassSC;
using TIHIDI.Business.Content;

namespace TIHIDI.Web.App_Start
{
    public class SimpleInjector:IPackage
    {
        public void RegisterServices(Container container)
        {
            container.Register(() => new SitecoreContext());
        }
    }
}
</code></pre>
<p>Now that we have all the plumbing necessary, we need to register this pipeline processor using a custom config in the App_Config &gt; Include folder.</p>
<pre><code class="language-xml">  
&lt;configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"
               xmlns:set="http://www.sitecore.net/xmlconfig/set/"&gt;
  &lt;sitecore&gt;
    &lt;pipelines&gt;
      &lt;initialize&gt;
        &lt;processor type="Sitecore.Mvc.Pipelines.Loader.InitializeControllerFactory, Sitecore.Mvc"
                   set:type="TIHIDI.SCExtensions.DI.Pipelines.InitializeSimpleInjectorControllerFactory, TIHIDI.SCExtensions" /&gt;
      &lt;/initialize&gt;
    &lt;/pipelines&gt;
  &lt;/sitecore&gt;
&lt;/configuration&gt;
</code></pre>
<p>Now let&#8217;s build and deploy this solution. The site loads and we can see our config patch in the showconfig.aspx</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/07/simple7.png"><img loading="lazy" class="alignnone size-large wp-image-2523" src="http://akshaysura.com/wp-content/uploads/2016/07/simple7-1024x520.png" alt="simple7" width="900" height="457" /></a></p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
<p><strong>UPDATE (7/21/2016): </strong>Following <a href="https://twitter.com/sitecorey" target="_blank">Corey Smith</a>&#8216;s comment, I went ahead and implemented the code I usually do. To my surprise it did not work, when I looked into it, I realized that all this while I have been working with Simple Injector versions lower than 3.0. As of Simple Injector 3.0 and above there have been a few API changes which I needed to make. I went ahead and make all appropriate changes for Simple Injector version 3.2. I also looked into my initialization code and realized that it was legacy code from when I started using Ninject a while back. Thanks Corey.</p>
]]></content:encoded>
    </item>
    <item>
      <title>TIHIDI: Install Sitecore 8.x</title>
      <link>https://akshaysura.com/blog/tihidi-install-sitecore-8-x/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/tihidi-install-sitecore-8-x/</guid>
      <pubDate>Wed, 29 Jun 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Installing Sitecore is very easy. Some of the developers prefer using the installer, some manually install it using the web root zip and some use Sitecore Instance Manger (SIM). Sitecore Instance Manger (SIM) is a great choice if you are spinning up multiple Sitecore instances on your local.]]></description>
      <content:encoded><![CDATA[<p>Installing Sitecore is very easy. Some of the developers prefer using the installer, some manually install it using the web root zip and some use Sitecore Instance Manger (SIM). Sitecore Instance Manger (SIM) is a great choice if you are spinning up multiple Sitecore instances on your local.</p>
<p><strong>TIHIDI: Stands for This Is How I Do It. I am going to write a series of blog posts going through how I do Sitecore related work. Hope it helps you!</strong></p>
<p>With a fresh install of SIM, we do not have the Sitecore root zip from dev.sitecore.net. We can either download it and place it in the SIM folder or we can do it from SIM itself.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/install1.png"><img loading="lazy" class="alignnone size-full wp-image-2451" src="http://akshaysura.com/wp-content/uploads/2016/06/install1.png" alt="install1" width="342" height="481" /></a></p>
<p>When you click on &#8220;Install Instance&#8221; without having any Sitecore install zips, you will get an error message prompting you to download.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/install2.png"><img loading="lazy" class="alignnone size-full wp-image-2452" src="http://akshaysura.com/wp-content/uploads/2016/06/install2.png" alt="install2" width="476" height="493" /></a></p>
<p>If you ever need to download Sitecore installs, go to &#8220;Bundled Tools&#8221; dropdown menu and select one of the download options. In my case I want to download Sitecore 8.1 Update 3, so I selected &#8220;Download Sitecore 8.x&#8221; option.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/install3.png"><img loading="lazy" class="alignnone size-full wp-image-2453" src="http://akshaysura.com/wp-content/uploads/2016/06/install3.png" alt="install3" width="445" height="494" /></a></p>
<p>Run through the following screens until you get to the Download screen.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/install4.png"><img loading="lazy" class="alignnone size-full wp-image-2454" src="http://akshaysura.com/wp-content/uploads/2016/06/install4.png" alt="install4" width="493" height="486" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/install5.png"><img loading="lazy" class="alignnone size-full wp-image-2455" src="http://akshaysura.com/wp-content/uploads/2016/06/install5.png" alt="install5" width="491" height="492" /></a></p>
<p>Here you can select the versions of Sitecore you would like to download. I am going to select the first option and click Next.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/install7.png"><img loading="lazy" class="alignnone size-full wp-image-2457" src="http://akshaysura.com/wp-content/uploads/2016/06/install7.png" alt="install7" width="501" height="490" /></a></p>
<p>Next provide your Dev.Sitecore.net credentials and click Next. PLEASE NOTE: You need to be a certified Sitecore Developer to download the installs. As the prompt says in UPPER CASE and <span style="color: red;">RED</span> SIM will not store your password elsewhere.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/install8.png"><img loading="lazy" class="alignnone size-full wp-image-2458" src="http://akshaysura.com/wp-content/uploads/2016/06/install8.png" alt="install8" width="493" height="488" /></a></p>
<p>SIM starts downloading the install and you get a confirmation screen. Click the Finish button.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/install12.png"><img loading="lazy" class="alignnone size-full wp-image-2459" src="http://akshaysura.com/wp-content/uploads/2016/06/install12.png" alt="install12" width="509" height="492" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/install13.png"><img loading="lazy" class="alignnone size-full wp-image-2460" src="http://akshaysura.com/wp-content/uploads/2016/06/install13.png" alt="install13" width="491" height="485" /></a></p>
<p>SIM has just downloaded the Sitecore website root zip to your SIM Folder.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/install15.png"><img loading="lazy" class="alignnone size-full wp-image-2462" src="http://akshaysura.com/wp-content/uploads/2016/06/install15.png" alt="install15" width="675" height="356" /></a></p>
<p>&nbsp;</p>
<p>Next click on the Install Instance button on the SIM screen to launch the installer. Set the proper options and click Next.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/install14.png"><img loading="lazy" class="alignnone size-full wp-image-2461" src="http://akshaysura.com/wp-content/uploads/2016/06/install14.png" alt="install14" width="491" height="512" /></a></p>
<p>In the Installing new instance screen, I usually uncheck all the options to get the purest Sitecore install.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/install16.png"><img loading="lazy" class="alignnone size-full wp-image-2463" src="http://akshaysura.com/wp-content/uploads/2016/06/install16.png" alt="install16" width="500" height="518" /></a></p>
<p>Currently we did not add any modules so we are going to click Next.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/install17.png"><img loading="lazy" class="alignnone size-full wp-image-2464" src="http://akshaysura.com/wp-content/uploads/2016/06/install17.png" alt="install17" width="493" height="489" /></a></p>
<p>We do not need any custom packages at this moment so we are going to click Next.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/install18.png"><img loading="lazy" class="alignnone size-full wp-image-2465" src="http://akshaysura.com/wp-content/uploads/2016/06/install18.png" alt="install18" width="490" height="487" /></a></p>
<p>On the install preview screen click the Install button.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/install20.png"><img loading="lazy" class="alignnone size-full wp-image-2467" src="http://akshaysura.com/wp-content/uploads/2016/06/install20.png" alt="install20" width="504" height="487" /></a></p>
<p>After a few moments SIM will install your instance with the options selected.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/install21.png"><img loading="lazy" class="alignnone size-full wp-image-2468" src="http://akshaysura.com/wp-content/uploads/2016/06/install21.png" alt="install21" width="494" height="489" /></a></p>
<p>On the confirmation screen, I usually select the &#8220;Open in Browser&#8221; and &#8220;Open in Browser (Sitecore Client; Log in as Admin)&#8221; options to validate the install. Click the Finish button.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/install22.png"><img loading="lazy" class="alignnone size-full wp-image-2469" src="http://akshaysura.com/wp-content/uploads/2016/06/install22.png" alt="install22" width="496" height="487" /></a></p>
<p>Done!</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/install23.png"><img loading="lazy" class="alignnone size-large wp-image-2470" src="http://akshaysura.com/wp-content/uploads/2016/06/install23-1024x720.png" alt="install23" width="900" height="633" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/install24.png"><img loading="lazy" class="alignnone size-full wp-image-2471" src="http://akshaysura.com/wp-content/uploads/2016/06/install24.png" alt="install24" width="760" height="233" /></a></p>
<p>Here is your new Sitecore instance.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/install25.png"><img loading="lazy" class="alignnone size-large wp-image-2472" src="http://akshaysura.com/wp-content/uploads/2016/06/install25-1024x719.png" alt="install25" width="900" height="632" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/install26.png"><img loading="lazy" class="alignnone size-large wp-image-2473" src="http://akshaysura.com/wp-content/uploads/2016/06/install26-1024x717.png" alt="install26" width="900" height="630" /></a></p>
<p>SIM saves a lot of time creating new Sitecore instances.</p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
    </item>
    <item>
      <title>TIHIDI: Setup a Visual Studio 2015 Sitecore 8.x MVC Solution</title>
      <link>https://akshaysura.com/blog/tihidi-setup-a-visual-studio-2015-sitecore-8-x-mvc-solution/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/tihidi-setup-a-visual-studio-2015-sitecore-8-x-mvc-solution/</guid>
      <pubDate>Wed, 29 Jun 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[This blog post will show you how I setup a Visual Studio 2015 MVC solution for Sitecore 8.1. I work outside of the web root, some work right in the web root. It truly depends on the tools you use, team size, location and your preferences.]]></description>
      <content:encoded><![CDATA[<p>This blog post will show you how I setup a Visual Studio 2015 MVC solution for Sitecore 8.1. I work outside of the web root, some work right in the web root. It truly depends on the tools you use, team size, location and your preferences.</p>
<p><strong>TIHIDI: Stands for This Is How I Do It. I am going to write a series of blog posts going through how I do Sitecore related work. Hope it helps you!</strong></p>
<p>1. Setup a site on your local. Refer to:</p>
<ol>
<li><a href="http://akshaysura.com/2016/06/29/tihidi-install-sitecore-8-x/" target="_blank">Install Sitecore 8.x</a></li>
<li><a href="http://akshaysura.com/2016/06/14/tihidi-install-mongodb-3-2-7-for-sitecore-8-x-in-one-step/" target="_blank">Install MongoDB 3.2.7 for Sitecore 8.x in one step!</a></li>
<li><a href="http://akshaysura.com/2016/06/10/tihidi-install-sitecore-instance-manager-sim/" target="_blank">Install Sitecore Instance Manager (SIM)</a></li>
</ol>
<p>2. Setup the folder where your solution is going to live. I setup the folder structure similar to what is shown below:</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/solution1.png"><img loading="lazy" class="alignnone size-full wp-image-2478" src="http://akshaysura.com/wp-content/uploads/2016/06/solution1.png" alt="solution1" width="137" height="117" /></a></p>
<p>You ultimately want to have several folders under Dependencies based on the different applications/modules or third party integrations you might have.</p>
<p>3. Copy the Sitecore.Kernel.dll and Sitecore.Mvc.dll from the website\bin folder in to the Dependencies\Sitecore folder.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/solution2.png"><img loading="lazy" class="alignnone size-large wp-image-2479" src="http://akshaysura.com/wp-content/uploads/2016/06/solution2-1024x423.png" alt="solution2" width="900" height="372" /></a></p>
<p>4. Open Visual Studio 2015. I set the options on Visual Studio 2015 to always Run as Administrator, this helps especially when you are debugging your code by attaching to the w3p process.</p>
<p>5. Create new Visual Studio 2015 Project:</p>
<ol>
<li>Click on File &gt; New &gt; Project.</li>
<li>Select Web &gt; ASP.NET Web Application.</li>
<li>Specify Name.</li>
<li>Select location.</li>
<li>Select other options as necessary.</li>
<li>Click OK button</li>
</ol>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/solution3.png"><img loading="lazy" class="alignnone size-large wp-image-2480" src="http://akshaysura.com/wp-content/uploads/2016/06/solution3-1024x716.png" alt="solution3" width="900" height="629" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/solution4.png"><img loading="lazy" class="alignnone size-large wp-image-2481" src="http://akshaysura.com/wp-content/uploads/2016/06/solution4-1024x711.png" alt="solution4" width="900" height="625" /></a></p>
<p>6. Once that is done you are presented with another dialog. Select Empty option in the Template section and select MVC in the Add folders and core references for section. Click the OK button to continue.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/solution6.png"><img loading="lazy" class="alignnone size-full wp-image-2483" src="http://akshaysura.com/wp-content/uploads/2016/06/solution6.png" alt="solution6" width="789" height="619" /></a></p>
<p>This will create the base solution as shown below:</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/solution7.png"><img loading="lazy" class="alignnone size-full wp-image-2484" src="http://akshaysura.com/wp-content/uploads/2016/06/solution7.png" alt="solution7" width="217" height="256" /></a></p>
<p>7. Delete the Web.config and Global.asax.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/solution8.png"><img loading="lazy" class="alignnone size-full wp-image-2487" src="http://akshaysura.com/wp-content/uploads/2016/06/solution8.png" alt="solution8" width="506" height="430" /></a></p>
<p>8. Copy the Web.config and Global.asax from the Website folder in to the TIHIDI.Web (Web project root) folder.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/solution9.png"><img loading="lazy" class="alignnone size-large wp-image-2488" src="http://akshaysura.com/wp-content/uploads/2016/06/solution9-1024x447.png" alt="solution9" width="900" height="393" /></a></p>
<p>9. Create an App_Config folder in your Web project root.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/solution10.png"><img loading="lazy" class="alignnone size-full wp-image-2489" src="http://akshaysura.com/wp-content/uploads/2016/06/solution10.png" alt="solution10" width="512" height="436" /></a></p>
<p>10. Copy the ConnectionStrings.config and Sitecore.config from the Website &gt; App_Config folder in to the TIHIDI.Web (Web project root) &gt; App_Config folder.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/solution11.png"><img loading="lazy" class="alignnone size-large wp-image-2490" src="http://akshaysura.com/wp-content/uploads/2016/06/solution11-1024x328.png" alt="solution11" width="900" height="288" /></a></p>
<p>11. Back in Visual Studio 2015, include the newly created App_Config folder.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/solution13.png"><img loading="lazy" class="alignnone size-large wp-image-2493" src="http://akshaysura.com/wp-content/uploads/2016/06/solution13-1024x625.png" alt="solution13" width="900" height="549" /></a></p>
<p>12. Also include the copied Global.asax and Web.config.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/solution14.png"><img loading="lazy" class="alignnone size-full wp-image-2494" src="http://akshaysura.com/wp-content/uploads/2016/06/solution14.png" alt="solution14" width="534" height="935" /></a></p>
<p>13. Add references to the Sitecore.Kernel.dll and Sitecore.Mvc.dll in the Dependencies\Sitecore folder.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/solution12-1.png"><img loading="lazy" class="alignnone size-large wp-image-2492" src="http://akshaysura.com/wp-content/uploads/2016/06/solution12-1-1024x712.png" alt="solution12" width="900" height="626" /></a></p>
<p>14. Open Views\web.config and add the following to the end of the &lt;namespaces&gt; node so that you can use @Html.Sitecore() in your views.</p>
<p>&lt;add namespace=&#8221;Sitecore.Mvc&#8221; /&gt;<br />
&lt;/namespaces&gt;</p>
<p>15. Restart Visual Studio 2015 and reopen the solution.</p>
<p>16. Rebuild solution.</p>
<p>17. At this point we have everything we need to deploy. Double check to make sure your MVC versions matchup before you deploy to the website. In my case, no additional work needed.</p>
<p>18. Setup a One Click Publish profile pointing to the website root. You can use post build scripts, TDS and other ways as well.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/solution15.png"><img loading="lazy" class="alignnone size-large wp-image-2496" src="http://akshaysura.com/wp-content/uploads/2016/06/solution15-1024x226.png" alt="solution15" width="900" height="199" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/solution16.png"><img loading="lazy" class="alignnone size-full wp-image-2497" src="http://akshaysura.com/wp-content/uploads/2016/06/solution16.png" alt="solution16" width="708" height="556" /></a></p>
<p>19. Finally publish.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/solution17.png"><img loading="lazy" class="alignnone size-large wp-image-2498" src="http://akshaysura.com/wp-content/uploads/2016/06/solution17-1024x399.png" alt="solution17" width="900" height="351" /></a></p>
<p>20. Now that we have our solution publishing to the website, lets reload the site and the Sitecore admin.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/solution18.png"><img loading="lazy" class="alignnone size-large wp-image-2499" src="http://akshaysura.com/wp-content/uploads/2016/06/solution18-1024x667.png" alt="solution18" width="900" height="586" /></a> <a href="http://akshaysura.com/wp-content/uploads/2016/06/solution19.png"><img loading="lazy" class="alignnone size-large wp-image-2500" src="http://akshaysura.com/wp-content/uploads/2016/06/solution19-1024x669.png" alt="solution19" width="900" height="588" /></a></p>
<p>All working as expected!</p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>TIHIDI: Install MongoDB 3.2.7 for Sitecore 8.x in one step!</title>
      <link>https://akshaysura.com/blog/tihidi-install-mongodb-3-2-7-for-sitecore-8-x-in-one-step/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/tihidi-install-mongodb-3-2-7-for-sitecore-8-x-in-one-step/</guid>
      <pubDate>Tue, 14 Jun 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Install MongoDB 3.2.7 for Sitecore 8.x in one step using Windows PowerShell.]]></description>
      <content:encoded><![CDATA[<p>Install MongoDB 3.2.7 for Sitecore 8.x in one step using Windows PowerShell.</p>
<p>Create a new file Sitecore_MongoDB_Install.ps1 and paste contents from <a href="https://gist.github.com/akshaysura/335d97ab7526b610a7f9e15b285b7eca" target="_blank">https://gist.github.com/akshaysura/335d97ab7526b610a7f9e15b285b7eca</a></p>
<p>Open Windows PowerShell ISE console as an Administrator.</p>
<p>Open the PowerShell file you just created and run it.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/mongo1.png"><img loading="lazy" class="alignnone size-large wp-image-2440" src="http://akshaysura.com/wp-content/uploads/2016/06/mongo1-1024x679.png" alt="mongo1" width="900" height="597" /></a></p>
<p>If you get the error: <strong><em>Sitecore_MongoDB_Install.ps1 cannot be loaded because the execution of scripts is disabled on this system</em></strong>.</p>
<p>Run <strong>Set-ExecutionPolicy RemoteSigned</strong> in your PowerShell console followed by the execution of the PowerShell file.</p>
<p>This will install the latest MongoDB 3.2.7 as of June 14th 2016 on your machine. I added code to Unblock a zip file downloaded onto windows. This WILL cause issues as windows sees this as unsafe.</p>
<p class="p1"><strong>Get-ChildItem <span class="s4">-Path</span> <span class="s5">$mongoDbPath</span> <span class="s4">-Recurse</span> <span class="s6">|</span> Unblock-File</strong></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/mongo2.png"><img loading="lazy" class="alignnone size-full wp-image-2441" src="http://akshaysura.com/wp-content/uploads/2016/06/mongo2.png" alt="mongo2" width="272" height="389" /></a></p>
<p><script src="https://gist.github.com/akshaysura/335d97ab7526b610a7f9e15b285b7eca.js"></script></p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
<p>P.S. <a href="https://twitter.com/kamsar" target="_blank">The Notorious F.I.G</a> helped me out in the past and I drew inspiration from his script and updated it. (<a href="https://gist.github.com/kamsar/98681b73979adc89610c" target="_blank">https://gist.github.com/kamsar/98681b73979adc89610c</a>)</p>
<p>&nbsp;</p>
]]></content:encoded>
    </item>
    <item>
      <title>TIHIDI: Implement a simple view rendering in Sitecore MVC and Glass</title>
      <link>https://akshaysura.com/blog/tihidi-implement-a-simple-view-rendering-in-sitecore-mvc-and-glass/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/tihidi-implement-a-simple-view-rendering-in-sitecore-mvc-and-glass/</guid>
      <pubDate>Fri, 10 Jun 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[This blog post will go through how I setup a basic View rendering using Glass Mapper Model.]]></description>
      <content:encoded><![CDATA[<p>This blog post will go through how I setup a basic View rendering using Glass Mapper Model.</p>
<p>Visit <a href="http://www.glass.lu/mapper/sc" target="_blank">http://www.glass.lu/mapper/sc</a> for more information on Glass Mapper for Sitecore.</p>
<p><strong>TIHIDI: Stands for This Is How I Do It. I am going to write a series of blog posts going through how I do Sitecore related work. Hope it helps you!</strong></p>
<p>Lets start by adding a simple template called TextBlock.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/view1.png"><img loading="lazy" class="alignnone size-large wp-image-2576" src="http://akshaysura.com/wp-content/uploads/2016/06/view1.png" alt="view1" width="900" height="444" /></a></p>
<p>Lets add some data we can use as a datasource.<br />
<a href="http://akshaysura.com/wp-content/uploads/2016/06/view2.png"><img loading="lazy" class="alignnone size-full wp-image-2575" src="http://akshaysura.com/wp-content/uploads/2016/06/view2.png" alt="view2" width="984" height="460" /></a></p>
<p>Once that is setup, lets add the Model and the Mapping in our projects.</p>
<pre><code class="language-csharp">
namespace TIHIDI.Models.Templates.Content
{
    public interface ITextBlock 
    {
        string Heading { get; set; }
        string SubHeading { get; set; }
        string Content { get; set; }
    }
}

</code></pre>
<pre><code class="language-csharp">
using Glass.Mapper.Sc.Maps;
using TIHIDI.Models;
using TIHIDI.Models.Templates.Content;

namespace TIHIDI.Mapping.Templates.Content
{
    public class TextBlockMap : SitecoreGlassMap&lt;ITextBlock&gt;
    {

        public override void Configure()
        {
            Map(x =&gt;
            {
                x.AutoMap();
            });
        }
    }
}

</code></pre>
<p>Once that is done, lets add a view in the web project.</p>
<pre><code class="language-csharp">
@inherits Glass.Mapper.Sc.Web.Mvc.GlassView&lt;TIHIDI.Models.Templates.Content.ITextBlock&gt;
@using Sitecore.Mvc

@if (Model != null)
{
    &lt;h3&gt;@Model.Heading&lt;/h3&gt;
    &lt;h4&gt;@Model.SubHeading&lt;/h4&gt;
    &lt;div class="content"&gt;@Html.Raw(Model.Content)&lt;/div&gt;
}

</code></pre>
<p>Add an associated View rendering in Sitecore and add it to the item you like, in my case I am adding it to the home item. Build and publish. Publish in Sitecore as well.</p>
<p>In a client browser it looks good.<br />
<a href="http://akshaysura.com/wp-content/uploads/2016/06/view3.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/06/view3.png" alt="view3" width="525" height="246" class="alignnone size-large wp-image-2578" /></a></p>
<p>In the Page Editor, oops sorry Experience Editor, which took forever to load it looks good but I am unable to edit the content.<br />
<a href="http://akshaysura.com/wp-content/uploads/2016/06/view4.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/06/view4.png" alt="view4" width="350" height="251" class="alignnone size-full wp-image-2577" /></a></p>
<p>If you have a need for this content to be editable you would need to do a couple of things. One, you would need to specify the Id attribute for the Model and two, you need to use Glass methods to make these fields editable.</p>
<pre><code class="language-csharp">
using System;

namespace TIHIDI.Models.Templates.Content
{
    public interface ITextBlock 
    {
        Guid Id { get; set; }
        string Heading { get; set; }
        string SubHeading { get; set; }
        string Content { get; set; }
    }
}

</code></pre>
<pre><code class="language-csharp">
@inherits Glass.Mapper.Sc.Web.Mvc.GlassView&lt;TIHIDI.Models.Templates.Content.ITextBlock&gt;
@using Sitecore.Mvc

@if (Model != null)
{
    &lt;h3&gt;@Editable(Model, y =&gt; y.Heading)&lt;/h3&gt;
    &lt;h4&gt;@Editable(Model, y =&gt; y.SubHeading)&lt;/h4&gt;
    &lt;div class="content"&gt;@Editable(Model, y =&gt; y.Content)&lt;/div&gt;
}

</code></pre>
<p>Build and publish, load the page in Experience Editor and (after while) there ya have it!<br />
<a href="http://akshaysura.com/wp-content/uploads/2016/06/view5.png"><img loading="lazy" src="http://akshaysura.com/wp-content/uploads/2016/06/view5.png" alt="view5" width="323" height="267" class="alignnone size-full wp-image-2579" /></a></p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>TIHIDI: Install Sitecore Instance Manager (SIM)</title>
      <link>https://akshaysura.com/blog/tihidi-install-sitecore-instance-manager-sim/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/tihidi-install-sitecore-instance-manager-sim/</guid>
      <pubDate>Fri, 10 Jun 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Sitecore Instance Manager is a great utility if you are a Sitecore developer working on multiple projects. It gives you the ability to install, maintain and delete Sitecore sites on a local machine among other things. You no longer need to run the Sitecore install exe.]]></description>
      <content:encoded><![CDATA[<p>Sitecore Instance Manager is a great utility if you are a Sitecore developer working on multiple projects. It gives you the ability to install, maintain and delete Sitecore sites on a local machine among other things. You no longer need to run the Sitecore install exe.</p>
<p><strong><span style="text-decoration: underline;">TIHIDI</span>: Stands for This Is How I Do It. I am going to be writing a series of blog posts going through how I do Sitecore related work. Hope it helps you!</strong></p>
<p>The newer versions of the SIM are ClickOnce installer based and makes it easy to install it on your machine.</p>
<p>You can go to the Sitecore Marketplace (<a href="https://marketplace.sitecore.net/" target="_blank">https://marketplace.sitecore.net/</a>) and search for &#8220;Sitecore Instance Manager&#8221;:</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/sim1.png"><img loading="lazy" class="alignnone size-large wp-image-2414" src="http://akshaysura.com/wp-content/uploads/2016/06/sim1-1024x665.png" alt="sim1" width="900" height="584" /></a></p>
<p>&nbsp;</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/sim2.png"><img loading="lazy" class="alignnone size-large wp-image-2415" src="http://akshaysura.com/wp-content/uploads/2016/06/sim2-1024x391.png" alt="sim2" width="900" height="344" /></a></p>
<p>&nbsp;</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/sim3.png"><img loading="lazy" class="alignnone size-large wp-image-2417" src="http://akshaysura.com/wp-content/uploads/2016/06/sim3-1024x662.png" alt="sim3" width="900" height="582" /></a></p>
<p>&nbsp;</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/sim4.png"><img loading="lazy" class="alignnone size-large wp-image-2418" src="http://akshaysura.com/wp-content/uploads/2016/06/sim4-1024x664.png" alt="sim4" width="900" height="584" /></a></p>
<p>Or visit <a href="http://dl.sitecore.net/updater/sim/" target="_blank">http://dl.sitecore.net/updater/sim/</a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/sim5.1.png"><img loading="lazy" class="alignnone size-large wp-image-2420" src="http://akshaysura.com/wp-content/uploads/2016/06/sim5.1-1024x665.png" alt="sim5.1" width="900" height="584" /></a></p>
<p>Click on the SIM.Tool.application file which was downloaded.</p>
<p>Click the Install button on the prompt as shown below:</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/sim6.png"><img loading="lazy" class="alignnone size-full wp-image-2421" src="http://akshaysura.com/wp-content/uploads/2016/06/sim6.png" alt="sim6" width="424" height="289" /></a></p>
<p>SIM starts to download on your machine.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/sim7.png"><img loading="lazy" class="alignnone size-large wp-image-2422" src="http://akshaysura.com/wp-content/uploads/2016/06/sim7.png" alt="sim7" width="258" height="177" /></a></p>
<p>If you are on Windows 10 (Windows 8 or later), you might see a prompt similar to the one shown below:</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/sim8.png"><img loading="lazy" class="alignnone size-full wp-image-2423" src="http://akshaysura.com/wp-content/uploads/2016/06/sim8.png" alt="sim8" width="509" height="202" /></a></p>
<p><strong>TEMPORARILY disable</strong> the SmartScreen setting by going to Control Panel&gt; System and Security&gt; Security and Maintenance&gt; Windows SmartScreen&gt; Change Settings:</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/sim9.png"><img loading="lazy" class="alignnone size-large wp-image-2424" src="http://akshaysura.com/wp-content/uploads/2016/06/sim9.png" alt="sim9" width="855" height="545" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/sim10.png"><img loading="lazy" class="alignnone size-large wp-image-2425" src="http://akshaysura.com/wp-content/uploads/2016/06/sim10.png" alt="sim10" width="365" height="254" /></a></p>
<p>Run the SIM.Tool.application again and follow the prompts.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/sim11.png"><img loading="lazy" class="alignnone size-full wp-image-2427" src="http://akshaysura.com/wp-content/uploads/2016/06/sim11.png" alt="sim11" width="366" height="287" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/sim12.png"><img loading="lazy" class="alignnone size-large wp-image-2428" src="http://akshaysura.com/wp-content/uploads/2016/06/sim12.png" alt="sim12" width="367" height="287" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/sim13.png"><img loading="lazy" class="alignnone size-large wp-image-2429" src="http://akshaysura.com/wp-content/uploads/2016/06/sim13.png" alt="sim13" width="367" height="288" /></a></p>
<p>Select the location where you will place the Sitecore installation zip files and location of your Sitecore license.xml file.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/sim14.png"><img loading="lazy" class="alignnone size-large wp-image-2430" src="http://akshaysura.com/wp-content/uploads/2016/06/sim14.png" alt="sim14" width="367" height="289" /></a></p>
<p>Specify the connection string to your local SQL Server.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/sim15.png"><img loading="lazy" class="alignnone size-large wp-image-2431" src="http://akshaysura.com/wp-content/uploads/2016/06/sim15.png" alt="sim15" width="365" height="284" /></a></p>
<p>Confirm the website location and click the Grant button.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/sim16.png"><img loading="lazy" class="alignnone size-large wp-image-2432" src="http://akshaysura.com/wp-content/uploads/2016/06/sim16.png" alt="sim16" width="365" height="288" /></a></p>
<p>If you installed your SQL Server to run under credentials other than Network Service account, you might see the error below:</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/sim17.png"><img loading="lazy" class="alignnone size-full wp-image-2433" src="http://akshaysura.com/wp-content/uploads/2016/06/sim17.png" alt="sim17" width="414" height="288" /></a></p>
<p>Stop the SQL Server service, modify the settings to login as the Network Service and start the service.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/sim18.png"><img loading="lazy" class="alignnone size-full wp-image-2434" src="http://akshaysura.com/wp-content/uploads/2016/06/sim18.png" alt="sim18" width="1008" height="661" /></a></p>
<p>Get back to the install and click the Grant button again. The install completed and you get the confirmation.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/sim19.png"><img loading="lazy" class="alignnone size-full wp-image-2435" src="http://akshaysura.com/wp-content/uploads/2016/06/sim19.png" alt="sim19" width="367" height="289" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/06/sim20.png"><img loading="lazy" class="alignnone size-full wp-image-2437" src="http://akshaysura.com/wp-content/uploads/2016/06/sim20.png" alt="sim20" width="258" height="363" /></a></p>
<p>If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).</p>
]]></content:encoded>
    </item>
    <item>
      <title>Unofficial Sitecore 8 Training Webinar Series – Session 3</title>
      <link>https://akshaysura.com/blog/unofficial-sitecore-8-training-webinar-series-session-3/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/unofficial-sitecore-8-training-webinar-series-session-3/</guid>
      <pubDate>Tue, 31 May 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[]]></description>
      <content:encoded><![CDATA[<h3><u>Agenda for the third Unofficial Sitecore training session</u></h3>
<ol>
<li><strong>Serialization</strong>
<ul>
<li>What is Serialization and how can it help me?</li>
<li>Developing with common DB’s or Serialization</li>
<li>Tools on the market</li>
<li>Demo of Unicorn/Rainbow and TDS</li>
</ul>
</li>
<li><strong>ORM</strong>
<ul>
<li>What is an ORM?</li>
<li>What is a Mapper?</li>
<li>What is a Wrapper?</li>
<li>Tools on the market</li>
<li>Demo of Glass, Synthesis and Fortis</li>
</ul>
</li>
</ol>
<h3>Video of the Webinar</h3>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/4hXhMRV3f4Q" frameborder="0" allowfullscreen></iframe></p>
<p>We have the following presenters:</p>
<ol>
<li><a href="https://twitter.com/mikeedwards83" target="_blank">Mike Edwards</a></li>
<li><a href="https://twitter.com/kamsar" target="_blank">Kam Figy</a></li>
<li><a href="https://twitter.com/seanholmesby" target="_blank">Sean Holmesby</a></li>
<li><a href="https://twitter.com/cardinal252" target="_blank">Nathanael Mann</a></li>
<li><a href="https://twitter.com/mike_i_reynolds" target="_blank">Mike Reynolds</a></li>
<li><a href="https://twitter.com/rich_seal" target="_blank">Richard Seal</a></li>
<li><a href="https://twitter.com/akshaysura13" target="_blank">Akshay Sura</a></li>
</ol>
<p><del>Please register for Unofficial Sitecore 8 Training Webinar Series &#8211; Session 3 on June 7th, 2016 8:00 AM PDT at:</del></p>
<p><del><a href="https://attendee.gotowebinar.com/register/9071377023822453762" target="_blank">https://attendee.gotowebinar.com/register/9071377023822453762</a></del></p>
<p><del>After registering, you will receive a confirmation email containing information about joining the webinar.</del></p>
<p>If you need more information get in touch with Akshay Sura or Mike Reynolds.</p>
<p>@akshaysura13 or @mike_i_reynolds on twitter or on Slack.</p>
<p>&nbsp;</p>
<p><span style="text-decoration: underline;"><strong>Webinar Analytics</strong></span></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/05/2016-06-07_10-07-28.png"><img loading="lazy" class="alignnone size-large wp-image-2376" src="http://akshaysura.com/wp-content/uploads/2016/05/2016-06-07_10-07-28-1024x354.png" alt="2016-06-07_10-07-28" width="900" height="311" /></a></p>
<p><span style="text-decoration: underline;"><strong>Session Q &amp; A (thanks to <a href="https://twitter.com/yippystar" target="_blank">Alan Yip</a> for the suggestion)</strong></span></p>
<p><strong>Q.</strong> should we exclude __Created Date in TDS project?<br />
<strong>A.</strong> _Created Date. You can if you want to&#8230;.but it&#8217;s not required.</p>
<p><strong>Q.</strong> youtube link given by mike in ppt https://www.youtube.com/watch?v=AFYOTFjtel0 is not work<br />
<strong>A.</strong> use https://www.youtube.com/watch?v=AFYOTFjteI0</p>
<p><strong>Q.</strong> Can i get a TDS trial license on my personal email?<br />
<strong>A.</strong> yes</p>
<p><strong>Q.</strong> Is there any best practice web resource/book/ebook link on TDS you could share?<br />
<strong>A.</strong> The main TDS wiki is the best at the moment. http://hedgehogdevelopment.github.io/tds/ It&#8217;s a lot of text though, but should cover everything. The TDS YouTube Playlist is more interested for this sort of stuff. https://www.youtube.com/playlist?list=PLb9QmtmxCbhl1uzG_XJ37Sc9fhsJNLfaM</p>
<p><strong>Q.</strong> Can you edit the field&#8217;s text when using TextFor like using the Field renderer from Sitecore, when in Page Experience Edit mode on synthesis? or is it just raw text rendered on the page?<br />
<strong>A.</strong> Yes you get experience editor with Synthesis</p>
<p><strong>Q.</strong> By using Glass mapper, do you loose the editability in Page Editor if you&#8217;re using generated Models in MVC views?<br />
<strong>A.</strong> Not from my experience &#8211; Akshay Sura</p>
<p><strong>Q.</strong> How code generation create models?<br />
<strong>A.</strong> T4 templates</p>
<p><strong>Q.</strong> Hi,, can we create two TDS project for same content folder?<br />
<strong>A.</strong> yes</p>
<p><strong>Q.</strong> What is main benefit of use Synthesis?<br />
<strong>A.</strong> The main benefit of using Synthesis is to avoid using magic strings or constants classes when accessing Sitecore items. It makes everything much more maintainable. As well the MVC rendering helpers keep view renderings very clean.</p>
<p><strong>Q.</strong> What&#8217;s the recommendation for Content and TDS? Is is recommended to have the content synchronized? or to have a initial/base content in TDS? or not to have anything related content?<br />
<strong>A.</strong> Depends on your need, mostly for the inital content.</p>
<p><strong>Q.</strong> ORM is tightly coupled with TDS? could be or we can use ORM indepedently as well ?<br />
<strong>A.</strong> you can use it independently or closely coupled</p>
]]></content:encoded>
    </item>
    <item>
      <title>Unofficial Sitecore 8 Training Webinar Series – Session 4</title>
      <link>https://akshaysura.com/blog/unofficial-sitecore-8-training-webinar-series-session-4/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/unofficial-sitecore-8-training-webinar-series-session-4/</guid>
      <pubDate>Tue, 31 May 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Link to GitHub source.]]></description>
      <content:encoded><![CDATA[<h3><u>Agenda for the fourth Unofficial Sitecore training session</u></h3>
<ol>
<li><strong>Presentation eh!</strong>
<ul>
<li>Types of Renderings</li>
<li>Importance of Datasources</li>
<li>Datasource restrictions</li>
<li>Placeholder settings</li>
<li>Page Editor friendly pages</li>
<li>Parameter templates</li>
<li>Demo on building a rendering and configuring it properly in Sitecore (participants are encouraged to follow along with the demo on their machines)</li>
</ul>
</li>
<li><strong>Admin Duties</strong>
<ol>
<li>Module installation via installation wizard</li>
<li>Package installation via update installation wizard</li>
<li>Admin pages such as stats, cache, showconfig, etc</li>
</ol>
</li>
</ol>
<h4>Source Code</h4>
<p><a href="https://github.com/jammykam/UnofficialTraining.Session4" target="_blank">Link to GitHub source</a>.</p>
<h4>Video</h4>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/oBF4U-TQgmQ" frameborder="0" allowfullscreen></iframe></p>
<p><del>Please register for Unofficial Sitecore 8 Training Webinar Series &#8211; Session 4 on October 27th, 2016 2:00 PM (14:00) &#8211; 3:00 PM (15:00) PDT at:</del></p>
<p><del><a href="https://attendee.gotowebinar.com/register/6906124171329030148" target="_blank">https://attendee.gotowebinar.com/register/6906124171329030148</a></del></p>
<p><del>After registering, you will receive a confirmation email containing information about joining the webinar.</del></p>
<p>If you need more information get in touch with Akshay Sura or Mike Reynolds or Kamruz Jaman.</p>
<p>@akshaysura13 or @mike_i_reynolds or @jammykam on twitter or on Slack.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Unofficial Sitecore 8 Training Webinar Series - Session 2</title>
      <link>https://akshaysura.com/blog/unofficial-sitecore-8-training-webinar-series-session-2/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/unofficial-sitecore-8-training-webinar-series-session-2/</guid>
      <pubDate>Thu, 05 May 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[After a long hiatus, we finally are able to schedule the second session of the series.]]></description>
      <content:encoded><![CDATA[<p>After a long hiatus, we finally are able to schedule the second session of the series.</p>
<h3><u>Agenda for the second Unofficial Sitecore training session</u></h3>
<ol>
<li><strong>Tour of Sitecore admin console</strong> (Content Editor, Media Library and Workbox)</li>
<li><strong>Fields fields everywhere</strong>
<ul>
<li>Simple Field Types</li>
<li>Link Field Types</li>
<li>List Field Types</li>
<li>A Demo on using fields with base Sitecore API (participants are encouraged to follow along with the demo on their machines)</li>
</ul>
</li>
<li><strong><strong>More API</strong></strong>
<ul>
<li>Working with items (creating, modifying and deleting items)</li>
<li>Demo on manipulating Sitecore items (participants are encouraged to follow along with the demo on their machines)</li>
<li>Sitecore Query</li>
<li>Fast Query</li>
<li>Demo of querying items (participants are encouraged to follow along with the demo on their machine</li>
</ul>
</li>
</ol>
<p>&nbsp;</p>
<h3>Video of the Webinar</h3>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/P2dhjPe6Zhw" frameborder="0" allowfullscreen="allowfullscreen"></iframe></p>
<p><del>Please register for Unofficial Sitecore 8 Training Webinar Series &#8211; Session 2 on May 26, 2016 9:00 PM PDT at:</del></p>
<p><del><a href="https://attendee.gotowebinar.com/register/8823055620741682435">https://attendee.gotowebinar.com/register/8823055620741682435</a></del></p>
<p><del>After registering, you will receive a confirmation email containing information about joining the webinar.</del></p>
<p>If you need more information get in touch with Akshay Sura or Mike Reynolds.</p>
<p>@akshaysura13 or @mike_i_reynolds on twitter or on Slack.</p>
<p>&nbsp;</p>
<p><span style="text-decoration: underline;"><strong>Webinar Analytics</strong></span></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2016/05/2016-06-07_10-28-37.png"><img loading="lazy" class="alignnone size-large wp-image-2380" src="http://akshaysura.com/wp-content/uploads/2016/05/2016-06-07_10-28-37-1024x353.png" alt="2016-06-07_10-28-37" width="900" height="310" /></a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Unofficial Sitecore 8 Training Webinar Series - Session 1 - Plan C</title>
      <link>https://akshaysura.com/blog/unofficial-sitecore-8-training-webinar-series-session-1-plan-c/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/unofficial-sitecore-8-training-webinar-series-session-1-plan-c/</guid>
      <pubDate>Thu, 25 Feb 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[What Happened?? First, we would like to apologize for the inconvenience. The webinar software crashed and google hangouts was having audio issues.]]></description>
      <content:encoded><![CDATA[<p><strong>What Happened??</strong><br />
First, we would like to apologize for the inconvenience. The webinar software crashed and google hangouts was having audio issues.</p>
<p><strong>What we did?</strong><br />
We got a subscription to a more reliable webinar software GoToWebinar by Citrix. We are sending out this email to notify you of the rescheduled webinar.</p>
<p><span style="text-decoration: underline;"><strong>We are rescheduling to March 3rd 2016 at 9 PM PST (Pacific Standard Time), 5AM GMT &amp; 10:30 AM IST.</strong></span></p>
<p>Please register for Unofficial Sitecore 8 Training Webinar Series &#8211; Session 1 &#8211; Plan C 😉 on Mar 3, 2016 9:00 PM PST at:</p>
<p><a href="https://attendee.gotowebinar.com/register/757718915532440068" target="_blank">https://attendee.gotowebinar.com/register/757718915532440068</a></p>
<p>After registering, you will receive a confirmation email containing information about joining the webinar.</p>
<p>Brought to you by GoToWebinar®</p>
<p>If you need more information get in touch with Akshay Sura or Mike Reynolds.</p>
<p>@akshaysura13 or @mike_i_reynolds on twitter or on Slack.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Unofficial Sitecore 8 Training Webinar Series</title>
      <link>https://akshaysura.com/blog/unofficial-sitecore-8-training-webinar-series/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/unofficial-sitecore-8-training-webinar-series/</guid>
      <pubDate>Wed, 03 Feb 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[First these webinars are not intended for seasoned Sitecore developers. These are meant for basic Sitecore training to bridge a knowledge gap I have been seeing for a while in the community.]]></description>
      <content:encoded><![CDATA[<p>First these webinars are not intended for seasoned Sitecore developers. These are meant for basic Sitecore training to bridge a knowledge gap I have been seeing for a while in the community.</p>
<p>I notice a lot of experienced and junior .NET resources who are pushed into Sitecore with just the training and a cert. Most of the time these resources end up developing poor solutions which we all have to fix later on.</p>
<p>This has been going long enough. There have been many times when attendees at user groups approached experienced Sitecore devs asking questions they have spend hours to figure out. I feel like there is no MSDN version (I am talking about MSDN in 2003 when it was really good) for Sitecore for reference and even if there was, it might be difficult for those new to Sitecore to figure out what to search for.</p>
<p>One search in google will give you a ton on results from all over the place but its all over the place.</p>
<p>Hence this series.</p>
<p>I plan on running these webinars to get people trained up in Sitecore (Unofficially) so they make better decisions and help progress this great community of ours.</p>
<p>My partner in crime <a href="https://twitter.com/mike_i_reynolds" target="_blank">Mike Reynolds</a> a two time Sitecore MVP will be working with me to deliver these sessions.</p>
<p><span style="text-decoration: underline;"><strong>This first session will be held on Thursday February 25 2016 (9PM PST, 12AM EST, 5AM London &#8211; Feb 26, 7AM Istanbul &#8211; Feb 26, 10:30AM Delhi &#8211; Feb 26, 4PM Sydney &#8211; Feb 26).</strong></span></p>
<h3><u>1. Agenda for the first Unofficial Sitecore training sessions is listed below</u> (306 registered)</h3>
<ol>
<li><strong>Overview</strong>
<ul>
<li>What is a Content Management System?</li>
<li>What is Sitecore?</li>
<li>Infrastructure perspective</li>
<li>Author perspective</li>
<li>Developer perspective</li>
</ul>
</li>
<li><strong>Installation</strong>
<ul>
<li>Requirements</li>
<li>Download and Install Sitecore from dev.sitecore.net</li>
<li>SIM</li>
</ul>
</li>
<li><strong>Developing Sitecore</strong>
<ul>
<li>MVC &#8211; what MVC? ya mean Sitecore MVC?</li>
<li>Structure</li>
<li>Presentation (View &amp; Controller Rendering)</li>
<li>Templates and Inheritance</li>
<li>Standard Values</li>
<li>Data binding</li>
</ul>
</li>
<li><strong>API</strong>
<ul>
<li>Basic Sitecore API</li>
<li>A Demo on rendering a simple menu (participants are encouraged to follow along with the demo on their machines)</li>
</ul>
</li>
</ol>
<p><strong>Each training session will last 2 hours.</strong> Will be focused and we will take questions.</p>
<p>If you have any questions or comments, please feel free to get in touch with me.</p>
<p>Here is a link to the <span style="text-decoration: underline;"><strong><a href="http://akshaysura.com/2016/02/03/unofficial-sitecore-8-training-webinar-series-full-curriculum/">Full Curriculum</a></strong></span>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Unofficial Sitecore 8 Training Webinar Series - Full Curriculum</title>
      <link>https://akshaysura.com/blog/unofficial-sitecore-8-training-webinar-series-full-curriculum/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/unofficial-sitecore-8-training-webinar-series-full-curriculum/</guid>
      <pubDate>Wed, 03 Feb 2016 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[We got a lot of requests to post our plan and here goes. This is what we have in mind for now. Depending on how popular these are we will add more.]]></description>
      <content:encoded><![CDATA[<p>We got a lot of requests to post our plan and here goes. This is what we have in mind for now. Depending on how popular these are we will add more.</p>
<p>Here is the list of webinars that are planned (<strong>Each training session will last 2 hours.</strong> Will be focused and we will take questions.):</p>
<h3><u>1. <a href="http://akshaysura.com/2016/02/25/unofficial-sitecore-8-training-webinar-series-session-1-plan-c/">Agenda</a> (306 registered)</u></h3>
<ol>
<li><strong>Overview</strong>
<ul>
<li>What is a Content Management System?</li>
<li>What is Sitecore?</li>
<li>Infrastructure perspective</li>
<li>Author perspective</li>
<li>Developer perspective</li>
</ul>
</li>
<li><strong>Installation</strong>
<ul>
<li>Requirements</li>
<li>Download and Install Sitecore from dev.sitecore.net</li>
<li>SIM</li>
</ul>
</li>
<li><strong>Developing Sitecore</strong>
<ul>
<li>MVC &#8211; what MVC? ya mean Sitecore MVC?</li>
<li>Structure</li>
<li>Presentation (View &amp; Controller Rendering)</li>
<li>Templates and Inheritance</li>
<li>Standard Values</li>
<li>Data binding</li>
</ul>
</li>
<li><strong>API</strong>
<ul>
<li>Basic Sitecore API</li>
<li>A Demo on rendering a simple menu (participants are encouraged to follow along with the demo on their machines)</li>
</ul>
</li>
</ol>
<p>&nbsp;</p>
<h3><u>2. <a href="http://akshaysura.com/2016/05/05/unofficial-sitecore-8-training-webinar-series-session-2/">Agenda</a> (257 Registered)</u></h3>
<ol>
<li><strong>Tour of Sitecore admin console</strong> (Content Editor, Media Library and Workbox)</li>
<li><strong>Fields fields everywhere</strong>
<ul>
<li>Simple Field Types</li>
<li>Link Field Types</li>
<li>List Field Types</li>
<li>A Demo on using fields with base Sitecore API (participants are encouraged to follow along with the demo on their machines)</li>
</ul>
</li>
<li><strong><strong>More API</strong></strong>
<ul>
<li>Working with items (creating, modifying and deleting items)</li>
<li>Demo on manipulating Sitecore items (participants are encouraged to follow along with the demo on their machines)</li>
<li>Sitecore Query</li>
<li>Fast Query</li>
<li>Demo of querying items (participants are encouraged to follow along with the demo on their machines)</li>
</ul>
</li>
</ol>
<p>&nbsp;</p>
<h3><u>3. <a href="http://akshaysura.com/2016/05/31/unofficial-sitecore-8-training-webinar-series-session-3/">Agenda</a> (230 Registered)</u></h3>
<ol>
<li><strong>Serialization</strong>
<ul>
<li>What is an Serialization and how can it help me?</li>
<li>Developing with common DB&#8217;s or Serialization</li>
<li>Tools on the market</li>
<li>Demo of Unicorn/Rainbow and TDS</li>
</ul>
</li>
<li><strong>ORM</strong>
<ul>
<li>What is an ORM?</li>
<li>What is a Mapper?</li>
<li>What is a Wrapper?</li>
<li>Tools on the market</li>
<li>Demo of Glass, Synthesis and Fortis</li>
</ul>
</li>
</ol>
<h3><u>4. <a href="http://akshaysura.com/2016/05/31/unofficial-sitecore-8-training-webinar-series-session-4/">Agenda</a> (160 Registered)</u></h3>
<ol>
<li><strong>Presentation eh!</strong>
<ul>
<li>Types of Renderings</li>
<li>Importance of Datasources</li>
<li>Datasource restrictions</li>
<li>Placeholder settings</li>
<li>Page Editor friendly pages</li>
<li>Parameter templates</li>
<li>Demo on building a rendering and configuring it properly in Sitecore (participants are encouraged to follow along with the demo on their machines)</li>
</ul>
</li>
<li><strong>Admin Duties</strong>
<ol>
<li>Module installation via installation wizard</li>
<li>Package installation via update installation wizard</li>
<li>Admin pages such as stats, cache, showconfig, etc</li>
</ol>
</li>
</ol>
<p>&nbsp;</p>
<h3><u>5. <a href="https://akshaysura.com/2016/10/28/unofficial-sitecore-8-training-webinar-series-session-5/" target="_blank">Agenda</a> (87 Registered)</u></h3>
<ol>
<li><strong>Introduction to Sitecore PowerShell Extensions (<a href="https://twitter.com/MichaelWest101" target="_blank">Michael West</a>)</strong>
<ol>
<li>Intro to SPE</li>
<li>No Coding Required</li>
<li>Nuts &amp; Bolts</li>
<li>Advanced Capabilities</li>
</ol>
</li>
<li><strong>Out of the Box</strong>
<ol>
<li>Bundled Tools</li>
<li>Audit Reports</li>
</ol>
</li>
<li><strong>Meat &amp; Potatoes </strong>
<ol>
<li>Windows PowerShell for Beginners</li>
<li>Console and ISE</li>
<li>Scripts, Libraries, and Modules</li>
<li>Integration Points</li>
</ol>
</li>
<li><strong>Remoting </strong>
<ol>
<li>Setup</li>
<li>Remote Code Execution</li>
<li>Best Practices</li>
</ol>
</li>
</ol>
<h3><u>6. <a href="https://akshaysura.com/2016/10/29/unofficial-sitecore-8-training-webinar-series-session-6/" target="_blank">Agenda</a> (74 Registered)</u></h3>
<ol>
<li><strong>Customizations</strong>
<ol>
<li>Pipelines &amp; Processors
<ol>
<li>What is a pipeline?</li>
<li>What is a processor?</li>
<li>Existing Pipelines in Sitecore</li>
<li>Implement custom functionality in a pipeline</li>
<li>Demo on customizing httpRequestBegin pipeline (participants are encouraged to follow along with the demo on their machines)</li>
<li>Can I create my own pipeline?</li>
</ol>
</li>
<li>Events &amp; Commands
<ol>
<li>Customizing Events</li>
<li>Demo on adding custom item:saved event handler</li>
<li>Create Custom commands</li>
</ol>
</li>
</ol>
</li>
</ol>
<h3><u>7. <a href="https://akshaysura.com/2016/10/29/unofficial-sitecore-8-training-webinar-series-session-7/" target="_blank">Agenda</a> (Postponed)</u></h3>
<ol>
<li><strong>Best Practices (<a href="https://twitter.com/VasiliyFomichev" target="_blank">Vasiliy Fomichev</a>)</strong>
<ul>
<li>Naming conventions</li>
<li>Provide help to content authors</li>
<li>Validation</li>
<li>Datasources</li>
<li>Scaling</li>
<li>CD CM configs</li>
<li>Media handling</li>
<li>Caching</li>
<li>Workflow</li>
</ul>
</li>
</ol>
<h3><u>8. <a href="https://akshaysura.com/2016/11/03/unofficial-sitecore-8-training-webinar-series-session-8/" target="_blank">Agenda</a> (167 Registered)</u></h3>
<ol>
<li><strong>Continuous Integration and Deployment (<a href="https://twitter.com/AgileStCyr" target="_blank">Jason St-Cyr</a>)</strong>
<ol>
<li>Continuous Everything: Improvement, Integration, Testing, Delivery, Deployment</li>
<li>Continuous Integration: The Dirty Details</li>
<li>Continuous Testing: The test team in the deployment pipeline</li>
<li>Production Deployments: The Big Bad Wolf</li>
<li>Demo on setting up a simple CI setup (participants are encouraged to follow along with the demo on their machines)</li>
</ol>
</li>
</ol>
<h3><u>9. <a href="https://akshaysura.com/2016/11/17/unofficial-sitecore-8-training-webinar-series-session-9/" target="_blank">Agenda</a> (72 Registered)</u></h3>
<ol>
<li><strong>Data enrichment and personalization (<a href="https://twitter.com/AmandaShiga" target="_blank">Amanda Shiga</a>)</strong>
<ol>
<li>Getting started: the importance of xDB data enrichment</li>
<li>Building your strategy: types of personalization in Sitecore and how/when to apply them</li>
<li>Keeping personalization manageable for marketing ops and website performance</li>
<li>Measuring success: how to determine if personalization is making a difference</li>
<li>Useful extensions: some helpful approaches to extend Sitecore’s personalization capabilitie</li>
</ol>
</li>
</ol>
<h3><u>10. Agenda</u></h3>
<ol>
<li><strong>Search baby!</strong>
<ol>
<li>Sitecore search basics</li>
<li>Main search technologies</li>
<li>Demo of Lucene, Solr and Coveo search</li>
<li>Search API</li>
<li>Inbound filters</li>
<li>Computed fields</li>
<li>Demo on search using Lucene (participants are encouraged to follow along with the demo on their machines)</li>
</ol>
</li>
</ol>
<h3><u>11. Agenda</u></h3>
<ol>
<li><strong>Buckets &#8211; what buckets yo! (<a href="https://twitter.com/mike_i_reynolds" target="_blank">Mike Reynolds</a>)</strong>
<ol>
<li>Item Buckets</li>
<li>Bucketing Strategies</li>
<li>Item Bucket customizations</li>
<li>Demo on Item Buckets (participants are encouraged to follow along with the demo on their machines)</li>
</ol>
</li>
</ol>
<h3><u>12. Agenda</u></h3>
<ol>
<li><strong>Infrastructure take 2</strong>
<ol>
<li>Build automation tools</li>
<li>Scaling
<ol>
<li>ScalabilitySettings.config</li>
<li>Multi environment configuration including CD/CM configs</li>
<li>Sample Scaling options</li>
<li>Caching</li>
</ol>
</li>
<li>More to come!</li>
</ol>
</li>
</ol>
<h3><u>13. Agenda</u></h3>
<ol>
<li><strong>Commerce What? Who? Which?</strong>
<ol>
<li>How to E-Commerce in Sitecore?</li>
<li>Tools on the market</li>
<li>Active Commerce by <a href="https://twitter.com/techphoria414" target="_blank">Nick Wesselman</a></li>
<li>Sitecore Commerce</li>
<li>uCommerce</li>
</ol>
</li>
</ol>
<p>More to come on Security, Publishing, Rules engine, xDB, Personalization, WFFM, Powershell and other modules.</p>
<p>If you have any questions please do get in touch with Mike Reynolds or I.</p>
]]></content:encoded>
    </item>
    <item>
      <title>How to join Sitecore Slack Community Chat</title>
      <link>https://akshaysura.com/blog/how-to-join-sitecore-slack-community-chat/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/how-to-join-sitecore-slack-community-chat/</guid>
      <pubDate>Tue, 27 Oct 2015 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[I started the Sitecore Slack channel nearly two months ago (8/30/2015) along with the help of Mike Reynolds and Johann Baziret. It’s amazing to see the growth of the community channel and the need for it. Here are some stats from today:]]></description>
      <content:encoded><![CDATA[<p>I started the Sitecore Slack channel nearly two months ago (8/30/2015) along with the help of <a href="https://twitter.com/mike_i_reynolds" target="_blank">Mike Reynolds</a> and <a href="https://twitter.com/bazijjoba" target="_blank">Johann Baziret</a>. It&#8217;s amazing to see the growth of the community channel and the need for it. Here are some stats from today:</p>
<p>There are <del>322</del> <strong>1300+ members</strong> on the Sitecore Slack community as of today.</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2015/10/slackupdateoct2016.png"><img loading="lazy" class="alignnone size-full wp-image-2782" src="https://akshaysura.com/wp-content/uploads/2015/10/slackupdateoct2016.png" alt="slackupdateoct2016" width="263" height="252" /></a></p>
<p>I honestly think that I would not have been able to chat with my fellow Sitecore developers from across the world, if it weren&#8217;t for Slack.</p>
<p><strong>Need an Invite? &#8211; Submit an entry through this form</strong> <a href="https://drive.google.com/open?id=1bAVDgP5-FhFh8ohPchHtifq-rz7EBkuPojAzdEofJyo" target="_blank">https://drive.google.com/open?id=1bAVDgP5-FhFh8ohPchHtifq-rz7EBkuPojAzdEofJyo</a></p>
<p>Feels like we are not only getting to know each other but modules like Sitecore Powershell, Glass and Unicorn are getting first hand feedback, thereby getting more releases out.</p>
<p>The plus side is all the laughs you get from the creative Giphy (fails!) and Meme&#8217;s.</p>
<p>We currently have a few admins who can help you get on Slack or help you get into channels/private groups. If you need to get on slack, message any of the following on Twitter or LinkedIn:</p>
<ol>
<li><a href="https://twitter.com/akshaysura13">Akshay Sura</a></li>
<li><a href="https://twitter.com/mike_i_reynolds">Michael Ian Reynolds</a></li>
<li><a href="https://twitter.com/jammykam">Kamruz Jaman</a></li>
<li><a href="https://twitter.com/adamnaj">Adam Najmanowicz</a></li>
<li><a href="https://twitter.com/nsgocev">Nikola Gotsev</a></li>
<li><a href="https://twitter.com/mikeedwards83">Mike Edwards</a></li>
<li><a href="https://twitter.com/bazijjoba">Johann Baziret</a></li>
<li><a href="https://twitter.com/AnichoCode">Anis Chohan</a></li>
<li><a href="https://twitter.com/rich_seal">Richard Seal</a></li>
<li><a href="https://twitter.com/DanSolovay">Dan Solovay</a></li>
<li><a href="https://twitter.com/cardinal252">Nathanael Mann</a></li>
<li><a href="https://twitter.com/AndersLaub">Anders Laub</a></li>
<li><a href="https://twitter.com/LonghornTaco">Jason Wilkerson</a></li>
<li><a href="https://twitter.com/MichaelWest101">Michael West</a></li>
<li><a href="https://twitter.com/steviemcgill">Steve McGill</a></li>
<li><a href="https://twitter.com/cassidydotdk">Mark Cassidy</a></li>
<li><a href="https://twitter.com/MarasM">Marek Musielak</a></li>
</ol>
<p>If you have questions or comments, please be sure to get in touch with me. As always, I love to be part of this great Sitecore Community. Live and Breathe Sitecore.</p>
<p>A special shout out to <a href="https://twitter.com/pieterbrink123" target="_blank">Pieter Brinkman</a>, who always volunteers to help with making the community better. In this case to a paid subscription of slack which is not needed the way we use it.</p>
<p>Another shout out to <a href="https://twitter.com/jammykam" target="_blank">Kamruz Jaman</a> for being the integration man!</p>
<p><a href="https://akshaysura.com/wp-content/uploads/2016/09/community-is-key.png"><img loading="lazy" class="alignnone size-full wp-image-2773" src="https://akshaysura.com/wp-content/uploads/2016/09/community-is-key.png" alt="community-is-key" width="605" height="783" /></a></p>
]]></content:encoded>
    </item>
    <item>
      <title>SUGCON - Sitecore User Group Conference - Status: Rocked it!</title>
      <link>https://akshaysura.com/blog/sugcon-sitecore-user-group-conference-status-rocked-it/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/sugcon-sitecore-user-group-conference-status-rocked-it/</guid>
      <pubDate>Fri, 02 Oct 2015 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[SUGCON Started about 5 months ago when we saw a need for a country wide developer conference. I teamed up with Mike Reynolds, BrainJocks (Sue Klumpp) and HedgeHog (Mike Shaw).]]></description>
      <content:encoded><![CDATA[<p>SUGCON Started about 5 months ago when we saw a need for a country wide developer conference. I teamed up with Mike Reynolds, BrainJocks (Sue Klumpp) and HedgeHog (Mike Shaw).</p>
<p>We never ever thought that we would have an issue with going over our initial limit of 200 registrations. Thanks to the sponsors and a strong community we did very well.</p>
<p>The conference was for the community by the community.</p>
<p>I want to call out Pieter Brinkman from Sitecore who helped us out a lot.</p>
<p>I would like to thank the sponsors, the speakers and the attendees of the conference. Without you we would not have had a successful conference.</p>
<p>I want to emphasize that we have an amazing community. Its amazing how we all know each other and share with each other.</p>
<p>The main surprise was that Mike and I opened the event with a performance, here is the video:</p>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/p_T2NUPlRUo" frameborder="0" allowfullscreen="allowfullscreen"></iframe></p>
<p>Here are some amazing stats:</p>
<h3>370+ Attendees</h3>
<h3>56 MVPs</h3>
<h3>37% End Users</h3>
<h3>67 Submissions</h3>
<h3>42 Presentations</h3>
<h3>&gt;40 Hours of Sessions</h3>
<p>More stats&#8230;</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2015/10/Activity.png"><img loading="lazy" class="alignnone size-full wp-image-2288" src="http://akshaysura.com/wp-content/uploads/2015/10/Activity.png" alt="Activity" width="953" height="298" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2015/10/Reach.png"><img loading="lazy" class="alignnone size-full wp-image-2291" src="http://akshaysura.com/wp-content/uploads/2015/10/Reach.png" alt="Reach" width="956" height="401" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2015/10/Top_Contributors.png"><img loading="lazy" class="alignnone size-full wp-image-2292" src="http://akshaysura.com/wp-content/uploads/2015/10/Top_Contributors.png" alt="Top_Contributors" width="368" height="362" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2015/10/Most_Reviewed_Tweets.png"><img loading="lazy" class="alignnone size-full wp-image-2290" src="http://akshaysura.com/wp-content/uploads/2015/10/Most_Reviewed_Tweets.png" alt="Most_Reviewed_Tweets" width="485" height="334" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2015/10/Contributors1.png"><img loading="lazy" class="alignnone size-full wp-image-2294" src="http://akshaysura.com/wp-content/uploads/2015/10/Contributors1.png" alt="Contributors1" width="457" height="387" /></a></p>
<p>Thanks to Sitecore and Sitecore employees for your support and for taking the time to travel &amp; speak at SUGCON.</p>
<p>In the future we plan to do SUGCON NA on Non-Symposium years.</p>
<p>I want to encourage everyone to share their knowledge. Without sharing there is no growth.</p>
<p>Go above and beyond. Look at our MVP&#8217;s, they have their regular jobs (60 hour weeks) but yet they go above and beyond and contribute. That is why they are MVP&#8217;s.</p>
<p>We as a community should be very proud to have pulled this off. The credit goes to each one of us!</p>
<p>You can visit <a href="http://www.sugcon.com/" target="_blank">www.sugcon.com</a> for more information.</p>
<p>I also want to thank the Speakers for participating in our Lip Sync video.</p>
<p>If you have any questions or comments, please feel free to get in touch with me.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Sitecore Chat on Twitter - #TwitterChat #SitecoreChat</title>
      <link>https://akshaysura.com/blog/sitecore-chat-on-twitter-twitterchat-sitecorechat/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/sitecore-chat-on-twitter-twitterchat-sitecorechat/</guid>
      <pubDate>Sun, 30 Aug 2015 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Twitter chat concept has been around for a while now and its wildly successful in discussing topics specific to the community. In our case, I would like to organize #SitecoreChat on Twitter to discuss Sitecore related topics regularly. These could be topics about bug fixes, features on a specific version, a specific piece of functionality such as WFFM, etc.]]></description>
      <content:encoded><![CDATA[<p>Twitter chat concept has been around for a while now and its wildly successful in discussing topics specific to the community. In our case, I would like to organize #SitecoreChat on Twitter to discuss Sitecore related topics regularly. These could be topics about bug fixes, features on a specific version, a specific piece of functionality such as WFFM, etc.</p>
<p>Gone are the days of IRC chats and since our community is spread across the world, the chance of all of us being on the same chat platform like skype are not possible. I got a lot of information about Twitter chat and its benefits and would like to try it out in our community to see if it helps. Most of the information of twitter chat was gathered from prominent web authorities and their links and name are listed at the bottom of this post.</p>
<p><strong>What is a Twitter chat?</strong><br />
A Twitter chat is a live Twitter event, usually moderated and focused around a general topic in our case Sitecore.  A Twitter chat is where a group of Twitter users meet at a pre-determined time to discuss a certain topic, using a designated hashtag (#) for each tweet contributed. A host or moderator will pose questions (designated with Q1, Q2…) to prompt responses from participants (using A1, A2…) and encourage interaction among the group. Chats typically last an hour. The same social customs apply—courtesy and respect—and it’s a great way to meet new people with similar interests. There are Twitter chats in almost every industry imaginable.</p>
<p>In our case the Hashtag <strong>#SitecoreChat</strong> will be used.</p>
<p><strong>Why participate in a Sitecore Chat (Twitter chat)?</strong></p>
<p>Sitecore chats aim to provide a chance to network and knowledge through shared interests. I am sure we can discover a whole host of useful tips, and super savvy people whom we might not have otherwise connected with.</p>
<p><strong>Tips for Sitecore Chat participants</strong></p>
<ol>
<li>Reply directly for targeted conversations with one or two people.</li>
<li>Include a &#8220;.&#8221; in front of an @ if you want your tweet to show up in all feeds. Do not start your tweet with @userhandle, this means that only the sender, the person mentioned and anyone who follows the person can see that tweet. Instead use a &#8220;.&#8221; if you are starting the tweet with a user handle.</li>
<li>It’s OK to dip in and out of a Twitter chat. Drop by for the time you have and don’t feel guilty if you can’t stay for the whole thing. Be polite and positive! 🙂</li>
<li>Don&#8217;t be afraid to contribute and jump in! It can be intimidating, but trust me, the moderators and participants will be glad to hear from you!</li>
<li>When answering a specific question or comment from another participant, use Twitter handles to identify who you’re speaking to in order to avoid confusion.</li>
<li>Remember Twitter chats are about connecting and learning, not selling your product. Use the time to provide as much value on the given topic as possible and show your expertise without over-promoting.</li>
<li>Always include the chat hashtag in your responses. In our case its #SitecoreChat</li>
<li>Follow up with people after the chat! Keep the conversation going or get to know fellow participants on a more personal level. You never know what new connections you can make!</li>
</ol>
<p><strong>Tools for a productive Sitecore Chat</strong></p>
<ol>
<li><a href="http://www.tweetchat.com/" target="_blank">TweetChat</a></li>
<li><a href="http://nurph.com/" target="_blank">Nurph</a></li>
<li><a href="http://twchat.com/" target="_blank">TwChat</a></li>
<li><a href="http://www.hootsuite.com/" target="_blank">HootSuite</a></li>
<li><a href="http://www.tweetdeck.com/" target="_blank">TweetDeck</a></li>
<li><a href="http://www.storify.com/" target="_blank">Storify</a></li>
<li><a href="http://twitterfall.com/" target="_blank">Twitterfall</a></li>
<li><a href="http://twubs.com/" target="_blank">Twubs</a></li>
</ol>
<p>&nbsp;</p>
<p>Hashtag <strong>#SitecoreChat</strong></p>
<p><strong>Event Date/Time:</strong> Will be determined soon based on the Community response.</p>
<p><strong>Sample Topics</strong></p>
<ol>
<li>Sitecore version specific bugs and possible fixes/workarounds</li>
<li>Features of a specific Sitecore version</li>
<li>WFFM with Sitecore MVC for version 8.x</li>
<li>SimpleInjector Issues with WFFM</li>
<li>xDB Usage thresholds</li>
<li>Real life experiences with xDB</li>
<li>etc.</li>
</ol>
<p><strong>Sources:</strong></p>
<p><a href="https://blog.bufferapp.com/twitter-chat-101" target="_blank">Buffer App</a></p>
<p><a href="http://www.forbes.com/sites/stevecooper/2013/09/30/the-ultimate-guide-to-hosting-a-tweet-chat/" target="_blank">Forbes</a></p>
<p>If this works out, this might be something we can move to community.sitecore.net. If you have any questions or comments please be sure to get in touch with me. Thank you.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Custom computed fields in Tealium Tag Management for Sitecore</title>
      <link>https://akshaysura.com/blog/custom-computed-fields-in-tealium-tag-management-for-sitecore/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/custom-computed-fields-in-tealium-tag-management-for-sitecore/</guid>
      <pubDate>Thu, 20 Aug 2015 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[In the last blog post we looked at Tealium tag management for Sitecore. In this post we will cover customization available to enabled computed fields. By default you have access to the following out of the box fields:]]></description>
      <content:encoded><![CDATA[<p>In the last blog post we looked at <a href="http://akshaysura.com/2015/08/19/tealium-tag-management-using-sitecore/" target="_blank">Tealium tag management for Sitecore</a>.  In this post we will cover customization available to enabled computed fields. By default you have access to the following out of the box fields:</p>
<p>item_id: &#8220;{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}&#8221;<br />
item_language: &#8220;en&#8221;<br />
item_name: &#8220;Home&#8221;<br />
item_path: &#8220;/sitecore/content/home&#8221;<br />
item_template_id: &#8220;{32B25AF5-4043-4776-BC20-098339109A4C}&#8221;<br />
item_template_name: &#8220;Home&#8221;</p>
<p>We also saw in the last post about how to add custom tags with fixed values (site_currency: [&#8220;USD&#8221;,&#8221;EUR&#8221;]). In the next post we will look at template specific tags and how we can render them.</p>
<p>For the purposes of this blog post, lets assume that we want the item url to be rendered as a tag. In order to make this available globally we can enable the Custom UDO property in /sitecore/system/Modules/Tealium Tag Management/Settings/Tealium Settings.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2015/08/Tealium1.png"><img loading="lazy" class="alignnone size-full wp-image-2256" src="http://akshaysura.com/wp-content/uploads/2015/08/Tealium1.png" alt="Tealium1" width="978" height="635" /></a></p>
<p>In order to do that we need to write some code which will inherit the IComputedFieldMapper interface.</p>
<pre><code>using System.Collections.Generic;

namespace Tealium.Sitecore.TagManagement.Mappings
{
    public interface IComputedFieldMapper
    {
        void AddComputedFields(IDictionary&lt;string, object&gt; utagParams);
    }
}
</code></pre>
<p>Follow the steps below:</p>
<ol>
<li>In your assembly add a reference to the Tealium.Sitecore.TagManagement.dll</li>
<li>Create a class TealiumComputedFields and inherit the IComputedFieldMapper, be sure to implement that interface</li>
<li>This will force you to define the AddComputedFields method, here add your code for the tags you would like to render
<pre><code>using Sitecore;
using Sitecore.Links;
using System.Collections.Generic;
using Tealium.Sitecore.TagManagement.Mappings;

namespace YOURNAMESPACE
{
    public class TealiumComputerFields : IComputedFieldMapper
    {
        public void AddComputedFields(IDictionary&lt;string, object&gt; utagParams)
        {
            utagParams.Add("item_url", LinkManager.GetItemUrl(Context.Item));

            //Sad part is you get only one of these and if you need to cater to multiple templates or render based on multiple templates
            //you have to end up using switch/if statements to do conditional logic based on template
            //switch (Context.Item.TemplateName)
            //{
            //    case "Product": //logic
            //        break;
            //    case "Article": //logic
            //        break;
            //}
        }
    }
}
</code></pre>
</li>
<li>Edit /sitecore/system/Modules/Tealium Tag Management/Settings/Tealium Settings item and check the Enable Custom UDO check box</li>
<li>Set the Custom UDO Type based on the information from your assembly (YOURNAMESPACE.TealiumComputerFields,YOURASSEMBLY)<br />
<a href="http://akshaysura.com/wp-content/uploads/2015/08/Tealium4.png"><img loading="lazy" class="alignnone size-full wp-image-2269" src="http://akshaysura.com/wp-content/uploads/2015/08/Tealium4.png" alt="Tealium4" width="927" height="636" /></a></li>
</ol>
<p>Sad part is that you only get one custom computed fields library and if you need to cater to multiple templates or render based on multiple templates, you have to end up using switch/if statements to do conditional logic based on template.</p>
<p>Here is the output generated:</p>
<pre><code>
&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
    

    &lt;title&gt;Sitecore Experience Platform&lt;/title&gt;
&lt;meta property="og:image" content=""  /&gt;
&lt;meta property="og:title" content="Sitecore Experience Platform"  /&gt;
&lt;meta property="og:url" content="/en"  /&gt;
&lt;meta property="twitter:image:src" content=""  /&gt;
&lt;meta property="twitter:card" content="summary"  /&gt;
&lt;meta property="twitter:title" content="Sitecore Experience Platform"  /&gt;
&lt;meta property="twitter:url" content="/en"  /&gt;

    &lt;!-- Global Header Scripts --&gt;&lt;!-- Page Header Scripts --&gt;
    &lt;link rel="canonical" href="http://www.google.com"/&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;script type="text/javascript"&gt; var utag_data = { 
item_id: "{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}", 
item_language: "en", 
item_name: "Home", 
item_path: "/sitecore/content/home", 
item_template_id: "{32B25AF5-4043-4776-BC20-098339109A4C}", 
item_template_name: "Home", 
site_currency: ["USD","EUR"], 
item_url: "/en", 
}; 
&lt;/script&gt; 
&lt;script type="text/javascript"&gt; (function(a,b,c,d){ a='//tags.tiqcdn.com/utag/testaccount/testprofile/dev/utag.js'; b=document; c='script'; d=b.createElement(c); d.src=a; d.type='text/java'+c; d.async=true; a=b.getElementsByTagName(c)[0]; a.parentNode.insertBefore(d,a); })(); &lt;/script&gt;



    &lt;!-- Global Start Body Scripts --&gt;&lt;!-- Page Start Body Scripts --&gt;
    &lt;header&gt;
        
    &lt;/header&gt;
    
    &lt;footer&gt;
        
    &lt;/footer&gt;
    &lt;!-- Global End Body Scripts --&gt;&lt;!-- Page End Body Scripts --&gt;
&lt;/body&gt;
&lt;/html&gt;

</code></pre>
<p>As usual if you have any questions or comments, please be sure to ping me.</p>
<p>Thanks.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Tealium tag management using Sitecore</title>
      <link>https://akshaysura.com/blog/tealium-tag-management-using-sitecore/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/tealium-tag-management-using-sitecore/</guid>
      <pubDate>Wed, 19 Aug 2015 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[“The Tealium iQ™ tag management system is a powerful and highly extensible solution that helps marketers easily manage their mission-critical technologies across web and mobile channels. Tealium iQ drives the complexity out of vendor tag deployments and is the cornerstone for achieving unified marketing, i.e., the ability to harmonize applications and data to drive superior cross-channel customer interactions.” – Quoted from Tealium website.]]></description>
      <content:encoded><![CDATA[<p>&#8220;The Tealium iQ™ tag management system is a powerful and highly extensible solution that helps marketers easily manage their mission-critical technologies across web and mobile channels. Tealium iQ drives the complexity out of vendor tag deployments and is the cornerstone for achieving unified marketing, i.e., the ability to harmonize applications and data to drive superior cross-channel customer interactions.&#8221; &#8211; Quoted from <a href="http://tealium.com/products/tealium-iq-tag-management-system/" target="_blank">Tealium website</a>.</p>
<p>According to <a href="https://en.wikipedia.org/wiki/Tag_management" target="_blank">Wikipedia</a>: &#8220;<strong>Tag management</strong> is the ability to manage user-generated tags (also known as categories, taxonomies or folksonomies) within collaborative software. Tag management features and processes are put in place to encourage cross-user consistency, navigation efficiency and compliance with an existing taxonomy.&#8221;</p>
<p>There are several paid providers available on the market, some of them are:</p>
<ul>
<li><a href="http://ensighten.com" target="_blank">Ensighten</a></li>
<li><a href="http://www.tagcommander.com/en/" target="_blank">Tag Commander</a></li>
<li><a href="http://www.tealium.com" target="_blank">Tealium</a></li>
<li><a href="http://www.searchdiscovery.com/satellite/" target="_blank">Satellite</a></li>
<li><a href="http://www.opentag.qubitproducts.com/" target="_blank">OpenTag</a></li>
<li><a href="http://supertag.datalicious.com/" target="_blank">Super Tag</a></li>
<li><a href="http://www.signal.co/products/tag/" target="_blank">Signal</a></li>
<li><a href="http://www.qubit.com/solutions/tag-management" target="_blank">Qubit</a></li>
<li><a href="http://tagman.com" target="_blank">TagMan</a></li>
</ul>
<p>Google provides a free tag manager called <a href="https://www.google.com/tagmanager/" target="_blank">Google Tag Manager</a>.</p>
<p><a href="https://moz.com/" target="_blank">Moz</a> has a great article about tag management <a href="https://moz.com/blog/what-is-tag-management" target="_blank">here</a> and Tealium also has an article about tag management available <a href="http://tealium.com/what-is-tag-management" target="_blank">here</a>.</p>
<p>For the purposes of this blog post lets stick to Tealium. Tealium released a Sitecore module which is available in the Sitecore <a href="https://marketplace.sitecore.net/Modules/T/Tealium_Tag_Management.aspx?sc_lang=en" target="_blank">Marketplace</a>.</p>
<p>&#8220;Tealium’s tag management integration with Sitecore enables marketers to easily deploy and manage their tag-based online marketing solutions on their own, without sapping valuable IT resources. To take advantage, Sitecore clients simply install the certified Tealium plug in and drop a single line of code onto their web pages. They can then add, edit and remove any digital marketing vendor tag through a convenient web-based interface without ever touching the web page.&#8221; &#8211; Quoted from the Sitecore <a href="https://marketplace.sitecore.net/Modules/T/Tealium_Tag_Management.aspx?sc_lang=en" target="_blank">Marketplace</a> module page.</p>
<p>One you are done installing the module from the Sitecore marketplace, you will end up with new items in /sitecore/templates/Tealium and /sitecore/system/modules/Tealium Tag Management folders. It also copies Tealium.Sitecore.TagManagement.dll and Tealium.Sitecore.TagManagement.config.</p>
<p>Now for configuration, head on over to /sitecore/system/Modules/Tealium Tag Management/Settings/Tealium Settings item where the most important part of the config is added:</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2015/08/Tealium1.png"><img loading="lazy" class="alignnone size-full wp-image-2256" src="http://akshaysura.com/wp-content/uploads/2015/08/Tealium1.png" alt="Tealium1" width="978" height="635" /></a></p>
<p>Provide the appropriate information:</p>
<p>Enable: The enable setting adds Tealium Tags<br />
Account: Tealium account name<br />
Profile: Tealium profile name<br />
Environment: Environment name (i.e. prod/qa/dev)<br />
Enable utag.sync.js: If selected, utag.sync.js is added to the head for A/B testing and personalization solutions such as Adobe Target, Optimizely, etc. Enable Custom UDO: If selected, you can add additional name/value pairs<br />
Custom UDO Type: Assembly/type for custom computed field(s) implementations</p>
<p>We will look into custom computed fields in the future blog posts.</p>
<p>Next go to /sitecore/system/Modules/Tealium Tag Management/Settings/Utag Data Mapping Settings and select appropriate boxes based on the information you need rendered. For the sake of this post I am going leave the default which has all the checkboxes checked.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2015/08/Tealium_2.png"><img loading="lazy" class="alignnone size-full wp-image-2258" src="http://akshaysura.com/wp-content/uploads/2015/08/Tealium_2.png" alt="Tealium_2" width="1010" height="462" /></a></p>
<p>You can also add additional custom params which get rendered without any logic. If you need multiple values, separate them by using comma (,) or pipe (|) delimiters.  I will leave it default for now.</p>
<p>Tealium for Sitecore has this nice feature which lets you add custom mapping based on template. What that means is that if you have a product template, you can render that template specific tags when that item is rendered. By default Tealium provides an example for a sample product template:</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2015/08/Tealium_3.png"><img loading="lazy" class="alignnone size-full wp-image-2260" src="http://akshaysura.com/wp-content/uploads/2015/08/Tealium_3.png" alt="Tealium_3" width="961" height="464" /></a></p>
<p>We will look at the template mapping in detail in the later posts.</p>
<p>The Tealium config is shown below:</p>
<pre><code>
&lt;!--
Purpose: This include file contains settings for the Tealium.Sitecore.TagManagement sitecore module
--&gt;
&lt;configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"&gt;
  &lt;sitecore&gt;
    &lt;events&gt;
      &lt;event name="publish:end"&gt;
        &lt;handler type="Tealium.Sitecore.TagManagement.Events.PublishEnd, Tealium.Sitecore.TagManagement" method="Refresh" /&gt;
      &lt;/event&gt;
      &lt;event name="publish:end:remote"&gt;
        &lt;handler type="Tealium.Sitecore.TagManagement.Events.PublishEnd, Tealium.Sitecore.TagManagement" method="Refresh" /&gt;
      &lt;/event&gt;

      &lt;event name="publish:complete"&gt;
        &lt;handler type="Tealium.Sitecore.TagManagement.Events.PublishEnd, Tealium.Sitecore.TagManagement" method="Refresh" /&gt;
      &lt;/event&gt;
      &lt;event name="publish:complete:remote"&gt;
        &lt;handler type="Tealium.Sitecore.TagManagement.Events.PublishEnd, Tealium.Sitecore.TagManagement" method="Refresh" /&gt;
      &lt;/event&gt;
    &lt;/events&gt;

    &lt;settings&gt;
      &lt;setting name="Tealium.DataProvider" value="Tealium.Sitecore.TagManagement.Data.UtagDataProvider, Tealium.Sitecore.TagManagement"&gt;&lt;/setting&gt;
      &lt;setting name="Tealium.MappingsProvider" value="Tealium.Sitecore.TagManagement.Mappings.TealiumMappingsProvider, Tealium.Sitecore.TagManagement"&gt;&lt;/setting&gt;
      &lt;setting name="Tealium.TealiumSettings.ItemID" value="{A5F3FD05-62D4-468A-BB54-6C9760F701A5}"&gt;&lt;/setting&gt;
      &lt;setting name="Tealium.UtagDataMappingSettings.ItemID" value="{D77D079B-6A79-490D-B4F5-408D773FC3E8}"&gt;&lt;/setting&gt;
      &lt;setting name="Tealium.Utag.Js.UriFormat" value="//tags.tiqcdn.com/utag/{0}/{1}/{2}/utag.js"&gt;&lt;/setting&gt;
      &lt;setting name="Tealium.Utag.Sync.Js.UriFormat" value="//tags.tiqcdn.com/utag/{0}/{1}/{2}/utag.sync.js"&gt;&lt;/setting&gt;
    &lt;/settings&gt;
  &lt;/sitecore&gt;
&lt;/configuration&gt;
</code></pre>
<p>The next task is to include this in any layouts you might be using, to do this:</p>
<ol>
<li>Add a reference to Tealium.Sitecore.TagManagement.dll</li>
<li>In your layout file add the following at the top:
<pre><code>
@using Sitecore.Mvc
@using Tealium.Sitecore.TagManagement
@{ var tealiumManager = TealiumFactory.TealiumManager;}
</code></pre>
</li>
<li>Next, add the following to the &lt;head&gt; tag:
<pre><code>
&lt;head&gt;
    &lt;meta charset="utf-8"&gt;
    &lt;meta http-equiv="X-UA-Compatible" content="IE=edge"&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes"&gt;

    &lt;!-- bundles for css --&gt;
    &lt;!-- bundles for scripts --&gt;

    @tealiumManager.HeadInjections()
&lt;/head&gt;
</code></pre>
</li>
<li>Finally, add the following to the first line after &lt;body&gt; tag:
<pre><code>
&lt;body&gt;
    @tealiumManager.BodyInjections()
&lt;/body&gt;
</code></pre>
</li>
</ol>
<p>Now lets run the code. Here is the output:</p>
<pre><code>
&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;meta charset="utf-8"&gt;
    &lt;meta http-equiv="X-UA-Compatible" content="IE=edge"&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes"&gt;

    &lt;!-- bundles for css --&gt;
    &lt;!-- bundles for scripts --&gt;
    
    &lt;title&gt;Sitecore Experience Platform&lt;/title&gt;
&lt;meta property="og:image" content=""  /&gt;
&lt;meta property="og:title" content="Sitecore Experience Platform"  /&gt;
&lt;meta property="og:url" content="/en"  /&gt;
&lt;meta property="twitter:image:src" content=""  /&gt;
&lt;meta property="twitter:card" content="summary"  /&gt;
&lt;meta property="twitter:title" content="Sitecore Experience Platform"  /&gt;
&lt;meta property="twitter:url" content="/en"  /&gt;

    &lt;!-- Global Header Scripts --&gt;&lt;!-- Page Header Scripts --&gt;
    &lt;link rel="canonical" href="http://www.google.com"/&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;script type="text/javascript"&gt; var utag_data = { 
item_id: "{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}", 
item_language: "en", 
item_name: "Home", 
item_path: "/sitecore/content/home", 
item_template_id: "{32B25AF5-4043-4776-BC20-098339109A4C}", 
item_template_name: "Home", 
site_currency: ["USD","EUR"], 
}; 
&lt;/script&gt; 
&lt;script type="text/javascript"&gt; (function(a,b,c,d){ a='//tags.tiqcdn.com/utag/testaccount/testprofile/dev/utag.js'; b=document; c='script'; d=b.createElement(c); d.src=a; d.type='text/java'+c; d.async=true; a=b.getElementsByTagName(c)[0]; a.parentNode.insertBefore(d,a); })(); &lt;/script&gt;
    &lt;!-- Global Start Body Scripts --&gt;&lt;!-- Page Start Body Scripts --&gt;
    &lt;header&gt;
    &lt;/header&gt;
    
    &lt;footer&gt;
    &lt;/footer&gt;
    &lt;!-- Global End Body Scripts --&gt;&lt;!-- Page End Body Scripts --&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>If you have any questions or concerns please get in touch with me. In the next post I will cover the customizations.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
    </item>
    <item>
      <title>Testable and reusable Sitecore MVC solution using SimpleInjector, Glass 4, NUnit and NSubstitute</title>
      <link>https://akshaysura.com/blog/testable-and-reusable-sitecore-mvc-solution-using-simpleinjector-glass-4-nunit-and-nsubstitute/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/testable-and-reusable-sitecore-mvc-solution-using-simpleinjector-glass-4-nunit-and-nsubstitute/</guid>
      <pubDate>Mon, 17 Aug 2015 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[I have been meaning to extract out this solution for quite a while but never got time to do this. Even now I would like to publish a lot more code but unfortunately that is going to take a while!]]></description>
      <content:encoded><![CDATA[<p>I have been meaning to extract out this solution for quite a while but never got time to do this. Even now I would like to publish a lot more code but unfortunately that is going to take a while!</p>
<p>I pushed an update to <a href="https://github.com/akshaysura/sitecoremvc" target="_blank">GitHub </a>(https://github.com/akshaysura/sitecoremvc) with the initial code. It currently does not have any unit tests but I will be pushing another update shortly.</p>
<p>First I would like to thank <a href="https://twitter.com/mikeedwards83" target="_blank">Mike Edwards</a> and <a href="https://twitter.com/cardinal252" target="_blank">Nathanael Mann</a> for helping me jump start my Glass knowledge. I was able to pick up Glass in no time.</p>
<p>The purpose of this solution is to give you a baseline solution on Sitecore MVC implementation. I have been using a flavor of this for a year now on various projects and found it to be very useful and setup in a way that lends itself to reuse and test-ability.</p>
<p>Now a note to the snuggle bunnies who just see the negative in the world: when a guy posts Sitecore tips you do not find what is wrong with it, you acknowledge that fact that this person is sharing it his/her knowledge and if you have a better way of doing it, say so! It does not cost you any more to be nice! If you know of a way to make this better, share it.</p>
<p>On another note, share your knowledge, no point in safeguarding it! The more you share the better the community gets.</p>
<p>Now back to the solution. It is no surprise that I love Simple Injector, its my favorite. You can read all about it in the links below:</p>
<p><a href="https://simpleinjector.org/" target="_blank">https://simpleinjector.org/</a></p>
<p><a href="http://simpleinjector.readthedocs.org/en/latest/" target="_blank">Simple Injector Documentation</a></p>
<p><a href="http://www.palmmedia.de/blog/2011/8/30/ioc-container-benchmark-performance-comparison" target="_blank">IoC Benchmark Performance</a></p>
<p><a href="http://cardinalcore.co.uk/2015/01/28/ioc-battle-in-2015-results-using-ninject-think-again/" target="_blank">IoC Battle Results</a></p>
<p>I found the combination of SimpleInjector, Glass4 and Sitecore MVC to be very stable and fast. In comparison we ran tests of 1000 active users, hitting the site at the rate of 635 requests per second, and the load being taken by two load balanced servers. The servers did not flinch and stayed at 35% CPU or below. This is a great example of how this can help you. Of course having good caching wouldn&#8217;t hurt!</p>
<p>I also tried out Kam&#8217;s Unicorn with <a href="http://www.nuget.org/packages/Unicorn/" target="_blank">Rainbow</a>, I have to say that its fast and easy to configure. Best of all it was seamless which is what attracted me to try it out!</p>
<p>I plan on adding a lot more functionality in the coming weeks. The concepts in this solution are nothing new but how all of it is brought together might be interesting. Typically code isn&#8217;t shared in the Sitecore community when it comes to the actual building of the solution, but if its a module of course people are willing to freely share.</p>
<p>I am also going to include several examples of how to decouple Sitecore from a solution with real world examples. You are encouraged to pick and choose the code as you wish.</p>
<p>One thing to point out is the way Simple Injector is being initialized. Typically this can be done via Global.asax, WebActivatorEx and/or a Pipeline (the Sitecore way). I chose to do it the Sitecore way and initialize it via config and a pipeline.</p>
<pre><code class="language-xml">
&lt;?xml version="1.0" encoding="utf-8" ?&gt;
&lt;configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"
               xmlns:set="http://www.sitecore.net/xmlconfig/set/"&gt;
  &lt;sitecore&gt;
    &lt;pipelines&gt;
      &lt;initialize&gt;
        &lt;!-- This could be done via global.asax, webactivatorex but doing it the Sitecore way --&gt;
        &lt;processor type="Sitecore.Mvc.Pipelines.Loader.InitializeControllerFactory, Sitecore.Mvc"
                   set:type="SitecoreMVC.SCExtensions.Pipelines.DI.InitializeControllerFactory, SitecoreMVC.SCExtensions" /&gt;
      &lt;/initialize&gt;
    &lt;/pipelines&gt;
  &lt;/sitecore&gt;
&lt;/configuration&gt;
</code></pre>
<pre><code>
using SimpleInjector;
using Sitecore.Pipelines;
using SitecoreMVC.SCExtensions.DI;
using System;
using System.Linq;
using System.Web.Mvc;

namespace SitecoreMVC.SCExtensions.Pipelines.DI
{
    public class InitializeControllerFactory
    {
        public virtual void Process(PipelineArgs args)
        {
            SetControllerFactory(args);
        }

        protected virtual void SetControllerFactory(PipelineArgs args)
        {
            var container = new Container();

            PackageExtensions.RegisterPackages(container, AppDomain.CurrentDomain.GetAssemblies().Where(a => a.FullName.StartsWith("SitecoreMVC."))); // you can customize this to what ever you need

            var simpleInjectorControllerFactory = new SimpleInjectorControllerFactory(container);
            var sitecoreControllerFactory = new Sitecore.Mvc.Controllers.SitecoreControllerFactory(simpleInjectorControllerFactory);

            ControllerBuilder.Current.SetControllerFactory(sitecoreControllerFactory);
        }
    }
}


</code></pre>
<pre><code>
using SimpleInjector;
using System;
using System.Web.Mvc;
using System.Web.Routing;

namespace SitecoreMVC.SCExtensions.DI
{
    /// &lt;summary&gt;
    /// Inspiration: http://blog.istern.dk/2012/10/23/sitecore-mvc-new-ninject-controller-factory-clean-version/
    /// &lt;/summary&gt;
    public class SimpleInjectorControllerFactory : DefaultControllerFactory
    {
        private Container _container;

        public SimpleInjectorControllerFactory(Container container)
        {
            _container = container;
        }

        protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        {
            return (IController)_container.GetInstance(controllerType);
        }
    }
}

</code></pre>
<p>If you have any questions or comments please let me know.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
    </item>
    <item>
      <title>Execute Sitecore Powershell from Sitecron Schedule Job</title>
      <link>https://akshaysura.com/blog/execute-sitecore-powershell-from-sitecron-schedule-job/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/execute-sitecore-powershell-from-sitecron-schedule-job/</guid>
      <pubDate>Wed, 05 Aug 2015 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Yes you heard it right. I was planning on writing a couple of sample jobs to do indexing etc but then I realized why not make it a lot more powerful. So I decided to add support to run Powershell scripts.]]></description>
      <content:encoded><![CDATA[<p>Yes you heard it right.  I was planning on writing a couple of sample jobs to do indexing etc but then I realized why not make it a lot more powerful.  So I decided to add support to run Powershell scripts.</p>
<p>As I mentioned earlier you can implement the IJob interface and implement what ever you choose to.  I am including a default Powershell execute job which can take in the parameters you would like to pass to your script and specify a link to the Powershell Script item.</p>
<p>This gives you a lot of power in terms of the kind of functionality you can build. Better yet, you can tweak this functionality and re-run it without recompiling the code.</p>
<p>First I would like to go over the fields and what you can do with them:</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2015/08/powershell_sitecron.png"><img loading="lazy" class="alignnone size-large wp-image-2237" src="http://akshaysura.com/wp-content/uploads/2015/08/powershell_sitecron-1024x345.png" alt="powershell_sitecron" width="900" height="303" /></a></p>
<ol>
<li>Type: class namespace, assembly (e.g. Sitecron.Powershell.ExecuteScript, Sitecron)</li>
<li>Cron Expression: 0 15 10 * * ? (e.g. Fire at 10:15am every day)</li>
<li>Parameters: test=1&amp;p=first (e.g. you can pass in anything like a guid/some value or values similar to the Sitecore parameters so that you can get a NameValueCollection. It all depends on your need.)</li>
<li>Items: Select one or more items you need to do the job. For instance if you need specific items to do import/rearrange items/rename etc.</li>
</ol>
<p>I tried to make this generic so that based on your needs you can implement the IJob Quartz.NET interface and achieve the functionality you need.</p>
<p>From my testing the scheduled tasks always executed on time every time.</p>
<p>The other thing to note is that as part of the output, you can output the execution time and next scheduled execution time.</p>
<pre><code class="language-csharp">
Log.Info(string.Format("Sitecron: Powershell.ExecuteScript Instance {0} of ExecuteScript Job - {5}Parameters: {1} ScriptIDs: {2} {5}Fired at: {3} 
{5}Next Scheduled For:{4}", context.JobDetail.Key, rawParameters, scriptIDs, context.FireTimeUtc.Value.ToString("r"), context.NextFireTimeUtc.Value.ToString("r"), Environment.NewLine), this);
</code></pre>
<p>Now for the Powershell script. Here is the code I implemented so that its part of Sitecron and you can utilize it or implement your own. Needless to say that in order for this Powershell job to run you would need to install Sitecore PowerShell module 3.1+</p>
<p>Adam Najmanowicz was nice enough to take time to suggest ways to implement it.</p>
<pre><code class="language-csharp">
using Cognifide.PowerShell.Core.Host;
using Cognifide.PowerShell.Core.Settings;
using Quartz;
using Sitecore.Configuration;
using Sitecore.Data;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecron.SitecronSettings;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;

namespace Sitecron.Powershell
{
    public class ExecuteScript : IJob
    {
        public void Execute(IJobExecutionContext context)
        {
            JobDataMap dataMap = context.JobDetail.JobDataMap;

            string scriptIDs = dataMap.GetString(FieldNames.Items);
            string rawParameters = dataMap.GetString(FieldNames.Parameters);

            Log.Info(string.Format("Sitecron: Powershell.ExecuteScript Instance {0} of ExecuteScript Job - {5}Parameters: {1} ScriptIDs: {2} {5}Fired at: {3} {5}Next Scheduled For:{4}", context.JobDetail.Key, rawParameters, scriptIDs, context.FireTimeUtc.Value.ToString("r"), context.NextFireTimeUtc.Value.ToString("r"), Environment.NewLine), this);

            if (!string.IsNullOrEmpty(scriptIDs))
            {
                Database masterDb = Factory.GetDatabase("master");

                List&lt;Item&gt; scriptItems = new List&lt;Item&gt;();
                string id = scriptIDs.Split('|').FirstOrDefault(); //only doing the first script item, running multiple scripts can cause issues especially if they call other scripts etc.

                Item scriptItem = masterDb.GetItem(new ID(id));

                Log.Info(string.Format("Sitecron: Powershell.ExecuteScript: Adding Script: {0} {1}", scriptItem.Name, id), this);

                NameValueCollection parameters = Sitecore.Web.WebUtil.ParseUrlParameters(rawParameters);

                Run(scriptItem, parameters);
            }
            else
                Log.Info("Sitecron: Powershell.ExecuteScript: No scripts found to execute!", this);
        }


        private void Run(Item speScript, NameValueCollection parameters)
        {
            var script = speScript[ScriptItemFieldNames.Script];
            if (!string.IsNullOrEmpty(script))
            {
                Log.Info(string.Format("Sitecron: Powershell.ExecuteScript: Running Script: {0} {1}", speScript.Name, speScript.ID.ToString()), this);

                //reset session for each script otherwise the position of the items and env vars set by the previous script will be inherited by the subsequent scripts
                using (var session = ScriptSessionManager.NewSession(ApplicationNames.Default, true))
                {
                    //here we are passing the param collection to the script
                    var paramItems = parameters.AllKeys.SelectMany(parameters.GetValues, (k, v) =&gt; new { Key = k, Value = v });
                    foreach (var p in paramItems)
                    {
                        if (String.IsNullOrEmpty(p.Key)) continue;
                        if (String.IsNullOrEmpty(p.Value)) continue;

                        if (session.GetVariable(p.Key) == null)
                        {
                            session.SetVariable(p.Key, p.Value);
                        }
                    }

                    session.SetExecutedScript(speScript);
                    session.SetItemLocationContext(speScript);
                    session.ExecuteScriptPart(script);
                }
            }

        }


        #region Multiple Scripts Scenario
        ////public void Execute(IJobExecutionContext context)
        ////{
        ////    JobDataMap dataMap = context.JobDetail.JobDataMap;

        ////    string scriptIDs = dataMap.GetString(FieldNames.Items);
        ////    string rawParameters = dataMap.GetString(FieldNames.Parameters);

        ////    Log.Info(string.Format("Sitecron: Powershell.ExecuteScript Instance {0} of ExecuteScript Job - {4}Parameters: {1} {4}Fired at: {2} {4}Next Scheduled For:{3}", context.JobDetail.Key, scriptParams, context.FireTimeUtc.Value.ToString("r"), context.NextFireTimeUtc.Value.ToString("r"), Environment.NewLine), this);

        ////    if (!string.IsNullOrEmpty(scriptIDs))
        ////    {
        ////        Database masterDb = Factory.GetDatabase("master");

        ////        List&lt;Item&gt; scriptItems = new List&lt;Item&gt;();
        ////        string[] ids = scriptIDs.Split('|');
        ////        foreach (string id in ids)
        ////        {
        ////            scriptItems.Add(masterDb.GetItem(new ID(id)));
        ////            Log.Info(string.Format("Sitecron: Powershell.ExecuteScript: Adding Script: {0}", id), this);
        ////        }

        ////        NameValueCollection parameters = Sitecore.Web.WebUtil.ParseUrlParameters(rawParameters);

        ////        Run(scriptItems.ToArray(), parameters);
        ////    }
        ////    else
        ////        Log.Info("Sitecron: Powershell.ExecuteScript: No scripts found to execute!", this);
        ////}


        //////general bad practive here to allow multiple powershell scripts as there might be dependency
        //////of one script on another etc, should be one script per scheduled task
        //////this is shown as an example
        ////private void Run(Item[] speScripts, NameValueCollection parameters)
        ////{
        ////    foreach (var item in speScripts)
        ////    {
        ////        var script = item[ScriptItemFieldNames.Script];
        ////        if (!String.IsNullOrEmpty(script))
        ////        {
        ////            Log.Info(string.Format("Sitecron: Powershell.ExecuteScript: Running Script: {0} {1}", item.Name, item.ID.ToString()), this);

        ////            //reset session for each script otherwise the position of the items and env vars set by the previous script will be inherited by the subsequent scripts
        ////            using (var session = ScriptSessionManager.NewSession(ApplicationNames.Default, true))
        ////            {
        ////                //here we are passing the same param collection to all the scripts
        ////                var paramItems = parameters.AllKeys.SelectMany(parameters.GetValues, (k, v) =&gt; new { Key = k, Value = v });
        ////                foreach (var p in paramItems)
        ////                { 
        ////                    if (String.IsNullOrEmpty(p.Key)) continue;
        ////                    if (String.IsNullOrEmpty(p.Value)) continue;

        ////                    if (session.GetVariable(p.Key) == null)
        ////                    {
        ////                        session.SetVariable(p.Key, p.Value);
        ////                    }
        ////                }

        ////                session.SetExecutedScript(item);
        ////                session.SetItemLocationContext(item);
        ////                session.ExecuteScriptPart(script);
        ////            }
        ////        }
        ////    }
        ////}
        #endregion
    }
}

</code></pre>
<p>One thing to note here is that although we have the ability to select multiple items, in this case multiple Powershell Scripts, it is not a good practice to execute multiple scripts via code consecutively.  There could be inter-dependencies, one of those scripts could be calling another script(s) etc. creating issues where there shouldn&#8217;t be one.</p>
<p>The intent is to select one item of type &#8220;PowerShell Script&#8221;.  If multiple are selected this specific implementation will only pick the first one and ignore the others.  I have included commented code which is capable of executing multiple script items but use it at your own risk.</p>
<p>I am posting the update to the module to the Sitecore Marketplace shortly. I updated GitHub.</p>
<p>GitHub: <a href="https://github.com/akshaysura/Sitecron" target="_blank">https://github.com/akshaysura/Sitecron</a><br />
Market Place: <a href="https://marketplace.sitecore.net/Modules/S/Sitecron" target="_blank">https://marketplace.sitecore.net/Modules/S/Sitecron</a><br />
For help with Cron Expressions you can use <a href="http://www.cronmaker.com/" target="_blank">http://www.cronmaker.com/</a></p>
<p>If you have any questions or comments, please get in touch with me.</p>
<p>&nbsp;</p>
]]></content:encoded>
    </item>
    <item>
      <title>Parameters in a Sitecron Job - Sitecore Scheduler Module updated! version 1.1.6</title>
      <link>https://akshaysura.com/blog/parameters-in-a-sitecron-job-sitecore-scheduler-module-updated-version-1-1-6/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/parameters-in-a-sitecron-job-sitecore-scheduler-module-updated-version-1-1-6/</guid>
      <pubDate>Mon, 03 Aug 2015 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[So it’s been a while since I have been using this module in production for a while and very happy with it. I made a few changes to help improve the usability. In this iteration I added the option to pass in parameters into the job when it runs. I have a nice surprise feature coming up shortly which will tie into this.]]></description>
      <content:encoded><![CDATA[<p>So it&#8217;s been a while since I have been using this module in production for a while and very happy with it.  I made a few changes to help improve the usability.  In this iteration I added the option to pass in parameters into the job when it runs.  I have a nice surprise feature coming up shortly which will tie into this.</p>
<p>First I added a few checks and logging which helps us better manage the scheduled jobs. With the parameters, you can pass in parameters in which ever format as you like.  It&#8217;s the job&#8217;s responsibility to utilize the parameters being passed to it.</p>
<p>For instance you can pass in &#8220;Testing123&#8221; or &#8220;someval=1&amp;who=me&amp;whichone=first&#8221;, in the later we could use the Sitecore util and treat it similar to the Sitecore parameters.</p>
<p>I modified the Sitecron Job template to include a Parameters field. If you choose to add a value you could do so in the job(s) in /sitecore/system/Modules/Sitecron</p>
<p>I setup two jobs:</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2015/08/Sitecron_116-2.png"><img loading="lazy" class="alignnone size-large wp-image-2230" src="http://akshaysura.com/wp-content/uploads/2015/08/Sitecron_116-2-1024x248.png" alt="Sitecron_116-2" width="900" height="218" /></a></p>
<p>and <a href="http://akshaysura.com/wp-content/uploads/2015/08/Sitecron_116-1.png"><img loading="lazy" class="alignnone size-large wp-image-2231" src="http://akshaysura.com/wp-content/uploads/2015/08/Sitecron_116-1-1024x254.png" alt="Sitecron_116-1" width="900" height="223" /></a></p>
<p>Here is a sample test class which pulls in the parameters:</p>
<pre><code>
using Quartz;
using Sitecore.Diagnostics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SampleJob.Parameters
{
    public class TestParams : IJob
    {
        public void Execute(IJobExecutionContext context)
        {
            JobDataMap dataMap = context.JobDetail.JobDataMap;

            string jobParams = dataMap.GetString("Parameters");

            Log.Info(string.Format("Instance {0} of TestParams Job - {4}Parameters: {1} {4}Fired at: {2} {4}Next Scheduled For:{3}"
, context.JobDetail.Key, jobParams, context.FireTimeUtc.Value.ToString("r")
, context.NextFireTimeUtc.Value.ToString("r"), Environment.NewLine), this);
        }
    }
}

</code></pre>
<p>Once the job executes you can see that it passes in the parameter values in these log entries:</p>
<pre><code>
DefaultQuartzScheduler_Worker-1 15:44:00 INFO  Instance DEFAULT.403e4e4c-2029-4311-ba12-7df4538a12ab of TestParams Job - 
Parameters: this is the parameters value 
Fired at: Mon, 03 Aug 2015 19:44:00 GMT 
Next Scheduled For:Mon, 03 Aug 2015 19:46:00 GMT

DefaultQuartzScheduler_Worker-2 15:45:00 INFO  Instance DEFAULT.12b63339-d791-42a2-a85b-a19f77b41db8 of TestParams Job - 
Parameters: print=1&target=me&group=first 
Fired at: Mon, 03 Aug 2015 19:45:00 GMT 
Next Scheduled For:Mon, 03 Aug 2015 19:48:00 GMT
</code></pre>
<p>Notice that you can output the execution time and the next scheduled execution time. This can be very useful.</p>
<p>&nbsp;<br />
GitHub: <a href="https://github.com/akshaysura/Sitecron" target="_blank">https://github.com/akshaysura/Sitecron</a><br />
Market Place: <a href="https://marketplace.sitecore.net/Modules/S/Sitecron" target="_blank">https://marketplace.sitecore.net/Modules/S/Sitecron</a><br />
For help with Cron Expressions you can use <a href="http://www.cronmaker.com/" target="_blank">http://www.cronmaker.com/</a><br />
&nbsp;<br />
If you need more information please do get in touch with me. I posted the update to the marketplace, I am waiting for the approval. Also I updated the GitHub.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Smart and Incremental publish using SiteCron for Sitecore</title>
      <link>https://akshaysura.com/blog/smart-and-incremental-publish-using-sitecron-for-sitecore/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/smart-and-incremental-publish-using-sitecron-for-sitecore/</guid>
      <pubDate>Thu, 25 Jun 2015 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[In this blog post we will be looking into building two SiteCron jobs, one for Smart publish and one for Incremental publish.]]></description>
      <content:encoded><![CDATA[<p>In this blog post we will be looking into building two SiteCron jobs, one for Smart publish and one for Incremental publish.</p>
<ol>
<li>Add a reference to Quartz.dll in your project</li>
<li>Implement a new class called SmartSitePublishJob which implements Quartz.IJob, sample code is shown below:
<pre><code>    public class SmartSitePublishJob : IJob
    {
        public void Execute(IJobExecutionContext context)
        {
            Log.Info("SmartSitePublishJob Execute - Start", this);

            Database master = Sitecore.Configuration.Factory.GetDatabase("master");

            Database[] targetDBs = new Database[] { Sitecore.Configuration.Factory.GetDatabase("web") }; //you can get this via config if you need customize targets
            Language[] languages = languages = LanguageManager.GetLanguages(master).ToArray();

            Sitecore.Publishing.PublishManager.PublishSmart(master, targetDBs, languages);

            Log.Info("SmartSitePublishJob Execute - End", this);
        }
    }
</code></pre>
</li>
<li>Implement a new class called IncrementalSitePublishJob which implements Quartz.IJob, sample code is shown below:
<pre><code>    public class IncrementalSitePublishJob : IJob
    {
        public void Execute(IJobExecutionContext context)
        {
            Log.Info("IncrementalSitePublishJob Execute - Start", this);

            Database master = Sitecore.Configuration.Factory.GetDatabase("master");

            Database[] targetDBs = new Database[] { Sitecore.Configuration.Factory.GetDatabase("web") }; //you can get this via config if you need customize targets
            Language[] languages = languages = LanguageManager.GetLanguages(master).ToArray();

            Sitecore.Publishing.PublishManager.PublishIncremental(master, targetDBs, languages);

            Log.Info("IncrementalSitePublishJob Execute - End", this);
        }
    }
</code></pre>
</li>
<li>Build and deploy to the Sitecore folder</li>
<li>Login to Sitecore admin and go to /sitecore/system/Modules/Sitecron</li>
<li>Add a new SiteCron job and name it Scheduled Smart Publish and set the values accordingly (Mon &#8211; Fri, run at 6:15AM):<br />
<a href="http://akshaysura.com/wp-content/uploads/2015/06/SiteCron_Smart_Publish.png"><img loading="lazy" class="alignnone size-full wp-image-2220" src="http://akshaysura.com/wp-content/uploads/2015/06/SiteCron_Smart_Publish.png" alt="SiteCron_Smart_Publish" width="997" height="405" /></a></li>
<li>Add a new SiteCron job and name it Scheduled Incremental Publish and set the values accordingly (Mon &#8211; Fri, run at 3:30AM):<br />
<a href="http://akshaysura.com/wp-content/uploads/2015/06/SiteCron_Incremental_Publish.png"><img loading="lazy" class="alignnone size-full wp-image-2221" src="http://akshaysura.com/wp-content/uploads/2015/06/SiteCron_Incremental_Publish.png" alt="SiteCron_Incremental_Publish" width="1006" height="399" /></a></li>
<li>Once saved the jobs are added to the scheduler and triggered accordingly.</li>
</ol>
<p>Here are some useful links:</p>
<p>Video: <a href="http://learnsitecore.akshaysura.com/video/sitecrondemo/" target="_blank">SiteCron Demo</a><br />
GitHub: <a href="https://github.com/akshaysura/Sitecron" target="_blank">https://github.com/akshaysura/Sitecron</a><br />
Market Place: <a href="https://marketplace.sitecore.net/Modules/S/Sitecron" target="_blank">https://marketplace.sitecore.net/Modules/S/Sitecron</a><br />
For help with Cron Expressions you can use <a href="http://www.cronmaker.com/" target="_blank">http://www.cronmaker.com/</a><br />
You can get more information about the Cron triggers and examples from Quartz.NET Scheduler website at: <a href="http://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/crontriggers.html" target="_blank">http://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/crontriggers.html</a></p>
<p>If you have any questions or comments, please get in touch with me.</p>
]]></content:encoded>
    </item>
    <item>
      <title>SiteCron Sitecore module for your everyday scheduling needs</title>
      <link>https://akshaysura.com/blog/sitecron-sitecore-module-for-your-everyday-scheduling-needs/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/sitecron-sitecore-module-for-your-everyday-scheduling-needs/</guid>
      <pubDate>Tue, 23 Jun 2015 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[SiteCron is a scheduling module based on Quartz.NET Job Scheduler. SiteCron can be used to create simple or complex schedules to execute jobs. This functionality is implemented using Quartz’s CronTrigger.]]></description>
      <content:encoded><![CDATA[<p>SiteCron is a scheduling module based on Quartz.NET Job Scheduler. SiteCron can be used to create simple or complex schedules to execute jobs. This functionality is implemented using Quartz&#8217;s CronTrigger.</p>
<p>&#8220;Quartz.NET is a pure .NET library written in C# and is a port of very popular open source Java job scheduling framework, Quartz.&#8221;</p>
<p>Cron has been around for a long time and is known for its powerful scheduling capabilities. CronTrigger in Quartz is based on the scheduling capabilities of cron and uses &#8220;cron expressions&#8221; to execute the jobs. Cron expressions specify the condition to fire the job such as execute this job at 8AM each day.</p>
<p>The current implementation of SiteCron only uses CronTrigger functionality of Quartz, which is more useful than the SimpleTrigger. It lets you have a job-firing schedule that recurs based on calendar type scenarios rather than on the exactly specified intervals of SimpleTrigger. The interval based jobs can be run using Sitecore agents.</p>
<p>CronTrigger lets you fire jobs based on schedules such as:</p>
<ul>
<li>Fire job every friday at 9PM</li>
<li>Fire job every day at 8AM from monday to thursday</li>
<li>Fire job every 3 minutes from 2PM to 4PM</li>
<li>Fire job at 3 pm on monday and wednesday</li>
</ul>
<p>Module installation is simple using the package installation in the Sitecore admin. Once the module is installed it gets initialized via the Initialize pipeline.</p>
<pre><code class="language-xml">    
    &lt;pipelines&gt;
      &lt;initialize&gt;
        &lt;processor type="Sitecron.InitializeSitecron, Sitecron" /&gt;
      &lt;/initialize&gt;
    &lt;/pipelines&gt;
</code></pre>
<p>Each time a job is saved or deleted, SiteCron reloads all schedules for consistency. There are OnSaved and OnDeleted events implemented to take care of this.</p>
<pre><code class="language-xml">    
    &lt;events&gt;
      &lt;event name="item:saved"&gt;
        &lt;handler type="Sitecron.Events.SitecronSavedHandler, Sitecron" method="OnItemSaved"/&gt;
      &lt;/event&gt;
      &lt;event name="item:deleted"&gt;
        &lt;handler type="Sitecron.Events.SitecronDeletedHandler, Sitecron" method="OnItemDeleted"/&gt;
      &lt;/event&gt;
    &lt;/events&gt;
</code></pre>
<p>The implementation of the CronTrigger is done using the code below:</p>
<pre><code>
    IJobDetail jobDetail = JobBuilder.Create(jobType).Build();

    ITrigger trigger = TriggerBuilder.Create()
        .WithIdentity(i.Name)
        .WithCronSchedule(i[cronExpressionField])
        .ForJob(jobDetail)
        .Build();
    scheduler.ScheduleJob(jobDetail, trigger);
</code></pre>
<p>Here is an example of the IJob implementation:</p>
<pre><code>using Quartz;
using Sitecore.Diagnostics;

namespace Sitecron.Samples
{
    public class SampleLogJob : IJob
    {
        public void Execute(IJobExecutionContext context)
        {
            Log.Info("Sample Log Job - Add Log Entry.", this);
        }
    }
}
</code></pre>
<p>The module has a check for Publishing.PublishingInstance setting, this is mainly used when Scalability settings are enabled. If you are in a multi-server environment, we want the scheduler to trigger only on the primary designated server. This setting will ensure that the check to validate the current instance to the publishing instance is verified.</p>
<p>Here are the steps to implement a job for SiteCron:</p>
<ol>
<li>Add a reference to Quartz.dll in your project</li>
<li>Implement a new class which implements Quartz.IJob</li>
<li>Build and deploy to the Sitecore folder</li>
<li>Login to Sitecore admin and go to /sitecore/system/Modules/Sitecron</li>
<li>Add a new SiteCron job</li>
<li>Set the Type to Class Namespace, Assembly</li>
<li>Set the Cron Expression for the schedule and save</li>
</ol>
<p>I plan on using this for Scheduled site publishes at specific times during the day to avoid peak traffic.</p>
<p>For more information on CronTriggers please visit the following urls:<br />
<a href="http://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/crontriggers.html" target="_blank">http://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/crontriggers.html</a></p>
<p>For help with Cron Expressions you can use http://www.cronmaker.com/</p>
<p><b>Expressions	</b><br />
0 15 10 * * ?	Fire at 10:15am every day<br />
0 15 20 * * ? *	Fire at 10:15pm (20:15) every day<br />
0 15 10 * * ? 2015	Fire at 10:15am every day during the year 2015<br />
0 15 10 ? * MON-FRI	Fire at 10:15am every Monday, Tuesday, Wednesday, Thursday and Friday<br />
0 15 10 15 * ?	Fire at 10:15am on the 15th day of every month<br />
0 15 10 L * ?	Fire at 10:15am on the last day of every month<br />
0 0 12 1/5 * ?	Fire at 12pm (noon) every 5 days every month, starting on the first day of the month.</p>
<p>It&#8217;s alive!! SiteCron published on the Sitecore marketplace!  <a href="https://marketplace.sitecore.net/Modules/S/Sitecron.aspx?sc_lang=en" target="_blank">https://marketplace.sitecore.net/Modules/S/Sitecron.aspx?sc_lang=en</a></p>
<p>If you have any questions or comments, please be sure to reach out. </p>
]]></content:encoded>
    </item>
    <item>
      <title>A different road to Sitecore 8 Upgrade - The final chapter: Presentation!</title>
      <link>https://akshaysura.com/blog/a-different-road-to-sitecore-8-upgrade-the-final-chapter-presentation/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/a-different-road-to-sitecore-8-upgrade-the-final-chapter-presentation/</guid>
      <pubDate>Wed, 03 Jun 2015 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[This post rounds out the series with presentation magic! Following my hypothetical 😉 theme, the next challenge is to somehow translate the presentation from webforms to MVC. Along with moving content, we would also have to set the presentation of these items.]]></description>
      <content:encoded><![CDATA[<p>This post rounds out the series with presentation magic! Following my hypothetical 😉 theme, the next challenge is to somehow translate the presentation from webforms to MVC. Along with moving content, we would also have to set the presentation of these items.</p>
<p>I know that in my hypothetical situation, I have made it a bit more difficult by not only upgrading to Sitecore 8 but also moving from webforms to MVC. Life would be easier if I just stayed with webforms!!! Nope!</p>
<p>I am glad in this situation I decided to go with Sitecore MVC. Was it the right decision, absolutely! Was it easy, absolutely not!</p>
<p>With the final solution it makes it feasible to have an infrastructure which forces re-usability and test-ability. No complaints about that.</p>
<p>Now back to presentation. The first thing you need to do is to keep a tally of the sublayouts to views translations in a spreadsheet. There might be cases where you have consolidate multiple sublayouts into one view or the other way round. You might also have a need for one sublayout to be replaced by multiple views.</p>
<p>In my case, I went with this simple assumption: For a specific kind of presentable item, the standard values presentation on that template should match the functionality in the webforms solution and the MVC solution. Both the standard values presentation (in webforms and MVC) might not match in terms of the number of presentation items but they will match in what they render.</p>
<p>Once that simple rule is set in stone (well for the most part, there will always be exceptions, right?), the rest should be achievable by scripts.</p>
<p>I am not an MVC guru by any means and I feel that in technology its not what you know its how you learn it!. I pride myself in picking up technology as I work, as do a lot of Sitecore folks I know!</p>
<p>For scripting I always use Sitecore PowerShell. I love using PowerShell commandlets and rolling out libraries in solutions to get complicated tasks done and have a repeatable process.</p>
<p>In this scenario we are going to do the following:</p>
<ol>
<li>Traverse through the current content tree ( you define what to go through, but typically be sitecore\content\home)
<ol>
<li>For each item we look to see if there is presentation on the standard values, if so we save it</li>
<li>We do a diff of the standard values and the item in questions and store the diff</li>
<li>At the end of this process, we should have an items.xml (diff&#8217;ed presentation for each item) and a standardvalues.xml</li>
</ol>
</li>
<li>Take these XML definitions and transfer them to the new site</li>
<li>Build an xml file called presentationdefinitions.xml which has the translation from sublayouts to views</li>
<li>At this point the assumption is that you have set the standard values on the new Sitecore 8 instance, so that template items have base UI</li>
<li>Traverse through the new content tree (this would be the same since we are importing content package from current Sitecore 6.5+)
<ol>
<li>While traversing the tree which should be the same as the current tree, we reset presentation</li>
<li>Look up the item in the items.xml from the current content site, find the translated presentation</li>
<li>Set the current item with the diff&#8217;ed and translated (sublayouts to views) presentation items</li>
</ol>
</li>
<li>Publish and enjoy!</li>
</ol>
<p><strong>Current PowerShell Commandlet in Sitecore 6.5+</strong><br />
The commandlet which I have in the Sitecore 6.5+ solution shown below. The main purpose is to catalog standard values, use the standard values to get diff&#8217;s on item presentation and also keep tabs of unique sublayouts used across the current 6.5+ website.</p>
<pre><code class="language-csharp">    [Cmdlet("Store", "Presentation")]
    public class PresentationCommandlet : BaseCommand
    {
        [Parameter]
        public string PassID { get; set; }

        XDocument docStandardValues = new XDocument(new XDeclaration("1.0", "utf-8", "yes"), new XElement("templates"));
        XDocument docItems = new XDocument(new XDeclaration("1.0", "utf-8", "yes"), new XElement("items"));
        XDocument docUniqueRenderings = new XDocument(new XDeclaration("1.0", "utf-8", "yes"), new XElement("renderings"));

        protected override void ProcessRecord()
        {
            //get the master database
            Sitecore.Data.Database master = Sitecore.Configuration.Factory.GetDatabase("master");
            var selectItem = master.GetItem(new ID(PassID));
            if (selectItem != null)
            {
                LoopForChildren(selectItem);
            }

            docStandardValues.Save(@"D:\inetpub\Sitecore\Website\temp\xml\StandardValues.xml");
            docItems.Save(@"D:\inetpub\Sitecore\Website\temp\xml\Items.xml");
            docUniqueRenderings.Save(@"D:\inetpub\Sitecore\Website\temp\xml\UniqueRenderings.xml");
        }

        private XElement StoreStandardValuesPresentation(TemplateItem template)
        {
            XElement svaluesNode = new XElement("temp");
            Item standardValues = template.StandardValues;

            if (!IsStandardValuesLoaded(template.ID.ToString(), ref svaluesNode) &amp;&amp; standardValues != null)
            {
                svaluesNode = new XElement("template", new XAttribute("id", template.ID.ToString()), new XAttribute("nm", template.Name));

                string rawLayout = Sitecore.Data.Fields.LayoutField.GetFieldValue(standardValues.Fields[Sitecore.FieldIDs.LayoutField]);
                Sitecore.Layouts.LayoutDefinition layout = Sitecore.Layouts.LayoutDefinition.Parse(rawLayout);

                for (int i = 0; i &lt; layout.Devices.Count; i++)
                {
                    Sitecore.Layouts.DeviceDefinition device = layout.Devices[i] as Sitecore.Layouts.DeviceDefinition;

                    if (device != null)
                    {
                        for (int j = 0; j &lt; device.Renderings.Count; j++)
                        {
                            Sitecore.Layouts.RenderingDefinition rendering = device.Renderings[j] as Sitecore.Layouts.RenderingDefinition;

                            if (rendering != null)
                            {
                                if (!string.IsNullOrEmpty(rendering.ItemID))
                                {
                                    Database master = Sitecore.Configuration.Factory.GetDatabase("master");

                                    Item renderingItem = master.GetItem(rendering.ItemID);

                                    string dataSource = string.IsNullOrEmpty(rendering.Datasource) ? "" : rendering.Datasource;

                                    XElement rNode = new XElement("r", new XAttribute("nm", renderingItem.DisplayName)
                                        , new XAttribute("ph", rendering.Placeholder), new XAttribute("id", rendering.ItemID), new XAttribute("ds", dataSource));

                                    svaluesNode.Add(rNode);
                                }
                            }
                        }
                    }
                }

                docStandardValues.Element("templates").Add(svaluesNode);
            }

            return svaluesNode;
        }

        private void StoreItemPresentation(Item itm, XElement svNode)
        {
            if (itm != null)
            {
                XElement itmNode = new XElement("item", new XAttribute("id", itm.ID.ToString()), new XAttribute("nm", itm.Name));

                string rawLayout = Sitecore.Data.Fields.LayoutField.GetFieldValue(itm.Fields[Sitecore.FieldIDs.LayoutField]);
                Sitecore.Layouts.LayoutDefinition layout = Sitecore.Layouts.LayoutDefinition.Parse(rawLayout);

                for (int i = 0; i &lt; layout.Devices.Count; i++)
                {
                    Sitecore.Layouts.DeviceDefinition device = layout.Devices[i] as Sitecore.Layouts.DeviceDefinition;

                    if (device != null)
                    {
                        for (int j = 0; j &lt; device.Renderings.Count; j++)
                        {
                            Sitecore.Layouts.RenderingDefinition rendering = device.Renderings[j] as Sitecore.Layouts.RenderingDefinition;

                            if (rendering != null)
                            {
                                if (!string.IsNullOrEmpty(rendering.ItemID))
                                {
                                    Database master = Sitecore.Configuration.Factory.GetDatabase("master");

                                    Item renderingItem = master.GetItem(rendering.ItemID);

                                    string dataSource = string.IsNullOrEmpty(rendering.Datasource) ? "" : rendering.Datasource;

                                    //check if there are rendering which match the standard values exactly, if they donot record them
                                    //we are only worried about one device, the default device, you can extend it further for all devices and versions
                                    var svItems = (from t in svNode.Descendants("r")
                                                   where t.Attribute("ph").Value == rendering.Placeholder
                                                    &amp;&amp; t.Attribute("id").Value == rendering.ItemID
                                                    &amp;&amp; t.Attribute("ds").Value == dataSource
                                                   select t).ToList();

                                    if (svItems != null &amp;&amp; svItems.Count() == 0)
                                    {
                                        StoreUniquePresentationDetails(renderingItem.DisplayName, rendering.ItemID);

                                        try
                                        {
                                            //depending on your situation, you would want to do before j-1 or after j+1 so that you get the right placement
                                            Sitecore.Layouts.RenderingDefinition nextRendering = device.Renderings[j - 1] as Sitecore.Layouts.RenderingDefinition;
                                            string nextDataSource = string.IsNullOrEmpty(nextRendering.Datasource) ? "" : nextRendering.Datasource;
                                            Item nextRenderingItem = master.GetItem(nextRendering.ItemID);

                                            XElement rNode = new XElement("r", new XAttribute("nm", renderingItem.DisplayName)
                                            , new XAttribute("ph", rendering.Placeholder), new XAttribute("id", rendering.ItemID), new XAttribute("ds", dataSource),
                                                new XElement("aftr", new XAttribute("nm", nextRenderingItem.DisplayName)
                                            , new XAttribute("ph", nextRendering.Placeholder), new XAttribute("id", nextRendering.ItemID), new XAttribute("ds", nextDataSource)));

                                            itmNode.Add(rNode);
                                        }
                                        catch
                                        {
                                            XElement rNode = new XElement("r", new XAttribute("nm", renderingItem.DisplayName)
                                                , new XAttribute("ph", rendering.Placeholder), new XAttribute("id", rendering.ItemID), new XAttribute("ds", dataSource));

                                            itmNode.Add(rNode);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                docItems.Element("items").Add(itmNode);
            }
        }

        private void StoreUniquePresentationDetails(string renderingName, string renderingID)
        {
            var items = (from t in docUniqueRenderings.Descendants("r")
                         where t.Attribute("id").Value == renderingID
                select t).ToList();

            if (items != null &amp;&amp; items.Count() == 0)
            {
                XElement itmNode = new XElement("r", new XAttribute("id", renderingID), new XAttribute("nm", renderingName));
                docUniqueRenderings.Element("renderings").Add(itmNode);
            }
        }


        private bool IsStandardValuesLoaded(string templateID, ref XElement svNode)
        {
            var svItems = (from t in docStandardValues.Descendants("template")
                          where t.Attribute("id").Value == templateID
                          select t).ToList();

            if (svItems != null &amp;&amp; svItems.Count() == 1)
                svNode = svItems.FirstOrDefault();

            return (svItems!= null &amp;&amp; svItems.Count() == 1);
        }

        private void LoopForChildren(Item itm)
        {
            if (!string.IsNullOrEmpty(itm[Sitecore.FieldIDs.LayoutField]))
            {
                XElement svNode = StoreStandardValuesPresentation(itm.Template); //get svNode if not recorded, create and get it

                //get the standard values node
                //look at the current item's layout details
                //ignore whats in the standard values
                //add whats not in the standard values

                StoreItemPresentation(itm, svNode);
            }

            //Iterate though children
            Sitecore.Collections.ChildList childList = itm.Children;
            foreach (Item child in childList)
            {
                LoopForChildren(child);
            }
        }

    }
</code></pre>
<p>This commandlet produced the following sample outputs.</p>
<p><strong>Items.xml</strong></p>
<pre><code class="language-xml"> 
&lt;items&gt;
  &lt;item id="{AEEA1D57-7EF3-4EAC-ADDC-80DC0179C911}" nm="About" /&gt;
  &lt;item id="{A8352EF1-0A3B-4677-9D4D-3F30DD148652}" nm="FAQ"&gt;
    &lt;r nm="FAQs" ph="phRight" id="{8603954E-6778-4042-A748-7F5A08E74DF3}" ds=""&gt;
      &lt;aftr nm="PageContent" ph="phRight" id="{EDC9B361-F1FE-4417-B5F2-03B279D85546}" ds="" /&gt;
    &lt;/r&gt;
  &lt;/item&gt;
  &lt;item id="{AA1C4479-01F2-47AB-ABDC-9CD4725A7956}" nm="Interview"&gt;
    &lt;r nm="WYSIWYG" ph="phRight" id="{655A9D00-4544-405D-86DF-CED7242A527E}" ds="/sitecore/content/Shared/Callouts/General/Gallery/Back to Videos"&gt;
      &lt;aftr nm="SuccessStoryDetail" ph="phRight" id="{F3F20D5B-F99A-4453-ABB4-17F019B69197}" ds="" /&gt;
    &lt;/r&gt;
    &lt;r nm="PageNav" ph="phBottom" id="{42C1A071-D928-4C57-9286-59E741F440D7}" ds=""&gt;
      &lt;aftr nm="Footer" ph="phContent" id="{FBAD96B5-BB5E-4C1D-8097-F9B9AC0F8227}" ds="/sitecore/content/Shared/Content/Footer" /&gt;
    &lt;/r&gt;
  &lt;/item&gt;
&lt;/items&gt;
</code></pre>
<p><strong>UniqueRenderings.xml</strong></p>
<pre><code class="language-xml"> 
&lt;renderings&gt;
  &lt;r id="{655A9D00-4544-405D-86DF-CED7242A527E}" nm="WYSIWYG" /&gt;
  &lt;r id="{824FEA5C-77D9-4A3E-9470-B61AE008352C}" nm="ModuleGraphic" /&gt;
  &lt;r id="{258D2E0E-779A-4550-9866-950E078367B3}" nm="LeftNav" /&gt;
  &lt;r id="{42C1A071-D928-4C57-9286-59E741F440D7}" nm="PageNav" /&gt;
  &lt;r id="{8603954E-6778-4042-A748-7F5A08E74DF3}" nm="FAQs" /&gt;
  &lt;r id="{8E6B1563-8CE7-48F7-B564-C70AB5597FAA}" nm="OneColumn" /&gt;
&lt;/renderings&gt;
</code></pre>
<p><strong>StandardValues.xml</strong></p>
<pre><code>  
&lt;templates&gt;
  &lt;template id="{14F438E4-6ABF-4EA0-B47B-AD3EAB71A81E}" nm="Content Page"&gt;
    &lt;r nm="UtilityNav" ph="phHeader" id="{87E9CC14-778D-4FF7-A4A4-F6DA9B1DE94B}" ds="" /&gt;
    &lt;r nm="TopLogoSearch" ph="phHeader" id="{BF899841-DC37-44DF-883E-41CE87ABE402}" ds="" /&gt;
    &lt;r nm="MainNav" ph="phHeader" id="{315B8893-6C04-4ED2-927F-6FA19F98D07F}" ds="" /&gt;
    &lt;r nm="HeaderPromo" ph="phHeader" id="{E1D82FBB-E3A7-4C2C-A456-C0CC7B73ABEE}" ds="" /&gt;
    &lt;r nm="TwoColumn" ph="phContent" id="{166F724C-6F1E-441B-894A-70658349D757}" ds="" /&gt;
    &lt;r nm="PageTitleBreadcrumb" ph="phBreadCrumb" id="{17D8A9D2-E4DA-443E-AFAF-B0027E251E99}" ds="" /&gt;
    &lt;r nm="LeftNavigation" ph="phLeft" id="{829B1FCC-F53E-4EA8-BB8B-8CB8F7BF182E}" ds="" /&gt;
    &lt;r nm="PageContent" ph="phRight" id="{EDC9B361-F1FE-4417-B5F2-03B279D85546}" ds="" /&gt;
    &lt;r nm="SocialSidebar" ph="phContent" id="{CB3D54FB-A436-48CE-BFF8-D9967D088D74}" ds="" /&gt;
    &lt;r nm="Footer" ph="phContent" id="{FBAD96B5-BB5E-4C1D-8097-F9B9AC0F8227}" ds="/sitecore/content/Shared/Content/Footer" /&gt;
    &lt;r nm="PageNav" ph="phBottom" id="{42C1A071-D928-4C57-9286-59E741F440D7}" ds="" /&gt;
  &lt;/template&gt;
  &lt;template id="{B960CBE4-381F-4A2B-9F44-A43C7A991A0B}" nm="RSS Feed" /&gt;
  &lt;template id="{DD8BD3DB-1254-43D4-9F2E-51F259C521E8}" nm="Landing Page"&gt;
    &lt;r nm="LandingPageForm" ph="phLeft" id="{A449EB92-AF25-4253-8C57-979553C39197}" ds="query:ancestor-or-self::*/Form Panel" /&gt;
  &lt;/template&gt;
&lt;/templates&gt;
</code></pre>
<p>&nbsp;<br />
Once this is done transfer the items.xml file to a location under the new Sitecore 8.x site. Define the mapping for the old sublayout to the new renderings and store them in PresentationDefinitions.xml</p>
<p><strong>PresentationDefinitions.xml</strong></p>
<pre><code class="language-xml"> 
&lt;pds&gt;
  &lt;pd oldid="{8A845008-E600-42BC-8339-B048175BBC7A}" nm="ContentTabs"&gt;
    &lt;r id="{4948ECCA-76EB-4457-B1C0-EEF4AE178DF4}" /&gt;
  &lt;/pd&gt;
  &lt;pd oldid="{42C1A071-D928-4C57-9286-59E741F440D7}" nm="PageNav"&gt;
    &lt;r id="{22C158CC-65E6-4328-8601-CBD78FDE8EE1}" /&gt;
    &lt;r id="{B460E0BD-E278-4291-9E39-1D9E6FE3D526}" /&gt;
  &lt;/pd&gt;
&lt;/pds&gt;
</code></pre>
<p>&nbsp;<br />
This is just a prototype but you could essentially customize it to your heart&#8217;s content. Store parameters, have the ability to push to different place holder than the origin etc.</p>
<p>Once this is done, you will be running the following script on the new Sitecore 8.x site.</p>
<pre><code>
    [Cmdlet("Fix", "Presentation")]
    public class FixPresentation : PSCmdlet
    {
        [Parameter(Mandatory = true)]
        [ValidateNotNullOrEmpty]
        public string XMLFolderPath { get; set; }

        [Parameter(Mandatory = true)]
        [ValidateNotNullOrEmpty]
        public string RootID { get; set; }

        XDocument docItems;
        XDocument docPresentationDefinitions;

        const string ItemsFileName = "items.xml";
        const string PresentationDefinitionsFileName = "presentationdefinitions.xml";

        protected override void ProcessRecord()
        {
            if (ValidFolderFiles(XMLFolderPath))
            {
                //get the master database
                Database master = Factory.GetDatabase("master");
                var selectItem = master.GetItem(new ID(RootID));
                if (selectItem != null)
                {
                    LoopForChildren(selectItem);
                }
            }
            else
            {
                WriteObject(string.Format("Could not find {0} and {1} in {2} folder.", ItemsFileName, PresentationDefinitionsFileName, XMLFolderPath));
            }
        }

        private void ResetPresentation(Item itm)
        {
            List&lt;Field&gt; fields = new List&lt;Field&gt;();
            fields.Add(itm.Fields[FieldIDs.LayoutField]); //shared layout field

            //reset versioned layout fields
            fields.AddRange(
                    from v in (IEnumerable&lt;Item&gt;)itm.Versions.GetVersions(true)
                    select v.Fields[FieldIDs.FinalLayoutField]);

            using (new Sitecore.SecurityModel.SecurityDisabler())
            {
                using (new EditContext(itm))
                {
                    foreach (Field layoutFieldsToReset in fields)
                    {
                        layoutFieldsToReset.Item.Editing.BeginEdit();
                        layoutFieldsToReset.Reset();
                        layoutFieldsToReset.Item.Editing.EndEdit();
                    }
                }
            }
        }

        private bool IsFoundInItemXml(string itemID, ref XElement itmNode)
        {
            var items = (from i in docItems.Descendants("item")
                           where i.Attribute("id").Value == itemID
                           select i).ToList();

            if (items != null &amp;&amp; items.Count() == 1)
                itmNode = items.FirstOrDefault();

            return (items != null &amp;&amp; items.Count() == 1);
        }

        private bool FoundInPresentatinDefinitionsXml(string itemID, ref XElement itmNode)
        {
            var items = (from i in docPresentationDefinitions.Descendants("pd")
                         where i.Attribute("oldid").Value == itemID
                         select i).ToList();

            if (items != null &amp;&amp; items.Count() == 1)
                itmNode = items.FirstOrDefault();

            return (items != null &amp;&amp; items.Count() == 1);
        }

        private void FixItemPresentation(Item itm, XElement itmNode)
        {
            //loop through the r items find replacements, add to the item layout
            using (new Sitecore.SecurityModel.SecurityDisabler())
            {
                // Get the layout definitions and the device definition
                LayoutField layoutField = new LayoutField(itm.Fields[Sitecore.FieldIDs.LayoutField]);
                LayoutDefinition layoutDefinition = LayoutDefinition.Parse(layoutField.Value);

                DeviceDefinition deviceDefinition = layoutDefinition.GetDevice("{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}");

                foreach (XElement r in itmNode.Descendants("r"))
                {
                    //for every sublayout/rendering we need to replace, find and entry from the presentation definitions xml
                    XElement xmlItem = new XElement("temp");
                    if (FoundInPresentatinDefinitionsXml(r.Attribute("id").Value, ref xmlItem))
                    {
                        //this allows us to have one old sublayout/rendering to be replaced by multiple new sublayouts/renderings
                        foreach (XElement newr in xmlItem.Descendants("r"))
                        {
                            //Create a RenderingDefinition and add the reference of sublayout or rendering
                            RenderingDefinition renderingDefinition = new RenderingDefinition();
                            //future enhancement can include changing the place holder and datasource
                            renderingDefinition.ItemID = newr.Attribute("id").Value; //pull the value for the new rendering and keep the same ph and ds
                            //Set placeholder where the rendering should be displayed
                            renderingDefinition.Placeholder = r.Attribute("ph").Value;
                            // Set the datasource of sublayout, if any
                            renderingDefinition.Datasource = r.Attribute("ds").Value;

                            XElement aftr = (from i in r.Descendants("aftr")
                                         select i).FirstOrDefault();

                            if (aftr != null)
                            {
                                //find the matching control in presentation details
                                // find that matched new rendering id and find it in the layout rendering
                                // if found, insert after that index


                                XElement xmlAfterItem = new XElement("temp");
                                if (FoundInPresentatinDefinitionsXml(aftr.Attribute("id").Value, ref xmlAfterItem))
                                {
                                    XElement xmlNewAfterItem = xmlAfterItem.Descendants("r").FirstOrDefault();

                                    RenderingDefinition afterRendering = null;

                                    if (string.IsNullOrEmpty(aftr.Attribute("ds").Value))
                                    {
                                        afterRendering = (from RenderingDefinition rd in deviceDefinition.Renderings
                                                          where rd.ItemID == xmlNewAfterItem.Attribute("id").Value
                                                          &amp;&amp; rd.Datasource == null
                                                          &amp;&amp; rd.Placeholder == aftr.Attribute("ph").Value
                                                          select rd).FirstOrDefault();

                                    }

                                    if (afterRendering == null) //if we couldnt find the item with ds as null try with ds = ""
                                    {
                                        afterRendering = (from RenderingDefinition rd in deviceDefinition.Renderings
                                                          where rd.ItemID == xmlNewAfterItem.Attribute("id").Value
                                                          &amp;&amp; rd.Datasource == aftr.Attribute("ds").Value
                                                          &amp;&amp; rd.Placeholder == aftr.Attribute("ph").Value
                                                          select rd).FirstOrDefault();
                                    }

                                    if (afterRendering != null)
                                    {
                                        var index = deviceDefinition.Renderings.IndexOf(afterRendering);
                                        if (index &gt;= 0)
                                        {
                                            //insert the rendering at a specific location
                                            deviceDefinition.Renderings.Insert((index + 1), renderingDefinition);
                                            continue; //skip to next
                                        }
                                    }
                                }
                            }

                            //Add the RenderingReference to the DeviceDefinition
                            deviceDefinition.AddRendering(renderingDefinition);
                        }
                    }
                }
                // Save the layout changes
                using (new EditContext(itm))
                {
                    layoutField.Value = layoutDefinition.ToXml();
                }
            }
        }

        public void AddRendering(DeviceDefinition deviceDefinition, RenderingDefinition renderingDefinition)
        {
            Assert.ArgumentNotNull(renderingDefinition, "renderingDefinition");
            ArrayList renderings = deviceDefinition.Renderings;
            if (renderings == null)
            {
                renderings = new ArrayList();
                deviceDefinition.Renderings = renderings;
            }
            renderings.Add(renderingDefinition);
        }

        private void LoopForChildren(Item itm)
        {
            if (!string.IsNullOrEmpty(itm[Sitecore.FieldIDs.LayoutField]))
            {
                WriteObject("Processing: " + itm.Paths.Path);
                XElement xmlItem = new XElement("temp");

                if (IsFoundInItemXml(itm.ID.ToString(), ref xmlItem))
                {
                    //assuming that we already setup the standard values for all applicable templates with display

                    //reset presentation
                    ResetPresentation(itm);

                    if (xmlItem.Descendants("r").Any())
                    {
                        FixItemPresentation(itm, xmlItem);
                    }
                }
            }

            //Iterate though children
            Sitecore.Collections.ChildList childList = itm.Children;
            foreach (Item child in childList)
            {
                LoopForChildren(child);
            }
        }

        private bool ValidFolderFiles(string path)
        {
            bool valid = false;
            if (Directory.Exists(path))
            {
                string[] files = Directory.GetFiles(path, "*.xml", SearchOption.AllDirectories);

                if (files.Where(f =&gt; f.ToLower().Contains(ItemsFileName) || f.ToLower().Contains(PresentationDefinitionsFileName)).Count() == 2)
                {
                    valid = true;

                    foreach (string s in files)
                    {
                        if (s.ToLower().Contains(ItemsFileName))
                            docItems = XDocument.Load(s);
                        else if (s.ToLower().Contains(PresentationDefinitionsFileName))
                            docPresentationDefinitions = XDocument.Load(s);
                    }
                }
            }

            return valid;
        }
    }
</code></pre>
<p>There you go, most of the work is done. There will be one off&#8217;s which you have to either run a script or manually do them.</p>
<p>If you have any questions or comments please let me know.<br />
&nbsp;</p>
]]></content:encoded>
    </item>
    <item>
      <title>A different road to Sitecore 8 Upgrade - Part 2</title>
      <link>https://akshaysura.com/blog/a-different-road-to-sitecore-8-upgrade-part-2/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/a-different-road-to-sitecore-8-upgrade-part-2/</guid>
      <pubDate>Thu, 28 May 2015 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[This is the continuation of the blog post “A different road to Sitecore 8 Upgrade”. I got a lot of great feedback and response from the previous post. I am rushing to get this one out as there seems to be a lot of people stuck in this situation.]]></description>
      <content:encoded><![CDATA[<p>This is the continuation of the blog post &#8220;<a class="row-title" title="Edit “A different road to Sitecore 8 Upgrade”" href="http://akshaysura.com/2015/05/22/a-different-road-to-sitecore-8-upgrade/">A different road to Sitecore 8 Upgrade</a>&#8221;. I got a lot of great feedback and response from the previous post.  I am rushing to get this one out as there seems to be a lot of people stuck in this situation.</p>
<p>Once we have determined the reasons to upgrade next steps include provisioning the infrastructure and have a game plan. The infrastructure I propose looks like below:</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2015/05/Future_Dev.png"><img loading="lazy" class="alignnone size-large wp-image-2177" src="http://akshaysura.com/wp-content/uploads/2015/05/Future_Dev.png" alt="Future_Dev" width="431" height="343" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2015/05/Future_QA.png"><img loading="lazy" class="alignnone size-large wp-image-2176" src="http://akshaysura.com/wp-content/uploads/2015/05/Future_QA.png" alt="Future_QA" width="685" height="335" /></a><br />
<a href="http://akshaysura.com/wp-content/uploads/2015/05/Future_Prod.png"><img loading="lazy" class="alignnone size-full wp-image-2175" src="http://akshaysura.com/wp-content/uploads/2015/05/Future_Prod.png" alt="Future_Prod" width="692" height="424" /></a><br />
Now that the infrastructure is setup, here are a few items for your consideration:</p>
<ul>
<li>Depending on the site you are dealing with, chances are that this is not a one man job!</li>
<li>Please contact your Sitecore rep to get temporary licenses for the duplicate Sitecore 8 instances. Sitecore is more than happy to give out temp licenses, as long as they know the purpose. <strong>(IMPORTANT)</strong></li>
<li>You need to plan it as you do for any other project. This is not a one day job.</li>
<li>By this time you have identified areas of the code and modules which would have to be completely overhauled.</li>
<li>Remember the blog post assumptions. In this hypothetical situation we are going from web forms into MVC. That by itself is a major hurdle since the modules you are using might not be compatible with MVC.</li>
<li>You can use the information from these posts for 6.5x web forms to 8.x web forms, just ignore my MVC ramblings.</li>
<li>I strongly recommend using a cloud based Mongo. Not a lot of places have infrastructure capability for Mongo in house. There are a lot of vendors out there. I found <a href="https://objectrocket.com/" target="_blank">Object Rocket</a> the best from my trials.</li>
<li>Taking a Mongo DBA course, does not make you a seasoned Mongo DBA.</li>
<li>You need to have redundancy for your Mongo environment.</li>
</ul>
<p><strong>Wants</strong></p>
<p>We want to move to Sitecore MVC and do it the right way with Dependency Injection with unit testing, the whole 9 yards!</p>
<p><strong>The Start</strong></p>
<p>Finally! the start can be daunting. Assuming that you keep the UI the same, it should not be difficult to map out how the MVC layout and views are going to be split up.</p>
<p>I am not an MVC guru by any means and I feel that in technology its not what you know its how you learn it!.</p>
<p>Follow your development methodologies and build the site in Sitecore MVC. I will be posting a few videos/blog posts about this soon. During development, its critical you keep a tally of the sublayouts you have with matching view(s) in the new solution.</p>
<p>The premise is that a &#8220;Product&#8221; page Standard Values in the old solution will have a similar Standard Values in the MVC solution, with a few view(s) changed/split-up/consolidated.</p>
<p>Once the solution is built and tested. You would need to come up with a game plan.</p>
<p>One Launch day and leading up to it, you would follow this process several times:</p>
<ol>
<li>Clean Sitecore 8.x dbs installed (optional/but recommended)</li>
<li>Package Content and Templates from the old system</li>
<li>Install Content and Templates from the new system</li>
<li>Install Layouts folder package from the new MVC Solution</li>
<li>Install Templates package from the new MVC Solution which has the standard values to match the new layouts and renderings</li>
<li>Run script to reset presentation and set appropriate presentation items in the tree (more on this coming soon)</li>
<li>Make any one off content tweaks</li>
<li>Test</li>
<li>Fix any issues found in the scripts and standard values</li>
<li>Repeat</li>
</ol>
<p>Once the above is done enough times you will have a fairly seamless process. The advantage to this solution is as follows:</p>
<ol>
<li>You do not have to do on server upgrade for each Sitecore instance</li>
<li>The new site is on the same box as the old one</li>
<li>The current (old) 6.5x site is preserved</li>
<li>All you need is a simple IIS change to point the host to the Sitecore 8 site on the same instance</li>
<li>If something goes wrong you can just switch in IIS and within a minute your old site is back!!</li>
</ol>
<p>I will follow up with at least one post about presentation details transfer/mapping.</p>
<p>If you have any questions or comments, be sure to get in touch with me.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
    </item>
    <item>
      <title>A different road to Sitecore 8 Upgrade</title>
      <link>https://akshaysura.com/blog/a-different-road-to-sitecore-8-upgrade/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/a-different-road-to-sitecore-8-upgrade/</guid>
      <pubDate>Fri, 22 May 2015 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[This series of posts will concentrate on the challenges of upgrading from an older version (6.x, 7.0 to 7.2) of Sitecore to the latest and greatest. I don’t need to bore you with all the cool things you get with Sitecore 8. Let me sum it up with one image:]]></description>
      <content:encoded><![CDATA[<p>This series of posts will concentrate on the challenges of upgrading from an older version (6.x, 7.0 to 7.2) of Sitecore to the latest and greatest. I don&#8217;t need to bore you with all the cool things you get with Sitecore 8. Let me sum it up with one image:</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2015/04/sitecore8.png"><img loading="lazy" class="alignnone size-large wp-image-2124" src="http://akshaysura.com/wp-content/uploads/2015/04/sitecore8-1024x618.png" alt="sitecore8" width="900" height="543" /></a></p>
<p>Our journey starts with a lot of decisions:</p>
<ul>
<li>Is the upgrade worth the cost?</li>
<li>My current system works fine, can we do the upgrade later?</li>
<li>How much is this going to cost?</li>
<li>Do we need a new infrastructure?</li>
<li>We have no internal resources who know Mongo, What do I do about MongoDB?</li>
<li>&#8212; and more?</li>
</ul>
<p>Some of the things which will help you make your decision:</p>
<ul>
<li>Do you purge/archive Analytics database often?</li>
<li>Are you on pre-Sitecore 7 version?</li>
<li>Do you rely on Sitecore support for your development effort?</li>
<li>Are you planning on implementing or enhancing your DMS capabilities/goals?</li>
<li>and the ton of features Sitecore 8 provides!</li>
</ul>
<p>For Sitecore versions 6.5 and 6.6 the main stream support ends this year. Please check out the <a href="https://kb.sitecore.net/articles/641167" target="_blank">Sitecore Product Support Lifecycle</a>.</p>
<p>There are several factors to consider before planning for a Sitecore upgrade. A few of them are listed below:</p>
<ul>
<li>Are all your custom config changes isolated in include configs in App_Config\Include folder?</li>
<li>Are you using Sitecore shared modules?</li>
<li>Do you have third party integrations into Sitecore?</li>
<li>Do you have custom Sitecore Support DLL&#8217;s for your current solution?</li>
<li>Do you have a lot of Sitecore customizations (Pipelines, processors, commands, etc.)?</li>
<li>Are your running Sitecore 6.5/6.6 (Search code consideration since Sitecore search changed drastically starting Sitecore 7)?</li>
</ul>
<p><strong>Assumptions</strong></p>
<p>Our case study is a hypothetical Sitecore 6.5 solution which we will assume that it has been in production for a few years. It was written in Web Forms. With a few shared source modules and a couple of external integrations. Config for the most part was in an external config but some changes needed to be done in the web.config due to the external integrations.</p>
<p><strong>Wants</strong></p>
<p>The wants are simple, we want the best for the site going forward. So in the best interest of the site, Sitecore 8 was picked. Now that release 3 is out, it should be a lot more stable!!</p>
<p>Also we want to move to Sitecore MVC and do it the right way with Dependency Injection with unit testing, the whole 9 yards!</p>
<p><strong>Current Environment in this Hypothetical Situation</strong></p>
<p>A typical Sitecore environment is shown in the images below:</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2015/05/Typical_Development1.png"><img loading="lazy" class="alignnone size-large wp-image-2168" src="http://akshaysura.com/wp-content/uploads/2015/05/Typical_Development1.png" alt="Typical_Development" width="589" height="457" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2015/05/Typical_QA1.png"><img loading="lazy" class="alignnone size-large wp-image-2167" src="http://akshaysura.com/wp-content/uploads/2015/05/Typical_QA1.png" alt="Typical_QA" width="900" height="444" /></a></p>
<p><a href="http://akshaysura.com/wp-content/uploads/2015/05/Typical_Production1.png"><img loading="lazy" class="alignnone size-full wp-image-2166" src="http://akshaysura.com/wp-content/uploads/2015/05/Typical_Production1.png" alt="Typical_Production" width="958" height="581" /></a></p>
<p>&nbsp;</p>
<p>As with any upgrade the main concern is the infrastructure and ongoing costs for the upgrade. Along with this concern if we look at the upgrade path for a 6.5 instance to a Sitecore 8 release 3, its mind blowing.</p>
<p>Technology considerations such as SQL Server version minimal requirement for 8 as opposed to an old 6.5 install, search technology like Solr or Coveo, WFFM and Mongo DB among others will come into play.</p>
<p>The normal upgrade path from a Sitecore 6.5 Initial release to Sitecore 8 Update 3 is depicted in the flow below:</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2015/05/sitecore-8-upgrade.png"><img loading="lazy" class="alignnone size-full wp-image-2170" src="http://akshaysura.com/wp-content/uploads/2015/05/sitecore-8-upgrade.png" alt="sitecore 8 upgrade" width="468" height="1013" /></a></p>
<p>Based on all of the above information, it looks like its a huge undertaking and it is. After each version upgrade there is testing to do, may be code changes etc. Is this enough for you to call it quits??</p>
<p>Well wait for my next blog post in this series to find out about a different approach. This might help you make your decision and cut your costs.</p>
<p>As usual if you have any questions or comments, do not hesitate to get in touch with me.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Look in to the Coveo Mirrors!</title>
      <link>https://akshaysura.com/blog/look-in-to-the-coveo-mirrors/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/look-in-to-the-coveo-mirrors/</guid>
      <pubDate>Tue, 12 May 2015 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[For the past 3 years I have done a lot of work with Coveo. Coveo is both easy and hard depending on which side of the equation you are on. You have to remember that Coveo isn’t just for Sitecore and that its a fairly complex piece of software with a lot of functionality.]]></description>
      <content:encoded><![CDATA[<p>For the past 3 years I have done a lot of work with Coveo. Coveo is both easy and hard depending on which side of the equation you are on. You have to remember that Coveo isn&#8217;t just for Sitecore and that its a fairly complex piece of software with a lot of functionality.</p>
<p>It is easy to point fingers but the first thing you need to do is to do your due diligence, check and recheck and when all fails add a ticket. The folks I have worked with from Coveo are amazing, knowledgeable and helpful. Although I am sure I am not the most popular person at Coveo!</p>
<p>Now back to the post!! Coveo offers a lot of functionality, there are several things you can do to optimize the query speed and serve as many search queries as possible. There comes a time when one Coveo Master server is not enough, especially when you need a load balanced, patch-able and fault tolerant environment.</p>
<ul>
<li>Each Coveo server can perform about 25 queries per second (unofficial).</li>
<li>The best thing you can do is to have a dedicated Coveo server on all your environments.</li>
<li>Make sure that the CES folder is installed on a separate drive. You do not want the index/logs/rabbit queue files to grow and take up your OS drive causing your server to fail.</li>
<li>Change your REST security key for each environment.</li>
<li>Optimize your instance for Indexing or Querying.</li>
<li>Increase the number of threads for conversion/indexing/querying based on your needs.</li>
<li>Check your License (especially if you are using free version) to see how many mirrors you can run.</li>
<li>If you are using the Free edition, I would suggest getting a support plan.</li>
</ul>
<p>The free edition typically comes with one mirror in production and one mirror in non-production environments. Any additional mirrors are charged accordingly.</p>
<p>I would recommend at least two production Coveo mirrors to share the load of the incoming queries.</p>
<p>The setup for Coveo mirrors is pretty straight forward. For more information you can use this link: <a href="https://onlinehelp.coveo.com/en/ces/7.0/administrator/installing_ces_mirror_components.htm" target="_blank">Installing CES Mirror Components</a>. Make sure that the anti-virus software is disabled when you run the Coveo install.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2015/05/CESInstWS2012-SelectSetupTypeMirror2.png"><img loading="lazy" class="alignnone size-full wp-image-2157" src="http://akshaysura.com/wp-content/uploads/2015/05/CESInstWS2012-SelectSetupTypeMirror2.png" alt="CESInstWS2012-SelectSetupTypeMirror2" width="514" height="393" /></a></p>
<p>Once the Mirror(s) install is done, you would then proceed to the Master Admin console to configure the mirror(s). Use the link: <a href="https://onlinehelp.coveo.com/en/ces/7.0/administrator/adding_a_mirror_server.htm" target="_blank">Adding a Mirror Server</a> to configure the master to talk to the mirror(s). At this point, the documents the Master receives are seamlessly transferred to the mirror(s).</p>
<p>Configure your load balanced url to use the Mirror(s), following which you would modify the Coveo.SearchProvider.Rest.Config and point the &lt;SearchApiUri&gt; to the load balanced url.</p>
<p>You can use the CES Console to look at the activity on the Coveo Mirror. Remember the Coveo Mirror does not have any admin interface.</p>
<p>For more information on mirrors and scalability, read through:<br />
<a href="https://onlinehelp.coveo.com/en/ces/7.0/administrator/coveo_scalability_model.htm" target="_blank">Coveo Scalability Model</a><br />
<a href="https://onlinehelp.coveo.com/en/ces/7.0/administrator/configuring_coveo_servers_in_a_network_load-balancing_cluster.htm" target="_blank">Configuring Coveo Servers in a Network Load-Balancing Cluster</a><br />
<a href="https://onlinehelp.coveo.com/en/ces/7.0/administrator/about_mirror_servers.htm" target="_blank">About Mirror Servers</a><br />
<a href="https://developers.coveo.com/display/public/SC201504/Scaling+Coveo+for+Sitecore+Over+Multiple+Servers" target="_blank">Scaling Coveo for Sitecore Over Multiple Servers</a><br />
<a href="https://developers.coveo.com/display/public/SC201504/FAQ" target="_blank">FAQ</a><br />
If you have any questions or comments please do not hesitate to reach out.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Add Max Message limit for RabbitMQ for Coveo</title>
      <link>https://akshaysura.com/blog/add-max-message-limit-for-rabbitmq-for-coveo/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/add-max-message-limit-for-rabbitmq-for-coveo/</guid>
      <pubDate>Fri, 01 May 2015 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[RabbitMQ is a messaging broker installed with Coveo Enterprise Search. It runs as a Windows service along with other Coveo services. Coveo Search Provider adds item into RabbitMQ queues (one per index) and the messages get picked up by the Queue Crawler, which runs as part of the Coveo Enterprise Search service.]]></description>
      <content:encoded><![CDATA[<p>RabbitMQ is a messaging broker installed with Coveo Enterprise Search. It runs as a Windows service along with other Coveo services. Coveo Search Provider adds item into RabbitMQ queues (one per index) and the messages get picked up by the Queue Crawler, which runs as part of the Coveo Enterprise Search service.</p>
<p>From time to time, RabbitMQ goes rabid 😉 and stacks all the messages in the queues causing one or more queue(s) to hold a lot of messages. I have seen up to 2 million stacked messages at one time for the web index queue. This results in physical files which take up all of the disk space, effectively pushing CES service to make all your indexes read-only.</p>
<p>Therefore, it is a good practice to have the Coveo and RabbitMQ installed on a non-OS drive.</p>
<p>Here is the link to the article from Coveo: <a href="https://developers.coveo.com/display/public/SC201404/RabbitMQ+Consumes+a+Large+Amount+of+Disk+Space" target="_blank">RabbitMQ Consumes a Large Amount of Disk Space</a></p>
<p>There are multiple options to help limit this behavior, for instance, you can add an alert in the Coveo Admin Console to notify you when an error occurs.</p>
<p>First, open the Coveo Admin and click on the Configuration link:</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2015/05/Coveo_Admin_Configuration.png"><img loading="lazy" class="alignnone size-full wp-image-2134" src="http://akshaysura.com/wp-content/uploads/2015/05/Coveo_Admin_Configuration.png" alt="Coveo_Admin_Configuration" width="863" height="196" /></a></p>
<p>Once you are in the configuration section, click on Alerts link:</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2015/05/Coveo_Admin_Alerts.png"><img loading="lazy" class="alignnone size-full wp-image-2133" src="http://akshaysura.com/wp-content/uploads/2015/05/Coveo_Admin_Alerts.png" alt="Coveo_Admin_Alerts" width="719" height="475" /></a></p>
<p>&nbsp;</p>
<p>Configure the email settings and click Accept Changes link.</p>
<p>You can also limit the Message limit on RabbitMQ. This will stop the queue from overloading and would also prevent the server from taking up all of the disk space.</p>
<p>Erlang is a general-purpose, concurrent, garbage-collected programming language and runtime system used by RabbitMQ.</p>
<p>RabbitMQ and Erlang are a third-party solutions and you cannot expect Coveo to support it 100%. I do not take responsibility for the following settings/changes to RabbitMQ. These changes worked for me but I cannot guarantee that they will work for you.</p>
<p>First you would need to set the location for the Erlang&#8217;s ERTS (Erlang Run-Time System Application) folder. To do this go into your computer properties &gt; Advanced System Settings &gt; Environment Variables.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2015/05/Coveo_Env_Variable.png"><img loading="lazy" class="alignnone size-full wp-image-2138" src="http://akshaysura.com/wp-content/uploads/2015/05/Coveo_Env_Variable.png" alt="Coveo_Env_Variable" width="394" height="437" /></a></p>
<p>Add a system variable by clicking he New button:</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2015/05/Coveo_Erlang.png"><img loading="lazy" class="alignnone size-full wp-image-2139" src="http://akshaysura.com/wp-content/uploads/2015/05/Coveo_Erlang.png" alt="Coveo_Erlang" width="417" height="437" /></a></p>
<p>&nbsp;</p>
<p>Add a variable with name ERLANG_HOME and the value pointing to the directory of the ERTS install folder which is usually DRIVELETTER:\Program Files\Coveo Enterprise Search 7\Third-Party\erl5.10.3\erts-<wbr />5.10.3</p>
<p>Click OK and confirm again by clicking OK on the Environment Variables dialog.</p>
<p>Next, we need to find and copy the .erlang.cookie file. This file can usually be found in C:\Windows\.erlang.cookie path for a standard RabbitMQ install. For Coveo RabbitMQ install you can find the file in DRIVELETTER:\Program Files\Coveo Enterprise Search 7\Third-Party folder.</p>
<p>Copy the .erlang.cookie file from that path to C:\Users\%USERNAME%\.erlang.cookie</p>
<p>You can find the destination folder by running %HOMEDRIVE%%HOMEPATH% in the Run command.</p>
<p>The file copy will grant you access to Add/Change policy on RabbitMQ. You can either change the policy by running the following query:</p>
<pre><code>
rabbitmqctl set_policy NAMEOFYOURPOLICY "^THEWEBINDEXQUEUENAME$" "{""max-length"":NUMBEROFMESSAGES}" --apply-to queues -n NODENAME
</code></pre>
<p>Parameters and the values:</p>
<p>NAMEOFYOURPOLICY: provide a useful name like Coveo Web</p>
<p>THEWEBINDEXQUEUENAME: this is the name of the queue representing your web index</p>
<p>NUMBEROFMESSAGES: this is the max number of message you want to cap it at. A number like 500000.</p>
<p>NODENAME: This is the node name of the install. For a typical Coveo RabbitMQ install the name is not the same as the default RabbitMQ install. Look on the Overview tab for the node name.</p>
<p>&nbsp;</p>
<p>Or you can do it via the admin console for RabbitMQ which can be found at http://localhost:15672 on the machine with CES installed.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2015/05/Coveo-Rabbit.png"><img loading="lazy" class="alignnone size-large wp-image-2141" src="http://akshaysura.com/wp-content/uploads/2015/05/Coveo-Rabbit-1024x667.png" alt="Coveo Rabbit" width="900" height="586" /></a></p>
<p>Once you add the policy, it will take effect immediately. Please keep in mind that by adding the Max Length value, the Messages will be dropped or dead-lettered from the front of the queue to make room for new messages once the limit is reached.</p>
<p>Please let me know if you have any questions or comments.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Sitecore Hackathon Fears!!</title>
      <link>https://akshaysura.com/blog/sitecore-hackathon-fears/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/sitecore-hackathon-fears/</guid>
      <pubDate>Wed, 29 Apr 2015 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[After a two month hiatus, I am finally back. This time on my own blog.]]></description>
      <content:encoded><![CDATA[<p>After a two month hiatus, I am finally back. This time on my own blog.</p>
<p>This is a personal blog. Any views or opinions represented in this blog are my own and do not represent those of people, institutions or organizations that the I may or may not be associated with in professional or personal capacity including past, current and future employers, unless explicitly stated.</p>
<p>In the past month, several of you reached out to me about the Sitecore Hackathon. Is the hackathon going to be run this coming year? will you be running it? etc.</p>
<p>Here are a few facts:</p>
<ol>
<li>I own Sitecorehackathons.org and operate it by myself.</li>
<li>I do not represent anyone or any organization for this blog or SitecoreHackathons.org</li>
<li>My previous employer was gracious enough to be the Sponsor of the first and the second Sitecore Hackathon. The upcoming hackathon will either have a sponsor or I will fund it myself.</li>
<li>The next Sitecore Hackathon will be held early 2016.</li>
</ol>
<p>Thanks again for all correspondence. If you have any questions or concerns please let me know.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
    </item>
    <item>
      <title>Use MongoDB to store Sitecore log entries centrally!</title>
      <link>https://akshaysura.com/blog/use-mongodb-to-store-sitecore-log-entries-centrally/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/use-mongodb-to-store-sitecore-log-entries-centrally/</guid>
      <pubDate>Tue, 24 Feb 2015 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Posted 02/24/2015 by Akshay Sura]]></description>
      <content:encoded><![CDATA[<p>Posted 02/24/2015 by Akshay Sura</p>
<p>The idea is to store a copy of the Sitecore logs in a central location such as a common MongoDB. Why? hmm why not? If you are running multiple CD servers and you want to view the logs for all of them in one location, might be one reason. The reason will become apparent in the coming days/weeks!</p>
<p>For now, the process. I used the following blog posts as reference:</p>
<p>1. Anders Laub &#8211;&nbsp;<a href="http://laubplusco.net/working-custom-mongodb-collections-sitecore-8-using-webapi/" target="_blank">Working with custom MongoDB collections in Sitecore 8 using WebApi</a></p>
<p>2. Thomas Stern &#8211;&nbsp;<a href="http://blog.istern.dk/2014/06/17/storing-sitecore-log-events-in-mongodb/" target="_blank">Storing Sitecore log events in MongoDB</a></p>
<p>First a class representing the data we want to store:</p>
<pre><code>
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net.helpers;
using log4net.spi;
using MongoDB.Bson;

namespace YOURNAMESPACE.Log
{
    public class LoggingEventEx 
    {
        //Id will get auto generated when a new record is added into MongoDB
        public ObjectId Id { get; set; }

        //The server name on which this logger is being run, you will find out the bigger purpose in the coming days/weeks!
        public string ServerId { get; set; }

        //fields we are interested in from LogginEvent without having to inherit it
        public string Domain { get; set; }
        public FixFlags Fix { get; set; }
        public string Identity { get; set; }
        public Level Level { get; set; }
        public LocationInfo LocationInformation { get; set; }
        public string LoggerName { get; set; }
        public IDictionary MappedContext { get; set; }
        public object MessageObject { get; set; }
        public string NestedContext { get; set; }
        public PropertiesCollection Properties { get; set; }
        public string RenderedMessage { get; set; }
        public static DateTime StartTime { get; set; }
        public string ThreadName { get; set; }
        public DateTime TimeStamp { get; set; }
        public string UserName { get; set; }
    }
}

</code></pre>
<p>Next, we need the LogRepository which will interact with MongoDB. You can use reflector to see how Sitecore is currently doing this for tracking and analytics:</p>
<pre><code>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sitecore.ContentSearch;
using Sitecore.ContentSearch.SearchTypes;
using Sitecore.ContentSearch.Security;
using Sitecore.ContentSearch.Utilities;
using Sitecore.Diagnostics;
using log4net.spi;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Builders;

namespace YOURNAMESPACE.Log
{
    public class LogRepository
    {
        private readonly MongoCollection _LoggingEventExCollection;

        private readonly string _connectionString;
        private readonly string _collectionName;

        public LogRepository(string connectionString, string collectionName)
        {
            _connectionString = connectionString;
            _collectionName = collectionName;

            _LoggingEventExCollection = GetCollection(connectionString, _collectionName);
            Assert.IsNotNull(_LoggingEventExCollection, "LoggingEventExsCollection");
        }

        public IEnumerable&lt;LoggingEventEx&gt; GetAll()
        {
            return _LoggingEventExCollection.FindAllAs&lt;LoggingEventEx&gt;();
        }
        
        public LoggingEventEx Get(ObjectId id)
        {
            return _LoggingEventExCollection.FindOneAs&lt;LoggingEventEx&gt;(GetIDQuery(id));
        }
        
        public bool Set(LoggingEventEx LoggingEventEx)
        {
            return _LoggingEventExCollection.Insert(LoggingEventEx).Ok;
        }
        
        protected IMongoQuery GetIDQuery(ObjectId id)
        {
            return Query&lt;LoggingEventEx&gt;.EQ(c =&gt; c.Id, id);
        }
        
        private static MongoCollection GetCollection(string connectionString, string collectionName)
        {
            var url = new MongoUrl(connectionString);
            return new MongoClient(url).GetServer().GetDatabase(url.DatabaseName).GetCollection(collectionName);
        }
    }
}

</code></pre>
<p>Next, we need a class MongoLogger, implementing the AppenderSkeleton from the log4net implementation tucked away in Sitecore.Logging.dll. We will pass in the connection string name and the collection name from the config.</p>
<pre><code>
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using log4net.Appender;
using log4net.spi;
using MongoDB.Bson;

namespace YOURNAMESPACE.Log
{
    public class MongoLogger : AppenderSkeleton
    {
        public string ConnectionString { get; set; }
        public string CollectionName { get; set; }
        private LogRepository _logRepository;

        public LogRepository LogRepository
        {
            get
            {
                if (_logRepository == null)
                {
                    _logRepository = new LogRepository(ConfigurationManager.ConnectionStrings[ConnectionString].ConnectionString, CollectionName);
                }
                return _logRepository;
            }
        }

        protected override void Append(LoggingEvent loggingEvent)
        {
            LoggingEventEx logEventEx = ToDerived&lt;LoggingEvent, LoggingEventEx&gt;(loggingEvent);
            logEventEx.ServerId = System.Environment.MachineName; //get current machine name ;)
            LogRepository.Set(logEventEx);
        }

        //use relection to copy property values from LoggingEvent to LoggingEventEx
        private TDerived ToDerived&lt;TBase, TDerived&gt;(TBase tBase)
    where TDerived: new()
        {
            TDerived tDerived = new TDerived();
            foreach (PropertyInfo propBase in typeof(TBase).GetProperties())
            {
                PropertyInfo propDerived = typeof(TDerived).GetProperty(propBase.Name);
                propDerived.SetValue(tDerived, propBase.GetValue(tBase, null), null);
            }
            return tDerived;
        }
    }
}

</code></pre>
<p>Once all the above are done, we get to the configs.&nbsp;</p>
<p>Add a connection string to the new MongoDB.</p>
<pre><code>
&lt;add name="mongologger" connectionString="mongodb://localhost:27017/mongologger" /&gt;
</code></pre>
<p>Here what I did is to define an Appender called MongoDBAppender for log4net calling the MongoLogger:</p>
<pre><code>
    &lt;appender name="MongoDBAppender" type="YOURNAMESPACE.Log.MongoLogger, YOURASSEMBLY"&gt;
      &lt;connectionstring value="mongologger" /&gt;
      &lt;collectionname value="log" /&gt;
    &lt;/appender&gt;
</code></pre>
<p>I also added a Logger which by default inherits the root. It&#8217;s generally not a good practice to add to the root node.&nbsp;</p>
<p>The MongoDBAppender logger is explicitly configured to log to MongoDBAppender, and is configured not to inherit settings from parent loggers (additivity=&#8221;false&#8221;). Therefore it doesn&#8217;t log to LogFileAppender. If you set additivity=&#8221;true&#8221; it will inherit settings and log to both LogFileAppender and MongoDBAppender.</p>
<p>Here we added the MongoDBAppender followed by LogFileAppender. What this does is that it duplicates the entries in to the MongoDB, which is exactly what I am looking for.</p>
<pre><code>
    &lt;logger name="MongoLogger" additivity="false"&gt;
      &lt;level value="INFO" /&gt;
      &lt;appender-ref ref="MongoDBAppender" /&gt;
      &lt;appender-ref ref="LogFileAppender" /&gt;
    &lt;/logger&gt;
</code></pre>
<p>Final product, log entries in the MongoDB and the regular Log file.</p>
<p><img loading="lazy" height="582" alt="Mongo Log" width="800" src="http://akshaysura.com/wp-content/uploads/2015/02/log.png" /></p>
<p>Please get in touch with me if you have questions or comments.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Using Robomongo as the Admin UI for Sitecore MongoDB's</title>
      <link>https://akshaysura.com/blog/using-robomongo-as-the-admin-ui-for-sitecore-mongodb39s/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/using-robomongo-as-the-admin-ui-for-sitecore-mongodb39s/</guid>
      <pubDate>Tue, 24 Feb 2015 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Posted 02/23/2015 by Akshay Sura]]></description>
      <content:encoded><![CDATA[<p>Posted 02/23/2015 by Akshay Sura</p>
<p>There are several MongoDB Admin UI tools out there, some are free and some are paid. One of them stands out as being clean, free and easy to use and that one is Robomongo.</p>
<p>To find a list of MongoDB management tools, please visit <a href="http://docs.mongodb.org/ecosystem/tools/administration-interfaces/" target="_blank">MongoDB site, Admin UIs page</a>. Some of the tools such as Fang for Mongo and Opricot have been abandoned.</p>
<p>You can download Robomongo from their <a href="http://robomongo.org/" target="_blank">website</a>. Setup is a breeze. The UI gives you the ability to connect to different Mongo instances.</p>
<p><img loading="lazy" height="510" alt="robo mongo" width="740" src="http://akshaysura.com/wp-content/uploads/2015/02/robomongo.png" /></p>
<p><img loading="lazy" height="318" alt="new connection" width="465" src="http://akshaysura.com/wp-content/uploads/2015/02/new_connection.png" /></p>
<p>Once connected, you can use the UI to traverse through the collections and the data stored in them. Additionally you can also run db commands against the collections and display results in three different formats (hierarchy, table view and text view). Apart from the features mentioned it has the ability to perform all admin tasks such as clearing data, get db statistics, repair/drop db, insert/update/delete records, etc.</p>
<p><img loading="lazy" height="649" alt="command" width="800" src="http://akshaysura.com/wp-content/uploads/2015/02/command_001.png" /></p>
<p><img loading="lazy" height="646" alt="command" width="800" src="http://akshaysura.com/wp-content/uploads/2015/02/command2.png" /></p>
<p>This tools makes it easy to manage MongoDB installs. If you have any questions or comments, please do get in touch with me.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Serialization woes with Sitecore and Windows</title>
      <link>https://akshaysura.com/blog/serialization-woes-with-sitecore-and-windows/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/serialization-woes-with-sitecore-and-windows/</guid>
      <pubDate>Mon, 23 Feb 2015 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Posted 02/23/2015 by Akshay Sura]]></description>
      <content:encoded><![CDATA[<p>Posted 02/23/2015 by Akshay Sura</p>
<p>This comes as no surprise when I say that Serialization for Sitecore has its limits and conditions. When you try to serialize a huge tree with muli-level folders you often run into issues.</p>
<p>First, there are not the limitations of Sitecore and products like Unicorn and TDS. This is a base Windows limitation where some of the Windows API, including the Windows explorer are limited by the MAX_PATH which is 260 characters.</p>
<p><em>In the Windows API (with some exceptions discussed in the following paragraphs), the maximum length for a path is MAX_PATH, which is defined as 260 characters. A local path is structured in the following order: drive letter, colon, backslash, name components separated by backslashes, and a terminating null character. For example, the maximum path on drive D is &#8220;D:some 256-character path string&lt;NUL&gt;&#8221; where &#8220;&lt;NUL&gt;&#8221; represents the invisible terminating null character for the current system codepage. (The characters &lt; &gt; are used here for visual clarity and cannot be part of a valid path string.)</em></p>
<p>There are workarounds to get around this in the explorer but how do we get around it from a Sitecore perspective. Glad you asked. Instead of performing the serialization the way it is, which is to create an item file and a folder for each parent node, we need to create top level, Sitecore system folders into which we can dump the serialization files.</p>
<p>I am not asking to change the actual Sitecore item to file serialization functionality but just the way we store it in the file system.</p>
<p><img loading="lazy" height="285" alt="serialize" width="780" src="http://akshaysura.com/wp-content/uploads/2015/02/serialize.png" /></p>
<p><img loading="lazy" height="466" alt="serialize folders" width="800" src="http://akshaysura.com/wp-content/uploads/2015/02/serialize-folders.png" /></p>
<p>References:</p>
<p><a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath" target="_blank">Naming Files, Paths, and Namespaces &#8211; MSDN</a></p>
<p><a href="http://support.code42.com/CrashPlan/Latest/Troubleshooting/Windows_File_Paths_Longer_Than_255_Characters" target="_blank">WINDOWS FILE PATHS LONGER THAN 255 CHARACTERS &#8211; Code 42</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Sitecore Powershell not working with Insite Installed</title>
      <link>https://akshaysura.com/blog/sitecore-powershell-not-working-with-insite-installed/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/sitecore-powershell-not-working-with-insite-installed/</guid>
      <pubDate>Mon, 23 Feb 2015 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Posted 02/23/2015 by Akshay Sura]]></description>
      <content:encoded><![CDATA[<p>Posted 02/23/2015 by Akshay Sura</p>
<p>With Sitecore Powershell 2.8 and the new version of Insite installed, the Powershell console does not work. Both Insite and Powershell use the Console folder on the website root. Insite&#8217;s MVC routes clash with the requests for the Powershell and so the Powershell console hangs.</p>
<p><img loading="lazy" height="663" alt="Empty Console" width="800" src="http://akshaysura.com/wp-content/uploads/2015/02/Powershell-empty-console.png" /></p>
<p>Also the subsequent KeepAlive requests also fail.</p>
<p><img loading="lazy" height="74" alt="Keep Alive" width="800" src="http://nttdatasitecore.com/~/media/Images/Blog/Blog%20Images/Sitecore%20Powershell%20not%20working%20with%20Insite%20Installed/Keep%20alive.png?h=74&amp;la=en&amp;w=800" /></p>
<p>So a temporary solution is to modify the console.js and the ise.js file and make the entire url lowercase.</p>
<div><img loading="lazy" height="230" alt="Console.js" width="800" src="http://akshaysura.com/wp-content/uploads/2015/02/Consolejs.png" /></div>
<p><img loading="lazy" height="207" alt="Ise.js" width="800" src="http://akshaysura.com/wp-content/uploads/2015/02/isejs.png" /></p>
<p>This seems to help and I am able to get the console running properly.</p>
<div><img loading="lazy" height="396" alt="Working" width="663" src="http://akshaysura.com/wp-content/uploads/2015/02/Powershell-working.png" /></div>
<div readability="6.39130434783">I put in a request on the Sitecore Powershell request page on <a href="https://github.com/SitecorePowerShell/Console/issues/304" target="_blank">GitHub</a>.</div>
]]></content:encoded>
    </item>
    <item>
      <title>Add Telephone Link to the General Link field type in Sitecore</title>
      <link>https://akshaysura.com/blog/add-telephone-link-to-the-general-link-field-type-in-sitecore/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/add-telephone-link-to-the-general-link-field-type-in-sitecore/</guid>
      <pubDate>Sun, 22 Feb 2015 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Posted 02/21/2015 by Akshay Sura]]></description>
      <content:encoded><![CDATA[<p>Posted 02/21/2015 by Akshay Sura</p>
<p>I wanted to extend the General Link field to add a new Menu Item to create a Telephone link. A Telephone link is primarily used to render a telephone number so that it helps the mobile user to dial out the phone number.</p>
<p>e.g.:&nbsp;&lt;a title=&#8221;Call Customer Service at 1-222-333-4455&#8243; class=&#8221;phone&#8221; href=&#8221;tel:12223334455&#8243;&gt;Call Customer Service&lt;/a&gt;</p>
<p>In order to achieve this functionality we need to do the following:</p>
<p>1. Go to the Core database, and add a menu item under&nbsp;/sitecore/system/Field types/Link Types/General Link/Menu. Name it Telephone.</p>
<p>2. Set the Display Name field of this newly created Menu Item to Insert Telephone Link</p>
<p>3. Set the Message field to&nbsp;contentlink:telephonelink(id=$Target)</p>
<p><img loading="lazy" height="670" alt="Menu Link" width="800" src="http://akshaysura.com/wp-content/uploads/2015/02/Telephone-Link-Menu-Link.png" />
<div readability="16">
<p>4. Create a class called TelephoneLink to handle the link message. The above entry in the Message Field should match the switch case statement.</p>
<pre><code>
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sitecore;
using Sitecore.Data;
using Sitecore.Diagnostics;
using Sitecore.Shell.Applications.ContentEditor;
using Sitecore.Text;

namespace YOURNAMESPACE
{
    public class TelephoneLink:Link
    {
        // Handles the message.
        public override void HandleMessage(Sitecore.Web.UI.Sheer.Message message)
        {
            Assert.ArgumentNotNull(message, "message");
            base.HandleMessage(message); //base handles other message requests

            string name = message.Name;
            string str = name;
            if (name != null)
            {
                switch (str)
                {
                    case "contentlink:telephonelink":
                        {
                            var url = new UrlString(UIUtil.GetUri("control:TelephoneLinkForm")); //find control and open url
                            base.Insert(url.ToString());
                            return;
                        }
                    default:
                        {
                            return;
                        }
                }
            }

            if (Value.Length &gt; 0)
            {
                SetModified();
            }
            Value = String.Empty;
        }
    }
}

</code></pre>
<p>5. Click on General Link and modify the Control property to&nbsp;content:TelephoneLink</p>
<p><img loading="lazy" height="624" alt="General Link" width="800" src="http://akshaysura.com/wp-content/uploads/2015/02/Telephone-Link-General-Link.png" /></div>
<div readability="12">
<p>6. Create a config patch file to register the control source.</p>
<pre><code>
&lt;controlSources&gt;
        &lt;source mode="on" namespace="YOURNAMESPACE" assembly="YOURASSEMBLY" prefix="content"/&gt;
&lt;/controlSources&gt;
</code></pre>
<p>7. Create a new folder called TelephoneLink under /sitecore/shell/Applications/Dialogs&nbsp;</p>
<p><img loading="lazy" height="489" alt="Explorer" width="758" src="http://akshaysura.com/wp-content/uploads/2015/02/Telephone-Link-Explorer.png" /></div>
<div readability="69">
<p>8. Create an xml file called&nbsp;TelephoneLink.xml</p>
<pre><code>
&lt;?xml version="1.0" encoding="utf-8" ?&gt;
&lt;control xmlns:def="Definition" xmlns="http://schemas.sitecore.net/Visual-Studio-Intellisense"&gt;
  &lt;TelephoneLinkForm&gt;
    &lt;FormDialog Icon="Network/32x32/mail.png" Header="Insert a telephone link" 
      Text="Please specify the telephone number address and any additional properties. When done, click OK."
      OKButton="OK"&gt;

      &lt;CodeBeside Type="YOURNAMESPACE.TelephoneLinkForm,YOURASSEMBLY"/&gt;

      &lt;a id="telephone"&gt;&lt;/a&gt;
      
      &lt;GridPanel Class="scFormTable" CellPadding="2" Columns="2" Width="100%"&gt;
        &lt;Label For="Text" GridPanel.NoWrap="true"&gt;&lt;Literal Text="Link description:"/&gt;&lt;/Label&gt;
        &lt;Edit ID="Text" Width="100%" GridPanel.Width="100%"/&gt;
        
        &lt;Label For="Url" GridPanel.NoWrap="true"&gt;&lt;Literal Text="Telephone Number:"/&gt;&lt;/Label&gt;
        &lt;Edit ID="Url" Width="100%" /&gt;

        &lt;Label For="Class" GridPanel.NoWrap="true"&gt;&lt;Literal Text="Style class:" /&gt;&lt;/Label&gt;
        &lt;Edit ID="Class" Width="100%" /&gt;
        
        &lt;Label for="Title" GridPanel.NoWrap="true"&gt;&lt;Literal Text="Alternate text:"/&gt;&lt;/Label&gt;
        &lt;Edit ID="Title" Width="100%" /&gt;
      &lt;/GridPanel&gt;
    &lt;/FormDialog&gt;
  &lt;/TelephoneLinkForm&gt;
&lt;/control&gt;
</code></pre>
<p>9. Create a class called&nbsp;TelephoneLinkForm to act as the code behind for TelephoneLink.xml</p>
<pre><code>
using System;
using System.Collections.Specialized;
using System.Text.RegularExpressions;
using Sitecore;
using Sitecore.Diagnostics;
using Sitecore.Shell.Applications.Dialogs;
using Sitecore.Web.UI.HtmlControls;
using Sitecore.Web.UI.Pages;
using Sitecore.Web.UI.Sheer;
using Sitecore.Xml;

namespace YOURNAMESPACE
{
    public class TelephoneLinkForm : LinkForm
    {
        protected Edit Class;
        protected Edit Text;
        protected Edit Title;
        protected Edit Url;

        public TelephoneLinkForm()
        {
        }

        private string GetTelephone()
        {
            string value = this.Url.Value;
            string str = value;
            if (str.Length &gt; 0)
            {
                if (str.IndexOf(":", StringComparison.InvariantCulture) &gt;= 0)
                {
                    str = str.Substring(str.IndexOf(":", StringComparison.InvariantCulture) + 1);
                }
                if (!(new Regex(@"^(1?(-?d{3})-?)?(d{3})(-?d{4})$", RegexOptions.IgnoreCase)).IsMatch(str))
                {
                    return "__Canceled";
                }
            }
            if (value.Length &gt; 0 &amp;&amp; value.IndexOf(":", StringComparison.InvariantCulture) &lt; 0)
            {
                value = string.Concat("tel:", value);
            }
            return value;
        }

        protected override void OnLoad(EventArgs e)
        {
            Assert.ArgumentNotNull(e, "e");
            base.OnLoad(e);
            if (Context.ClientPage.IsEvent)
            {
                return;
            }
            string item = base.LinkAttributes["url"];
            if (base.LinkType != "tel")
            {
                item = string.Empty;
            }
            this.Text.Value = base.LinkAttributes["text"];
            this.Url.Value = item.Replace("tel:", "");
            this.Class.Value = base.LinkAttributes["class"];
            this.Title.Value = base.LinkAttributes["title"];
        }

        protected override void OnOK(object sender, EventArgs args)
        {
            Assert.ArgumentNotNull(sender, "sender");
            Assert.ArgumentNotNull(args, "args");
            string tel = this.GetTelephone();
            if (tel == "__Canceled")
            {
                SheerResponse.Alert("The telephone number is invalid.", new string[0]);
                return;
            }
            Packet packet = new Packet("link", new string[0]);
            LinkForm.SetAttribute(packet, "text", this.Text);
            LinkForm.SetAttribute(packet, "linktype", "tel");
            LinkForm.SetAttribute(packet, "url", tel);
            LinkForm.SetAttribute(packet, "anchor", string.Empty);
            LinkForm.SetAttribute(packet, "title", this.Title);
            LinkForm.SetAttribute(packet, "class", this.Class);
            SheerResponse.SetDialogValue(packet.OuterXml);
            base.OnOK(sender, args);
        }
    }
}
</code></pre>
<p>10. We need to handle the Rendering of the Telephone Link, so create processor&nbsp;RenderPhoneLink&nbsp;</p>
<pre><code>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.Pipelines.RenderField;
using Sitecore.Xml.Xsl;

namespace YOURNAMESPACE
{
    public class RenderPhoneLink
    {
        public void Process(Sitecore.Pipelines.RenderField.RenderFieldArgs args)
        {
            if (args != null &amp;&amp; (args.FieldTypeKey == "link" || args.FieldTypeKey == "general link"))
            {
                Sitecore.Data.Fields.LinkField linkField = args.Item.Fields[args.FieldName];
                if (!string.IsNullOrEmpty(linkField.Url) &amp;&amp; linkField.LinkType == "tel")
                {
                    args.Parameters["href"] = linkField.Url;
                }
            }
        }

    }
}

</code></pre>
<p>11. Add to config patch file to run the RenderPhoneLink processor right before the GetLinkFieldValue processor</p>
<pre><code>
&lt;configuration xmlns:x="http://www.sitecore.net/xmlconfig/"&gt;
    &lt;sitecore&gt;
        &lt;controlSources&gt;
             &lt;source mode="on" namespace="YOURNAMESPACE" assembly="YOURASSEMBLY" prefix="content"/&gt;
        &lt;/controlSources&gt;
        &lt;pipelines&gt;
            &lt;renderField&gt;
                &lt;processor patch:before="*[@type='Sitecore.Pipelines.RenderField.GetLinkFieldValue, Sitecore.Kernel']" type="YOURNAMESPACE.RenderPhoneLink, YOURASSEMBLY" /&gt;
            &lt;/renderField&gt;
        &lt;/pipelines&gt;
    &lt;/sitecore&gt;
&lt;/configuration&gt;
</code></pre>
<p>Now all you have to do is to keep using the sc fields such as &lt;sc:Link and the field value will be rendered properly.</p>
<p><img loading="lazy" height="362" alt="Final" width="800" src="http://akshaysura.com/wp-content/uploads/2015/02/Telephone-Link-Final.png" />
<p>If you have any questions or comments please get in touch with me. Thank you.</p>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Sitecore 8 Config File Sequence</title>
      <link>https://akshaysura.com/blog/sitecore-8-config-file-sequence/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/sitecore-8-config-file-sequence/</guid>
      <pubDate>Thu, 19 Feb 2015 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Posted 02/18/2015 by Akshay Sura]]></description>
      <content:encoded><![CDATA[<p>Posted 02/18/2015 by Akshay Sura</p>
<p>My original idea was to extend the ShowConfig.aspx to display other parts of the web.config. For instance to look at the handlers or webservice references in &lt;system.web&gt; and &lt;system.webserver&gt;.</p>
<p>What I found is that for each custom config section we need to specify a IConfigurationHandler class which handles the configuration for that section. Now if you try to cast that section to a different IConfigurationHandler than what is in the config, it will generate an error.</p>
<pre><code>
  &lt;configSections&gt;
    &lt;section name="sitecore" type="Sitecore.Configuration.ConfigReader, Sitecore.Kernel"/&gt;
    &lt;section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, Sitecore.Logging"/&gt;
    &lt;sectionGroup name="fiftyOne"&gt;
      &lt;section name="log" type="FiftyOne.Foundation.Mobile.Configuration.LogSection, FiftyOne.Foundation" requirePermission="false" allowDefinition="Everywhere" restartOnExternalChanges="false" allowExeDefinition="MachineToApplication"/&gt;
      &lt;section name="wurfl" type="FiftyOne.Foundation.Mobile.Detection.Wurfl.Configuration.WurflSection, FiftyOne.Foundation" requirePermission="false" allowDefinition="Everywhere" restartOnExternalChanges="false" allowExeDefinition="MachineToApplication"/&gt;
    &lt;/sectionGroup&gt;
    &lt;sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"&gt;
    &lt;/sectionGroup&gt;
  &lt;/configSections&gt;
</code></pre>
<p>That along with other concerns, I abandoned that idea. During the same time I also wanted to build a config file sequence page which will prove useful during debugging. Here is what I came up with:</p>
<p>1. A ConfigSequence.aspx file in /sitecore/admin directory</p>
<pre><code>
&lt;%@ Page Language="C#" AutoEventWireup="true" Inherits="YOURNAMESPACE.ConfigSequence" %&gt;
</code></pre>
<p>2. A Class to go through the configs and build the sequence</p>
<pre><code>
using Sitecore;
using Sitecore.Collections;
using Sitecore.Diagnostics;
using Sitecore.Xml;
using System;
using System.Collections;
using System.IO;
using System.Xml;

namespace YOURNAMESPACE
{
    /// &lt;summary&gt;
    /// The Factory.
    /// &lt;/summary&gt;
    public class FactoryEx
    {
        /// &lt;summary&gt;
        /// List of files in the sequence its loaded.
        /// &lt;/summary&gt;
        private ArrayList filesList = new ArrayList();
        
        /// &lt;summary&gt;
        /// Gets the configuration.
        /// &lt;/summary&gt;
        /// &lt;returns&gt;
        /// Xml document containing the entire Sitecore configuration.
        /// &lt;/returns&gt;
        public ArrayList GetConfigFileSequence()
        {
            if (filesList.Count &gt; 0)
                return filesList;

            XmlNode configNode = Sitecore.Configuration.ConfigReader.GetConfigNode();
            Assert.IsNotNull(configNode, "Could not read Sitecore configuration.");
            XmlDocument xmlDocument1 = new XmlDocument();
            xmlDocument1.AppendChild(xmlDocument1.ImportNode(configNode, true));
            filesList.Add("web.config");
            ExpandIncludeFiles(xmlDocument1.DocumentElement, new Hashtable());
            LoadAutoIncludeFiles();
            ReplaceGlobalVariables(xmlDocument1.DocumentElement);
            return filesList;
        }

        /// &lt;summary&gt;
        /// Loads the auto include files.
        /// &lt;/summary&gt;
        /// &lt;param name="patcher"&gt;
        /// The patcher.
        /// &lt;/param&gt;
        /// &lt;param name="folder"&gt;
        /// The folder.
        /// &lt;/param&gt;
        private void LoadAutoIncludeFiles( string folder)
        {
            Assert.ArgumentNotNull(folder, "folder");
            try
            {
                if (Directory.Exists(folder))
                {
                    string[] files = Directory.GetFiles(folder, "*.config");
                    for (int i = 0; i &lt; (int)files.Length; i++)
                    {
                        string str = files[i];
                        try
                        {
                            if ((int)(File.GetAttributes(str) &amp; FileAttributes.Hidden) == 0)
                            {
                                filesList.Add(StripDriveInfo(str));
                            }
                        }
                        catch (Exception exception)
                        {
                            object[] objArray = new object[] { "Could not load configuration file: ", str, ": ", exception };
                            Log.Error(string.Concat(objArray), typeof(FactoryEx));
                        }
                    }
                    string[] directories = Directory.GetDirectories(folder);
                    for (int j = 0; j &lt; (int)directories.Length; j++)
                    {
                        string str1 = directories[j];
                        try
                        {
                            if ((int)(File.GetAttributes(str1) &amp; FileAttributes.Hidden) == 0)
                            {
                                LoadAutoIncludeFiles(str1);
                            }
                        }
                        catch (Exception exception1)
                        {
                            object[] objArray1 = new object[] { "Could not scan configuration folder ", str1, " for files: ", exception1 };
                            Log.Error(string.Concat(objArray1), typeof(FactoryEx));
                        }
                    }
                }
            }
            catch (Exception exception2)
            {
                object[] objArray2 = new object[] { "Could not scan configuration folder ", folder, " for files: ", exception2 };
                Log.Error(string.Concat(objArray2), typeof(FactoryEx));
            }
        }

        /// &lt;summary&gt;
        /// Strips the drive info and converts to virtual path.
        /// &lt;/summary&gt;
        /// &lt;param name="filePath"&gt;
        /// The file path which may or maynot have the drive information.
        /// &lt;/param&gt;
        private string StripDriveInfo(string filePath)
        {
            string result = "";
            int foundIndex = filePath.IndexOf(@"app_config", StringComparison.InvariantCultureIgnoreCase);
            if (foundIndex &gt;= 0)
                result = filePath.Substring(foundIndex);
            else
                result = filePath;

            return result.Replace(@"", "/").ToLowerInvariant();
        }

        /// &lt;summary&gt;
        /// Replaces global variables.
        /// &lt;/summary&gt;
        /// &lt;param name="rootNode"&gt;
        /// The root node.
        /// &lt;/param&gt;
        private void ReplaceGlobalVariables(XmlNode rootNode)
        {
            Assert.ArgumentNotNull(rootNode, "rootNode");
            XmlNodeList xmlNodeLists = rootNode.SelectNodes(".//sc.variable");
            StringDictionary stringDictionary = new StringDictionary();
            foreach (XmlAttribute attribute in rootNode.Attributes)
            {
                string name = attribute.Name;
                string[] value = new string[] { attribute.Value };
                string str = StringUtil.GetString(value);
                if (name.Length &lt;= 0)
                {
                    continue;
                }
                stringDictionary[string.Concat("$(", name, ")")] = str;
            }
            for (int i = 0; i &lt; xmlNodeLists.Count; i++)
            {
                string attribute1 = XmlUtil.GetAttribute("name", xmlNodeLists[i]);
                string str1 = XmlUtil.GetAttribute("value", xmlNodeLists[i]);
                if (attribute1.Length &gt; 0)
                {
                    stringDictionary[string.Concat("$(", attribute1, ")")] = str1;
                }
            }
            if (stringDictionary.Count == 0)
            {
                return;
            }
            ReplaceGlobalVariables(rootNode, stringDictionary);
        }

        /// &lt;summary&gt;
        /// Replaces global variables.
        /// &lt;/summary&gt;
        /// &lt;param name="node"&gt;
        /// The root node.
        /// &lt;/param&gt;
        /// &lt;param name="variables"&gt;
        /// The variables.
        /// &lt;/param&gt;
        private void ReplaceGlobalVariables(XmlNode node, StringDictionary variables)
        {
            Assert.ArgumentNotNull(node, "node");
            Assert.ArgumentNotNull(variables, "variables");
            foreach (XmlAttribute attribute in node.Attributes)
            {
                string value = attribute.Value;
                if (value.IndexOf('$') &lt; 0)
                {
                    continue;
                }
                foreach (string key in variables.Keys)
                {
                    value = value.Replace(key, variables[key]);
                }
                attribute.Value = value;
            }
            foreach (XmlNode childNode in node.ChildNodes)
            {
                if (childNode.NodeType != XmlNodeType.Element)
                {
                    continue;
                }
                ReplaceGlobalVariables(childNode, variables);
            }
        }

        /// &lt;summary&gt;
        /// Replaces the variables.
        /// &lt;/summary&gt;
        /// &lt;param name="value"&gt;
        /// The value.
        /// &lt;/param&gt;
        /// &lt;param name="node"&gt;
        /// The Xml node.
        /// &lt;/param&gt;
        /// &lt;param name="parameters"&gt;
        /// The parameters.
        /// &lt;/param&gt;
        /// &lt;returns&gt;
        /// The replace variables.
        /// &lt;/returns&gt;
        private string ReplaceVariables(string value, XmlNode node, string[] parameters)
        {
            Assert.ArgumentNotNull(value, "value");
            Assert.ArgumentNotNull(node, "node");
            node = node.ParentNode;
            while (node != null &amp;&amp; node.NodeType == XmlNodeType.Element &amp;&amp; value.IndexOf("$(", StringComparison.InvariantCulture) &gt;= 0)
            {
                foreach (XmlAttribute attribute in node.Attributes)
                {
                    string str = string.Concat("$(", attribute.LocalName, ")");
                    value = value.Replace(str, attribute.Value);
                }
                value = value.Replace("$(name)", node.LocalName);
                node = node.ParentNode;
            }
            if (parameters != null)
            {
                for (int i = 0; i &lt; (int)parameters.Length; i++)
                {
                    value = value.Replace(string.Concat("$(", i, ")"), parameters[i]);
                }
            }
            return value;
        }

        /// &lt;summary&gt;
        /// Loads the auto include files.
        /// &lt;/summary&gt;
        /// &lt;param name="element"&gt;
        /// The element.
        /// &lt;/param&gt;
        private void LoadAutoIncludeFiles()
        {
            LoadAutoIncludeFiles(MainUtil.MapPath("/App_Config/Sitecore/Components"));
            LoadAutoIncludeFiles(MainUtil.MapPath("/App_Config/Include"));
        }

        
        /// &lt;summary&gt;
        /// Expands the include files embedded in the configuration document.
        /// &lt;/summary&gt;
        /// &lt;param name="rootNode"&gt;
        /// The root node.
        /// &lt;/param&gt;
        /// &lt;param name="cycleDetector"&gt;
        /// The cycle detector.
        /// &lt;/param&gt;
        private void ExpandIncludeFiles(XmlNode rootNode, Hashtable cycleDetector)
        {
            Assert.ArgumentNotNull(rootNode, "rootNode");
            Assert.ArgumentNotNull(cycleDetector, "cycleDetector");
            if (rootNode.LocalName == "sc.include")
            {
                ExpandIncludeFile(rootNode, cycleDetector);
                return;
            }
            XmlNodeList xmlNodeLists = rootNode.SelectNodes(".//sc.include");
            for (int i = 0; i &lt; xmlNodeLists.Count; i++)
            {
                ExpandIncludeFile(xmlNodeLists[i], cycleDetector);
            }
        }

        /// &lt;summary&gt;
        /// Gets the attribute.
        /// &lt;/summary&gt;
        /// &lt;param name="name"&gt;
        /// The attribute name.
        /// &lt;/param&gt;
        /// &lt;param name="node"&gt;
        /// The Xml node.
        /// &lt;/param&gt;
        /// &lt;param name="parameters"&gt;
        /// The parameters.
        /// &lt;/param&gt;
        /// &lt;returns&gt;
        /// The attribute.
        /// &lt;/returns&gt;
        public string GetAttribute(string name, XmlNode node, string[] parameters)
        {
            Assert.ArgumentNotNullOrEmpty(name, "name");
            Assert.ArgumentNotNull(node, "node");
            string attribute = XmlUtil.GetAttribute(name, node);
            return ReplaceVariables(attribute, node, parameters);
        }

        /// &lt;summary&gt;
        /// Expands the include file represented by a single configuration element (node).
        /// &lt;/summary&gt;
        /// &lt;param name="xmlNode"&gt;
        /// The XML node.
        /// &lt;/param&gt;
        /// &lt;param name="cycleDetector"&gt;
        /// The cycle detector.
        /// &lt;/param&gt;
        private void ExpandIncludeFile(XmlNode xmlNode, Hashtable cycleDetector)
        {
            Assert.ArgumentNotNull(xmlNode, "xmlNode");
            Assert.ArgumentNotNull(cycleDetector, "cycleDetector");
            string lowerInvariant = GetAttribute("file", xmlNode, null).ToLowerInvariant();
            if (lowerInvariant.Length == 0)
            {
                return;
            }
            object[] objArray = new object[] { lowerInvariant };
            Assert.IsTrue(!cycleDetector.ContainsKey(lowerInvariant), "Cycle detected in configuration include files. The file '{0}' is being included directly or indirectly in a way that causes a cycle to form.", objArray);
            XmlDocument xmlDocument = XmlUtil.LoadXmlFile(lowerInvariant);
            if (xmlDocument.DocumentElement == null)
            {
                return;
            }

            filesList.Add(StripDriveInfo(lowerInvariant));

            XmlNode parentNode = xmlNode.ParentNode;
            XmlNode xmlNodes = xmlNode.OwnerDocument.ImportNode(xmlDocument.DocumentElement, true);
            parentNode.ReplaceChild(xmlNodes, xmlNode);
            cycleDetector.Add(lowerInvariant, string.Empty);
            ExpandIncludeFiles(xmlNodes, cycleDetector);
            cycleDetector.Remove(lowerInvariant);
            while (xmlNodes.FirstChild != null)
            {
                parentNode.AppendChild(xmlNodes.FirstChild);
            }
            foreach (XmlNode childNode in xmlNodes.ChildNodes)
            {
                parentNode.AppendChild(childNode);
            }
            XmlUtil.TransferAttributes(xmlNodes, parentNode);
            parentNode.RemoveChild(xmlNodes);
        }

    }
}
</code></pre>
<p>3. A Class for the code behind for the aspx file</p>
<pre><code>
using Sitecore.Configuration;
using Sitecore.sitecore.admin;
using System;
using System.Collections;
using System.Web;
using System.Web.UI;
using System.Xml;

namespace YOURNAMESPACE
{
    public class ConfigSequence : AdminPage
    {
        public ConfigSequence()
        {
        }

        /// &lt;summary&gt;
        /// Handles the Load event of the Page control.
        /// &lt;/summary&gt;
        /// &lt;param name="sender"&gt;The source of the event.&lt;/param&gt;
        /// &lt;param name="e"&gt;The &lt;see cref="T:System.EventArgs" /&gt; instance containing the event data.&lt;/param&gt;
        protected void Page_Load(object sender, EventArgs e)
        {
            base.CheckSecurity();
            FactoryEx factory = new FactoryEx();
            ArrayList filesList = factory.GetConfigFileSequence();
            
            for (int i = 0; i &lt; filesList.Count; i++)
            {
                base.Response.Write(string.Format("{0}: {1}&lt;BR&gt;", (i+1).ToString(), filesList[i]));
            }
        }
    }
}
</code></pre>
<p>And here is the output:</p>
<pre><code>
1: web.config
2: /app_config/prototypes.config
3: /app_config/prefetch/common.config
4: /app_config/prefetch/core.config
5: /app_config/prefetch/common.config
6: /app_config/prefetch/master.config
7: /app_config/prefetch/common.config
8: /app_config/prefetch/webdb.config
9: /app_config/fieldtypes.config
10: /app_config/xamlsharp.config
11: /app_config/languagedefinitions.config
12: /app_config/mimetypes.config
13: /app_config/commands.config
14: /app_config/icons.config
15: /app_config/portraits.config
16: /app_config/include/.sitecore.speak.important.config
17: /app_config/include/datafolder.config
18: /app_config/include/sitecore.analytics.automation.timeoutprocessing.config
19: /app_config/include/sitecore.analytics.compatibility.config
20: /app_config/include/sitecore.analytics.config
21: /app_config/include/sitecore.analytics.conversion.config
22: /app_config/include/sitecore.analytics.excluderobots.config
23: /app_config/include/sitecore.analytics.marketingtaxonomy.config
24: /app_config/include/sitecore.analytics.model.config
25: /app_config/include/sitecore.analytics.mongodb.config
26: /app_config/include/sitecore.analytics.outcome.config
27: /app_config/include/sitecore.analytics.processing.aggregation.config
28: /app_config/include/sitecore.analytics.processing.aggregation.processingpools.config
29: /app_config/include/sitecore.analytics.processing.aggregation.services.config
30: /app_config/include/sitecore.analytics.processing.config
31: /app_config/include/sitecore.analytics.processing.services.config
32: /app_config/include/sitecore.analytics.reporting.config
33: /app_config/include/sitecore.analytics.tracking.aggregation.config
34: /app_config/include/sitecore.analytics.tracking.config
35: /app_config/include/sitecore.analytics.tracking.database.config
36: /app_config/include/sitecore.analytics.tracking.robotdetection.config
37: /app_config/include/sitecore.anticsrf.config
38: /app_config/include/sitecore.apps.taginjection.config
39: /app_config/include/sitecore.buckets.config
40: /app_config/include/sitecore.contentsearch.analytics.config
41: /app_config/include/sitecore.contentsearch.config
42: /app_config/include/sitecore.contentsearch.defaultconfigurations.config
43: /app_config/include/sitecore.contentsearch.lucene.defaultindexconfiguration.config
44: /app_config/include/sitecore.contentsearch.lucene.index.analytics.config
45: /app_config/include/sitecore.contentsearch.lucene.index.core.config
46: /app_config/include/sitecore.contentsearch.lucene.index.master.config
47: /app_config/include/sitecore.contentsearch.lucene.index.web.config
48: /app_config/include/sitecore.experienceeditor.config
49: /app_config/include/sitecore.experienceeditor.speak.requests.config
50: /app_config/include/sitecore.experienceexplorer.config
51: /app_config/include/sitecore.experienceexplorer.speak.requests.config
52: /app_config/include/sitecore.itemwebapi.config
53: /app_config/include/sitecore.marketing.client.config
54: /app_config/include/sitecore.marketing.config
55: /app_config/include/sitecore.marketing.definitions.marketingassets.repositories.config
56: /app_config/include/sitecore.marketing.definitions.marketingassets.repositories.lucene.index.master.config
57: /app_config/include/sitecore.marketing.definitions.marketingassets.repositories.lucene.index.web.config
58: /app_config/include/sitecore.marketing.definitions.marketingassets.repositories.lucene.indexconfiguration.config
59: /app_config/include/sitecore.media.requestprotection.config
60: /app_config/include/sitecore.mvc.config
61: /app_config/include/sitecore.mvcanalytics.config
62: /app_config/include/sitecore.mvcexperienceeditor.config
63: /app_config/include/sitecore.mvcsimulator.config
64: /app_config/include/sitecore.pathanalyzer.client.config
65: /app_config/include/sitecore.pathanalyzer.config
66: /app_config/include/sitecore.pathanalyzer.processing.config
67: /app_config/include/sitecore.pathanalyzer.services.config
68: /app_config/include/sitecore.segmentbuilder.config
69: /app_config/include/sitecore.services.client.config
70: /app_config/include/sitecore.shell.marketingautomation.config
71: /app_config/include/sitecore.speak.anticsrf.sheerui.config
72: /app_config/include/sitecore.speak.applications.config
73: /app_config/include/sitecore.speak.config
74: /app_config/include/sitecore.speak.itemwebapi.config
75: /app_config/include/sitecore.speak.launchpad.config
76: /app_config/include/sitecore.speak.mvc.config
77: /app_config/include/sitecore.webdav.config
78: /app_config/include/synthesis.config
79: /app_config/include/channel/sitecore.analytics.channel.config
80: /app_config/include/contenttesting/sitecore.contenttesting.config
81: /app_config/include/contenttesting/sitecore.contenttesting.intelligence.config
82: /app_config/include/contenttesting/sitecore.contenttesting.lucene.indexconfiguration.config
83: /app_config/include/contenttesting/sitecore.contenttesting.mvc.config
84: /app_config/include/contenttesting/sitecore.contenttesting.processing.aggregation.config
85: /app_config/include/experienceanalytics/sitecore.experienceanalytics.aggregation.config
86: /app_config/include/experienceanalytics/sitecore.experienceanalytics.client.config
87: /app_config/include/experienceanalytics/sitecore.experienceanalytics.reduce.config
88: /app_config/include/experienceanalytics/sitecore.experienceanalytics.storageproviders.config
89: /app_config/include/experienceanalytics/sitecore.experienceanalytics.webapi.config
90: /app_config/include/experienceprofile/sitecore.experienceprofile.client.config
91: /app_config/include/experienceprofile/sitecore.experienceprofile.config
92: /app_config/include/experienceprofile/sitecore.experienceprofile.reporting.config
93: /app_config/include/fxm/sitecore.fxm.bundle.config
94: /app_config/include/fxm/sitecore.fxm.config
95: /app_config/include/fxm/sitecore.fxm.lucene.index.domainssearch.config
96: /app_config/include/fxm/sitecore.fxm.speak.config
97: /app_config/include/listmanagement/sitecore.listmanagement.client.config
98: /app_config/include/listmanagement/sitecore.listmanagement.config
99: /app_config/include/listmanagement/sitecore.listmanagement.lucene.index.list.config
100: /app_config/include/listmanagement/sitecore.listmanagement.lucene.indexconfiguration.config
101: /app_config/include/listmanagement/sitecore.listmanagement.services.config
102: /app_config/include/simpleinjector/simpleinjector.config
103: /app_config/include/social/sitecore.social.config
104: /app_config/include/social/sitecore.social.experienceprofile.config
105: /app_config/include/social/sitecore.social.facebook.config
106: /app_config/include/social/sitecore.social.googleplus.config
107: /app_config/include/social/sitecore.social.linkedin.config
108: /app_config/include/social/sitecore.social.lucene.index.master.config
109: /app_config/include/social/sitecore.social.lucene.index.web.config
110: /app_config/include/social/sitecore.social.lucene.indexconfiguration.config
111: /app_config/include/social/sitecore.social.profilemapping.facebook.config
112: /app_config/include/social/sitecore.social.profilemapping.googleplus.config
113: /app_config/include/social/sitecore.social.profilemapping.linkedin.config
114: /app_config/include/social/sitecore.social.profilemapping.twitter.config
115: /app_config/include/social/sitecore.social.socialmarketer.config
116: /app_config/include/social/sitecore.social.twitter.config

</code></pre>
<p>Let me know if you have any questions or comments.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Dependency Injection using Simple Injector for Sitecore 8 WebApi Attribute Routing in APIControllers</title>
      <link>https://akshaysura.com/blog/dependency-injection-using-simple-injector-for-sitecore-8-webapi-attribute-routing-in-apicontrollers/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/dependency-injection-using-simple-injector-for-sitecore-8-webapi-attribute-routing-in-apicontrollers/</guid>
      <pubDate>Sat, 24 Jan 2015 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Posted 01/24/2015 by Akshay Sura]]></description>
      <content:encoded><![CDATA[<p>Posted 01/24/2015 by Akshay Sura</p>
<p>I have been working with <a href="https://simpleinjector.codeplex.com/" target="_blank">Simple Injector</a> for a while now, partly because its way faster than Ninject and also because it lands in the top <a href="http://www.palmmedia.de/blog/2011/8/30/ioc-container-benchmark-performance-comparison" target="_blank">5 in speed</a>. Simple Injector has very good .NET Support.</p>
<p>There are a few challenges getting WebAPI attribute routing in place in Sitecore 8 with dependency injection using Simple Injector. My Scenario is to communicate with Jive to pull data into a JSON based UI.</p>
<p>First I start of with &#8220;<a href="http://nttdatasitecore.com/Blog/2014/September/Highly-testable-Sitecore-code-using-MVC-Ninject-Synthesis-Moq-and-NUnit">Highly testable Sitecore code using MVC, Ninject, Synthesis, Moq, and NUnit</a>&#8221; but modified to use Simple Injector. This sets up dependency injection for regular controllers, no problem.</p>
<p>The issue is when you add in APIControllers to the solution. I wasn&#8217;t able to get Attribute routing working, worse yet, its different to get it working in Sitecore 7.2, 7.5 and 8. The following posts helped me figure out a solution:</p>
<p>My issue was that I didn&#8217;t want to add in configs and overriding pipeline processors. I wanted it to be simple. Based on the blog posts above, I ended up using <a href="http://www.nuget.org/packages/WebActivatorEx/" target="_blank">WebActivatorEx</a>.</p>
<p>Now for my simple APIController with Simple Injector:</p>
<pre><code>
namespace PROJECTNAME.Website.Controllers.Services
{
    // the RoutePrefix is the base path to the API controller
    //[RoutePrefix("api/jive")]
    public class JiveController : ApiController
    {
        private readonly ICache _currentCache;
        private readonly IJiveData _jiveData;

        public JiveController(ICache CurrentCache, IJiveData JiveData)
        {
            _currentCache = CurrentCache;
            _jiveData = JiveData;
        }

        [HttpPost]
        public IHttpActionResult GetJiveItems(JiveRequest jiveRequest)
        {
            List&lt;PostItem&gt; returnPosts = _currentCache.GetOrCreateItem(jiveRequest.IDs, () =&gt; _jiveData.RefreshData(jiveRequest.IDs, jiveRequest.Type, jiveRequest.Url), new TimeSpan(12, 0, 0));

            if (returnPosts != null &amp;&amp; returnPosts.Count &gt; 0)
                return Ok(returnPosts.Take(jiveRequest.Count));
            else
                return Ok(new List&lt;PostItem&gt;());

            //the default MediaTypeFormatter will handle the serialization
        }
    }

}

</code></pre>
<p>The problem was that I got the following error:</p>
<pre><code>
Server Error in '/' Application.

The object has not yet been initialized. Ensure that HttpConfiguration.EnsureInitialized() is called in the application's startup code after all other initialization code.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.InvalidOperationException: The object has not yet been initialized. Ensure that HttpConfiguration.EnsureInitialized() is called in the application's startup code after all other initialization code.

</code></pre>
<p>I was already registering the Interfaces for Injection in the App_Start for Simple Injector, what else do I need to do?</p>
<pre><code>
namespace PROJECTNAME.Website.App_Start
{
    public class WebsitePackage : IPackage
    {
        public void RegisterServices(Container container)
        {
            container.Register&lt;IScriptLogic, ScriptLogic&gt;();
            container.Register&lt;IProgramInfo, ProgramInfo&gt;();
            container.Register&lt;ICanonical, Canonical&gt;();
            container.Register&lt;IMetaTags, MetaTags&gt;();
            container.Register&lt;INavigationLogic, NavigationLogic&gt;();
            container.Register&lt;ISettings, SiteSettings&gt;(Lifestyle.Singleton);
            container.Register&lt;IFooterLogic, FooterLogic&gt;();
            container.Register&lt;ICarouselLogic, CarouselLogic&gt;();
            container.Register&lt;IDateTime, DefaultDateTime&gt;();
            container.Register&lt;ICache, SimpleCache&gt;();
        }
    }
}
</code></pre>
<p>Since Simple Injector was having an issue I found a few articles on how to resolve this with filters etc but found <a href="https://www.nuget.org/packages/SimpleInjector.Integration.WebApi.WebHost.QuickStart" target="_blank">Simple Injector ASP.NET Web API Integration Quick Start for IIS-hosted applications</a>. By adding the Simple Injector Web API and the following into the App_Start WebActivatorEx code, it started working.&nbsp;</p>
<pre><code>
[assembly: WebActivatorEx.PostApplicationStartMethod(typeof(PROJECTNAME.Website.App_Start.SimpleInjectorWebApiInitializer), "Initialize")]
namespace PROJECTNAME.Website.App_Start
{
    public static class SimpleInjectorWebApiInitializer
    {
        public static void Initialize()
        {
            var container = new Container();

            container.RegisterWebApiRequest&lt;IDateTime, DefaultDateTime&gt;();
            container.RegisterWebApiRequest&lt;ICache, SimpleCache&gt;();
            container.RegisterWebApiRequest&lt;IJiveData, JiveData&gt;();
            container.Verify();
            
            GlobalConfiguration.Configuration.DependencyResolver =
                new SimpleInjectorWebApiDependencyResolver(container);

            GlobalConfiguration.Configuration.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
            );
        }
    }
}
</code></pre>
<p>The thing to note is that we are registering the WebApiRequests.</p>
<p>The results passed back from your APIController are based on the default MediaTypeFormatter. The objects you return as a list, the default media type formatter will handle the serialization based on the content type specified from the client (providing it is json or xml). I didn&#8217;t need to do the following since JSON was the default provider:</p>
<pre><code>
GlobalConfiguration.Configuration.Formatters.Clear();
GlobalConfiguration.Configuration.Formatters.Add(new JsonMediaTypeFormatter());
</code></pre>
<p>Here are a few useful links:</p>
]]></content:encoded>
    </item>
    <item>
      <title>Generic Multilist Computed Field in Coveo for Sitecore</title>
      <link>https://akshaysura.com/blog/generic-multilist-computed-field-in-coveo-for-sitecore/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/generic-multilist-computed-field-in-coveo-for-sitecore/</guid>
      <pubDate>Mon, 11 Aug 2014 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Posted 08/10/2014 by Akshay Sura]]></description>
      <content:encoded><![CDATA[<p>Posted 08/10/2014 by Akshay Sura</p>
<p>Computed fields are very useful, especially if you are implementing a multi-site / multi-lingual Sitecore solution. In some of the previous blog posts, we have covered foreign keys, auto suggestions and other important topics related to Coveo JS Framework.</p>
<p>In this post we will concentrate on multilist fields and how to create ONE generic unit of code that can handle either text or guids in the computed fields. Generally if you were to add a computed field, you need a piece of configuration as shown below and a class to perform the work needed to generate the output for the computed field.&nbsp;</p>
<pre><code>
YOURNAMESPACE.Business.Search.ComputedFields.CUSTOMFIELDComputedField,YOURNAMESPACE.Business
</code></pre>
<p>This gets very tedious as you are creating multiple fields that store a delimited list of text or guids in the raw. Here is a great solution to cut down on code but achieve the same functionality. First we need configuration where we can call the same class but pass in the values. Here is a sample piece of config:</p>
<pre><code>
YOURNAMESPACE.Business.Search.ComputedFields.MultilistComputedField, YOURNAMESPACE.Business
</code></pre>
<p>YOURNAMESPACE.Business.Search.ComputedFields.MultilistComputedField, YOURNAMESPACE.Business YOURNAMESPACES.Business.Search.ComputedFields.MultilistComputedField, YOURNAMESPACE.Business</p>
<p>As you can see, we are calling the same code to generate the computed field value but we are passing in additional parameters via the config to specify which fields we want processed. Now for some code! As with any other computed field, we need to create a class which inherits IComputedField. The difference is that we need to pull in the additional configuration. Checkout the code below:</p>
<pre><code>
namespace YOURNAMESPACE.Business.Search.ComputedFields
{
    public class MultilistComputedField : IComputedIndexField
    {
        #region PrivateProtected
        //store xml configuration
        private readonly XmlNode m_Configuration;

        protected string GetConfigurationValue(string p_ConfigurationKey)
        {
            string configurationValue = null;
            if (m_Configuration != null &amp;&amp; m_Configuration.Attributes != null)
            {
                XmlAttribute configurationAttribute = m_Configuration.Attributes[p_ConfigurationKey];
                if (configurationAttribute != null)
                {
                    configurationValue = configurationAttribute.Value;
                }
            }
            return configurationValue;
        }

        protected string PrimaryField
        {
            get
            {
                return GetConfigurationValue(Constants.Global.IndexFields.ComputedFieldPrimary);
            }
        }

        protected string LookupField
        {
            get
            {
                return GetConfigurationValue(Constants.Global.IndexFields.ComputedFieldLookup);
            }
        }
        #endregion

        #region Properties
        /// 
        public string FieldName
        {
            get;
            set;
        }
        /// 
        public string ReturnType
        {
            get;
            set;
        }
        #endregion


        #region Public Methods

        public MultilistComputedField(XmlNode p_Configuration)
        {
            m_Configuration = p_Configuration;
        }

        /// 
        public object ComputeFieldValue(IIndexable p_Indexable)
        {
            //get the primary field 
            IIndexableDataField multivalueField = p_Indexable.GetFieldByName(PrimaryField);
            Item currentItem = (Item)(p_Indexable as SitecoreIndexableItem);
            //check for null
            if (multivalueField != null &amp;&amp; currentItem != null)
            {
                string fieldValue = multivalueField.Value.ToString();
                //if the field has values
                if (!string.IsNullOrEmpty(fieldValue))
                {
                    List guids = fieldValue.Split('|').ToList(); //split the fields using a pipe delimiter
                    List returnVals = new List();

                    //get the master database
                    Sitecore.Data.Database master = Sitecore.Configuration.Factory.GetDatabase("master");
                    foreach (string guid in guids)
                    {
                        //if we have a valid id, get the item
                        ID refID;
                        if (ID.TryParse(guid, out refID))
                        {
                            Item tempItem = master.GetItem(refID, currentItem.Language);
                            if (tempItem != null)
                            {
                                //if value is returned add it to the collection
                                returnVals.Add(tempItem.Fields[LookupField].ToString());
                            }
                        }
                        else //process it as text
                        {
                            Log.Warn(string.Format("Textbased Multivalue: Parent ID:{0} GUID:{1} Primary Field:{2} Lookup Field:{3}", p_Indexable.Id.ToString(), guid, PrimaryField, LookupField), this);
                            returnVals.Add(guid);
                        }
                    }
                    //return values with semi-colon delimited
                    return string.Join(";", returnVals);
                }
            }
            return null;
        }

        #endregion

    }
}
</code></pre>
<p>The ComputedFieldValue method exists as in any other computed field implementation, the difference is the constructor that takes in the XmlNode and when the properties are called we extract the attributes. I hope this helps you with your computed fields, let me know if you have any questions or need additional information.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Add Dynamic Query Suggestions to Your Search Box in Coveo JS Framework</title>
      <link>https://akshaysura.com/blog/add-dynamic-query-suggestions-to-your-search-box-in-coveo-js-framework/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/add-dynamic-query-suggestions-to-your-search-box-in-coveo-js-framework/</guid>
      <pubDate>Wed, 06 Aug 2014 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Posted 08/05/2014 by Akshay Sura]]></description>
      <content:encoded><![CDATA[<p>Posted 08/05/2014 by Akshay Sura</p>
<p>In almost every search implementation we had to add an auto suggestions for the search box. This job is made easy by using the Coveo JS Framework. You can achieve the basic functionality using the article found <a href="https://developers.coveo.com/display/public/SC201407/Add+Query+Suggestions+to+Your+Search+Box" target="_blank">HERE</a>.</p>
<p>But in most cases you do not want a set list of auto suggestions, rather you would want it to use the index to pull the list. Below is a standard implementation where we are pulling results from a Sitecore folder.</p>
<pre><code>
&lt;code readability="2"&gt;
&amp;lt;div class="CoveoSearchInterface" id="productfinder"&amp;gt;&lt;br /&gt;&amp;lt;span class="CoveoTopFieldSuggestions"&lt;br /&gt;data-field="&amp;lt;%= Coveo.UI.SitecoreUtilities.ToCoveoFieldName("Auto Suggestion Keyword") %&amp;gt;"&lt;br /&gt;data-header-title="Suggested Products"&amp;gt;&amp;lt;/span&amp;gt;&lt;p&gt;&amp;lt;div class="CoveoSearchBox" data-activate-omnibox="true"&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;/p&gt;&lt;/code&gt;
</code></pre>
<pre><code>

</code></pre>
<pre><code>
&lt;code readability="8.5"&gt;&lt;code readability="17"&gt;
&amp;lt;script type="text/javascript"&amp;gt;&lt;br /&gt;var pathField = "&amp;lt;%= Coveo.UI.SitecoreUtilities.ToCoveoFieldName("_Path") %&amp;gt;";&lt;p&gt;$(function () {&lt;br /&gt;var productSearchInterface = $("#productfinder");&lt;br /&gt;productSearchInterface.on("afterInitialization", function () {&lt;br /&gt;productSearchInterface.on("newQuery", function (e, args) {&lt;br /&gt;var currentKeyword = productSearchInterface.coveo("state", "q");&lt;br /&gt;if (currentKeyword != "") {&lt;br /&gt;window.location.href = productSearchPage + "?typ=product#q=" + encodeURIComponent(currentKeyword)&lt;br /&gt;}&lt;br /&gt;})&lt;br /&gt;})&lt;/p&gt;&lt;p&gt;$('#productfinder').coveo('init', {&lt;br /&gt;SearchInterface: {&lt;br /&gt;autoTriggerQuery: false,&lt;br /&gt;hideUntilFirstQuery: false,&lt;br /&gt;enableHistory: false&lt;br /&gt;},&lt;br /&gt;TopFieldSuggestions: {&lt;br /&gt;queryOverride: pathField + "=G44E5065B7EE4C1AA257D9440D3B30SS"&lt;br /&gt;}&lt;br /&gt;});&lt;br /&gt;});&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/p&gt;&lt;/code&gt;&lt;/code&gt;
</code></pre>
<pre><code>

</code></pre>
<p><code>In order for us to make this a bit more dynamic, we need to identify the template or templates we want the results to come from, along with the field or fields which need to be searched. As an example, lets say we have a Product template with a field Product Name. When a user starts typing in to a product finder, we would like to search the index for all items which are based on the Product Template and we would match the search string against the Product Name field.</code></p>
<pre><code>
&lt;code&gt;&lt;code&gt;
   &amp;lt;div class="CoveoSearchInterface" id="productfinder"&amp;gt;&lt;br /&gt;&amp;lt;span class="CoveoTopFieldSuggestions"&lt;br /&gt;data-field="&amp;lt;%= Coveo.UI.SitecoreUtilities.ToCoveoFieldName("Product Name") %&amp;gt;"&lt;br /&gt;data-header-title="Suggested Products"&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;&amp;lt;div class="CoveoSearchBox" data-activate-omnibox="true"&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/code&gt;
</code></pre>
<pre><code>

</code></pre>
<pre><code>
&lt;code readability="8.5"&gt;&lt;code readability="17"&gt;
&amp;lt;script type="text/javascript"&amp;gt;&lt;br /&gt;var pathField = "&amp;lt;%= Coveo.UI.SitecoreUtilities.ToCoveoFieldName("_Path") %&amp;gt;";&lt;br /&gt;var templateField = "&amp;lt;%= Coveo.UI.SitecoreUtilities.ToCoveoFieldName("templatename") %&amp;gt;";&lt;p&gt;$(function () {&lt;br /&gt;var productSearchInterface = $("#productfinder");&lt;br /&gt;productSearchInterface.on("afterInitialization", function () {&lt;br /&gt;productSearchInterface.on("newQuery", function (e, args) {&lt;br /&gt;var currentKeyword = productSearchInterface.coveo("state", "q");&lt;br /&gt;if (currentKeyword != "") {&lt;br /&gt;window.location.href = productSearchPage + "?typ=product#q=" + encodeURIComponent(currentKeyword)&lt;br /&gt;}&lt;br /&gt;})&lt;br /&gt;})&lt;/p&gt;&lt;p&gt;$('#productfinder').coveo('init', {&lt;br /&gt;SearchInterface: {&lt;br /&gt;autoTriggerQuery: false,&lt;br /&gt;hideUntilFirstQuery: false,&lt;br /&gt;enableHistory: false&lt;br /&gt;},&lt;br /&gt;TopFieldSuggestions: {&lt;br /&gt;queryOverride: templateField  + "=Product"&lt;br /&gt;}&lt;br /&gt;});&lt;br /&gt;});&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/p&gt;&lt;/code&gt;&lt;/code&gt;
</code></pre>
<p><code>In the above example, we are setting the template field to find Product Template and in the html markup we are are asking for Coveo to search in the Product Name field.&nbsp;</code></p>
<p><code>All of this works great. But if you add in a multi-lingual website and want results from multiple templates and fields, here is how you do it:</code></p>
<pre><code>
&lt;code&gt;&lt;code&gt;&amp;lt;div class="CoveoSearchInterface" id="generalfinder"&amp;gt;&lt;br /&gt;&amp;lt;span class="CoveoTopFieldSuggestions"&lt;br /&gt;data-field="&amp;lt;%= Coveo.UI.SitecoreUtilities.ToCoveoFieldName("Products") %&amp;gt;"&lt;br /&gt;data-header-title="Suggested Products"&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;&amp;lt;span class="CoveoTopFieldSuggestions"&lt;br /&gt;data-field="&amp;lt;%= Coveo.UI.SitecoreUtilities.ToCoveoFieldName("Article Title") %&amp;gt;"&lt;br /&gt;data-header-title="Suggested Articles"&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;&amp;lt;span class="CoveoTopFieldSuggestions"&lt;br /&gt;data-field="&amp;lt;%= Coveo.UI.SitecoreUtilities.ToCoveoFieldName("Heading") %&amp;gt;"&lt;br /&gt;data-header-title="Suggested Items"&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;&amp;lt;div class="CoveoSearchBox" data-activate-omnibox="true"&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/code&gt;
</code></pre>
<pre><code>
&lt;code&gt;
&amp;lt;script type="text/javascript"&amp;gt;&lt;br /&gt;var templateField = "&amp;lt;%= Coveo.UI.SitecoreUtilities.ToCoveoFieldName("templatename") %&amp;gt;";&lt;/code&gt;
</code></pre>
<pre><code>
&lt;code&gt;&lt;code&gt;    var languageField = "&amp;lt;%= Coveo.UI.SitecoreUtilities.ToCoveoFieldName("language") %&amp;gt;";&lt;/code&gt;&lt;/code&gt;
</code></pre>
<pre><code>

</code></pre>
<pre><code>
&lt;code&gt;&lt;code&gt;    var currentLang = "&amp;lt;%= Model.CultureName %&amp;gt;";&lt;/code&gt;&lt;/code&gt;
</code></pre>
<pre><code>

&lt;br /&gt;$('#generalfinder').coveo('init', {&lt;br /&gt;SearchInterface: {&lt;br /&gt;autoTriggerQuery: false,&lt;br /&gt;hideUntilFirstQuery: false,&lt;br /&gt;enableHistory: false&lt;br /&gt;},&lt;br /&gt;TopFieldSuggestions: {&lt;br /&gt;queryOverride: templateField  + "='News Article' OR " + templateField  + "=Product OR " + templateField  + "='Press Releases' AND " + languageField + "=" + currentLang&lt;br /&gt;}&lt;br /&gt;});&lt;br /&gt;});&lt;br /&gt;&amp;lt;/script&amp;gt;
</code></pre>
<p>Fields used for auto suggestions have to be setup as Facets.</p>
<p>Let me know if you have any questions or comments.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Foreign Keys and Computed Fields in Coveo for Sitecore</title>
      <link>https://akshaysura.com/blog/foreign-keys-and-computed-fields-in-coveo-for-sitecore/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/foreign-keys-and-computed-fields-in-coveo-for-sitecore/</guid>
      <pubDate>Wed, 30 Jul 2014 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Posted 07/29/2014 by Akshay Sura]]></description>
      <content:encoded><![CDATA[<p>Posted 07/29/2014 by Akshay Sura</p>
<p>Coveo JS Framework allows us to deploy search pages with minimal coding. Most of the functionality can be achieved via configuration from the page/content editor. Eventually you would need to add in facets or fields that require you to define relationships between templates. For instance a News items has News Categories, and while displaying the News items in the search we would also like to display the category/categories the news item belongs to.</p>
<p>To achieve this functionality, we can use Foreign Keys. There is some documentation on the Coveo website at this <a href="https://developers.coveo.com/display/public/SC201407/Using+the+Sitecore+Search+Provider" target="_blank">Link</a>. Foreign Keys are pretty straight forward, we need to know the parent/main Template, in our case its News and the Field (guid(s)), which link to the child template, which is News Categories. We then need the child template, which is News Category, and its ID and Value fields, id and Category Name respectively.</p>
<p>Knowing the above, you would add it to your custom config, here is a sample:</p>
<pre><code>
  
    
      
        
          
            
              
                
                  News
</code></pre>
<p>News Categories News Category id Category Name</p>
<p>Foreign Keys work great, they do not increase the indexing time but are not suitable in a multilingual scenario. For a site running on multiple languages you would need to use computed fields or modify the REST pipeline to get the values in the context language. We will cover the REST pipeline for Coveo in future posts.</p>
<p>Creating a computed field is very easy and you can find some documentation on the Coveo website at this <a href="https://developers.coveo.com/display/public/SC201407/Create+Computed+Fields" target="_blank">Link</a>. &nbsp;</p>
<p>A computed field allows us to store a computed/calculated value in an additional field in the index. So for instance if you are storing products, we can have a computed field which automatically calculates the shipping cost based on the product weight and dimensions and stores it. This way the UI does not have to do this calculation.</p>
<p>Similarly, in a multilingual scenario, we can use the computed field to store the language specific value(s) for foreign key relationships.</p>
<p>Here is an example of a computed field that clears any html from a summary field and stores it in the index for display purposes:</p>
<pre><code>
using Sitecore;
using Sitecore.ContentSearch;
using Sitecore.ContentSearch.ComputedFields;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace YOURNAMESPACE.ComputedFields
{
    //computed field to strip html from the summary field.
    public class CleanSummaryField : IComputedIndexField
    {
        public object ComputeFieldValue(Sitecore.ContentSearch.IIndexable p_Indexable)
        {
                        //get the field from the item which needs to be processed
            IIndexableDataField field = p_Indexable.GetFieldByName("Summary");
            var value = string.Empty;

            //check if the summary field is not null and has a value
            if (field != null &amp;&amp; !string.IsNullOrEmpty(field.Value.ToString()))
            {
                var nonClean = field.Value.ToString();

                //use html agility pack to load the document and get just text
                var doc = new HtmlAgilityPack.HtmlDocument();
                doc.LoadHtml(nonClean);
                                
                value = doc.DocumentNode.InnerText;
            }

            return value;
        }

        public string FieldName { get; set; }
        public string ReturnType { get; set; }
    }
}

</code></pre>
<p>Here is the sample configuration in your custom config:</p>
<pre><code>
  
    
      
        
          
            Sitecore.ContentSearch.ComputedFields.AllTemplates, Sitecore.ContentSearch
</code></pre>
<p>YOURNAMESPACE.ComputedFields.CleanSummaryField, YOURNAMESPACE</p>
]]></content:encoded>
    </item>
    <item>
      <title>Coveo JS Framework with Sitecore 7</title>
      <link>https://akshaysura.com/blog/coveo-js-framework-with-sitecore-7/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/coveo-js-framework-with-sitecore-7/</guid>
      <pubDate>Fri, 25 Jul 2014 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Posted 07/25/2014 by Akshay Sura]]></description>
      <content:encoded><![CDATA[<p>Posted 07/25/2014 by Akshay Sura</p>
<p>The new Coveo JS Framework for Sitecore 7.x has a lot of features out of the box that are especially great for the end user (the Content Admin). After the initial growing pains of adopting the bleeding edge of the new framework, the product is maturing and stabilizing.&nbsp;</p>
<p>We have been using this product for the past 9 months on two huge Sitecore implementations and have learned a lot. Coveo integrates into the Sitecore CMS well and most of the work can be performed using configuration and Sitecore admin.</p>
<p>The setup starts with an installer, provider Sitecore package and an Interface Sitecore package. If you leave the default options, there are no configuration changes needed. If you happen to change the install directory, you would have to update the config file with the modified path. By default it install it to c:CES7.</p>
<p>Like all systems, customization is key. Most of the customization for the Coveo JS framework is markup and js. Coveo has some documentation on developer.coveo.com and they have also added answers.coveo.com, these can guide you in the right direction. I often found myself wanting more information and so had to reach out to support. The team at Coveo is very helpful at resolving issues.</p>
<p>The following are a few of the customizations you might run into:</p>
<ol>
<li>Top Suggestions in the search box (results coming in from a static list or based on multiple templates and fields)</li>
<li>Custom Facets</li>
<li>Multi-Lingual Facets</li>
<li>Customize search result items (since all data come from the REST webservice the index needs to have all the values you need for the js framework)</li>
<li>Customize REST Pipeline (to pass in additional data to the front end without having to index everything, item look up etc.)</li>
<li>Foreign Keys</li>
</ol>
<p>Needless to say that we have lived and breathed Coveo along with Sitecore in the last 9 months and feel like we have seen it grow. Matt Schultz&#8217;s idea of extending the REST pipeline to add in additional information to the response is sure to be picked up and included into the future builds of Coveo.</p>
<p>If you have any questions or need more information, be sure to reach out. We will be publishing a few more blog posts on Coveo in the coming days.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Multilist with Search bug in Sitecore 7.1 (rev. 130926)</title>
      <link>https://akshaysura.com/blog/multilist-with-search-bug-in-sitecore-7-1-rev-130926/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/multilist-with-search-bug-in-sitecore-7-1-rev-130926/</guid>
      <pubDate>Tue, 15 Apr 2014 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Posted 04/15/2014 by Akshay Sura]]></description>
      <content:encoded><![CDATA[<p>Posted 04/15/2014 by Akshay Sura</p>
<p>The Multilist with Search control is very useful, especially when using it with items in an Item Bucket. The issue is that all the new controls with search are not properly documented. There are several blog posts online providing different ways to set the source in order to get the desired results.</p>
<p>The issue we faced was specifically in Sitecore 7.1&nbsp;(rev. 130926).</p>
<p>Issue/Bug: When Multilist with Search control was used in a source item which was located in the same item bucket as the datasource for the Multilist, it did not render any results and the search would fail. If the source item is located outside of the item bucket the Multilist with Search works fine.</p>
<p>For example, a product having similar products field. The products node is an Item Bucket with product items, for each product item there is a field to tag similar products which points back to the Item Bucket.</p>
<p>So I added a Sitecore support ticket and started working with the support Tech. Once we were able to reproduce this on multiple environments we knew this was a real bug.</p>
<p>First step was to remove all customizations and that did not help. It ended up being the combination of the Link Provider&#8217;s languageEmbedding&nbsp;setting and Item Bucket&#8217;s Show Search Results setting (/sitecore/system/Settings/Buckets/Item Buckets Settings).</p>
<p>If the Item Bucket&#8217;s &#8216;Show Search Results&#8217; setting is set to New Tab and the Link Provider&#8217;s languageEmbedding=&#8221;asNeeded&#8221; &nbsp;it works.<br />If the Item Bucket&#8217;s &#8216;Show Search Results&#8217; setting is set to New Tab and the Link Provider&#8217;s&nbsp;languageEmbedding=&#8221;always&#8221; it fails.</p>
<p>The setting I was trying to use was to set the Show Search Results to open in a New Content Editor and languageEmbedding as always. Sitecore filed an official bug and provided a bug fix.</p>
<p>Here is how you apply the patch:&nbsp;<br />1. Place the Sitecore.Support.406408.dll assembly to the Bin folder.<br />2. In the WebsitesitecoreshellApplicationsBucketsScripts folder, rename the &#8216;ItemBucket.js&#8217; file to &#8216;ItemBucket.js.ORIGINAL&#8217;. Place the attached ItemBucket.js file to the folder.<br />3. In the uiLaunchSearchResult pipeline of the web.config file, replace the following processor:<br />&lt;processor mode=&#8221;on&#8221; type=&#8221;Sitecore.Shell.Framework.Pipelines.LaunchSearchResult,Sitecore.Kernel&#8221; method=&#8221;OpenItem&#8221;/&gt;<br />with this one:<br />&lt;processor mode=&#8221;on&#8221; type=&#8221;Sitecore.Support.Shell.Framework.Pipelines.LaunchSearchResult,Sitecore.Support.406408&#8243; method=&#8221;OpenItem&#8221;/&gt;<br />4. In the Commands.config file, replace the following command:&nbsp;<br />&lt;command name=&#8221;search:launchresult&#8221; type=&#8221;Sitecore.Shell.Applications.Search.Instant.Commands.LaunchResult,Sitecore.Client&#8221;/&gt;<br />with this one<br />&lt;command name=&#8221;search:launchresult&#8221; type=&#8221;Sitecore.Support.Shell.Applications.Search.Instant.Commands.LaunchResult,Sitecore.Support.406408&#8243;/&gt;<br />5. Clear browser cache.</p>
<p>Here is the <a href="http://nttdatasitecore.com/files/Sitecore.Support.406408.zip" target="_blank">link to the zip file</a>.</p>
<p>In the process of resolving this bug, I ended up replicating the Multilist with Search, which basically uses a web handler (.ashx) to process the request. If you require the code please get in touch with me.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Is Sitecore Azure right for you?</title>
      <link>https://akshaysura.com/blog/is-sitecore-azure-right-for-you/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/is-sitecore-azure-right-for-you/</guid>
      <pubDate>Thu, 12 Dec 2013 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Posted 12/11/2013 by asura]]></description>
      <content:encoded><![CDATA[<p>Posted 12/11/2013 by asura</p>
<p>In a recent discovery project I was evaluating Sitecore Azure. I have worked with Amazon AWS and EC2 before and so I was really excited to learn about Azure.</p>
<p>Site in the cloud, limitless possibilities, scalability&hellip;. Wrong.</p>
<p>I was extremely disappointed that Sitecore Azure cannot handle the solution we were proposing due to limitation on the Azure platform. In my mind a cloud based solution shouldn&rsquo;t have the limits I was encountering with Azure.</p>
<p>We scoped out and built applications similar to this before, applications that are multi-lingual with multiple country sites. Typically this kind of Sitecore application with out of the box analytics is consuming around 52GB of data.</p>
<p>This is with only a handful of country websites. The master and web databases are not that far behind, they are running between 30 &ndash; 40GB.</p>
<p>The requirements were simple:</p>
<ul>
<li>Sitecore Application will host and run over 100 website.</li>
<li>Each website will have an average of 2 languages.</li>
<li>Most of the sites will use out of the box DMS features.</li>
<li>Some sites will host content while others will host products.</li>
<li>There was a need to store a huge amount of documents in the media library.</li>
<li>Store videos in Azure Media Services.</li>
</ul>
<p>Based on the previous experience, we are looking at an analytics db which can run at 520GB for an application with about 150 websites. Imagine the sizes for the master and web databases.</p>
<p>Consider the facts of Sitecore Azure (it&rsquo;s not really Sitecore&rsquo;s fault, I put this mostly on Azure):</p>
<ul>
<li>Sitecore Azure can only run on SQL Azure.</li>
<li>SQL Azure limits the maximum database size to 150GB (in our case, may be 3 sites)</li>
<li>Sitecore Azure does not support file media.</li>
<li>Sitecore Azure does not have a media connector for Azure Media similar to Brightcove and Ooyala. This meant we had to create on ourselves.</li>
</ul>
<p>Same scenario, Amazon fares a lot better than Azure. Azure mind you is Microsoft and I do not understand why Microsoft cant do what Amazon does with a Microsoft product.</p>
<p>Amazon RDS can support a single database instance for SQL Server with 1TB of storage.</p>
<p>Microsoft SQL Server 2012 R2 by itself, loaded on to a powerful server can store upto 524 PB, that is right, petabites.</p>
<p>Now to me this whole thing could have been solved if Sitecore Azure can connect to a SQL Server instance on a VM in Azure IaaS environment. But that is not the case.</p>
<p>Based on the requirements and the facts we could not go with Sitecore Azure. Depending on your requirements, Sitecore Azure might fit your needs.</p>
<p>Here are some useful links:</p>
<p><a href="http://technet.microsoft.com/en-us/library/ms143432.aspx" target="_blank">http://technet.microsoft.com/en-us/library/ms143432.aspx</a></p>
<p><a href="http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_SQLServer.html" target="_blank">http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_SQLServer.html</a></p>
<p><a href="http://www.develop.com/sqlazurevsamazonrds" target="_blank">http://www.develop.com/sqlazurevsamazonrds</a></p>
<p>If you have any questions or need the source, email me at Akshay dot sura at nttdata dot com.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Installing and Configuring Custom Workflow Comments Module (CWC) for Sitecore 7</title>
      <link>https://akshaysura.com/blog/installing-and-configuring-custom-workflow-comments-module-cwc-for-sitecore-7/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/installing-and-configuring-custom-workflow-comments-module-cwc-for-sitecore-7/</guid>
      <pubDate>Wed, 20 Nov 2013 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Posted 11/19/2013 by asura]]></description>
      <content:encoded><![CDATA[<p>Posted 11/19/2013 by asura</p>
<p>The module was posted to the marketplace recently and can be accessed using this url:&nbsp;<a href="http://marketplace.sitecore.net/en/Modules/Custom_Workflow_Comments_-_CWC.aspx" target="_blank">http://marketplace.sitecore.net/en/Modules/Custom_Workflow_Comments_-_CWC.aspx</a></p>
<p>Here are the instructions for installing and configuring the module:</p>
<ol>
<li>Install the Custom Workflow Comments (CWC) Module, when prompted, overwrite the workflow template</li>
<li>Define a template to gather information during Workflow actions</li>
<li>Modify the template defined to inherit from templates/modules/Custom Workflow Comments/Custom Workflow Comments Base and also set the Bucketable checkbox to true</li>
<li>Modify Workflow item under sitecore/System/Workflows and set the field Custom Template to the template you created</li>
<li>Assign the Workflow to an item/template</li>
<li>Turn on the Bucket Items in the Application Options</li>
<li>Turn on the Developer Tab</li>
<li>Click on sitecoreContentWorkflow Comments, then click on Configure tab and click on Sync</li>
<li>Click on the Developer tab and click Re-Index Tree to index Workflow Comments and its dependents (at this moment, none!).</li>
<li>Once item is available in the Workbox, you can see the module work when you Submit/Approve/Reject item in workflow</li>
<li>You can check the history by clicking on the More link on the item in the Workbox or when the item is selected in the content editor, click on the Review tab and then click on History</li>
</ol>
<p>I have also put together the video below to help with the configuration and also demo the capabilities.</p>
<p><iframe width="640" height="360" src="//www.youtube.com/embed/JTxvIyOphoc" frameborder="0">[embedded content]</iframe></p>
<div readability="8">
<p>If you have any questions or need the source, email me at Akshay dot sura at nttdata dot com.</p>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Custom Workflow Comments CWC Module for Sitecore 7 Part 2</title>
      <link>https://akshaysura.com/blog/custom-workflow-comments-cwc-module-for-sitecore-7-part-2/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/custom-workflow-comments-cwc-module-for-sitecore-7-part-2/</guid>
      <pubDate>Mon, 18 Nov 2013 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Posted 11/17/2013 by asura]]></description>
      <content:encoded><![CDATA[<p>Posted 11/17/2013 by asura</p>
<p>Part 2 of this blog post will focus on the UI aspects. We will be modifying the display of Comments in the Workbox and the History in the Review tab.</p>
<p>Using a refactor tool like the .NET Reflector or JetBrains dotPeek to decompile Sitecore.Client and grab code for&nbsp;Sitecore.Shell.Applications.Workbox.WorkboxHistoryXmlControl.</p>
<p><strong>Step 1 &#8211; Override</strong></p>
<p>To implement this we need to override the functionality in WorkboxHistory.xml. To do this, create the following folders under WebsitesitecoreshellOverride folder:</p>
<ul>
<li>Applications</li>
</ul>
<p>Copy WorkboxHistory.xml from WebsitesitecoreshellApplicationsWorkbox<br />To<br />WebsitesitecoreshellOverrideApplicationsWorkbox</p>
<p><strong>Step 2 &ndash; Code Behind</strong></p>
<p>Use a refactor tool like the .NET Reflector or JetBrains dotPeek to decompile Sitecore.Client and grab code for Sitecore.Shell.Applications.Workbox.WorkBoxHistoryXmlControl.</p>
<p>Add a WorkboxHistoryXmlControl class in your BL or Sitecore Extensions project to mirror the Sitecore.Shell.Applications.Workbox.WorkboxHistoryXmlControl class.</p>
<p><strong>Step 3 &#8211; CodeBeside</strong></p>
<p>Modify the WorkboxHistory.xml file in the override folder to replace the value in the CodeBeside tag.</p>
<pre><code>
  
</code></pre>
<p><strong>Step 4 &ndash; Config</strong></p>
<p>Since we are modifying an Xml Control, we need at add our library to the uiusings and uireferences nodes in the web.config.</p>
<p><strong>Step 5 &#8211; Code</strong></p>
<p>In your WorkboxHistoryXmlControl class, modify the OnLoad method to detect custom template comments. See the highlighted rows below:</p>
<pre><code>
protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            this.WriteLanguageCssClass();
            if (!Sitecore.Context.ClientPage.IsEvent)
            {
                IWorkflowProvider workflowProvider = Sitecore.Context.ContentDatabase.WorkflowProvider;
                if (workflowProvider != null)
                {
                    IWorkflow workflow = workflowProvider.GetWorkflow(this.WorkflowID);
                    Error.Assert(workflow != null, string.Concat("Workflow "", this.WorkflowID, "" not found."));
                    Item item = Sitecore.Context.ContentDatabase.Items[this.ItemID, Sitecore.Globalization.Language.Parse(this.Language), Sitecore.Data.Version.Parse(this.Version)];
                    if (item != null)
                    {
                        NameValueCollection nameValueCollection = new NameValueCollection();
                        NameValueCollection nameValueCollection1 = new NameValueCollection();
                        WorkflowState[] states = workflow.GetStates();
                        for (int i = 0; i &amp;lt; (int)states.Length; i++)
                        {
                            WorkflowState workflowState = states[i];
                            nameValueCollection.Add(workflowState.StateID, workflowState.DisplayName);
                            nameValueCollection1.Add(workflowState.StateID, workflowState.Icon);
                        }
                        WorkflowEvent[] history = workflow.GetHistory(item);
                        string name = Sitecore.Context.Domain.Name;
                        WorkflowEvent[] workflowEventArray = history;
                        for (int j = 0; j &amp;lt; (int)workflowEventArray.Length; j++)
                        {
                            WorkflowEvent workflowEvent = workflowEventArray[j];
                            string user = workflowEvent.User;
                            if (user.StartsWith(string.Concat(name, ""), StringComparison.OrdinalIgnoreCase))
                            {
                                user = StringUtil.Mid(user, name.Length + 1);
                            }
                            string[] strArrays = new string[] { user, Translate.Text("Unknown") };
                            user = StringUtil.GetString(strArrays);
                            string str = nameValueCollection1[workflowEvent.NewState];
                            string[] item1 = new string[] { nameValueCollection[workflowEvent.OldState], "?" };
                            string str1 = StringUtil.GetString(item1);
                            string[] strArrays1 = new string[] { nameValueCollection[workflowEvent.NewState], "?" };
                            string str2 = StringUtil.GetString(strArrays1);
                            string str3 = DateUtil.FormatDateTime(workflowEvent.Date, "D", Sitecore.Context.User.Profile.Culture);
                            XmlControl webControl = Resource.GetWebControl("WorkboxHistoryEntry") as XmlControl;
                            this.History.Controls.Add(webControl);
                            webControl["User"] = user;
                            webControl["Icon"] = str;
                            webControl["Date"] = str3;
                            webControl["Action"] = string.Format(Translate.Text("Changed from &lt;strong&gt;{0}&lt;/strong&gt; to &lt;strong&gt;{1}&lt;/strong&gt;."), str1, str2);

                            //check if the value in the Text field is an ID
                            Sitecore.Data.ID customWorkFlowItemID;
                            if (Sitecore.Data.ID.TryParse(workflowEvent.Text, out customWorkFlowItemID))
                            {
                                //get the rendered text from the fields of the custom template item from the item bucket
                                webControl["Text"] = GetWorkflowItemDetails(customWorkFlowItemID);                                
                            }
                            else
                                webControl["Text"] = workflowEvent.Text;
                        }
                    }
                }
            }
        }
</code></pre>
<p>Also we added the GetWorkflowItemDetails method to gather all fields and their values to be rendered on the UI.</p>
<pre><code>
    
        /// 
        /// Returns the output with all the fields and their values associated with the custom template item from the item bucket
        /// 
</code></pre>
<p>/// The ID of the custom template item. private string GetWorkflowItemDetails(Sitecore.Data.ID customWorkFlowItemID) { StringBuilder returnString = new StringBuilder(); //get the item and make sure its not null Item customWorkflowItem = Sitecore.Context.ContentDatabase.GetItem(customWorkFlowItemID); if (customWorkflowItem != null) { //loop through all the item fields foreach (Field field in customWorkflowItem.Fields) { //only extract the template fields and their values if (!(field.Name == &#8220;Additional Parameters&#8221;) &amp;&amp; (!(field.Name == &#8220;Personalization&#8221;) || UserOptions.View.ShowPersonalizationSection) &amp;&amp; ((!(field.Name == &#8220;Tests&#8221;) || UserOptions.View.ShowTestLabSection) &amp;&amp; RenderingItem.IsAvalableNotBlobNotSystemField(field))) returnString.AppendLine(string.Format(&#8220;<strong>{0}</strong>: {1}<br />&#8221;, field.DisplayName, field.Value)); } } return returnString.ToString(); }</p>
<p>Compile the dll and shown below are the results.&nbsp;</p>
<p><img loading="lazy" alt="" height="538" width="467" src="http://akshaysura.com/wp-content/uploads/2013/11/Workbox_Comments.png" /></p>
<p><img loading="lazy" alt="" height="510" width="547" src="http://akshaysura.com/wp-content/uploads/2013/11/Review_History.png" /></p>
<p><strong>Step 6 &#8211; Magic Code</strong></p>
<p>The class to take over the WorkboxForm does all the heavy lifting. It has the logic to switch between standard functionality and Custom template functionality. The Comments method does the work for us in deciding if a custom template form needs to be displayed and how the results are going to be stored. See the highlighted rows below:</p>
<pre><code>
/// 
        /// Comments the specified args.
        /// 
</code></pre>
<p>/// /// The arguments. /// public void Comment(ClientPipelineArgs args) { Assert.ArgumentNotNull(args, &#8220;args&#8221;); if (!args.IsPostBack) { bool showCustom = false; //get workflow item Item workflowItem = Context.ContentDatabase.GetItem(Context.ClientPage.ServerProperties[&#8220;workflowid&#8221;] as string); Template customTemplate = null; //check if the custom template field has a value if (workflowItem != null &amp;&amp; !string.IsNullOrEmpty(workflowItem[new ID(Consts.FieldIDs.CustomTemplate)])) { //load custom template based on the field value customTemplate = TemplateManager.GetTemplate(new ID(workflowItem[new ID(Consts.FieldIDs.CustomTemplate)].ToString()), Context.ContentDatabase); //check if it inherits Custom Workflow Comments Base template if (customTemplate != null &amp;&amp; customTemplate.InheritsFrom(new ID(Consts.TemplateIDs.CustomWorkflowCommentsBase))) showCustom = true; } //decide if we show the standard comments dialog or custom dialog if (showCustom) { if (!new RenderCustomTemplate() { Args = args, ItemID = new ID(Context.ClientPage.ServerProperties[&#8220;id&#8221;].ToString()), CustomTemplateID = customTemplate.ID, Language = Language.Parse(Context.ClientPage.ServerProperties[&#8220;language&#8221;] as string), Version = Sitecore.Data.Version.Parse(Context.ClientPage.ServerProperties[&#8220;version&#8221;] as string) }.Show()) return; } else { //display regular comments dialog Context.ClientPage.ClientResponse.Input(&#8220;Enter a comment:&#8221;, string.Empty); args.WaitForPostBack(); } return; } if (args.Result.Length &gt; 2000) { Context.ClientPage.ClientResponse.ShowError(new Exception(string.Format(&#8220;The comment is too long.nnYou have entered {0} characters.nA comment cannot contain more than 2000 characters.&#8221;, args.Result.Length))); Context.ClientPage.ClientResponse.Input(&#8220;Enter a comment:&#8221;, string.Empty); args.WaitForPostBack(); return; } if (args.Result != null &amp;&amp; args.Result != &#8220;null&#8221; &amp;&amp; args.Result != &#8220;undefined&#8221;) { string language = Context.ClientPage.ServerProperties[&#8220;language&#8221;].ToString(); string version = Context.ClientPage.ServerProperties[&#8220;version&#8221;].ToString(); //check if the return is text comments or from a custom template IEnumerable resultingFields = (IEnumerable)RenderingParametersFieldEditorOptions.Parse(args.Result).Fields; string comments = &#8220;&#8221;; comments = args.Result; //if the result is from a custom template if (resultingFields.Count() &gt; 0) { //get the item bucket var bucketItem = Context.ContentDatabase.GetItem(Consts.ItemIDs.WorkflowCommentsItemBucket); if (bucketItem != null &amp;&amp; BucketManager.IsBucket(bucketItem)) { //get workflow item Item workflowItem = Context.ContentDatabase.GetItem(Context.ClientPage.ServerProperties[&#8220;workflowid&#8221;] as string); //check if the custom template field has a value if (workflowItem != null &amp;&amp; !string.IsNullOrEmpty(workflowItem[new ID(Consts.FieldIDs.CustomTemplate)])) { // locate item in bucket by name using ( var searchContext = ContentSearchManager.GetIndex(bucketItem as IIndexable).CreateSearchContext()) { //ShortID.Encode(item.ID).ToLowerInvariant()) string searchCustomWorkflowCommentsItemTemplate = ShortID.Encode(Consts.TemplateIDs.CustomWorkflowCommentsItem).ToLowerInvariant(); string searchWorkflowItemID = ShortID.Encode(Context.ClientPage.ServerProperties[&#8220;id&#8221;].ToString()).ToLowerInvariant(); var result = searchContext.GetQueryable() .Where( x =&gt; x.Template.Equals(searchCustomWorkflowCommentsItemTemplate) &amp;&amp; x.WorkflowItemID == searchWorkflowItemID &amp;&amp; x.Language == language &amp;&amp; x.Version == version) .FirstOrDefault(); //generate valid unique name string validItemName = ItemUtil.ProposeValidItemName(DateUtil.IsoNow.ToString()); Item parent = null; //based on the result, assign parent as the item found or the item bucket if (result != null) { parent = Context.ContentDatabase.GetItem(result.ID); } //load templates for Custom template and the Custom Workflow Comments Item TemplateItem customTemplate = Context.ContentDatabase.GetTemplate(new ID(workflowItem[new ID(Consts.FieldIDs.CustomTemplate)].ToString())); TemplateItem customWorkflowCommentsItem = Context.ContentDatabase.GetTemplate(new ID(Consts.TemplateIDs.CustomWorkflowCommentsItem)); using (new SecurityDisabler()) { if (parent == null) { //create an item based on Custom Workflow Comments Item and store the workflow item values Item newItem = bucketItem.Add(validItemName, customWorkflowCommentsItem); newItem.Editing.BeginEdit(); newItem.Fields[new ID(Consts.FieldIDs.CustomWorkflowCommentsItem.WorkflowItemID)].Value = Context.ClientPage.ServerProperties[&#8220;id&#8221;].ToString(); //workflow item id newItem.Fields[new ID(Consts.FieldIDs.CustomWorkflowCommentsItem.Language)].Value = language; //language newItem.Fields[new ID(Consts.FieldIDs.CustomWorkflowCommentsItem.Version)].Value = version; //version newItem.Editing.AcceptChanges(); parent = newItem; } //generate another valid unique name validItemName = ItemUtil.ProposeValidItemName(DateUtil.IsoNow.ToString()); //create an item based on the custom template you chose under the Custom Workflow Comments Item Item customItem = parent.Add(validItemName, customTemplate); customItem.Editing.BeginEdit(); foreach (FieldDescriptor fieldDescriptor in resultingFields) customItem.Fields[fieldDescriptor.FieldID].Value = fieldDescriptor.Value; customItem.Editing.AcceptChanges(); //set comments to the guid of the newly created item comments = customItem.ID.ToString(); } } } } } IWorkflowProvider workflowProvider = Context.ContentDatabase.WorkflowProvider; if (workflowProvider != null) { IWorkflow workflow = workflowProvider.GetWorkflow(Context.ClientPage.ServerProperties[&#8220;workflowid&#8221;] as string); if (workflow != null) { ItemRecords items = Context.ContentDatabase.Items; object item = Context.ClientPage.ServerProperties[&#8220;id&#8221;]; object empty = item; if (item == null) { empty = string.Empty; } Item item1 = items[empty.ToString(), Language.Parse(Context.ClientPage.ServerProperties[&#8220;language&#8221;] as string), Sitecore.Data.Version.Parse(Context.ClientPage.ServerProperties[&#8220;version&#8221;] as string)]; if (item1 != null) { try { workflow.Execute(Context.ClientPage.ServerProperties[&#8220;command&#8221;] as string, item1, comments, true, new object[0]); //workflow.Execute(Context.ClientPage.ServerProperties[&#8220;command&#8221;] as string, item1, args.Result, true, new object[0]); } catch (WorkflowStateMissingException workflowStateMissingException) { SheerResponse.Alert(&#8220;One or more items could not be processed because their workflow state does not specify the next step.&#8221;, new string[0]); } UrlString urlString = new UrlString(WebUtil.GetRawUrl()); urlString[&#8220;reload&#8221;] = &#8220;1&#8221;; Context.ClientPage.ClientResponse.SetLocation(urlString.ToString()); } } } } }</p>
<p>The code and module are published.</p>
<p>The module can be accessed using the url:&nbsp;<a href="http://marketplace.sitecore.net/en/Modules/Custom_Workflow_Comments_-_CWC.aspx" target="_blank">http://marketplace.sitecore.net/en/Modules/Custom_Workflow_Comments_-_CWC.aspx</a></p>
<p>I have plans to tweak this module to add more features. If you have any questions or need the source, email me at Akshay dot sura at nttdata dot com.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Custom Workflow Comments (CWC) Module for Sitecore 7 – Part 1</title>
      <link>https://akshaysura.com/blog/custom-workflow-comments-cwc-module-for-sitecore-7-part-1/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/custom-workflow-comments-cwc-module-for-sitecore-7-part-1/</guid>
      <pubDate>Sat, 16 Nov 2013 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Posted 11/16/2013 by asura]]></description>
      <content:encoded><![CDATA[<p>Posted 11/16/2013 by asura</p>
<p>Based on my previous blog post: <a href="http://nttdatasitecore.com/Blog/2013/October/Sitecore-7-Workflow-with-more-than-a-Comment">Sitecore 7: Workflow with more than a Comment</a>, I got a lot of positive feedback and requests to improve the functionality. Thank you for all the requests and feedback. I appreciate it.</p>
<p>The concept has evolved into using any template with standard fields to accept input in the Workbox. The concept is simple, per workflow we should be able to define one template that represents fields we want to capture. For instance Workflow 1 would like to capture Name and Comments and Workflow 2 would like to capture Date, Name, Comments, Some ID values.</p>
<p>This is an attempt at building version 1 of the Custom Workflow Comments Module (CWC Module). I know there are a lot of areas where we can optimize code and add UI elements. Those will be added on in the later versions.</p>
<p>CWC module allows you to create an item template per workflow to store additional information during the workflow process of an item. When an item is processed in the workflow a dynamic form will render the fields defined in the custom template. The values entered will be store in an Item Bucket.</p>
<p>UI enhancements include changes to the workflow section in the Review tab and the more links in the Workbox.</p>
<p>To implement this I have taken the Rendering Parameters concept in the Layout details. Using a refactor tool like the .NET Reflector or JetBrains dotPeek to decompile Sitecore.Client and grab code for&nbsp;Sitecore.Shell.Applications.WorkboxForm and Sitecore.Shell.Applications.Layouts.DeviceEditor.RenderingParameters, these would act as a base for our code.</p>
<p><strong>Step 1 &#8211; Override</strong></p>
<p>To implement this we need to override the functionality in Workbox.xml. To do this, create the following folders under WebsitesitecoreshellOverride folder:</p>
<ul>
<li>Applications</li>
</ul>
<p>Copy Workbox.xml from WebsitesitecoreshellApplicationsWorkbox<br />To<br />WebsitesitecoreshellOverrideApplicationsWorkbox</p>
<p><strong>Step 2 &ndash; Code Behind</strong></p>
<p>Use a refactor tool like the .NET Reflector or JetBrains dotPeek to decompile Sitecore.Client and grab code for Sitecore.Shell.Applications.WorkboxForm and Sitecore.Shell.Applications.Layouts.DeviceEditor.RenderingParameters.</p>
<p>Add a WorkboxForm class and RenderCustomTemplate (RenderingParameters) in your BL or Sitecore Extensions project to mirror the Sitecore.Shell.Applications.Workbox.WorkboxForm class and Sitecore.Shell.Applications.Layouts.DeviceEditor.RenderingParameters class.</p>
<p><strong>Step 3 &#8211; CodeBeside</strong></p>
<p>Modify the Workbox.xml file in the override folder to replace the value in the CodeBeside tag.</p>
<pre><code>
    
</code></pre>
<p><strong>Step 4 &ndash; Templates</strong></p>
<p>I have setup the following templates</p>
<ol>
<li>Custom Workflow Comments Settings</li>
<li>Custom Workflow Comments Item</li>
<li>Custom Workflow Comments Base</li>
</ol>
<p><strong><em>Custom Workflow Comments Settings</em></strong><br />This template is inherited by the /sitecore/templates/System/Workflow/Workflow template so that we can choose to specify a custom template per workflow to gather user input.</p>
<p><img loading="lazy" alt="" height="275" width="701" src="http://akshaysura.com/wp-content/uploads/2013/11/CWC-Part-1-Workflow-Inherits.png" /></p>
<p>The value in the Custom Template field can be left blank so that the default comment input is requested. If a template is selected in this field, the CWC module will dynamically display the editor needed to accept input for that template. The only prerequisite is that the template selected has to inherit the Custom Workflow Comments Base template.</p>
<p><strong><em>Custom Workflow Comments Item</em></strong><br />This template is used to store the Workflow item&#8217;s ID, Language and Version. The idea is that we would have one instance of this template and the child items would represent items based on the custom template you decide to use. I also selected the Lock Child Relationship so that the parent and children maintain the relationship in the item bucket.</p>
<p><strong><em>Custom Workflow Comments Base</em></strong><br />The custom template you define to store user input has to inherit this template. This template has the Bucketable option selected. There is also a check in the WorkboxForm class.</p>
<p><strong>Step 4 &#8211; Custom Templates</strong></p>
<p>It&#8217;s time to define custom templates. I defined two,&nbsp;Client Custom Workflow External and&nbsp;Client Custom Workflow Internal.</p>
<p><img loading="lazy" alt="" height="204" width="792" src="http://akshaysura.com/wp-content/uploads/2013/11/CWC-Part-1-Internal.png" /></p>
<p><img loading="lazy" alt="" height="163" width="789" src="http://akshaysura.com/wp-content/uploads/2013/11/CWC-Part-1-External.png" /></p>
<p><strong>Step 5 &#8211; Item Buckets</strong><br />I created a folder under sitecorecontent folder called Workflow Comments and made it an Item Bucket.&nbsp;</p>
<p><strong>Step 6 &#8211; Code, Finally!! &#8211; Search Class</strong><br />The first thing is to define a class to hold search results for Custom Workflow Comments Item.</p>
<pre><code>
    public class CustomWorkflowCommentsItem: SearchResultItem
    {
        [IndexField("_name")]
        public string ItemName { get; set; }

        public virtual string WorkflowItemID { get; set; }
        public virtual string Language { get; set; }
        public virtual string Version { get; set; }

        [IndexField("_template")]
        public string Template { get; set; }

        [IndexField(BuiltinFields.ID)]
        public virtual ID ID { get; set; }
    }
</code></pre>
<p><strong>Step 7 &#8211; Modify&nbsp;Sitecore.ContentSearch.Lucene.DefaultIndexConfiguration.config</strong><br />By default, single line text is not indexed and depending on the project, its upto the client to make that decision. We need to add the fields to index the Workflow Item ID, Language and Version.</p>
<pre><code>
            Workflow Item ID
</code></pre>
<p>Language Version</p>
<p>Step 8 &#8211; Magic<br />The final item for this blog post is the code which pulls the fields from the custom template we pass and called the UI used by FormEditorPage.</p>
<pre><code>
    public class RenderCustomTemplate
    {
        /// 
        /// The current pipeline arguments.
        /// 
        /// 
</code></pre>
<p>private ClientPipelineArgs args; /// /// The name of the handle. /// /// private string handleName; /// /// Gets or sets the args. /// /// /// /// /// The args. /// /// public ClientPipelineArgs Args { get { return this.args; } set { Assert.ArgumentNotNull((object)value, &#8220;value&#8221;); this.args = value; } } /// /// Gets or sets the item id. /// /// /// /// /// The item id. /// public ID ItemID { private get; set; } /// /// Gets or sets the custom template id. /// /// /// /// /// The custom template id. /// public ID CustomTemplateID { private get; set; } /// /// Gets or sets the item language. /// /// /// /// /// The item language. /// public Language Language { private get; set; } /// /// Gets or sets the item version. /// /// /// /// /// The item version. /// public Version Version { private get; set; } /// /// Gets or sets the name of the handle. /// /// /// /// /// The name of the handle. /// /// public string HandleName { get { return this.handleName ?? &#8220;SC_DEVICEEDITOR&#8221;; } set { Assert.ArgumentNotNull((object)value, &#8220;value&#8221;); this.handleName = value; } } /// /// Shows this instance. /// /// /// /// /// The boolean. /// /// public bool Show() { if (!this.Args.IsPostBack) { //get the fields from the custom template RenderingParametersFieldEditorOptions fieldEditorOptions = new RenderingParametersFieldEditorOptions((IEnumerable)RenderCustomTemplate.GetFields(CustomTemplateID)); fieldEditorOptions.DialogTitle = Consts.Strings.DialogTitle; fieldEditorOptions.HandleName = this.HandleName; fieldEditorOptions.PreserveSections = true; RenderingParametersFieldEditorOptions options = fieldEditorOptions; //create url based on options UrlString urlString = options.ToUrlString(); //display UI SheerResponse.ShowModalDialog(urlString.ToString(), &#8220;720&#8221;, &#8220;480&#8221;, string.Empty, true); this.args.WaitForPostBack(); } return false; } /// /// Gets the fields. /// /// /// The custom template id to be used for this UI. /// /// The fields. /// /// public static List GetFields(ID customTemplateID) { List fieldDescriptors = new List(); Item standardValuesItem; using (new SecurityDisabler()) { //get the customTemplateID template TemplateItem templateItem = (TemplateItem)Client.ContentDatabase.GetItem(customTemplateID); if (templateItem == null) return fieldDescriptors; else standardValuesItem = templateItem.StandardValues ?? templateItem.CreateStandardValues(); //if item doesnt have any standard values, create them } //make sure we got the Item if (standardValuesItem == null) return fieldDescriptors; //get all fields FieldCollection fields = standardValuesItem.Fields; fields.ReadAll(); fields.Sort(); //for each field make sure they are not standard system fields and then add the to the List foreach (Field field in fields) { //weed out system fields if (!(field.Name == &#8220;Additional Parameters&#8221;) &amp;&amp; (!(field.Name == &#8220;Personalization&#8221;) || UserOptions.View.ShowPersonalizationSection) &amp;&amp; ((!(field.Name == &#8220;Tests&#8221;) || UserOptions.View.ShowTestLabSection) &amp;&amp; RenderingItem.IsAvalableNotBlobNotSystemField(field))) { FieldDescriptor fieldDescriptor = new FieldDescriptor(standardValuesItem, field.Name) { Value = field.Value }; fieldDescriptors.Add(fieldDescriptor); } } return fieldDescriptors; } }</p>
<p>This is how the custom templates get rendered dynamically.</p>
<p><img loading="lazy" alt="" height="519" width="736" src="http://akshaysura.com/wp-content/uploads/2013/11/CWC_Part_1_Internal_Field_Editor.png" /></p>
<p><img loading="lazy" alt="" height="519" width="736" src="http://akshaysura.com/wp-content/uploads/2013/11/CWC_Part_1_External_Field_Editor.png" /></p>
<p>I have a few more posts to complete this module and I will post the links on the social networks for the upcoming parts.</p>
<p>If you have any questions or need the source, email me at Akshay dot sura at nttdata dot com.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Sitecore 7: Workflow with more than a Comment</title>
      <link>https://akshaysura.com/blog/sitecore-7-workflow-with-more-than-a-comment/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/sitecore-7-workflow-with-more-than-a-comment/</guid>
      <pubDate>Tue, 29 Oct 2013 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Posted 10/28/2013 by asura]]></description>
      <content:encoded><![CDATA[<p>Posted 10/28/2013 by asura</p>
<p>We recently got a requirement where the client wanted to store more than just a comment when a workflow item is approved or denied. So we built a proof of concept.</p>
<p>Truthfully, if the client were to implement this, I would want to use item buckets to store the values (based on a template) and store the item&rsquo;s GUID in place of the comments (GUID:{81FEEE94-5A2F-4629-A791-4F25E69C75B1}). This would need customization of the whole Work Box. We will reassess this when the client gives the go ahead.</p>
<p>As per the proof of concept, I ended up just storing the delimited string in the comments. It does not look that bad since it only has 3 fields but if we were to store multiple fields of different data types it would get messy.</p>
<p><img loading="lazy" height="178" alt="Comments Sample" width="349" src="http://akshaysura.com/wp-content/uploads/2013/10/Comments-Sample.png" /></p>
<p>A standard workflow item approval/rejection will prompt you with the box similar to what is shown below:</p>
<p><img loading="lazy" height="149" alt="Standard Workflow Comment" width="416" src="http://akshaysura.com/wp-content/uploads/2013/10/Standard_Workflow_Comment.png" /></p>
<p>I modified it to the one shown below:</p>
<p><img loading="lazy" height="206" alt="Customized Workflow Comment" width="516" src="http://akshaysura.com/wp-content/uploads/2013/10/Customized_Workflow_Comment.png" /></p>
<p>The fields you see in the dialog are for DEMO purposes only. The actual fields used in the proof of concept were from the client&rsquo;s standard workflow process and had to meet their guidelines.</p>
<p><strong>Step 1 &#8211; Override</strong></p>
<p>To implement this we need to override the functionality in Workbox.xml. To do this, create the following folders under WebsitesitecoreshellOverride folder:</p>
<ul>
<li>Applications</li>
</ul>
<p>Copy Workbox.xml from WebsitesitecoreshellApplicationsWorkbox<br />To<br />WebsitesitecoreshellOverrideApplicationsWorkbox</p>
<p><strong>Step 2 &ndash; Code Behind</strong></p>
<p>Use a refactor tool like the .NET Reflector or JetBrains dotPeek to decompile Sitecore.Client and grab code for Sitecore.Shell.Applications.WorkboxForm.</p>
<p>Add a WorkboxForm class in your BL or Sitecore Extensions project to mirror the Sitecore.Shell.Applications.Workbox.WorkboxForm class.</p>
<p><strong>Step 3 &#8211; CodeBeside</strong></p>
<p>Modify the Workbox.xml file in the override folder to replace the value in the CodeBeside tag.</p>
<pre><code>

</code></pre>
<p><strong>Step 4 &ndash; Create Custom Dialog Layout</strong></p>
<p>We will create a XAML interface using an XML Layout.</p>
<ol>
<li>Switch to Core</li>
<li>Open Dev Center</li>
<li>Create new file of type CML Layout&nbsp;</li>
<li>Name the file Workflow Info</li>
<li>Select the LayoutsDialogs location and click next</li>
<li>Select file location as you choose (Layouts) and click next</li>
<li>Click finish</li>
</ol>
<p><strong>Step 4 &ndash; XAML</strong></p>
<p>Once the Layout file is created use the following code to define the interface elements.</p>
<pre><code>










</code></pre>
<p><strong>Step 5 &ndash; Dialog CodeBeside</strong></p>
<p>Create a new class in your BL or SitecoreExtensions project called WorkflowInfo. We are going to define two events as shown below:</p>
<pre><code>
using Sitecore.Web.UI.Pages;
using Sitecore.Web.UI.Sheer;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sitecored7.Business.Workflow
{
    public class WorkflowInfo : DialogForm
    {
        protected Sitecore.Web.UI.HtmlControls.Edit CRB;
        protected Sitecore.Web.UI.HtmlControls.Edit Release;
        protected Sitecore.Web.UI.HtmlControls.Edit Comments;
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
        }

        protected override void OnOK(object sender, EventArgs args)
        {
            //Write the response value that will be available to the Workbox Form
            var xml = string.Format("CRB:{0};Release:{1};Comments:{2};", CRB.Value, Release.Value, Comments.Value);
            SheerResponse.SetDialogValue(xml);
            base.OnOK(sender, args);
        }
    }
}
</code></pre>
<p>As you can see in the OnOK event, we format the values from the interface elements and pass it back to the caller.</p>
<p><strong>Step 6 &ndash; Back to Core</strong></p>
<p>While in Core db via Sitecore admin console, navigate tot sitecorecontentApplicationsDialogs and create an item of type Folder, name it Workflow Info.</p>
<p>Set the layout on this item to LayoutsDialogsWorkflow Info</p>
<p><img loading="lazy" height="438" alt="Core DB" width="600" src="http://akshaysura.com/wp-content/uploads/2013/10/Core_DB.png" /></p>
<p><strong>Step 7 &#8211; Magic</strong></p>
<p>In the WorkboxForm class in your code, locate the Comment method. Comment out the Enter a comment line as shown highlighted in the code below and replace it with the line 15 &ndash; 19.</p>
<pre><code>
        /// 
        /// Comments the specified args.
        /// 
</code></pre>
<p>/// /// The arguments. /// public void Comment(ClientPipelineArgs args) { Assert.ArgumentNotNull(args, &#8220;args&#8221;); if (!args.IsPostBack) { //Context.ClientPage.ClientResponse.Input(&#8220;Enter a comment:&#8221;, string.Empty); //args.WaitForPostBack(); //get core db var db = Sitecore.Data.Database.GetDatabase(&#8220;core&#8221;); //get the dialog item we created under applications var item = db.GetItem(Sitecored7.Utils.Constants.ItemsID.WorkFlowInfoDialog); //get dialog link var url = new UrlString(LinkManager.GetItemUrl(item)); //display Modal and wait for the post back Sitecore.Context.ClientPage.ClientResponse.ShowModalDialog(url.ToString(), true); args.WaitForPostBack(); return; } if (args.Result.Length &gt; 2000) { Context.ClientPage.ClientResponse.ShowError(new Exception(string.Format(&#8220;The comment is too long.nnYou have entered {0} characters.nA comment cannot contain more than 2000 characters.&#8221;, args.Result.Length))); Context.ClientPage.ClientResponse.Input(&#8220;Enter a comment:&#8221;, string.Empty); args.WaitForPostBack(); return; } if (args.Result != null &amp;&amp; args.Result != &#8220;null&#8221; &amp;&amp; args.Result != &#8220;undefined&#8221;) { IWorkflowProvider workflowProvider = Context.ContentDatabase.WorkflowProvider; if (workflowProvider != null) { IWorkflow workflow = workflowProvider.GetWorkflow(Context.ClientPage.ServerProperties[&#8220;workflowid&#8221;] as string); if (workflow != null) { ItemRecords items = Context.ContentDatabase.Items; object item = Context.ClientPage.ServerProperties[&#8220;id&#8221;]; object empty = item; if (item == null) { empty = string.Empty; } Item item1 = items[empty.ToString(), Language.Parse(Context.ClientPage.ServerProperties[&#8220;language&#8221;] as string), Sitecore.Data.Version.Parse(Context.ClientPage.ServerProperties[&#8220;version&#8221;] as string)]; if (item1 != null) { try { workflow.Execute(Context.ClientPage.ServerProperties[&#8220;command&#8221;] as string, item1, args.Result, true, new object[0]); } catch (WorkflowStateMissingException workflowStateMissingException) { SheerResponse.Alert(&#8220;One or more items could not be processed because their workflow state does not specify the next step.&#8221;, new string[0]); } UrlString urlString = new UrlString(WebUtil.GetRawUrl()); urlString[&#8220;reload&#8221;] = &#8220;1&#8221;; Context.ClientPage.ClientResponse.SetLocation(urlString.ToString()); } } } } }</p>
<p>And that is it. If you have any questions or need the source, email me at Akshay dot sura at nttdata dot com.</p>
<p></p>
]]></content:encoded>
    </item>
    <item>
      <title>Sitecore – Display number of items in a folder</title>
      <link>https://akshaysura.com/blog/sitecore-display-number-of-items-in-a-folder/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/sitecore-display-number-of-items-in-a-folder/</guid>
      <pubDate>Wed, 20 Jun 2012 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Problem: When working with folders, I often find it frustrating that I can’t see the number of items in that folder. If there are a few, you can count, but if there are many it becomes a problem. If there is a parent folder, it is as simple as looking into the parent folder to see the number of sub-items in the folder you are interested in. That might not always be the case.]]></description>
      <content:encoded><![CDATA[<p>Problem: When working with folders, I often find it frustrating that I can&rsquo;t see the number of items in that folder. &nbsp;If there are a few, you can count, but if there are many it becomes a problem. &nbsp;If there is a parent folder, it is as simple as looking into the parent folder to see the number of sub-items in the folder you are interested in. &nbsp;That might not always be the case.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2012/06/Folder-Problem1.png"><img loading="lazy" title="Folder Problem" src="http://akshaysura.com/wp-content/uploads/2012/06/Folder-Problem1.png" alt="" width="997" height="400" /></a></p>
<p>To resolve this, I thought it would be nice to show the count when you are viewing a folder. &nbsp;Here is what I did with the help of Mr. Matt Hovany:</p>
<p>1. Open Folder.xaml.xml file in&nbsp;WebsitesitecoreshellApplicationsContent ManagerEditorsFolder folder.</p>
<p>2. Add a Literal right above the GridPanel as shown below:</p>
<pre><code>
    &lt;Sitecore.Controls.HtmlPage runat="server"&gt;
      &lt;Stylesheet runat="server" Src="Folder.css" DeviceDependant="true" x:placeholder="Stylesheets"/&gt;
      &lt;AjaxScriptManager runat="server"/&gt;
      &lt;ContinuationManager runat="server" /&gt;
      &lt;div&gt; &lt;!-- Line Added --&gt;
        &lt;asp:Literal ID="TotalLit" runat="server" Visible="false"  /&gt; &lt;!-- Line Added --&gt;
      &lt;/div&gt; &lt;!-- Line Added --&gt;
      &lt;GridPanel runat="server" Width="100%" Height="100%"&gt;
        &lt;Scrollbox runat="server" ID="ItemList" Width="100%" Height="100%" Border="none" Padding="0px" Background="transparent" GridPanel.Height="100%" ContextMenu="FileList_ContextMenu" /&gt;
      &lt;/GridPanel&gt;
    &lt;/Sitecore.Controls.HtmlPage&gt;
</code></pre>
<p>3. Create a new class similar to the one below:</p>
<pre><code>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using Sitecore.Shell.Applications.ContentEditor.Editors.Folder;
using Sitecore.Web.UI.XamlSharp.Xaml;
using Sitecore.Web;
using Sitecore.Data;
using Sitecore.Globalization;
using Sitecore.Data.Items;

namespace SitecoreCustomFolder
{
    public class CustomFolder : Sitecore.Shell.Applications.ContentEditor.Editors.Folder.FolderPage
    {

        protected System.Web.UI.WebControls.Literal TotalLit;

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            if (!XamlControl.AjaxScriptManager.IsEvent)
            {
                string queryString = WebUtil.GetQueryString("id");
                string name = WebUtil.GetQueryString("language");
                string databaseName = WebUtil.GetQueryString("database");
                ItemUri uri = new ItemUri(queryString, Language.Parse(name), Sitecore.Data.Version.Latest, databaseName);
                Item item = Database.GetItem(uri);

                if (item != null)
                {
                    List&lt;Item&gt; items = this.GetItems(item);
                    if (items.Count != 0)
                    {
                        this.TotalLit.Text = "&lt;div class="scTitle scTilesTitle"&gt;Items in Folder: " + items.Count.ToString() + " &lt;/div&gt;";
                        this.TotalLit.Visible = true;
                    }
                }
            }
        }
    }
}
</code></pre>
<p>4. Modify the Folder.xaml.xml to reflect the new class on the inherits attribute:</p>
<pre><code>
&lt;Sitecore.Shell.Applications.ContentEditor.Editors.Folder x:inherits="SitecoreCustomFolder.CustomFolder"&gt;
</code></pre>
<p>5. Here is the end result:</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2012/06/end-result.png"><img loading="lazy" title="end result" src="http://akshaysura.com/wp-content/uploads/2012/06/end-result.png" alt="" width="857" height="699" /></a></p>
<p><span><strong>Tagged as:</strong> <a href="http://www.webdatasource.com/tag/ajax/" rel="tag">ajax</a>, <a href="http://www.webdatasource.com/tag/content-manager/" rel="tag">content manager</a>, <a href="http://www.webdatasource.com/tag/customfolder/" rel="tag">CustomFolder</a>, <a href="http://www.webdatasource.com/tag/editors/" rel="tag">editors</a>, <a href="http://www.webdatasource.com/tag/folders/" rel="tag">folders</a>, <a href="http://www.webdatasource.com/tag/globalization/" rel="tag">Globalization</a>, <a href="http://www.webdatasource.com/tag/namespace/" rel="tag">namespace</a>, <a href="http://www.webdatasource.com/tag/sitecore/" rel="tag">Sitecore</a></span></p>
]]></content:encoded>
    </item>
    <item>
      <title>Sitecore: Publish Item with Sub-Items quicker!</title>
      <link>https://akshaysura.com/blog/sitecore-publish-item-with-sub-items-quicker/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/sitecore-publish-item-with-sub-items-quicker/</guid>
      <pubDate>Sat, 16 Jun 2012 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Here is a quicker way to publish item with subitems. Usually when I try to access the publish menu dropdown it takes a while depending on what is happening on the dev boxes. I know this is not much of an improvement but its definitely quicker. Typically it takes 3 clicks to reach the menu item as shown below.]]></description>
      <content:encoded><![CDATA[<p>Here is a quicker way to publish item with subitems. &nbsp;Usually when I try to access the publish menu dropdown it takes a while depending on what is happening on the dev boxes. &nbsp;I know this is not much of an improvement but its&nbsp;definitely&nbsp;quicker. &nbsp;Typically it takes 3 clicks to reach the menu item as shown below.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2012/06/publishproblem.png"><img loading="lazy" title="publishproblem" src="http://akshaysura.com/wp-content/uploads/2012/06/publishproblem.png" alt="" width="409" height="172" /></a></p>
<p>Here is how you can improve that.</p>
<p><strong>Step 1</strong>: Change db to core</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2012/06/publishstep1.png"><img loading="lazy" title="publishstep1" src="http://akshaysura.com/wp-content/uploads/2012/06/publishstep1.png" alt="" width="167" height="122" /></a></p>
<p><strong>Step 2</strong>: Navigate to /sitecore/content/Applications/Content Editor/Ribbons/Chunks/Publish</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2012/06/publishstep2.png"><img loading="lazy" title="publishstep2" src="http://akshaysura.com/wp-content/uploads/2012/06/publishstep2.png" alt="" width="312" height="514" /></a></p>
<p><strong>Step 3</strong>: Right click and insert from template on the Publish item</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2012/06/publishstep3.png"><img loading="lazy" title="publishstep3" src="http://akshaysura.com/wp-content/uploads/2012/06/publishstep3.png" alt="" width="305" height="252" /></a></p>
<p><strong>Step 4</strong>: Select&nbsp;/sitecore/templates/System/Ribbon/Large Button template and name it Publish Item (you can name it as you please)</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2012/06/publishstep4.png"><img loading="lazy" title="publishstep4" src="http://akshaysura.com/wp-content/uploads/2012/06/publishstep4.png" alt="" width="513" height="636" /></a></p>
<p><strong>Step 5</strong>: Enter the following values in the corresponding fields as shown in the screenshot for the newly created item.</p>
<p>Header: Publish Item</p>
<p>Icon:&nbsp;Network/16&times;16/earth_add.png ( you can pick what you like)</p>
<p>Click:&nbsp;item:publish(id=$Target)</p>
<p>Tooltip:&nbsp;Publish the item with subitems</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2012/06/publishstep5.png"><img loading="lazy" title="publishstep5" src="http://akshaysura.com/wp-content/uploads/2012/06/publishstep5.png" alt="" width="1280" height="542" /></a></p>
<p><strong>Step 6</strong>: Switch back to Master db.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2012/06/publishstep6.png"><img loading="lazy" title="publishstep6" src="http://akshaysura.com/wp-content/uploads/2012/06/publishstep6.png" alt="" width="170" height="115" /></a></p>
<p><strong>Step 7</strong>: Access the newly created item under the publish ribbon.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2012/06/publishstep7.png"><img loading="lazy" title="publishstep7" src="http://akshaysura.com/wp-content/uploads/2012/06/publishstep7.png" alt="" width="1280" height="679" /></a></p>
<p><strong>Step 8</strong>: This brings up the same dialog as the publish item menu in the publish dropdown.</p>
<p><a href="http://akshaysura.com/wp-content/uploads/2012/06/publishstep8.png"><img loading="lazy" title="publishstep8" src="http://akshaysura.com/wp-content/uploads/2012/06/publishstep8.png" alt="" width="516" height="638" /></a></p>
<p>Link to an older post:&nbsp;<a href="http://www.bolaky.net/post/Creating-a-Publishing-Context-Menu-Item-in-Sitecore-Content-Editor.aspx" target="_blank">http://www.bolaky.net/post/Creating-a-Publishing-Context-Menu-Item-in-Sitecore-Content-Editor.aspx</a></p>
<p><span><strong>Tagged as:</strong> <a href="http://www.webdatasource.com/tag/button-template/" rel="tag">button template</a>, <a href="http://www.webdatasource.com/tag/content-applications/" rel="tag">content applications</a>, <a href="http://www.webdatasource.com/tag/content-editor/" rel="tag">content editor</a>, <a href="http://www.webdatasource.com/tag/ribbon/" rel="tag">ribbon</a>, <a href="http://www.webdatasource.com/tag/screenshot/" rel="tag">screenshot</a>, <a href="http://www.webdatasource.com/tag/sitecore/" rel="tag">Sitecore</a>, <a href="http://www.webdatasource.com/tag/sitecore-api/" rel="tag">sitecore api</a>, <a href="http://www.webdatasource.com/tag/sitecore-cms/" rel="tag">sitecore cms</a>, <a href="http://www.webdatasource.com/tag/sitecore-development/" rel="tag">sitecore development</a></span></p>
]]></content:encoded>
    </item>
    <item>
      <title>Exporting and Importing packages from Sitecore through Code using Sitecore API</title>
      <link>https://akshaysura.com/blog/exporting-and-importing-packages-from-sitecore-through-code-using-sitecore-api/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/exporting-and-importing-packages-from-sitecore-through-code-using-sitecore-api/</guid>
      <pubDate>Wed, 03 Aug 2011 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[If you ever needed to export or import Sitecore packages dynamically through code, this is the article for you. You could be integrating it into automated build process or simply trying to move items between two environments.]]></description>
      <content:encoded><![CDATA[<p>If you ever needed to export or import Sitecore packages dynamically through code, this is the article for you. You could be integrating it into automated build process or simply trying to move items between two environments.</p>
<p>Here is the Export Code:</p>
<pre><code>
            using (new Sitecore.SecurityModel.SecurityDisabler())
            {
                Sitecore.Data.Database db = Sitecore.Configuration.Factory.GetDatabase("master");
                Sitecore.Install.PackageProject document = new Sitecore.Install.PackageProject();

                document.Metadata.PackageName = "INSERT PACKAGE NAME";
                document.Metadata.Author = "INSERT AUTHOR NAME";

                Sitecore.Install.Items.ExplicitItemSource source = new Sitecore.Install.Items.ExplicitItemSource(); //Create source &ndash; source should be based on BaseSource
                source.Name = "INSERT SOURCE NAME";
                Sitecore.Data.Items.Item[] items = db.Items.Database.SelectItems("SPECIFY THE SITECORE ITEM PATH TO EXPORT FROM");

                foreach (Sitecore.Data.Items.Item item in items)
                {
                    source.Entries.Add(new Sitecore.Install.Items.ItemReference(item.Uri, false).ToString());
                }

                document.Sources.Add(source);
                document.SaveProject = true;

                //path where the zip file package is saved
                using (Sitecore.Install.Zip.PackageWriter writer = new Sitecore.Install.Zip.PackageWriter("/data/packages/"  + " INSERT ZIP FILE NAME " + DateTime.Now.Ticks.ToString() + ".zip"))
                {
                    Sitecore.Context.SetActiveSite("shell");

                    writer.Initialize(Sitecore.Install.Installer.CreateInstallationContext());

                    Sitecore.Install.PackageGenerator.GeneratePackage(document, writer);

                    Sitecore.Context.SetActiveSite("website");
                }

            }
</code></pre>
<p>Here is the Import Code:</p>
<pre><code>
                using (new SecurityDisabler())
                {
                    using (new ProxyDisabler())
                    {
                        using (new SyncOperationContext())
                        {
                            IProcessingContext context = new SimpleProcessingContext();
                            IItemInstallerEvents events = new DefaultItemInstallerEvents(new BehaviourOptions(InstallMode.Overwrite, MergeMode.Undefined));
                            context.AddAspect(events);
                            IFileInstallerEvents events1 = new DefaultFileInstallerEvents(true);
                            context.AddAspect(events1);

                            Sitecore.Install.Installer installer = new Sitecore.Install.Installer();
                            installer.InstallPackage(MainUtil.MapPath("INSERT PACKAGE PATH INCLUDING THE FILE NAME"), context);
                        }
                    }
                }
</code></pre>
<p><span><strong>Tagged as:</strong> <a href="http://www.webdatasource.com/tag/api/" rel="tag">API</a>, <a href="http://www.webdatasource.com/tag/behaviouroptions/" rel="tag">BehaviourOptions</a>, <a href="http://www.webdatasource.com/tag/createinstallationcontext/" rel="tag">CreateInstallationContext</a>, <a href="http://www.webdatasource.com/tag/defaultiteminstallerevents/" rel="tag">DefaultItemInstallerEvents</a>, <a href="http://www.webdatasource.com/tag/document-sources/" rel="tag">document sources</a>, <a href="http://www.webdatasource.com/tag/environment/" rel="tag">environment</a>, <a href="http://www.webdatasource.com/tag/environments/" rel="tag">environments</a>, <a href="http://www.webdatasource.com/tag/explicititemsource/" rel="tag">ExplicitItemSource</a>, <a href="http://www.webdatasource.com/tag/export/" rel="tag">export</a>, <a href="http://www.webdatasource.com/tag/exporting/" rel="tag">exporting</a>, <a href="http://www.webdatasource.com/tag/factory/" rel="tag">Factory</a>, <a href="http://www.webdatasource.com/tag/getdatabase/" rel="tag">GetDatabase</a>, <a href="http://www.webdatasource.com/tag/ifileinstallerevents/" rel="tag">IFileInstallerEvents</a>, <a href="http://www.webdatasource.com/tag/import/" rel="tag">import</a>, <a href="http://www.webdatasource.com/tag/importing/" rel="tag">importing</a>, <a href="http://www.webdatasource.com/tag/master/" rel="tag">Master</a>, <a href="http://www.webdatasource.com/tag/meta/" rel="tag">meta</a>, <a href="http://www.webdatasource.com/tag/metadata/" rel="tag">metadata</a>, <a href="http://www.webdatasource.com/tag/model/" rel="tag">Model</a>, <a href="http://www.webdatasource.com/tag/package/" rel="tag">PACKAGE</a>, <a href="http://www.webdatasource.com/tag/packagegenerator/" rel="tag">PackageGenerator</a>, <a href="http://www.webdatasource.com/tag/packageproject/" rel="tag">PackageProject</a>, <a href="http://www.webdatasource.com/tag/packagewriter/" rel="tag">PackageWriter</a>, <a href="http://www.webdatasource.com/tag/per/" rel="tag">Per</a>, <a href="http://www.webdatasource.com/tag/processing/" rel="tag">processing</a>, <a href="http://www.webdatasource.com/tag/project/" rel="tag">project</a>, <a href="http://www.webdatasource.com/tag/proxydisabler/" rel="tag">ProxyDisabler</a>, <a href="http://www.webdatasource.com/tag/saveproject/" rel="tag">SaveProject</a>, <a href="http://www.webdatasource.com/tag/security/" rel="tag">Security</a>, <a href="http://www.webdatasource.com/tag/securitydisabler/" rel="tag">SecurityDisabler</a>, <a href="http://www.webdatasource.com/tag/ses/" rel="tag">SES</a>, <a href="http://www.webdatasource.com/tag/setactivesite/" rel="tag">SetActiveSite</a>, <a href="http://www.webdatasource.com/tag/shell/" rel="tag">shell</a>, <a href="http://www.webdatasource.com/tag/simple/" rel="tag">Simple</a>, <a href="http://www.webdatasource.com/tag/simpleprocessingcontext/" rel="tag">SimpleProcessingContext</a>, <a href="http://www.webdatasource.com/tag/sitecore/" rel="tag">Sitecore</a>, <a href="http://www.webdatasource.com/tag/sitecore-api/" rel="tag">sitecore api</a>, <a href="http://www.webdatasource.com/tag/sitecore-packages/" rel="tag">sitecore packages</a>, <a href="http://www.webdatasource.com/tag/source/" rel="tag">source</a>, <a href="http://www.webdatasource.com/tag/source-document/" rel="tag">source document</a>, <a href="http://www.webdatasource.com/tag/source-entries/" rel="tag">source entries</a>, <a href="http://www.webdatasource.com/tag/source-name/" rel="tag">source name</a>, <a href="http://www.webdatasource.com/tag/specify/" rel="tag">SPECIFY</a>, <a href="http://www.webdatasource.com/tag/syncoperationcontext/" rel="tag">SyncOperationContext</a></span></p>
]]></content:encoded>
    </item>
    <item>
      <title>Sitecore Lucene Search Index</title>
      <link>https://akshaysura.com/blog/sitecore-lucene-search-index/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/sitecore-lucene-search-index/</guid>
      <pubDate>Wed, 27 Jul 2011 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Sitecore has been using Lucene search since version 5, which used the Sitecore.Data.Indexing namespace and Sitecore -> Indexes section in the Web.Config.]]></description>
      <content:encoded><![CDATA[<p>Sitecore has been using Lucene search since version 5, which used the Sitecore.Data.Indexing namespace and Sitecore -&gt; Indexes section in the Web.Config.</p>
<p>Starting in Sitecore 6.4, they introduced a new Search namespace &ndash; Sitecore.Search, this uses the Sitecore -&gt; Search -&gt; Configuration -&gt; Indexes section in Web.Config.</p>
<p>From what I know, Sitecore recommends using the new namespace and the old namespace is going to be deprecated starting Sitecore 6.5. The following is a blurb from Sitecore 6.5 Release notes from SDN:<br />
&ldquo;The Sitecore.Data.Indexing namespace has been deprecated and will be removed in a future version of the CMS in favor of the more powerful and flexible Sitecore.Search classes and corresponding index definitions. &rdquo;</p>
<p>Since there is only one document on this new namespace, it&rsquo;s difficult to get more information when you find yourself in a bind. I had to google search to find bits and pieces and so I am writing this post.</p>
<p>Here is the link to the PDF on this site. <a href="http://www.webdatasource.com/pdf/sitecore_search_and_indexing-a4.pdf" target="_blank">Click Here</a> (NO SDN access needed)</p>
<p>The basic configuration is given below:</p>
<pre><code>
      &lt;configuration type="Sitecore.Search.SearchConfiguration, Sitecore.Kernel" singleInstance="true"&gt;
        &lt;indexes hint="list:AddIndex"&gt;
          ... ... ...
          &lt;index id="IndexNAME" type="Sitecore.Search.Index, Sitecore.Kernel"&gt;
            &lt;param desc="name"&gt;$(id)&lt;/param&gt;
            &lt;param desc="folder"&gt;im_index&lt;/param&gt;
            &lt;Analyzer ref="search/analyzer"/&gt;
            &lt;locations hint="list:AddCrawler"&gt;
              &lt;master type="Sitecore.Search.Crawlers.DatabaseCrawler, Sitecore.Kernel"&gt;
                &lt;Database&gt;master&lt;/Database&gt;
                &lt;Tags&gt;master content&lt;/Tags&gt;
                &lt;Root&gt;/sitecore/content&lt;/Root&gt;
                &lt;IndexAllFields&gt;true&lt;/IndexAllFields&gt;
                &lt;include hint="list:IncludeTemplate"&gt;
                  &lt;template comment="Template1"&gt;{8917CADF-2148-4328-B595-217C5A9CCA7D}&lt;/template&gt;
                  &lt;template comment="Template2"&gt;{2A18027D-CA51-4E5D-A7C1-51096E09C16C}&lt;/template&gt;
                &lt;/include&gt;
                &lt;include hint="list:ExcludeTemplate"&gt;
                  &lt;template&gt;{8C18027D-CA51-4E5D-A7C1-510965555C}&lt;/template&gt;
                &lt;/include&gt;
                &lt;!--&lt;include hint="list:IncludeField"&gt;
                  &lt;fieldId&gt;{GUID}&lt;/fieldId&gt;
                &lt;/include&gt;--&gt;
              &lt;/master&gt;
            &lt;/locations&gt;
          &lt;/index&gt;
        &lt;/indexes&gt;
      &lt;/configuration&gt;
</code></pre>
<p>Here is a piece of sample code to query the index:</p>
<pre><code>
    Sitecore.Search.Index searchIndex = Sitecore.Search.SearchManager.GetIndex("Search Index Name"); //replace string with the name of the search index
    using (IndexSearchContext context = searchIndex.CreateSearchContext())
    {
        SearchHits hits = context.Search("search string");  //replace string with the actual search string
        SomeRepeater.DataSource = hits.FetchResults(0, 25); //first param is the start item, second is the count
        SomeRepeater.DataBind();
        ResultsCount = hits.FetchResults(0, hits.Length).Count();
    }
</code></pre>
<p>Here are some useful links:</p>
<p><a href="http://sitecoreblog.alexshyba.com/2011/04/search-index-troubleshooting.html" target="_blank">Search Index Troubleshooting</a> by Alex Shyba</p>
<p><a href="http://trac.sitecore.net/IndexViewer" target="_blank">Index Viewer</a> in Sitecore Shared Source</p>
<p>I hope this is useful. If you have any questions please don&rsquo;t hesitate to get in touch!</p>
<p><span><strong>Tagged as:</strong> <a href="http://www.webdatasource.com/tag/access/" rel="tag">access</a>, <a href="http://www.webdatasource.com/tag/addcrawler/" rel="tag">AddCrawler</a>, <a href="http://www.webdatasource.com/tag/addindex/" rel="tag">AddIndex</a>, <a href="http://www.webdatasource.com/tag/basic/" rel="tag">Basic</a>, <a href="http://www.webdatasource.com/tag/ces/" rel="tag">CES</a>, <a href="http://www.webdatasource.com/tag/class/" rel="tag">class</a>, <a href="http://www.webdatasource.com/tag/cms/" rel="tag">CMS</a>, <a href="http://www.webdatasource.com/tag/config/" rel="tag">Config</a>, <a href="http://www.webdatasource.com/tag/configuration/" rel="tag">Configuration</a>, <a href="http://www.webdatasource.com/tag/crawlers/" rel="tag">Crawlers</a>, <a href="http://www.webdatasource.com/tag/database/" rel="tag">database</a>, <a href="http://www.webdatasource.com/tag/databasecrawler/" rel="tag">DatabaseCrawler</a>, <a href="http://www.webdatasource.com/tag/definition/" rel="tag">definition</a>, <a href="http://www.webdatasource.com/tag/excludetemplate/" rel="tag">ExcludeTemplate</a>, <a href="http://www.webdatasource.com/tag/goog/" rel="tag">GOOG</a>, <a href="http://www.webdatasource.com/tag/google/" rel="tag">Google</a>, <a href="http://www.webdatasource.com/tag/google-search/" rel="tag">google search</a>, <a href="http://www.webdatasource.com/tag/guid/" rel="tag">GUID</a>, <a href="http://www.webdatasource.com/tag/includetemplate/" rel="tag">IncludeTemplate</a>, <a href="http://www.webdatasource.com/tag/index-definitions/" rel="tag">index definitions</a>, <a href="http://www.webdatasource.com/tag/index-id/" rel="tag">index id</a>, <a href="http://www.webdatasource.com/tag/indexes/" rel="tag">indexes</a>, <a href="http://www.webdatasource.com/tag/indexing/" rel="tag">indexing</a>, <a href="http://www.webdatasource.com/tag/links/" rel="tag">Links</a>, <a href="http://www.webdatasource.com/tag/location/" rel="tag">location</a>, <a href="http://www.webdatasource.com/tag/lucene/" rel="tag">Lucene</a>, <a href="http://www.webdatasource.com/tag/manage/" rel="tag">Manage</a>, <a href="http://www.webdatasource.com/tag/master-content/" rel="tag">master content</a>, <a href="http://www.webdatasource.com/tag/namespace/" rel="tag">namespace</a>, <a href="http://www.webdatasource.com/tag/need/" rel="tag">need</a>, <a href="http://www.webdatasource.com/tag/net/" rel="tag">NET</a>, <a href="http://www.webdatasource.com/tag/pdf/" rel="tag">PDF</a>, <a href="http://www.webdatasource.com/tag/release/" rel="tag">release</a>, <a href="http://www.webdatasource.com/tag/sdn/" rel="tag">SDN</a>, <a href="http://www.webdatasource.com/tag/search/" rel="tag">Search</a>, <a href="http://www.webdatasource.com/tag/search-classes/" rel="tag">search classes</a>, <a href="http://www.webdatasource.com/tag/search-crawlers/" rel="tag">search crawlers</a>, <a href="http://www.webdatasource.com/tag/searchconfiguration/" rel="tag">SearchConfiguration</a>, <a href="http://www.webdatasource.com/tag/section/" rel="tag">section</a>, <a href="http://www.webdatasource.com/tag/ses/" rel="tag">SES</a>, <a href="http://www.webdatasource.com/tag/sitecore/" rel="tag">Sitecore</a>, <a href="http://www.webdatasource.com/tag/tags/" rel="tag">Tags</a>, <a href="http://www.webdatasource.com/tag/target/" rel="tag">target</a>, <a href="http://www.webdatasource.com/tag/template/" rel="tag">template</a>, <a href="http://www.webdatasource.com/tag/www/" rel="tag">www</a>, <a href="http://www.webdatasource.com/tag/xml/" rel="tag">xml</a></span></p>
]]></content:encoded>
    </item>
    <item>
      <title>Sitecore – Upload to Media Library Issue/Problem</title>
      <link>https://akshaysura.com/blog/sitecore-upload-to-media-library-issueproblem/</link>
      <guid isPermaLink="true">https://akshaysura.com/blog/sitecore-upload-to-media-library-issueproblem/</guid>
      <pubDate>Thu, 23 Sep 2010 00:00:00 GMT</pubDate>
      <dc:creator>Akshay Sura</dc:creator>
      <description><![CDATA[Recently I had an issue while importing few thousand images and documents into the Sitecore Media Library. I had the following settings in Web.Config:]]></description>
      <content:encoded><![CDATA[<p>Recently I had an issue while importing few thousand images and documents into the Sitecore Media Library. I had the following settings in Web.Config:</p>
<pre><code>

&lt;!--  UPLOAD AS FILES
Determines if media should be uploaded as files or as database blobs.
Default: false
--&gt;

&lt;setting name="Media.UploadAsFiles" value="false" /&gt;

&lt;!--  MEDIA - USE ITEM PATHS FOR URLS
This setting controls if item paths are used for constructing media URLs.
If false, short ids will be used.
Default value: true
--&gt;

&lt;setting name="Media.UseItemPaths" value="true" /&gt;
</code></pre>
<p>Each time, it would import only a few files and it would stop. I tried killing all processes, lower the CPU and Memory usage but that didn&rsquo;t make any difference.</p>
<p>According to the friendly and helpful Sitecore Customer Service Rep, Upload folder is managed by Sitecore.Resources.Media.UploadWatcher. Each time a file is added to the upload folder, UploadWatcher creates similar structure in media library. It is not a separate task or webservice, just simple uploading job started by &ldquo;Created&rdquo; event on filesystem.</p>
<p>The reason for this issue is that Sitecore uses System.IO.FileSystemWatcher object for file uploading (Sitecore use it to watch changes); when a lot of files are added at once, the FileSystemWatcher&rsquo;s internalBuffer fills up and starts skipping files.</p>
<p>Checkout this article <a href="http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.aspx" target="_blank">http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.aspx</a></p>
<p>As a result of my Ticket, they created a workaround which is available at <a href="http://sdn.sitecore.net/scrapbook/sitecore%20doesn%E2%80%99t%20upload%20files%20from%20upload%20folder.aspx" target="_blank">http://sdn.sitecore.net/scrapbook/sitecore%20doesn%E2%80%99t%20upload%20files%20from%20upload%20folder.aspx</a>. You would need a Sitecore developer account to login.</p>
<p>As a workaround you need to use Sitecore.Support.322918.dll file. The workaround increases the InternalBuffer to avoid the unexpected skipping of files.</p>
<p>1. Add the string &lt;add type=&rdquo;Sitecore.Support.UploadWatcher,Sitecore.Support.322918&Prime; name=&rdquo;SitecoreUploadWatcher&rdquo;/&gt; before each occurrence of the string &lt;add type=&rdquo;Sitecore.Resources.Media.UploadWatcher, Sitecore.Kernel&rdquo; name=&rdquo;SitecoreUploadWatcher&rdquo;/&gt;</p>
<p>(see &lt;system.webServer&gt;/&lt;modules&gt; section and &lt;system.web&gt;/&lt;httpModules&gt; section)</p>
<p>2. Comment out all such lines: &lt;add type=&rdquo;Sitecore.Resources.Media.UploadWatcher, Sitecore.Kernel&rdquo; name=&rdquo;SitecoreUploadWatcher&rdquo;/&gt;</p>
<p>3. Put the Sitecore.Support.322918.dll file into the /bin folder of your web site</p>
<p>4. In the web.config file, add the following string under the &lt;settings&gt; section</p>
<p>&lt;setting name=&rdquo;FileSystemWatcherBufferSize&rdquo; value=&rdquo;4096000&Prime;/&gt;</p>
<p>Such value seems to be enough for 5000 files, but you can increase it further to be sure that even files with very long names are uploaded.</p>
<p>For example:</p>
<p>If the full file path contains 100 symbols, it takes 200 bytes, 32000 files will take 6400000 bytes (6250 kb), so the setting value should be:</p>
<p>&lt;setting name=&rdquo;FileSystemWatcherBufferSize&rdquo; value=&rdquo;6400000 &ldquo;/&gt;</p>
<p><strong>As always, please backup before making any significant changes.</strong></p>
<p>P.S.: UploadWatcher calls&nbsp;MediaManager.Creator.FileCreated(filePath); &ndash; you can try to fire the same method with path to the missing folder as parameter. There is another methos for FolderCreated as well.</p>
<p>Hope this helps. Credit goes to Sitecore and its Customer Service Reps.</p>
<p><span><strong>Tagged as:</strong> <a href="http://www.webdatasource.com/tag/checkout/" rel="tag">checkout</a>, <a href="http://www.webdatasource.com/tag/config/" rel="tag">Config</a>, <a href="http://www.webdatasource.com/tag/creator/" rel="tag">Creator</a>, <a href="http://www.webdatasource.com/tag/customer/" rel="tag">customer</a>, <a href="http://www.webdatasource.com/tag/database/" rel="tag">database</a>, <a href="http://www.webdatasource.com/tag/determines/" rel="tag">Determines</a>, <a href="http://www.webdatasource.com/tag/developer/" rel="tag">developer</a>, <a href="http://www.webdatasource.com/tag/difference/" rel="tag">difference</a>, <a href="http://www.webdatasource.com/tag/dll/" rel="tag">dll</a>, <a href="http://www.webdatasource.com/tag/filesystem/" rel="tag">filesystem</a>, <a href="http://www.webdatasource.com/tag/filesystemwatcher/" rel="tag">FileSystemWatcher</a>, <a href="http://www.webdatasource.com/tag/filesystemwatchera/" rel="tag">FileSystemWatcher&acirc;</a>, <a href="http://www.webdatasource.com/tag/filesystemwatcherbuffersize/" rel="tag">FileSystemWatcherBufferSize</a>, <a href="http://www.webdatasource.com/tag/folder/" rel="tag">folder</a>, <a href="http://www.webdatasource.com/tag/foldercreated/" rel="tag">FolderCreated</a>, <a href="http://www.webdatasource.com/tag/internalbuffer/" rel="tag">internalBuffer</a>, <a href="http://www.webdatasource.com/tag/media-library/" rel="tag">media library</a>, <a href="http://www.webdatasource.com/tag/mediamanager/" rel="tag">MediaManager</a>, <a href="http://www.webdatasource.com/tag/memory/" rel="tag">memory</a>, <a href="http://www.webdatasource.com/tag/method/" rel="tag">method</a>, <a href="http://www.webdatasource.com/tag/microsoft/" rel="tag">Microsoft</a>, <a href="http://www.webdatasource.com/tag/name/" rel="tag">name</a>, <a href="http://www.webdatasource.com/tag/parameter/" rel="tag">parameter</a>, <a href="http://www.webdatasource.com/tag/sitecore/" rel="tag">Sitecore</a>, <a href="http://www.webdatasource.com/tag/sitecoreuploadwatcher/" rel="tag">SitecoreUploadWatcher</a>, <a href="http://www.webdatasource.com/tag/structure/" rel="tag">structure</a>, <a href="http://www.webdatasource.com/tag/system/" rel="tag">System</a>, <a href="http://www.webdatasource.com/tag/task/" rel="tag">task</a>, <a href="http://www.webdatasource.com/tag/upload-files/" rel="tag">upload files</a>, <a href="http://www.webdatasource.com/tag/upload-to-media-library/" rel="tag">upload to media library</a>, <a href="http://www.webdatasource.com/tag/uploadasfiles/" rel="tag">UploadAsFiles</a>, <a href="http://www.webdatasource.com/tag/urls/" rel="tag">URLs</a>, <a href="http://www.webdatasource.com/tag/usage/" rel="tag">usage</a>, <a href="http://www.webdatasource.com/tag/useitempaths/" rel="tag">UseItemPaths</a>, <a href="http://www.webdatasource.com/tag/webserver/" rel="tag">webServer</a>, <a href="http://www.webdatasource.com/tag/webservice/" rel="tag">webservice</a>, <a href="http://www.webdatasource.com/tag/workaround/" rel="tag">workaround</a></span></p>
]]></content:encoded>
    </item>
  </channel>
</rss>
