Jekyll2019-03-13T08:58:40+00:00https://www.ghostwheel.co.uk/feed.xmlGhostwheel LtdGhostwheel Ltd provides .Net and Sitecore development services.Neil Duncanneil@ghostwheel.co.ukAdd custom information to WFFM emails2016-12-31T00:00:00+00:002016-12-31T00:00:00+00:00https://www.ghostwheel.co.uk/sitecore/add-custom-information-to-wffm-emails<p>I was recently asked to add some additional non-form based information to an email sent by Web Forms for Marketers. Specifically, they wanted to include a referral code that was stored in the user’s session.</p>
<p>After some false starts, I came up with this.</p>
<h2 id="the-form">The form</h2>
<p>First I set up the form. It had the usual number of fields for the user to fill in.</p>
<p><img src="/images/posts/wffm/form-fields.png" alt="Form fields" title="Note there's no 'Referral' field." /></p>
<p>Then I added a Save Action to send an email.
<img src="/images/posts/wffm/save-actions.png" alt="Save actions" /></p>
<p><img src="/images/posts/wffm/send-email-action.png" alt="Save actions" /></p>
<p>Here’s what I ended up with for the email body text. Note that there’s a <code class="highlighter-rouge">[Referral]</code> token in there, despite there not being a <code class="highlighter-rouge">Referral</code> field on the form.</p>
<p><img src="/images/posts/wffm/email-body.png" alt="Email body" title="Note the [Referral] token." /></p>
<h2 id="adding-the-custom-data">Adding the custom data</h2>
<p>I chose to do this using a ProcessMessage pipeline, which is one of the ones provided by WFFM.</p>
<p>First I added a new processor.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="nn">Sitecore.WFFM.Abstractions.Mail</span><span class="p">;</span>
<span class="k">namespace</span> <span class="nn">MyAssembly</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ProcessMessage</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">AddCustomData</span><span class="p">(</span><span class="n">ProcessMessageArgs</span> <span class="n">args</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">sidValue</span> <span class="p">=</span> <span class="n">HttpContext</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">Session</span><span class="p">[</span><span class="s">"some-key"</span><span class="p">]</span> <span class="p">??</span> <span class="s">""</span><span class="p">;</span>
<span class="n">args</span><span class="p">.</span><span class="n">Mail</span><span class="p">.</span><span class="nf">Replace</span><span class="p">(</span><span class="s">"[Referral]"</span><span class="p">,</span> <span class="n">sidValue</span><span class="p">.</span><span class="nf">ToString</span><span class="p">());</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>It is configured using a patch config file in the <code class="highlighter-rouge">App_Config\Include</code> folder like this. Note that it’s patched in <em>before</em> the <code class="highlighter-rouge">SendEmail</code> processor.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><?xml version="1.0" encoding="utf-8" ?></span>
<span class="nt"><configuration</span> <span class="na">xmlns:patch=</span><span class="s">"http://www.sitecore.net/xmlconfig/"</span><span class="nt">></span>
<span class="nt"><sitecore></span>
<span class="nt"><pipelines></span>
<span class="nt"><processMessage></span>
<span class="nt"><processor</span> <span class="na">patch:before=</span><span class="s">"processor[@method='SendEmail']"</span> <span class="na">type=</span><span class="s">"MyAssembly.ProcessMessage, MyAssembly"</span> <span class="na">method=</span><span class="s">"AddCustomData"</span> <span class="nt">/></span>
<span class="nt"></processMessage></span>
<span class="nt"></pipelines></span>
<span class="nt"></sitecore></span>
<span class="nt"></configuration></span>
</code></pre></div></div>
<p>Hey presto. Done!</p>Neil Duncanneil@ghostwheel.co.ukAdd custom information to emails from Sitecore Web Forms for Marketers.How to enable queries in Sitecore Rendering Data Sources2016-12-30T00:00:00+00:002016-12-30T00:00:00+00:00https://www.ghostwheel.co.uk/sitecore/queries-in-sitecore-rendering-datasources<p>I recently needed to use a query in a Sitecore Rendering Datasource. I wanted to have a rendering added to the standard values for a page, which used the parent of the page for its data source.</p>
<p>I tried a few different ways before realizing that this is not something that is provided by default!</p>
<p>So. Time to pull out my trusty decompiler, and work out how to add this.</p>
<h2 id="running-the-query">Running the query</h2>
<p>Sitecore uses an <code class="highlighter-rouge">ItemLocator</code> to resolve the target item for a data source, so the first thing we need to do is to create a custom one of those.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="nn">System.Linq</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">Sitecore</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">Sitecore.Data.Items</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">Sitecore.Mvc.Data</span><span class="p">;</span>
<span class="k">namespace</span> <span class="nn">MyAssembly</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">QueryItemLocator</span> <span class="p">:</span> <span class="n">ItemLocator</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">override</span> <span class="n">Item</span> <span class="nf">GetItem</span><span class="p">(</span><span class="kt">string</span> <span class="n">pathOrId</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="nf">GetItemByQuery</span><span class="p">(</span><span class="n">pathOrId</span><span class="p">)</span> <span class="p">??</span> <span class="k">base</span><span class="p">.</span><span class="nf">GetItem</span><span class="p">(</span><span class="n">pathOrId</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">override</span> <span class="n">Item</span> <span class="nf">GetItem</span><span class="p">(</span><span class="kt">string</span> <span class="n">pathOrId</span><span class="p">,</span> <span class="n">Item</span> <span class="n">contextItem</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="nf">GetItemByQuery</span><span class="p">(</span><span class="n">pathOrId</span><span class="p">)</span> <span class="p">??</span> <span class="k">base</span><span class="p">.</span><span class="nf">GetItem</span><span class="p">(</span><span class="n">pathOrId</span><span class="p">,</span> <span class="n">contextItem</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">override</span> <span class="n">Item</span> <span class="nf">GetItem</span><span class="p">(</span><span class="kt">string</span> <span class="n">pathOrId</span><span class="p">,</span> <span class="kt">string</span> <span class="n">basePath</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="nf">GetItemByQuery</span><span class="p">(</span><span class="n">pathOrId</span><span class="p">)</span> <span class="p">??</span> <span class="k">base</span><span class="p">.</span><span class="nf">GetItem</span><span class="p">(</span><span class="n">pathOrId</span><span class="p">,</span> <span class="n">basePath</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">private</span> <span class="n">Item</span> <span class="nf">GetItemByQuery</span><span class="p">(</span><span class="kt">string</span> <span class="n">query</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(!</span><span class="n">query</span><span class="p">.</span><span class="nf">StartsWith</span><span class="p">(</span><span class="s">"query:"</span><span class="p">))</span> <span class="k">return</span> <span class="k">null</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">innerQuery</span> <span class="p">=</span> <span class="n">query</span><span class="p">.</span><span class="nf">Replace</span><span class="p">(</span><span class="s">"query:"</span><span class="p">,</span> <span class="s">""</span><span class="p">);</span>
<span class="k">return</span> <span class="n">Context</span><span class="p">.</span><span class="n">Item</span><span class="p">.</span><span class="n">Axes</span><span class="p">.</span><span class="nf">SelectSingleItem</span><span class="p">(</span><span class="n">innerQuery</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>This will look for data sources starting with the string <code class="highlighter-rouge">query:</code> and then use the standard Sitecore querying API to find an item. If one isn’t found (or if the data source doesn’t start with <code class="highlighter-rouge">query:</code>) then it will fall back to the base behaviour.</p>
<h2 id="using-the-new-itemlocator">Using the new ItemLocator</h2>
<p>Next, we need to tell Sitecore to use our new <code class="highlighter-rouge">ItemLocator</code>. I’ve done this using a Hook, which is the recommended way to add initialization code.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="nn">Sitecore.Events.Hooks</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">Sitecore.Mvc.Configuration</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">Sitecore.Mvc.Data</span><span class="p">;</span>
<span class="k">namespace</span> <span class="nn">MyAssembly.Pipelines</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">QueryItemLocatorInitializer</span> <span class="p">:</span> <span class="n">IHook</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">MvcSettings</span><span class="p">.</span><span class="n">RegisterObject</span><span class="p"><</span><span class="n">ItemLocator</span><span class="p">>(()</span> <span class="p">=></span> <span class="k">new</span> <span class="nf">QueryItemLocator</span><span class="p">());</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The <code class="highlighter-rouge">MvcSettings.RegisterObject</code> call will replace the existing registration with our new <code class="highlighter-rouge">ItemLocator</code>.</p>
<p>To configure this hook to run on application startup, you’ll need to add a config patch to your <code class="highlighter-rouge">App_Config\Include</code> folder.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><?xml version="1.0" encoding="utf-8" ?></span>
<span class="nt"><configuration</span> <span class="na">xmlns:patch=</span><span class="s">"http://www.sitecore.net/xmlconfig/"</span><span class="nt">></span>
<span class="nt"><sitecore></span>
<span class="nt"><hooks></span>
<span class="nt"><hook</span> <span class="na">type=</span><span class="s">"MyAssembly.Pipelines.QueryItemLocatorInitializer, MyAssembly"</span> <span class="nt">/></span>
<span class="nt"></hooks></span>
<span class="nt"></sitecore></span>
<span class="nt"></configuration></span>
</code></pre></div></div>
<h2 id="adding-to-a-rendering">Adding to a rendering</h2>
<p>Now we’re ready to use it.</p>
<p><img src="/images/posts/datasources/query-datasource.png" alt="Datasource with a query" title="This query refers to the parent of the current item." /></p>
<p>This query refers to the parent of the current item.</p>
<h2 id="other-methods">Other methods</h2>
<p>I’m not the first to run into this issue, and it looks like there have been a few other attempts to do the same thing.</p>
<p>For example, <a href="http://sitecorepro.blogspot.co.uk/2015/05/sitecore-query-in-mvc-rendering.html">this one</a> where Konstantin Cherkasov is using a <code class="highlighter-rouge">RenderRenderingProcessor</code> pipeline.</p>Neil Duncanneil@ghostwheel.co.ukAllow the use of queries in Rendering Data Sources.Feature Toggles with Sitecore2016-09-27T00:00:00+00:002016-09-27T00:00:00+00:00https://www.ghostwheel.co.uk/sitecore/feature-toggles-with-sitecore<blockquote>
<p>“Feature Toggling” is a set of patterns which can help a team to deliver new functionality to users rapidly but safely.</p>
</blockquote>
<p><cite>Martin Fowler</cite> — <a href="http://martinfowler.com/articles/feature-toggles.html">Feature Toggles</a></p>
<p>If you’ve not heard of feature toggles before, then I suggest you go ahead and read the Martin Fowler article linked above. Since starting to use Continuous Delivery techniques in my development, I’ve found feature toggles to be an essential tool.</p>
<ol>
<li>It allows developers to work on a feature for a long time before releasing it to the public. This can be done <strong>without</strong> having to maintain a long lived branch, and all the merge issues which that creates.</li>
<li>It allows control over which features are available on which environment, and to which users. You can (for example) use feature toggles to do phased deployments to specified cohorts of your user-base.</li>
<li>It makes failed deployments and rollbacks much less stressful. Your code doesn’t work? It’s just a config change to hide your shame.</li>
</ol>
<p>I’ve written (with help from people like <a href="https://twitter.com/marto83">Martin Georgiev</a>, <a href="https://twitter.com/dannylee_c">Dan Curtis</a> and various others) a library to help bring this handy technique into the Sitecore world.</p>
<p>You can <a href="https://github.com/aqueduct/Aqueduct.Toggles">clone it from Github</a> to see how it works, but here’s an introduction to some of the features.</p>
<h2 id="introduction">Introduction</h2>
<p>In it’s simplest state, you’ll have a config file defining your available toggles.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><?xml version="1.0" encoding="utf-8" ?></span>
<span class="nt"><featureToggles></span>
<span class="nt"><feature</span> <span class="na">name=</span><span class="s">"ExampleFeature"</span> <span class="na">enabled=</span><span class="s">"true"</span> <span class="nt">/></span>
<span class="nt"></featureToggles></span>
</code></pre></div></div>
<p>In your code, you might have a very simple <code class="highlighter-rouge">if</code> statement. Take a new code path if the toggle is turned on, otherwise use the existing behaviour.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="n">FeatureToggles</span><span class="p">.</span><span class="nf">IsEnabled</span><span class="p">(</span><span class="s">"ExampleFeature"</span><span class="p">))</span>
<span class="p">{</span>
<span class="c1">//New behaviour</span>
<span class="p">}</span>
<span class="k">else</span>
<span class="p">{</span>
<span class="c1">//Original behaviour</span>
<span class="p">}</span>
</code></pre></div></div>
<p>So now, we’ve got some brand new code - committed to master, totally untested, and not ready for users. By adding a <a href="https://msdn.microsoft.com/en-us/library/dd465318(v=vs.100).aspx">config transform</a> that sets <code class="highlighter-rouge">enabled="false"</code> in the Production environment, we’re still safe to deploy. Hooray!</p>
<p class="notice--info"><strong>Note:</strong> This is all defined in the Aqueduct.Toggles assembly, so you can use it in any .Net project, not just Sitecore ones.</p>
<h2 id="feature-toggles-in-sitecore">Feature Toggles in Sitecore</h2>
<p>Usually when I’m developing a new feature in Sitecore, it will be a brand new rendering. In this case, you’re in luck! There’s no need for feature toggles - just don’t put the rendering on any pages, and the users won’t see it.</p>
<p>Sometimes however, I’ve got a more difficult feature to work on. Perhaps I’m replacing an existing rendering with a totally new one, or switching a whole layout? Sometimes these are defined in multiple places, or come from standard values, making them hard to swap out.</p>
<p>The way we did this in Aqueduct.Toggles.Sitecore was to override the processors that select a layout and renderings. We then also extended the toggle config to allow you to add some additional properties to the basic feature definition.</p>
<h3 id="scenario-1---swap-a-rendering-for-another-type-of-rendering">Scenario 1 - Swap a rendering for another type of rendering</h3>
<p>This is the most basic scenario. You might use this to replace a popular rendering which is used on multiple pages and templates throughout the site, such as navigation.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><feature</span> <span class="na">name=</span><span class="s">"SwapRenderingsFeature"</span> <span class="na">enabled=</span><span class="s">"true"</span><span class="nt">></span>
<span class="nt"><renderings></span>
<span class="nt"><rendering</span> <span class="na">name=</span><span class="s">"navigation"</span>
<span class="na">originalId=</span><span class="s">"{AD909EB2-A8E8-484C-BA23-E0CC137142A1}"</span>
<span class="na">newId=</span><span class="s">"{E8A4B6F9-E787-45A1-AB8A-3883405C4436}"</span> <span class="nt">/></span>
<span class="nt"></renderings></span>
<span class="nt"></feature></span>
</code></pre></div></div>
<p>The feature above tells Sitecore that every time it sees a rendering with ID <code class="highlighter-rouge">{AD909EB2-A8E8-484C-BA23-E0CC137142A1}</code> that you want to swap it with a totally different rendering with ID <code class="highlighter-rouge">{E8A4B6F9-E787-45A1-AB8A-3883405C4436}</code>.</p>
<h3 id="scenario-2---swap-the-whole-layout-and-renderings-for-a-template-type">Scenario 2 - Swap the whole layout and renderings for a template type</h3>
<p>Another case that I’ve come across might be that a specific template type (say “News Articles”) might be getting a design refresh. In this case, you might want to switch out the layout and renderings coming from standard values, for many thousands of pages at once.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><feature</span> <span class="na">name=</span><span class="s">"NewLayoutForTemplateType"</span> <span class="na">enabled=</span><span class="s">"true"</span><span class="nt">></span>
<span class="nt"><templates></span>
<span class="nt"><template</span> <span class="na">id=</span><span class="s">"{03AFA791-2A92-46E8-8A10-47EC6502B633}"</span>
<span class="na">newLayoutId=</span><span class="s">"{0C993911-CCAB-4303-8D6F-9811E0BB0847}"</span><span class="nt">></span>
<span class="nt"><rendering</span> <span class="na">name=</span><span class="s">"navigation"</span>
<span class="na">placeholder=</span><span class="s">"topnav"</span>
<span class="na">id=</span><span class="s">"{BBDBC750-D502-4B1B-A5B4-77A4AB947DE8}"</span> <span class="nt">/></span>
<span class="nt"><rendering</span> <span class="na">name=</span><span class="s">"content"</span>
<span class="na">placeholder=</span><span class="s">"main"</span>
<span class="na">id=</span><span class="s">"{039BF107-3806-464E-B137-CF46A139D1F8}"</span> <span class="nt">/></span>
<span class="nt"><rendering</span> <span class="na">name=</span><span class="s">"footer"</span>
<span class="na">placeholder=</span><span class="s">"pagebottom"</span>
<span class="na">id=</span><span class="s">"{E30B60DC-87EF-4B31-8031-B07B3324BDD8}"</span> <span class="nt">/></span>
<span class="nt"></template></span>
<span class="nt"></templates></span>
<span class="nt"></feature></span>
</code></pre></div></div>
<h3 id="scenario-3---swap-the-layout-and-renderings-for-a-specific-item">Scenario 3 - Swap the layout and renderings for a specific item</h3>
<p>It’s also possible to swap the layout and renderings for a specific item. This might be useful if you want to refresh a homepage, or a specific landing page.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><feature</span> <span class="na">name=</span><span class="s">"featurewithsublayouts"</span> <span class="na">enabled=</span><span class="s">"true"</span><span class="nt">></span>
<span class="nt"><items></span>
<span class="nt"><item</span> <span class="na">id=</span><span class="s">"{9E316C3C-9494-4C99-8AF6-653560D20F76}"</span>
<span class="na">newLayoutId=</span><span class="s">"{0C993911-CCAB-4303-8D6F-9811E0BB0847}"</span><span class="nt">></span>
<span class="nt"><rendering</span> <span class="na">name=</span><span class="s">"navigation"</span>
<span class="na">placeholder=</span><span class="s">"topnav"</span>
<span class="na">id=</span><span class="s">"{BBDBC750-D502-4B1B-A5B4-77A4AB947DE8}"</span> <span class="nt">/></span>
<span class="nt"><rendering</span> <span class="na">name=</span><span class="s">"content"</span>
<span class="na">placeholder=</span><span class="s">"main"</span>
<span class="na">id=</span><span class="s">"{039BF107-3806-464E-B137-CF46A139D1F8}"</span> <span class="nt">/></span>
<span class="nt"><rendering</span> <span class="na">name=</span><span class="s">"footer"</span>
<span class="na">placeholder=</span><span class="s">"pagebottom"</span>
<span class="na">id=</span><span class="s">"{E30B60DC-87EF-4B31-8031-B07B3324BDD8}"</span> <span class="nt">/></span>
<span class="nt"></item></span>
<span class="nt"></items></span>
<span class="nt"></feature></span>
</code></pre></div></div>
<h2 id="overrides">Overrides</h2>
<p>One other useful feature of this library is the concept of overrides. By implementing <code class="highlighter-rouge">IOverrideProvider</code>, you can provide alternative ways to toggle a feature on or off.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">interface</span> <span class="nc">IOverrideProvider</span>
<span class="p">{</span>
<span class="kt">string</span> <span class="n">Name</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
<span class="n">Dictionary</span><span class="p"><</span><span class="kt">string</span><span class="p">,</span> <span class="kt">bool</span><span class="p">></span> <span class="nf">GetOverrides</span><span class="p">();</span>
<span class="k">void</span> <span class="nf">SetOverrides</span><span class="p">(</span><span class="n">Dictionary</span><span class="p"><</span><span class="kt">string</span><span class="p">,</span> <span class="kt">bool</span><span class="p">></span> <span class="n">overrides</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>To configure the library to use the new Provider, you need to initialize it.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">provider</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">FancyOverrideProvider</span><span class="p">();</span>
<span class="n">FeatureToggles</span><span class="p">.</span><span class="nf">SetOverrideProvider</span><span class="p">(</span><span class="n">provider</span><span class="p">);</span>
</code></pre></div></div>
<p>One provider that we’ve included is the <code class="highlighter-rouge">CookieOverrideProvider</code>. By setting an encrypted cookie, it is possible to allow a tester to browse the site with a feature enabled, <em>even if the feature is disabled for everyone else</em>.</p>
<p>This is a really popular ability with clients - they love to see new features working with Production content.</p>
<p class="notice--info">Remember earlier, when I mentioned that you could use feature toggles to enable features for cohorts of users? This is where you’d do it. Create a new <code class="highlighter-rouge">CohortOverrideProvider</code> and configure it, and then you’re ready to do fancy phased rollouts!</p>
<h2 id="front-end-feature-toggles">Front end feature toggles</h2>
<p>One other place where you might run into difficulty is when you’ve got CSS or JavaScript changes that need to go along with your new feature. These are all applied client-side, in the browser. How to control these from the server?</p>
<p>The way we work around this is to add a series of CSS classes to the <code class="highlighter-rouge"><body></code> tag of your HTML. Your (simplified) layout file might look like this.</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><!doctype html></span>
<span class="nt"><html</span> <span class="na">lang=</span><span class="s">"en"</span><span class="nt">></span>
<span class="nt"><head></span>
<span class="nt"></head></span>
<span class="nt"><body</span> <span class="na">class=</span><span class="s">"@FeatureToggles.GetCssClassesForFeatures(Sitecore.Context.Language.Name)"</span><span class="nt">></span>
@RenderBody()
<span class="nt"></body></span>
<span class="nt"></html></span>
</code></pre></div></div>
<p>This renders in a browser with a list of all enabled features.</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><body</span> <span class="na">class=</span><span class="s">"feat-EnabledFeature feat-AnotherEnabledFeature no-feat-DisabledFeature"</span><span class="nt">></span>
</code></pre></div></div>
<p>This enables the CSS and JavaScript to target only enabled features.</p>
<h2 id="continuous-delivery">Continuous Delivery</h2>
<p>This is just one technique to allow developers to minimise the amount of time spent branching and merging, as to concentrate on shipping code as quickly and painlessly as possible.</p>
<p>The site should always be in a state where you can push to Production at any point, without users getting “incomplete” features and a bad experience.</p>Neil Duncanneil@ghostwheel.co.ukHow to use feature toggling with Sitecore to enable Continuous Delivery.Model binding with Glass Mapper and Sitecore2016-09-22T00:00:00+00:002016-09-22T00:00:00+00:00https://www.ghostwheel.co.uk/sitecore/model-binding-with-glass-mapper-and-sitecore<p>When I first started using <a href="http://glass.lu">Glass Mapper</a> with Sitecore, I had lots of code like this in my controllers.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="nn">System.Web.Mvc</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">Glass.Mapper.Sc</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">My.Site.Models</span><span class="p">;</span>
<span class="k">namespace</span> <span class="nn">My.Site.Controllers</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">WidgetController</span> <span class="p">:</span> <span class="n">Controller</span>
<span class="p">{</span>
<span class="k">public</span> <span class="n">ViewResult</span> <span class="nf">Widget</span><span class="p">()</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">context</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SitecoreContext</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">model</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">GetCurrentItem</span><span class="p"><</span><span class="n">Widget</span><span class="p">>();</span>
<span class="k">return</span> <span class="nf">View</span><span class="p">(</span><span class="n">model</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Basically - get a new context… get me the current item mapped to my model type… stuff it in a view… done.
There are a few things that you can do to tidy this up. Injecting the context in a constructor is an obvious example.</p>
<h2 id="second-attempt">Second attempt</h2>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">WidgetController</span> <span class="p">:</span> <span class="n">Controller</span>
<span class="p">{</span>
<span class="k">private</span> <span class="k">readonly</span> <span class="n">ISitecoreContext</span> <span class="n">_context</span><span class="p">;</span>
<span class="k">public</span> <span class="nf">WidgetController</span><span class="p">(</span><span class="n">ISitecoreContext</span> <span class="n">context</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">_context</span> <span class="p">=</span> <span class="n">context</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">public</span> <span class="n">ViewResult</span> <span class="nf">Widget</span><span class="p">()</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">model</span> <span class="p">=</span> <span class="n">_context</span><span class="p">.</span><span class="n">GetCurrentItem</span><span class="p"><</span><span class="n">Widget</span><span class="p">>();</span>
<span class="k">return</span> <span class="nf">View</span><span class="p">(</span><span class="n">model</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>There were a few issues that I was still not happy about though.</p>
<ol>
<li>It doesn’t use the datasource for renderings. It just grabs the current item, blindly.</li>
<li>You end up with <code class="highlighter-rouge">ISitecoreContext</code> all over the place. Every controller now has a dependency on it.</li>
<li>You’re still mapping the model in every action.</li>
</ol>
<h2 id="a-better-approach">A better approach</h2>
<p>The next approach was to use <a href="https://docs.asp.net/en/latest/mvc/models/model-binding.html">model binding</a>.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">WidgetController</span> <span class="p">:</span> <span class="n">Controller</span>
<span class="p">{</span>
<span class="k">public</span> <span class="n">ViewResult</span> <span class="nf">Widget</span><span class="p">([</span><span class="n">Glass</span><span class="p">]</span> <span class="n">Widget</span> <span class="n">model</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="nf">View</span><span class="p">(</span><span class="n">model</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Now we’re getting somewhere! No more dependency on <code class="highlighter-rouge">ISitecoreContext</code>, and we don’t need to explicitly bind the model on each action.</p>
<p class="notice--info">Note how we’ve decorated the model being passed in with the <code class="highlighter-rouge">Glass</code> attribute. This is what tells ASP.Net MVC to use our new model binder.</p>
<p>Here’s what the code for <code class="highlighter-rouge">GlassAttribute</code> looks like.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">GlassAttribute</span> <span class="p">:</span> <span class="n">CustomModelBinderAttribute</span><span class="p">,</span> <span class="n">IModelBinder</span>
<span class="p">{</span>
<span class="k">private</span> <span class="k">readonly</span> <span class="n">IGlassBinder</span> <span class="n">_binder</span><span class="p">;</span>
<span class="k">public</span> <span class="nf">GlassAttribute</span><span class="p">()</span> <span class="p">:</span> <span class="k">this</span><span class="p">(</span><span class="n">DependencyResolver</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">GetService</span><span class="p"><</span><span class="n">IGlassBinder</span><span class="p">>())</span>
<span class="p">{</span>
<span class="p">}</span>
<span class="k">public</span> <span class="nf">GlassAttribute</span><span class="p">(</span><span class="n">IGlassBinder</span> <span class="n">binder</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">_binder</span> <span class="p">=</span> <span class="n">binder</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">public</span> <span class="kt">bool</span> <span class="n">InferType</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="k">public</span> <span class="kt">bool</span> <span class="n">IsLazy</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="k">public</span> <span class="k">virtual</span> <span class="kt">object</span> <span class="nf">BindModel</span><span class="p">(</span><span class="n">ControllerContext</span> <span class="n">controllerContext</span><span class="p">,</span> <span class="n">ModelBindingContext</span> <span class="n">bindingContext</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">_binder</span><span class="p">.</span><span class="n">InferType</span> <span class="p">=</span> <span class="n">InferType</span><span class="p">;</span>
<span class="n">_binder</span><span class="p">.</span><span class="n">IsLazy</span> <span class="p">=</span> <span class="n">IsLazy</span><span class="p">;</span>
<span class="k">return</span> <span class="n">_binder</span><span class="p">.</span><span class="nf">BindType</span><span class="p">(</span><span class="n">bindingContext</span><span class="p">.</span><span class="n">ModelType</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">override</span> <span class="n">IModelBinder</span> <span class="nf">GetBinder</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">return</span> <span class="k">this</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>You’ll probably recognize the <code class="highlighter-rouge">InferType</code> and <code class="highlighter-rouge">IsLazy</code> properties if you’ve done any work with Glass before. They’re used here to be able to pass down our preferences for how we want our mapping to work to the binder.</p>
<p>Because this is an Attribute, it’s not easy to pass in an <code class="highlighter-rouge">IGlassBinder</code>, so I’ve done the next best thing and grabbed it from the current <code class="highlighter-rouge">DependencyResolver</code>. There is still a public constructor which takes an <code class="highlighter-rouge">IGlassBinder</code> for use in tests.</p>
<p>Speaking of <code class="highlighter-rouge">IGlassBinder</code>…</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">interface</span> <span class="nc">IGlassBinder</span>
<span class="p">{</span>
<span class="kt">bool</span> <span class="n">InferType</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="kt">bool</span> <span class="n">IsLazy</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="kt">object</span> <span class="nf">BindType</span><span class="p">(</span><span class="n">Type</span> <span class="n">modelType</span><span class="p">);</span>
<span class="n">T</span> <span class="n">BindType</span><span class="p"><</span><span class="n">T</span><span class="p">>();</span>
<span class="p">}</span>
</code></pre></div></div>
<p>… and here’s the implementation…</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">GlassBinder</span> <span class="p">:</span> <span class="n">IGlassBinder</span>
<span class="p">{</span>
<span class="k">private</span> <span class="k">readonly</span> <span class="n">ISitecoreContext</span> <span class="n">_sitecoreContext</span><span class="p">;</span>
<span class="k">public</span> <span class="nf">GlassBinder</span><span class="p">(</span><span class="n">ISitecoreContext</span> <span class="n">sitecoreContext</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">_sitecoreContext</span> <span class="p">=</span> <span class="n">sitecoreContext</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">public</span> <span class="kt">bool</span> <span class="n">InferType</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="k">public</span> <span class="kt">bool</span> <span class="n">IsLazy</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="k">public</span> <span class="kt">object</span> <span class="nf">BindType</span><span class="p">(</span><span class="n">Type</span> <span class="n">modelType</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">_sitecoreContext</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">Exception</span><span class="p">(</span><span class="s">"Unable to resolve dependency for ISitecoreContext."</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">item</span> <span class="p">=</span> <span class="n">Sitecore</span><span class="p">.</span><span class="n">Mvc</span><span class="p">.</span><span class="n">Presentation</span><span class="p">.</span><span class="n">RenderingContext</span><span class="p">.</span><span class="n">CurrentOrNull</span><span class="p">?.</span><span class="n">Rendering</span><span class="p">?.</span><span class="n">Item</span> <span class="p">??</span>
<span class="n">Sitecore</span><span class="p">.</span><span class="n">Context</span><span class="p">.</span><span class="n">Item</span><span class="p">;</span>
<span class="k">return</span> <span class="n">_sitecoreContext</span><span class="p">.</span><span class="nf">CreateType</span><span class="p">(</span><span class="n">modelType</span><span class="p">,</span> <span class="n">item</span><span class="p">,</span> <span class="n">IsLazy</span><span class="p">,</span> <span class="n">InferType</span><span class="p">,</span> <span class="k">null</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="n">T</span> <span class="n">BindType</span><span class="p"><</span><span class="n">T</span><span class="p">>()</span>
<span class="p">{</span>
<span class="k">return</span> <span class="p">(</span><span class="n">T</span><span class="p">)</span> <span class="nf">BindType</span><span class="p">(</span><span class="k">typeof</span> <span class="p">(</span><span class="n">T</span><span class="p">));</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Phew! There’s a few things going on here, so lets break it down.</p>
<p>First, this is where we’ve moved our dependency on <code class="highlighter-rouge">ISitecoreContext</code>. It’s a single place, so that’s an improvement on shotgunning it all over the controllers.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="nf">GlassBinder</span><span class="p">(</span><span class="n">ISitecoreContext</span> <span class="n">sitecoreContext</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">_sitecoreContext</span> <span class="p">=</span> <span class="n">sitecoreContext</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>In the <code class="highlighter-rouge">BindType</code> method, we do a little validation to check that we can get a valid <code class="highlighter-rouge">ISitecoreContext</code> and throw an exception if not.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="n">_sitecoreContext</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">Exception</span><span class="p">(</span><span class="s">"Unable to resolve dependency for ISitecoreContext."</span><span class="p">);</span>
</code></pre></div></div>
<p>Next we work out what <code class="highlighter-rouge">Item</code> we need to bind to - has a content editor set a datasource on the rendering, or are we defaulting to the current Sitecore item?</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">item</span> <span class="p">=</span> <span class="n">Sitecore</span><span class="p">.</span><span class="n">Mvc</span><span class="p">.</span><span class="n">Presentation</span><span class="p">.</span><span class="n">RenderingContext</span><span class="p">.</span><span class="n">CurrentOrNull</span><span class="p">?.</span><span class="n">Rendering</span><span class="p">?.</span><span class="n">Item</span> <span class="p">??</span>
<span class="n">Sitecore</span><span class="p">.</span><span class="n">Context</span><span class="p">.</span><span class="n">Item</span><span class="p">;</span>
</code></pre></div></div>
<p>Finally, we map the model using our Glass context, and return it.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">return</span> <span class="n">_sitecoreContext</span><span class="p">.</span><span class="nf">CreateType</span><span class="p">(</span><span class="n">modelType</span><span class="p">,</span> <span class="n">item</span><span class="p">,</span> <span class="n">IsLazy</span><span class="p">,</span> <span class="n">InferType</span><span class="p">,</span> <span class="k">null</span><span class="p">);</span>
</code></pre></div></div>
<h2 id="conclusion">Conclusion</h2>
<p>I’ve found this to be a really nice way to work. The mapping of my models is all nicely kept in a single place. It copes well with datasources, and makes my controllers very simple to test.</p>
<p>I’ve also extended this to add other attributes like <code class="highlighter-rouge">GlassHome</code> for mapping the home item for the current site. This is used for things like a footer rendering so you can store the data in a single place for the whole site.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="n">ViewResult</span> <span class="nf">Footer</span><span class="p">([</span><span class="n">GlassHome</span><span class="p">]</span> <span class="n">NavigationSource</span> <span class="n">source</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="nf">View</span><span class="p">(</span><span class="n">source</span><span class="p">.</span><span class="n">Footer</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>There is also a <code class="highlighter-rouge">GlassCurrentItem</code> attribute for when you have some properties that you need from the current item, as well as others that are coming from a datasource. One example for a place where this is useful is if you’re trying to get related content for a specific article page. The information about the rendering (background colour, title) can come from the datasource, and the information about the page (tags, linked articles) can come from the current item.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="n">ActionResult</span> <span class="nf">RelatedContent</span><span class="p">([</span><span class="n">Glass</span><span class="p">]</span> <span class="n">RelatedContentModule</span> <span class="n">module</span><span class="p">,</span> <span class="p">[</span><span class="n">GlassCurrentItem</span><span class="p">]</span> <span class="n">ContentPage</span> <span class="n">page</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">model</span> <span class="p">=</span> <span class="n">_processor</span><span class="p">.</span><span class="nf">Process</span><span class="p">(</span><span class="k">new</span> <span class="nf">PopulateRelatedContentQuery</span><span class="p">(</span><span class="n">module</span><span class="p">,</span> <span class="n">page</span><span class="p">));</span>
<span class="k">return</span> <span class="nf">View</span><span class="p">(</span><span class="n">model</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Happy data binding!</p>Neil Duncanneil@ghostwheel.co.ukWhen I first started using Glass Mapper with Sitecore, I had lots of code like this in my controllers.Green padlocks for local development2016-09-17T00:00:00+00:002016-09-17T00:00:00+00:00https://www.ghostwheel.co.uk/ssl/green-padlock-for-local-development<p>We’ve all done it.</p>
<p>You’ve been developing a site for weeks or months, deploy it to the production server, and everything falls over because you’ve done something dumb related to SSL and browser security. It’s easily done.</p>
<p>Usually, this is because either developers don’t use SSL at all when building (<em>really bad</em>), or are using self signed certificates and are used to having to ignore certificate errors (<em>not quite as bad, but still bad</em>).</p>
<p>The way I mitigate this is - when I’m building a site that requires SSL on the server, I <em>run totally valid SSL certificates on my local machine</em>. I usually work for <a href="http://www.aqueduct.co.uk">digital agencies</a>, so I run LOTS of different sites on my developer PC.</p>
<p>What I really want is a self signed wildcard certificate that validates correctly and gives me nice green padlocks in my browser. Here’s how to do it.</p>
<h2 id="install-a-fake-trusted-root-authority">Install a fake trusted root authority</h2>
<p>Before we generate our fancy new certificate, we’ll need a fake authority to sign it for us.
On Windows 7, you can run <code class="highlighter-rouge">makecert</code>, which is a tool that comes with Visual Studio or the Windows SDK.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>makecert.exe -n "CN=Ghostwheel Development Root CA,O=Ghostwheel,OU=Development,L=London,S=London,C=UK" -pe -ss Root -sr LocalMachine -sky exchange -m 120 -a sha1 -len 2048 -r
</code></pre></div></div>
<p>If you’re on Windows 10, you’ll need to run the Powershell command <a href="https://technet.microsoft.com/library/hh848633">New-SelfSignedCertificate</a>.</p>
<h2 id="install-a-wildcard-certificate-for-localcom">Install a wildcard certificate for *.local.com</h2>
<p>Next, we need a wildcard certificate, signed by the new root authority.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>makecert.exe -n "CN=*.local.com" -pe -ss My -sr LocalMachine -sky exchange -m 120 -in "Ghostwheel Development Root CA" -is Root -ir LocalMachine -a sha1 -eku 1.3.6.1.5.5.7.3.1
</code></pre></div></div>
<h2 id="bind-the-certificate-to-port-443">Bind the certificate to port 443</h2>
<p>To use the new certificate in IIS, it needs to be bound to port 443. This will allow us to have <em>lots</em> of sites all running valid SSL.</p>
<p>Open up powershell then</p>
<div class="language-posh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">dir </span>Cert:\LocalMachine\My
</code></pre></div></div>
<p>Find the thumbprint of the new cert (XXXXXXXXX)</p>
<div class="language-posh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Import-Module WebAdministration
<span class="nb">cd </span>IIS:\SslBindings
<span class="nb">Remove-Item</span> .\0.0.0.0!443
<span class="nb">Get-Item </span>cert:\LocalMachine\My\XXXXXXXXX | <span class="nb">New-Item </span>0.0.0.0!443
</code></pre></div></div>
<p>Once the steps above have been done once, there’s no need to ever do them again.</p>
<h2 id="add-the-binding-for-your-site">Add the binding for your site</h2>
<p>First, add an entry in your <a href="https://support.rackspace.com/how-to/modify-your-hosts-file/">hosts file</a> for the website you want to use. It needs to be of the form *.local.com for the certificate to validate properly.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>127.0.0.1 mysite.local.com
</code></pre></div></div>
<p>Finally, we need to add a binding in IIS so that we can serve our local site as <code class="highlighter-rouge">https://</code>
The IIS UI is a bit deficient here. It’s expecting that you’ll never have more than one site running against a single certificate (port/IP address). Luckily, we can do it via the command line.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>%systemroot%\system32\inetsrv\appcmd set site /site.name: mysite.local.com /+bindings.[protocol='https',bindingInformation='*:443:mysite.local.com']
</code></pre></div></div>Neil Duncanneil@ghostwheel.co.ukWe've all done it. You've been developing a site for weeks or months, deploy it to the production server, and everything falls over because you've done something dumb related to SSL and browser security. It's easily done.Log file cleanup2016-09-17T00:00:00+00:002016-09-17T00:00:00+00:00https://www.ghostwheel.co.uk/sysadmin/log-file-clean-up<p>I recently got a call from our sysadmin, asking me to tidy up some of our web servers. My diligent logging had filled up 100s of Gb of disk space, and it was becoming an issue.</p>
<p><img src="/images/posts/logging/log-all-the-things.png" alt="Log all the things" title="Maybe I've gone overboard here?" /></p>
<p>I <em>hate</em> having to remember to manually clean stuff up like this, so I put on my Powershell hat, and wrote some scripts to do the job.
They are designed to delete files older than a certain time, and can be run on specified lists of folders. The scripts are open source, and live <a href="https://github.com/aqueduct/Aqueduct.Server.Scripts">here</a>.</p>
<h2 id="public-health-warning">Public Health Warning!</h2>
<div class="notice--danger">
<p>These will spider a list of folders, and <em>all sub folders</em>, deleting any file that is older than 7 days.
If you run it on <code>C:\</code> or <code>C:\Users\Neil\non-backed-up-photos-of-my-kids\</code> or something, then you <em>will lose your files</em>.</p>
<p><strong>Please be careful!</strong></p>
</div>
<h2 id="usage">Usage</h2>
<p>First clone the repository to the server that you want to keep maintained.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://github.com/aqueduct/Aqueduct.Server.Scripts.git
</code></pre></div></div>
<p>Create a new file in the same directory as the scripts called “folders.txt”. Each line in this file is a folder that will be tidied up. Some examples of folders you might want to clean up - IIS logs, Sitecore logs, Temporary ASP.Net files. Here’s an example.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>C:\inetpub\logs\LogFiles
C:\Octopus\Applications\Production\*REDACTED*.Site\Data\logs
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root
</code></pre></div></div>
<p>Next, make sure you’ve allowed Powershell scripts to run. Open a Powershell prompt, and type</p>
<div class="language-posh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">Set-ExecutionPolicy </span>Unrestricted
</code></pre></div></div>
<p>Then you can run the scripts, and tidy up the listed folders.</p>
<div class="language-posh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.\Execute.ps1
</code></pre></div></div>
<h2 id="scheduling">Scheduling</h2>
<p>Of course, if you have to run this manually, it’s not much good. Much better to set this up as a scheduled task!</p>
<p>Open up Task Scheduler (<code class="highlighter-rouge">Run > Task Scheduler</code>), and create a new Task.
Give it a name like “Server Maintenance”, and then click the “Change User or Group” button.</p>
<p><img src="/images/posts/logging/new-task.png" alt="New Task" title="Change User or Group" /></p>
<p>I usually run this task as “SYSTEM”.</p>
<p>Next, you’ll need to trigger your task. I usually run this weekly at a time when I know that the server is not going to be under load.</p>
<p><img src="/images/posts/logging/new-task-schedule.png" alt="New Task Trigger" title="Weekly, Sunday, 2AM" /></p>
<p>Now, we need to tell the scheduler what action to run. The location should be the folder path that the scripts are on.</p>
<p><img src="/images/posts/logging/new-task-action.png" alt="New Task Action" title="Powershell .\Execute.ps1" /></p>
<h2 id="how-it-works">How it works</h2>
<p>The script is super simple. The bulk of the work is done by a function called <code class="highlighter-rouge">Remove-FilesOlderThan</code> in the <code class="highlighter-rouge">Maintenance-Helpers.psm1</code> file.</p>
<p>There are a few parameters that you can pass into this function.</p>
<div class="language-posh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">Param</span><span class="o">(</span>
<span class="o">[</span>Parameter<span class="o">(</span><span class="nv">Mandatory</span><span class="o">=</span><span class="nv">$true</span><span class="o">)]</span>
<span class="o">[</span><span class="kt">String</span><span class="o">]</span>
<span class="nv">$folderPath</span>,
<span class="o">[</span><span class="kt">Int</span><span class="o">]</span>
<span class="nv">$days</span> <span class="o">=</span> 30,
<span class="o">[</span><span class="k">Switch</span><span class="o">]</span>
<span class="nv">$recurse</span>
<span class="o">)</span>
</code></pre></div></div>
<p>The only mandatory one is <code class="highlighter-rouge">$folderPath</code> - the rest have sensible default values.</p>
<p>The script does a <code class="highlighter-rouge">Get-ChildItem</code>, and then loops over the files looking for ones that are older than the specified date.</p>
<div class="language-posh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$age</span> <span class="o">=</span> <span class="o">(</span><span class="nv">$now</span> - <span class="nv">$item</span>.CreationTime<span class="o">)</span>.Days
</code></pre></div></div>
<p>If it finds one, it tries to delete, skipping it if it doesn’t have access.</p>
<div class="language-posh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">try</span>
<span class="o">{</span>
<span class="nb">Remove-Item</span> <span class="nv">$item</span>.FullName -Force -ErrorAction Stop
<span class="nv">$deleted</span> +<span class="o">=</span> 1
<span class="o">}</span>
<span class="k">catch</span>
<span class="o">{</span>
<span class="nv">$failed</span> +<span class="o">=</span> 1
<span class="o">}</span>
</code></pre></div></div>
<p>Most of the rest of the script is error-handling, and progress bar management, which I won’t cover here.</p>Neil Duncanneil@ghostwheel.co.ukI recently got a call from our sysadmin, asking me to tidy up some of our web servers. My diligent logging had filled up 100s of Gb of disk space, and it was becoming an issue.