<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Søren Kruse | .NET, C# and Azure]]></title><description><![CDATA[Søren Kruse | .NET, C# and Azure]]></description><link>https://blog.krusen.dk</link><generator>RSS for Node</generator><lastBuildDate>Sat, 18 Apr 2026 23:19:55 GMT</lastBuildDate><atom:link href="https://blog.krusen.dk/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Dynamic caching policy with Polly]]></title><description><![CDATA[Polly is great library for easily configuring different kinds of policies around code execution, be it retry, circuit breaker, caching or lots of other things. It's probably most often used around HTTP requests. If you haven't heard about it you defi...]]></description><link>https://blog.krusen.dk/dynamic-caching-policy-with-polly</link><guid isPermaLink="true">https://blog.krusen.dk/dynamic-caching-policy-with-polly</guid><dc:creator><![CDATA[Søren Kruse]]></dc:creator><pubDate>Fri, 15 Jan 2021 20:20:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484623826/n-vCzz99c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a target="_blank" href="https://github.com/App-vNext/Polly">Polly</a> is great library for easily configuring different kinds of policies around code execution, be it retry, circuit breaker, caching or lots of other things. It's probably most often used around HTTP requests. If you haven't heard about it you definitely should check it out.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/App-vNext/Polly">https://github.com/App-vNext/Polly</a></div>
<p>Recently I worked on configuring a caching policy, but only wanted to cache the returned models from an API call in certain cases depending on the values of the model received and that's what this blog post is about.</p>
<h1 id="heading-the-challenge">The challenge</h1>
<p>If you just want to selectively cache for a specific response type, e.g. <code>HttpResponseMessage</code>, then that is actually not too difficult and you can read about how to do that in the following blog post, where the policy gets configured to only cache 200 OK responses.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://nodogmablog.bryanhogan.net/2019/03/selectively-caching-a-httpresponsemessage-with-polly/">https://nodogmablog.bryanhogan.net/2019/03/selectively-caching-a-httpresponsemessage-with-polly/</a></div>
<p>It's basically just a <code>ITtlStrategy</code> that in certain situations returns a "time-to-live" of 0, meaning the item expires from the cache immediately.</p>
<p>Caching at the <code>HttpResponseMessage</code> level might not be the right thing though, <a target="_blank" href="https://github.com/App-vNext/Polly/wiki/Polly-and-HttpClientFactory#is-caching-at-the-httpresponsemessage-level-the-right-fit">and there are some thing to consider</a> in that regard, like re-reading response streams, deserializing the response again etc. Instead I wanted to selectively cache the deserialized result model. Doing this for different models seemed too cumbersome, as I would have to create specific policies for each return type (because of generics, i.e. <code>ResultTtl&lt;T&gt;</code>).</p>
<h1 id="heading-the-solution">The solution</h1>
<p>The solution I came up with was to create a custom <code>ITtlStrategy</code> that would look for a specific interface and choose depending on that.</p>
<p>Here's the interface <code>ICacheable</code>:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">ICacheable</span>
{
    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
    <span class="hljs-comment"><span class="hljs-doctag">///</span> Should return true if the object shouldn't be cached in its current state.</span>
    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
    <span class="hljs-function"><span class="hljs-keyword">bool</span> <span class="hljs-title">DisallowCaching</span>(<span class="hljs-params"></span>)</span>;
}
</code></pre>
<p>Any model can implement that interface and return a fitting value depending on it's current state.</p>
<p>For this interface to have any effect we need a <code>ITtlStrategy</code>, and here it is:</p>
<pre><code class="lang-csharp"><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
<span class="hljs-comment"><span class="hljs-doctag">///</span> Dynamic TTL strategy that doesn't cache the item if it implements</span>
<span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;see cref="ICacheable"/&gt;</span> interface and doesn't allow caching in its current state.</span>
<span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CacheableFilterTtl</span> : <span class="hljs-title">ITtlStrategy</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">readonly</span> ZeroTtl = <span class="hljs-keyword">new</span> Ttl(TimeSpan.Zero);

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ITtlStrategy _innerStrategy;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">CacheableFilterTtl</span>(<span class="hljs-params">ITtlStrategy innerStrategy</span>)</span>
    {
        _innerStrategy = innerStrategy ?? <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(innerStrategy));
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">CacheableFilterTtl</span>(<span class="hljs-params">TimeSpan ttl</span>)</span>
    {
        _innerStrategy = <span class="hljs-keyword">new</span> RelativeTtl(ttl);
    }

    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;inheritdoc /&gt;</span></span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Ttl <span class="hljs-title">GetTtl</span>(<span class="hljs-params">Context context, <span class="hljs-keyword">object</span> result</span>)</span>
    {

        <span class="hljs-keyword">if</span> (result <span class="hljs-keyword">is</span> ICacheable cacheable &amp;&amp; cacheable.DisallowCaching())
        {
            <span class="hljs-keyword">return</span> ZeroTtl;
        }

        <span class="hljs-keyword">return</span> _innerStrategy.GetTtl(context, result);
    }
}
</code></pre>
<p>It's rather simple, really. It can either be created as wrapping another <code>ITtlStrategy</code> as a fallback strategy, or with a simple <code>RelativeTtl</code> based on a <code>TimeSpan</code>.</p>
<p>When figuring out the <code>Ttl</code> to return it looks at the result and if it implements <code>ICacheable</code> and does not allow caching then it returns a <code>Ttl</code> of 0. If the result is not of type <code>ICacheable</code> then it just uses the fallback strategy.</p>
<p>Creating the cache policy using the custom <code>ITtlStrategy</code> is very simple:</p>
<pre><code class="lang-csharp">IAsyncCacheProvider cacheProvider = <span class="hljs-literal">null</span>; <span class="hljs-comment">// Get from Service Provider</span>
Policy.CacheAsync(cacheProvider, <span class="hljs-keyword">new</span> CacheableFilterTtl(TimeSpan.FromHours(<span class="hljs-number">1</span>));
</code></pre>
<p>This will create a cache policy with a relative time-to-live of 1 hour as the default, unless the result implements <code>ICacheable</code> and does not allow caching.</p>
]]></content:encoded></item><item><title><![CDATA[Unit Testing - Part 2: Naming, structure and readability]]></title><description><![CDATA[This is part 2 of my series on unit testing in .NET (C#) and will be about my conventions regarding naming unit tests, how to structure them and which parts to test. And lastly I will help you increase readability of assertions and potential error me...]]></description><link>https://blog.krusen.dk/unit-testing-part-2-naming-structure-readability</link><guid isPermaLink="true">https://blog.krusen.dk/unit-testing-part-2-naming-structure-readability</guid><dc:creator><![CDATA[Søren Kruse]]></dc:creator><pubDate>Sat, 09 Jan 2021 13:45:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484616861/tJwSSC8WC.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is part 2 of my series on unit testing in .NET (C#) and will be about my conventions regarding naming unit tests, how to structure them and which parts to test. And lastly I will help you increase readability of assertions and potential error messages with the <a target="_blank" href="https://fluentassertions.com/">FluentAssertions</a> library.</p>
<ul>
<li><a target="_blank" href="https://blog.krusen.dk/unit-testing-part-1-getting-started">Part 1: Getting started</a></li>
<li><strong>Part 2: Naming, structure, and readability (FluentAssertions)</strong></li>
<li>Part 3: Mocking and writing testable code (NSubstitute)</li>
<li>Part 4: Keeping it DRY and maintainable (AutoFixture)</li>
<li>Part 5: Test Driven Development (TDD) with Live Unit Testing (LUT)</li>
</ul>
<h1 id="heading-naming-tests">Naming tests</h1>
<p>Test method names should generally be detailed, descriptive and readable.</p>
<p>We don't really care about normal naming conventions here, because we want to be able to tell what a test is supposed to test for at a glance. This also helps when a test inevitably fails; you don't have to dig into the code to figure out what scenario is actually failing.</p>
<p>The test class itself should normally just match the class your are testing postfixed with <code>Tests</code>, e.g. <code>BasketTests</code>.</p>
<p>For the naming of the test methods I usually go by a pattern like this <code>{method-name}_{scenario}_{expected-outcome}</code>. Some examples:</p>
<ol>
<li><code>AddItem_NullItem_ThrowsArgumentNullException</code></li>
<li><code>AddItem_NewItem_AddsNewItem</code></li>
<li><code>AddItem_ExistingItem_DoesNotAddNewItem</code></li>
<li><code>AddItem_ExistingItem_ShouldIncreaseQuantityOfExistingItem</code></li>
</ol>
<p><code>AddItem</code> is the method being tested.</p>
<p><code>NullItem</code>, <code>NewItem</code>, <code>ExistingItem</code> indicates a sort of input for the test, or as a way to sort of grouping the tests by a specific scenario.</p>
<p>The last part is self-explanatory and just rather precisely describes what we expect to happen, given the scenario.</p>
<p>Compare that to test names like these:</p>
<ul>
<li><code>AddNullItemTest</code></li>
<li><code>AddNewItemTest</code></li>
<li><code>AddExistingItemTest</code></li>
</ul>
<p>You can't tell much just from the name of these; you will have to look at the code to see what is actually being tested and what is causing it to fail. What method is actually being tested? What was the expected outcome?</p>
<p>This also illustrates a common thing - maybe the tests are testing too much? Keeping the tests simple and focused on a single thing instead of a bit of everything will help make the tests more readably and easier to debug.</p>
<h1 id="heading-what-parts-of-your-code-to-test">What parts of your code to test</h1>
<p>A common issue I hear or notice is that many people are unsure of what to actually test.</p>
<p>As I see it there at least two ways to approach this:</p>
<ol>
<li>From the outside. Looking at the method signature and the inputs, what do you expect the outcome should be?</li>
<li>From the inside. Looking at the code where does it branch into different scenarios and edge-cases (if-conditions, exceptions etc.)</li>
</ol>
<p>Starting with the 1. case - looking at it from the outside - is sort of close to Test Driven Development (TTD) in my eyes, where you can have some requirements that should be matched by the code which you want to verify. It could be acceptance criteria of a feature request or the expected outcome detailed in a bug report.</p>
<p>An example could be the basket example from Part 1 of this series. A requirement for when adding items is that it should not create a new (duplicate) item in the basket if the item already exist, instead it should add the quantity to the existing item. Here we are just looking at the input and expected outcome.</p>
<p>The 2. approach is to look at it from the inside; looking at the code itself and if there are any obvious logic branches or handling of edge cases. You can then add tests to make sure cover all the different scenarios and thereby increase your code coverage (although just because the code is covered doesn't mean that all cases are covered).</p>
<p>I find that approach number 1 is best at finding requirements that were missed during development, while number 2 is good for legacy code before adding new features or doing refactoring, because it helps ensure the existing functionality doesn't break.</p>
<h1 id="heading-structuring-tests">Structuring tests</h1>
<p>When writing test they should really - like most stuff - be structured for readability and maintainability. As much as possible you want to easily be able to tell at a glance what a test does.</p>
<p>I always follow the "Arrange, Act and Assert" pattern (AAA). Shortly explained that means:</p>
<ol>
<li>Arrange: Setup and prepare everything for your test</li>
<li>Act: Execute the code to be tested</li>
<li>Assert: Verify that the results are as expected</li>
</ol>
<p>It's not strictly necessary but I almost always add a comment above each section unless it's 2-liner or something very very simple. It helps me to visually separate the sections and allows me to have empty lines between logically grouped arrange-steps.</p>
<pre><code class="lang-csharp">[<span class="hljs-meta">Fact</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">AddItem_ExistingItem_DoesNotAddNewItem</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-comment">// Arrange</span>
    <span class="hljs-keyword">var</span> itemNo = <span class="hljs-string">"qwerty"</span>;
    <span class="hljs-keyword">var</span> basket = <span class="hljs-keyword">new</span> Basket
    {
        Items = <span class="hljs-keyword">new</span> List&lt;BasketItem&gt;
        {
            <span class="hljs-keyword">new</span> BasketItem
            {
                ItemNo = itemNo,
                Quantity = <span class="hljs-number">1</span>
            }
        }
    };
    Assert.Equal(<span class="hljs-number">1</span>, basket.Items.Count);

    <span class="hljs-comment">// Act</span>
    basket.AddItem(itemNo, <span class="hljs-number">1</span>);

    <span class="hljs-comment">// Assert</span>
    Assert.Equal(<span class="hljs-number">1</span>, basket.Items.Count);
}
</code></pre>
<blockquote>
<p>Example of the Arrange-Act-Assert pattern with comments for each section to visually separate them.</p>
</blockquote>
<h2 id="heading-readability-versus-repetition-dry">Readability versus repetition (DRY)</h2>
<p>Usually I prefer to have a bit of repetition in favor of sacrificing readability. It can often be tempting - and I see this often - to extract the arrange-section into a separate method and just call that as the setup for a lot of different test, e.g. a <code>CreateBasket()</code> setup method.</p>
<p>That can be okay in some scenarios, but what usually ends up happening is that the setup-method is then made to work with all your different tests and has some setup that is not necessary for every test and might even mask some issues that would have been noticed if the setup was done more specifically for each test. It also make it harder to see at a glance what the setup for the test actually is without having to jump to that method.</p>
<p>Sometimes a compromise can be made if you use the same setup for a group of tests and another setup for another group of tests. Then you could have setup-methods like <code>CreateEmptyBasket()</code>, <code>CreateBasketWith3Items()</code> etc., making the method describe the setup being done.</p>
<h2 id="heading-test-a-single-thing-per-test">Test a single thing per test</h2>
<p>The last thing I want to mention regarding the structure of your tests is try to focus on testing a single thing per test. If you test too much in a single test and the test fails, then it will not be immediately apparent what is actually failing.</p>
<p>If you have a failed test named something like <code>TestThatBasketWorks()</code> which tests both adding and deleting items, then you won't know if it is adding or deleting items that failed the test and you have to spent time figuring that out first.</p>
<p>If you instead have 2 tests - <code>AddItem_AddsANewItem()</code> and <code>DeleteItem_RemovesItem()</code> - and one of them fails, then you know right away which part of the basket has broken.</p>
<h1 id="heading-increasing-readability-of-assertions-and-error-messages">Increasing readability of assertions and error messages</h1>
<p>I always use the <strong><a target="_blank" href="https://fluentassertions.com/">FluentAssertions</a></strong>package when writing unit tests.</p>
<pre><code class="lang-csharp">&lt;PackageReference Include=<span class="hljs-string">"FluentAssertions"</span> Version=<span class="hljs-string">"5.10.3"</span> /&gt;
&lt;PackageReference Include=<span class="hljs-string">"FluentAssertions.Analyzers"</span> Version=<span class="hljs-string">"0.11.4"</span> /&gt;
</code></pre>
<p>It's a very nice set of extension methods that helps you write more natural assertions and also more descriptive error messages in case a test fails. You simply add a call to the extension method <code>Should()</code> after the object/value that you want to do one ore more assertions on and then you can chain other calls like <code>Be("something")</code> or <code>BeTrue()</code> or <code>HaveCount(2)</code> for verifying the amount of items in a collection.</p>
<p>Go check out their <a target="_blank" href="https://fluentassertions.com/introduction">"Getting stared" section</a> in the documentation for more information.</p>
<pre><code class="lang-csharp">Assert.NotNull(basket.Items);
Assert.Empty(basket.Items);

<span class="hljs-comment">// With FluentAssertions we can write the above like this:</span>
basket.Items.Should().NotBeNull();
basket.Items.Should().BeEmpty();

<span class="hljs-comment">// You can even chain assertions like this:</span>
basket.Items.Should().NotBeNull().And.BeEmpty();
</code></pre>
<p>Using the normal way with the <code>Assert</code> class the assertions reads a bit as if spoken by Yoda: "assert that not null, the basket items are".</p>
<p>The assertions made with <strong>FluentAssertions</strong>reads more naturally like "basket items should not be null" and "basket items should not be empty".</p>
<p>Regarding the more descriptive error messages, let's look at this example:</p>
<pre><code class="lang-csharp">Assert.Equal(<span class="hljs-number">1</span>, basket.Items.Count);
<span class="hljs-comment">// Error message:</span>
<span class="hljs-comment">//   Assert.Equal() Failure</span>
<span class="hljs-comment">//   Expected: 1</span>
<span class="hljs-comment">//   Actual: 0</span>

basket.Items.Should().HaveCount(<span class="hljs-number">1</span>);
<span class="hljs-comment">// Error message with FluentAssertions:</span>
<span class="hljs-comment">//   Expected collection to contain 1 item(s) but found 0.</span>
</code></pre>
<p>The error message with <strong>FluentAssertions</strong>contains more information about the assertion being made. In this case that we were expecting a collection to have a specific count. Without <strong>FluentAssertions</strong>we just now that some comparison of integer values were not equal as expected.</p>
<p>You can also add a "because" text to the assertion, specifying why the assertion is needed.</p>
<pre><code class="lang-csharp">basket.Items.Should().HaveCount(<span class="hljs-number">3</span>, <span class="hljs-string">"because we added 3 different items"</span>);
<span class="hljs-comment">// Error message:</span>
<span class="hljs-comment">//   Expected collection to contain 3 item(s) because we added 3 different items, but found 1.</span>
</code></pre>
<h1 id="heading-next-up-in-part-3">Next up in Part 3</h1>
<p>That's all for this time. In the next part I'll talk about mocking dependencies with NSubstitute and about how to make you code more easily testable.</p>
<ul>
<li><a target="_blank" href="https://blog.krusen.dk/unit-testing-part-1-getting-started">Part 1: Getting started</a></li>
<li><strong>Part 2: Naming, structure, and readability (FluentAssertions)</strong></li>
<li>Part 3: Mocking and writing testable code (NSubstitute)</li>
<li>Part 4: Keeping it DRY and maintainable (AutoFixture)</li>
<li>Part 5: Test Driven Development (TDD) with Live Unit Testing (LUT)</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Unit Testing - Part 1: Getting started with unit tests in .NET]]></title><description><![CDATA[I feel like unit testing is very important and very beneficial in a lot of ways. It helps with not breaking existing functionality and thereby also making you more confident in changing code without fear of breaking important stuff. Often it also mak...]]></description><link>https://blog.krusen.dk/unit-testing-part-1-getting-started</link><guid isPermaLink="true">https://blog.krusen.dk/unit-testing-part-1-getting-started</guid><dc:creator><![CDATA[Søren Kruse]]></dc:creator><pubDate>Mon, 28 Dec 2020 19:32:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484611031/arL34hfsv.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I feel like unit testing is very important and very beneficial in a lot of ways. It helps with not breaking existing functionality and thereby also making you more confident in changing code without fear of breaking important stuff. Often it also makes the code less coupled because highly coupled code can be difficult to test.</p>
<p>But most people I know really don't write a lot of unit tests or are not very good at it - which might be the reason they don't do it to begin with.</p>
<p>So I've been wanting to do a series of blog post about the whole process of writing unit tests in .NET (C#), how to get going and how to make it easier and faster to write good, maintainable unit tests.</p>
<ul>
<li><strong>Part 1: Getting started</strong></li>
<li><a target="_blank" href="https://blog.krusen.dk/unit-testing-part-1-getting-started/unit-testing-part-2-naming-structure-readability">Part 2: Naming, structure and readability (FluentAssertions)</a></li>
<li>Part 3: Mocking and writing testable code (NSubstitute)</li>
<li>Part 4: Keeping it DRY and maintainable (AutoFixture)</li>
<li>Part 5: Test Driven Development (TDD) with Live Unit Testing (LUT)</li>
</ul>
<h1 id="heading-choosing-a-test-framework">Choosing a test framework</h1>
<p>Before getting started you will need to choose a test framework. The two most popular ones are <a target="_blank" href="https://xunit.net/">xUnit</a>and <a target="_blank" href="https://nunit.org/">NUnit</a>.</p>
<p>I personally much prefer xUnit and feel it's more intuitive and requires less scaffolding. xUnit is also used internally by Microsoft and for the unit tests of the .NET code base itself.</p>
<h1 id="heading-creating-a-test-project">Creating a test project</h1>
<p>For this blog series I've created a simple solution named <strong>Blog.Commerce</strong> to use as an example and build upon during the series.</p>
<p>Normally you would create a test project per library/web project you want to add unit tests for.</p>
<p>In Visual Studio you can simply add a new xUnit test project like shown below or you can create it with <code>dotnet new xunit</code>.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484598851/gaUcqrMUM.png" alt />
There's no set rule on what to name your test project or where to place it. Personally I usually name it <code>{OtherProjectName}.Tests</code>, which in this case would then be <strong>Blog.Commerce.Tests</strong>, and place it next to the existing project. Some people prefer to keep it separate in different folders.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484600752/yAhbmKSRw.png" alt />
The default basic project file for a test project should look close to this:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">Project</span> <span class="hljs-attr">Sdk</span>=<span class="hljs-string">"Microsoft.NET.Sdk"</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">PropertyGroup</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- You can change this to 'netcoreapp3.1' if working with .NET Standard or .NET Core --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">TargetFramework</span>&gt;</span>net5.0<span class="hljs-tag">&lt;/<span class="hljs-name">TargetFramework</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">IsPackable</span>&gt;</span>false<span class="hljs-tag">&lt;/<span class="hljs-name">IsPackable</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">PropertyGroup</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">ItemGroup</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">PackageReference</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"Microsoft.NET.Test.Sdk"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"16.8.3"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">PackageReference</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"xunit"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"2.4.1"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">PackageReference</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"xunit.runner.visualstudio"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"2.4.3"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">IncludeAssets</span>&gt;</span>runtime; build; native; contentfiles; analyzers; buildtransitive<span class="hljs-tag">&lt;/<span class="hljs-name">IncludeAssets</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">PrivateAssets</span>&gt;</span>all<span class="hljs-tag">&lt;/<span class="hljs-name">PrivateAssets</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">PackageReference</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">PackageReference</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"coverlet.collector"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"3.0.2"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">IncludeAssets</span>&gt;</span>runtime; build; native; contentfiles; analyzers; buildtransitive<span class="hljs-tag">&lt;/<span class="hljs-name">IncludeAssets</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">PrivateAssets</span>&gt;</span>all<span class="hljs-tag">&lt;/<span class="hljs-name">PrivateAssets</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">PackageReference</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">ItemGroup</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">Project</span>&gt;</span>
</code></pre>
<blockquote>
<p>Tip: You can change the <code>&lt;TargetFramework&gt;</code> to <code>&lt;TargetFrameworks&gt;</code> and add multiple targets to run your tests for multiple frameworks, for example <code>&lt;TargetFrameworks&gt;netcoreapp3.1.;net5.0&lt;/TargetFrameworks&gt;</code></p>
</blockquote>
<p>There you go. That wasn't so complicated - let's get started with writing some tests.</p>
<h1 id="heading-setting-the-scene">Setting the scene</h1>
<p>For this example I've created a simple <code>Basket</code> with a list of <code>BasketItem</code>s.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> System.Collections.Generic;
<span class="hljs-keyword">using</span> System.Linq;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Blog.Commerce</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Basket</span>
    {
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">IList</span>&lt;<span class="hljs-title">BasketItem</span>&gt; Items</span> { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } = <span class="hljs-keyword">new</span> List&lt;BasketItem&gt;();

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">AddItem</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> itemNo, <span class="hljs-keyword">int</span> quantity</span>)</span>
        {
            <span class="hljs-keyword">if</span> (TryGetItem(itemNo, <span class="hljs-keyword">out</span> <span class="hljs-keyword">var</span> basketItem))
            {
                basketItem.Quantity += quantity;
            }
            <span class="hljs-keyword">else</span>
            {
                Items.Add(<span class="hljs-keyword">new</span> BasketItem
                {
                    ItemNo = itemNo,
                    Quantity = quantity
                });
            }
        }

        <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">bool</span> <span class="hljs-title">TryGetItem</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> itemNo, <span class="hljs-keyword">out</span> BasketItem basketItem</span>)</span>
        {
            basketItem = Items.SingleOrDefault(x =&gt; x.ItemNo == itemNo);
            <span class="hljs-keyword">return</span> basketItem != <span class="hljs-literal">null</span>;
        }
    }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">Blog.Commerce</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">BasketItem</span>
    {
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> ItemNo { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

        <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> Quantity { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    }
}
</code></pre>
<p>I have some simple expectations (or requirements) for this basket that I would like to verify with some simple unit tests:</p>
<ol>
<li>A new basket has an non-null, empty list of items</li>
<li>Adding a new item will add a new item to the list of items</li>
<li>Adding an item that already exist will add to the existing quantity and not add a new item to the list</li>
</ol>
<h1 id="heading-creating-a-test">Creating a test</h1>
<p>I want to create a test for my <code>Basket.cs</code> class, so I make a new class (following the same folder structure of the class I want to test) and naming it <code>{Class}Tests.cs</code> which in this cases becomes <code>BasketTests.cs</code>.</p>
<p>For testing my 1. expectation above I create a new method called <code>Ctor_ItemsIsEmpty</code> (with <em>Ctor</em>meaning <em>Constructor</em>) and add the <code>[Fact]</code> attribute above it (this marks it as a test that should be executed by the xUnit test runner).</p>
<p>In the method I then create a new basket and makes some assertions to verify the outcome I expect of the test.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> System.Collections.Generic;
<span class="hljs-keyword">using</span> Xunit;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Blog.Commerce.Tests</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">BasketTests</span>
    {
        [<span class="hljs-meta">Fact</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Ctor_ItemsIsEmpty</span>(<span class="hljs-params"></span>)</span>
        {
            <span class="hljs-keyword">var</span> basket = <span class="hljs-keyword">new</span> Basket();

            Assert.NotNull(basket.Items);
            Assert.Empty(basket.Items);
        }
    }
}
</code></pre>
<p>Above you see the finished code for our first test. We simply create a new basket and then assert that the items is neither null nor empty. When the test is run those assertions will throw an exception and make the test fail if they are not correct.</p>
<blockquote>
<p>How to name, organizing and structe your tests will be expanded on in Part 2 of this series.</p>
</blockquote>
<p>Below is how my solution looks at this point.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484602107/_7tP5lQLA.png" alt /></p>
<h1 id="heading-running-your-tests">Running your tests</h1>
<p>In Visual Studio you can run your tests by going to the <strong>Test</strong> menu and selecting <strong>Run All Tests</strong> which will then open the Test Explorer window and run your tests.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484603429/p3PAkPsLW.png" alt /><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484605369/yk8ivoKIz.png" alt />
Or you can run your tests with  <code>dotnet test</code> in your solution directory (or by specifying a <code>.sln</code> or <code>.csproj</code> file directly) which should give you this output:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484607455/aRcdC7ZX5.png" alt />
If for example we didn't initialize the list of items to an empty list, then the test would fail and it would look something like this:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484609505/xG3NGo4WtI.png" alt /></p>
<h1 id="heading-running-the-same-test-with-different-input">Running the same test with different input</h1>
<p>Another common case is to reuse the same test with different input, saving you time and lines of code.</p>
<p>To do that we add some parameters to the test method and instead of the <code>[Fact]</code> attribute we use a <code>[Theory]</code> attribute.</p>
<p>The simplest way to supply input data is by using multiple <code>[InlineData]</code> attributes for each set of input parameters you want to run the test with. There are a lot of other ways to supply data to a test like the <code>[ClassData]</code> and <code>[MemberData]</code> attribute - you can even create your own custom implementation.</p>
<p>So let's add an example of a test for (part of) our 3. case mentioned earlier - adding an item that already exists should add to the quantity of the existing item.</p>
<pre><code class="lang-csharp">[<span class="hljs-meta">Theory</span>]
[<span class="hljs-meta">InlineData(1, 1, 2)</span>]
[<span class="hljs-meta">InlineData(1, 3, 4)</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">AddItem_ExistingItem_ShouldIncreaseQuantityOfExistingItem</span>(<span class="hljs-params">
    <span class="hljs-keyword">int</span> originalQuantity, <span class="hljs-keyword">int</span> addQuantity, <span class="hljs-keyword">int</span> expectedQuantity</span>)</span>
{
    <span class="hljs-comment">// Arrange</span>
    <span class="hljs-keyword">var</span> itemNo = <span class="hljs-string">"qwerty"</span>;

    <span class="hljs-keyword">var</span> basket = <span class="hljs-keyword">new</span> Basket
    {
        Items = <span class="hljs-keyword">new</span> List&lt;BasketItem&gt;
        {
            <span class="hljs-keyword">new</span> BasketItem
            {
                ItemNo = itemNo,
                Quantity = originalQuantity
            }
        }
    };

    <span class="hljs-comment">// Act</span>
    basket.AddItem(itemNo, addQuantity);

    <span class="hljs-comment">// Assert</span>
    Assert.Equal(expectedQuantity, basket.Items[<span class="hljs-number">0</span>].Quantity);
}
</code></pre>
<p>Here we have 3 input parameters: <code>originalQuantity</code>, <code>addQuantity</code> and <code>expectedQuantity</code>. We have added the <code>[InlineData]</code> twice, each with a value for every method parameter. The test will now be executed twice and with the specified inputs respectively.</p>
<p>Adding a few mere tests to cover my expectations mentioned earlier and I end up with the following final test class for now.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> System.Collections.Generic;
<span class="hljs-keyword">using</span> Xunit;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Blog.Commerce.Tests</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">BasketTests</span>
    {
        [<span class="hljs-meta">Fact</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Ctor_ItemsIsEmpty</span>(<span class="hljs-params"></span>)</span>
        {
            <span class="hljs-keyword">var</span> basket = <span class="hljs-keyword">new</span> Basket();

            Assert.NotNull(basket.Items);
            Assert.Empty(basket.Items);
        }

        [<span class="hljs-meta">Fact</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">AddItem_NewItem_AddsNewItem</span>(<span class="hljs-params"></span>)</span>
        {
            <span class="hljs-comment">// Arrange</span>
            <span class="hljs-keyword">var</span> basket = <span class="hljs-keyword">new</span> Basket();
            Assert.Equal(<span class="hljs-number">0</span>, basket.Items.Count);

            <span class="hljs-comment">// Act</span>
            basket.AddItem(<span class="hljs-string">"qwerty"</span>, <span class="hljs-number">1</span>);

            <span class="hljs-comment">// Assert</span>
            Assert.Equal(<span class="hljs-number">1</span>, basket.Items.Count);
        }

        [<span class="hljs-meta">Fact</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">AddItem_ExistingItem_DoesNotAddNewItem</span>(<span class="hljs-params"></span>)</span>
        {
            <span class="hljs-comment">// Arrange</span>
            <span class="hljs-keyword">var</span> itemNo = <span class="hljs-string">"qwerty"</span>;
            <span class="hljs-keyword">var</span> basket = <span class="hljs-keyword">new</span> Basket
            {
                Items = <span class="hljs-keyword">new</span> List&lt;BasketItem&gt;
                {
                    <span class="hljs-keyword">new</span> BasketItem
                    {
                        ItemNo = itemNo,
                        Quantity = <span class="hljs-number">1</span>
                    }
                }
            };
            Assert.Equal(<span class="hljs-number">1</span>, basket.Items.Count);

            <span class="hljs-comment">// Act</span>
            basket.AddItem(itemNo, <span class="hljs-number">1</span>);

            <span class="hljs-comment">// Assert</span>
            Assert.Equal(<span class="hljs-number">1</span>, basket.Items.Count);
        }

        [<span class="hljs-meta">Theory</span>]
        [<span class="hljs-meta">InlineData(1, 1, 2)</span>]
        [<span class="hljs-meta">InlineData(1, 3, 4)</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">AddItem_ExistingItem_ShouldIncreaseQuantityOfExistingItem</span>(<span class="hljs-params">
            <span class="hljs-keyword">int</span> originalQuantity, <span class="hljs-keyword">int</span> addQuantity, <span class="hljs-keyword">int</span> expectedQuantity</span>)</span>
        {
            <span class="hljs-comment">// Arrange</span>
            <span class="hljs-keyword">var</span> itemNo = <span class="hljs-string">"qwerty"</span>;

            <span class="hljs-keyword">var</span> basket = <span class="hljs-keyword">new</span> Basket
            {
                Items = <span class="hljs-keyword">new</span> List&lt;BasketItem&gt;
                {
                    <span class="hljs-keyword">new</span> BasketItem
                    {
                        ItemNo = itemNo,
                        Quantity = originalQuantity
                    }
                }
            };

            <span class="hljs-comment">// Act</span>
            basket.AddItem(itemNo, addQuantity);

            <span class="hljs-comment">// Assert</span>
            Assert.Equal(expectedQuantity, basket.Items[<span class="hljs-number">0</span>].Quantity);
        }
    }
}
</code></pre>
<h1 id="heading-coming-up-in-part-2">Coming up in Part 2</h1>
<p>In the next part I'll go a bit more in-depth with how I prefer to name and structure my tests, what to test and how to write more readable assertions with more descriptive error messages in case things blow up ;)</p>
<ul>
<li><strong>Part 1: Getting started</strong></li>
<li><a target="_blank" href="https://blog.krusen.dk/unit-testing-part-2-naming-structure-readability">Part 2: Naming, structure and readability (FluentAssertions)</a></li>
<li>Part 3: Mocking and writing testable code (NSubstitute)</li>
<li>Part 4: Keeping it DRY and maintainable (AutoFixture)</li>
<li>Part 5: Test Driven Development (TDD) with Live Unit Testing (LUT)</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Getting NSwag to work behind reverse proxy]]></title><description><![CDATA[I've been working with Swagger through NSwag a lot recently and also needed to get it to work when hidden behind a reverse proxy - i.e. another service forwarding a request to the service exposing the Swagger UI.
Some of the issues I've had along the...]]></description><link>https://blog.krusen.dk/swagger-nswag-behind-reverse-proxy</link><guid isPermaLink="true">https://blog.krusen.dk/swagger-nswag-behind-reverse-proxy</guid><dc:creator><![CDATA[Søren Kruse]]></dc:creator><pubDate>Fri, 18 Dec 2020 13:37:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484592722/RlaSnHkvU.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I've been working with Swagger through <a target="_blank" href="https://github.com/RicoSuter/NSwag">NSwag</a> a lot recently and also needed to get it to work when hidden behind a reverse proxy - i.e. another service forwarding a request to the service exposing the Swagger UI.</p>
<p>Some of the issues I've had along the way:
</p>
<ul>
<li>Not working at all...</li>
<li><p>"Try it out" not working because:</p>
<ul>
<li>HTTP/HTTPS not being picked up</li>
<li>Document being cached by different host or scheme meaning the opposite would not work</li>
</ul>

<p>It wasn't that straight forward but through a lot of googling and reading GitHub issues I got a working solution put together.</p>
</li>
</ul>
<p>In my specific case I was running ASP.NET Core 3.1 in a linux docker container in Azure, which some of the solution might be colored by.</p>
<p>If I remember correctly the most important parts are the <code>X-Forwarded-Host</code> and  <code>X-Forwarded-PathBase</code> HTTP headers, so it's important that these are forwarded from your proxy to your Swagger service.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Startup</span>
{
    <span class="hljs-comment">// ...</span>

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Configure</span>(<span class="hljs-params">IApplicationBuilder app, IWebHostEnvironment env</span>)</span>
    {
        <span class="hljs-comment">// ...</span>

        app.UseXForwardedHeaders();
        app.UseSwaggerWithReverseProxySupport();
    }
}

<span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">StartupExtensions</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IApplicationBuilder <span class="hljs-title">UseXForwardedHeaders</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> IApplicationBuilder app</span>)</span>
    {
        <span class="hljs-keyword">var</span> options = <span class="hljs-keyword">new</span> ForwardedHeadersOptions
        {
            ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
        };

        <span class="hljs-comment">// Only loopback proxies are allowed by default.</span>
        <span class="hljs-comment">// Clear that restriction because forwarders are being enabled by explicit configuration.</span>
        <span class="hljs-comment">// https://stackoverflow.com/a/56469499/5358985</span>
        options.KnownNetworks.Clear();
        options.KnownProxies.Clear();

        app.UseForwardedHeaders(options);

        app.Use((context, next) =&gt;
        {
            <span class="hljs-keyword">if</span> (context.Request.Headers.TryGetValue(<span class="hljs-string">"X-Forwarded-PathBase"</span>, <span class="hljs-keyword">out</span> <span class="hljs-keyword">var</span> pathBases))
            {
                context.Request.PathBase = pathBases.First();
            }
            <span class="hljs-keyword">return</span> next();
        });

        <span class="hljs-keyword">return</span> app;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IApplicationBuilder <span class="hljs-title">UseSwaggerWithReverseProxySupport</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> IApplicationBuilder app</span>)</span>
    {
        app.UseOpenApi(config =&gt;
        {
            <span class="hljs-comment">// Without this the document will be cached with wrong URLs </span>
            <span class="hljs-comment">// and not work if later accessed from another host/path/scheme</span>
            config.CreateDocumentCacheKey = request =&gt; request.Headers[<span class="hljs-string">"X-Forwarded-Host"</span>].FirstOrDefault() +
                                                        request.Headers[<span class="hljs-string">"X-Forwarded-PathBase"</span>].FirstOrDefault() +
                                                        request.IsHttps;

            <span class="hljs-comment">// Change document host and base path from headers (if set)</span>
            config.PostProcess = (document, request) =&gt;
            {
                document.BasePath = request.Headers[<span class="hljs-string">"X-Forwarded-PathBase"</span>].FirstOrDefault();
                document.Host = request.Headers[<span class="hljs-string">"X-Forwarded-Host"</span>].FirstOrDefault();
            };
        });

        app.UseSwaggerUi3(settings =&gt;
        {
            settings.TransformToExternalPath = (route, request) =&gt;
            {
                <span class="hljs-keyword">var</span> pathBase = request.Headers[<span class="hljs-string">"X-Forwarded-PathBase"</span>].FirstOrDefault();
                <span class="hljs-keyword">return</span> !<span class="hljs-keyword">string</span>.IsNullOrEmpty(pathBase)
                    ? <span class="hljs-string">$"<span class="hljs-subst">{pathBase}</span><span class="hljs-subst">{route}</span>"</span>
                    : route;
            };
        });

        <span class="hljs-keyword">return</span> app;
    }
}
</code></pre>
]]></content:encoded></item><item><title><![CDATA[NSubstitute - make async method (Task) throw an exception]]></title><description><![CDATA[The other day I was writing a unit test to verify what was supposed to happen when a Task would throw an exception when awaited. It wasn't as straight forward as I first assumed, but I quickly found this Stack Overflow post that helped me:
https://st...]]></description><link>https://blog.krusen.dk/nsubstitute-make-async-method-throw</link><guid isPermaLink="true">https://blog.krusen.dk/nsubstitute-make-async-method-throw</guid><dc:creator><![CDATA[Søren Kruse]]></dc:creator><pubDate>Sat, 12 Dec 2020 19:11:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484586326/Pl3ONiYpv.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The other day I was writing a unit test to verify what was supposed to happen when a <code>Task</code> would throw an exception when awaited. It wasn't as straight forward as I first assumed, but I quickly found this Stack Overflow post that helped me:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://stackoverflow.com/questions/38338906/nsubstitute-mock-throwing-an-exception-in-method-returning-task">https://stackoverflow.com/questions/38338906/nsubstitute-mock-throwing-an-exception-in-method-returning-task</a></div>
<p>Normally, for synchronous calls, you can just add a <code>.Throws&lt;TException&gt;()</code> after the method you want to mock throwing an exception (or <code>.ThrowsForAnyArgs&lt;TException&gt;()</code> if you don't care about the input arguments). If you do this on a method returning a <code>Task</code> then that call would instantly throw, which is - most often - not what happens; it's the work being done by the <code>Task</code> throwing an exception, not the action of creating the <code>Task</code>.</p>
<p>As you can read in the Stack Overflow post the way to simulate a <code>Task</code> throwing an exception is to have the method return an already faulted <code>Task</code>, which can be done (sort of easily) with the static method <code>Task.FromException&lt;TReturn&gt;(Exception)</code>.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">interface</span> <span class="hljs-title">IService</span>
{
    <span class="hljs-function">Task&lt;MyModel&gt; <span class="hljs-title">GetAsync</span>(<span class="hljs-params"></span>)</span>;
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> service = Substitute.For&lt;IService&gt;();
service.GetAsync().Returns(Task.FromException&lt;MyModel&gt;(<span class="hljs-keyword">new</span> ArgumentException(<span class="hljs-string">"bla bla"</span>));
</code></pre>
<p>But that's a bit too verbose for my taste, compared to this synchronous version:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> service = Substitute.For&lt;IService&gt;();
service.Get().Throws&lt;ArgumentException&gt;();
</code></pre>
<p>So I ended up creating a few extension methods enabling a more simple and readable syntax, so I could instead write it like this:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> service = Substitute.For&lt;IService&gt;();

<span class="hljs-comment">// Any Exception</span>
service.GetAsync().TaskThrowsException(<span class="hljs-string">"optional message"</span>);

<span class="hljs-comment">// Specific Exception v1</span>
service.GetAsync().TaskThrows&lt;MyModel, ArgumentException&gt;(<span class="hljs-string">"optional message"</span>);
<span class="hljs-comment">// Specific Exception v2</span>
service.GetAsync().TaskThrows(<span class="hljs-keyword">typeof</span>(ArgumentException), <span class="hljs-string">"optional message"</span>);

<span class="hljs-comment">// Specific Exception instance</span>
service.GetAsync().TaskThrows(<span class="hljs-keyword">new</span> ArgumentException());
</code></pre>
<p>That's a lot cleaner and more readable in my eyes :)</p>
<p>The <code>TaskThrows&lt;MyModel, ArgumentException&gt;()</code> might seem a little weird, but for the generic <code>Task&lt;T&gt;</code> we sadly can't have the generic arguments inferred as we can for the others :(</p>
<p>Here are all the extension methods for both <code>Task</code> and <code>Task&lt;T&gt;</code>:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">NSubstituteExtensions</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ConfiguredCall <span class="hljs-title">TaskThrowsException</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> Task&lt;T&gt; task, <span class="hljs-keyword">string</span> message = <span class="hljs-literal">null</span></span>)</span>
    {
        <span class="hljs-keyword">return</span> TaskThrows&lt;T, Exception&gt;(task, message);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ConfiguredCall <span class="hljs-title">TaskThrows</span>&lt;<span class="hljs-title">T</span>, <span class="hljs-title">TException</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> Task&lt;T&gt; task, <span class="hljs-keyword">string</span> message = <span class="hljs-literal">null</span></span>)
        <span class="hljs-keyword">where</span> TException : Exception</span>
    {
        <span class="hljs-keyword">return</span> TaskThrows(task, <span class="hljs-keyword">typeof</span>(TException));
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ConfiguredCall <span class="hljs-title">TaskThrows</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> Task&lt;T&gt; task, Type exceptionType, <span class="hljs-keyword">string</span> message = <span class="hljs-literal">null</span></span>)</span>
    {
        <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">typeof</span>(Exception).IsAssignableFrom(exceptionType))
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentException(<span class="hljs-string">$"Type has to be a subclass of System.Exception"</span>, <span class="hljs-keyword">nameof</span>(exceptionType));

        <span class="hljs-keyword">var</span> exception = Activator.CreateInstance(exceptionType, message) <span class="hljs-keyword">as</span> Exception;
        <span class="hljs-keyword">return</span> TaskThrows(task, exception);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ConfiguredCall <span class="hljs-title">TaskThrows</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> Task&lt;T&gt; task, Exception exception</span>)</span>
    {
        <span class="hljs-keyword">return</span> task.Returns(Task.FromException&lt;T&gt;(exception));
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ConfiguredCall <span class="hljs-title">TaskThrows</span>&lt;<span class="hljs-title">TException</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> Task task, <span class="hljs-keyword">string</span> message = <span class="hljs-literal">null</span></span>)
        <span class="hljs-keyword">where</span> TException : Exception</span>
    {
        <span class="hljs-keyword">return</span> TaskThrows(task, <span class="hljs-keyword">typeof</span>(TException));
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ConfiguredCall <span class="hljs-title">TaskThrows</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> Task task, Type exceptionType, <span class="hljs-keyword">string</span> message = <span class="hljs-literal">null</span></span>)</span>
    {
        <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">typeof</span>(Exception).IsAssignableFrom(exceptionType))
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentException(<span class="hljs-string">$"Type has to be a subclass of System.Exception"</span>, <span class="hljs-keyword">nameof</span>(exceptionType));

        <span class="hljs-keyword">var</span> exception = Activator.CreateInstance(exceptionType, message) <span class="hljs-keyword">as</span> Exception;
        <span class="hljs-keyword">return</span> TaskThrows(task, exception);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ConfiguredCall <span class="hljs-title">TaskThrows</span>(<span class="hljs-params"><span class="hljs-keyword">this</span> Task task, Exception exception</span>)</span>
    {
        <span class="hljs-keyword">return</span> task.Returns(Task.FromException(exception));
    }
}
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Handling EPiServer UI descriptors for built-in types like PageData]]></title><description><![CDATA[When you want to make content types appear or behave differently in EPiServer - for example changing the default view or disable sticky view - you would create a UI Descriptor for that specific content type. If you want to change the default for all ...]]></description><link>https://blog.krusen.dk/uidescriptor-for-existing-type-e-g-pagedata</link><guid isPermaLink="true">https://blog.krusen.dk/uidescriptor-for-existing-type-e-g-pagedata</guid><dc:creator><![CDATA[Søren Kruse]]></dc:creator><pubDate>Sun, 15 Mar 2020 12:29:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484579983/8YwbMCrU9.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When you want to make content types appear or behave differently in EPiServer - for example changing the default view or disable sticky view - you would create a UI Descriptor for that specific content type. If you want to change the default for all content types without having to remember to add an interface or base class then you could create a UI Descriptor for <code>PageData</code>.</p>
<p>However, you might experience weird behavior where it only works sometimes. This post is about explaining why and how to work around it.</p>
<h2 id="heading-the-issue">The issue</h2>
<p>Let us start with an example of changing the publish view (the view used after publishing a page) by using an interface <code>IAllPropertiesPublishView</code>.</p>
<pre><code class="lang-csharp"><span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
<span class="hljs-comment"><span class="hljs-doctag">///</span> Interface for changing PublishView to AllPropertiesView.</span>
<span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IAllPropertiesPublishView</span> { }

[<span class="hljs-meta">UIDescriptorRegistration</span>]
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">AllPropertiesPublishViewDescriptor</span> : <span class="hljs-title">UIDescriptor</span>&lt;<span class="hljs-title">IAllPropertiesPublishView</span>&gt;
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">AllPropertiesPublishViewDescriptor</span>(<span class="hljs-params"></span>)</span>
    {
        PublishView = CmsViewNames.AllPropertiesView;
    }
}
</code></pre>
<p>We can add this interface to all the page types where we want to change the publish view to the <strong>All Properties</strong> view.</p>
<p>Now, if we want this to apply to all page types extending <code>PageData</code> instead of having to remember to add the interface, then we can change this to inherit <code>UIDescriptor&lt;PageData&gt;</code> instead. That should work, right? It will. Sometimes. It depends on the order of initialization/assembly scanning.</p>
<blockquote>
<p>If you enable <code>debug</code> logging you should see a message in the log like <code>Discarding ui descriptor registration for type {0} provided by {1} since a desciptor for the type is already registered.</code></p>
</blockquote>
<p>EPiServer already has an internal UI Descriptor, <code>PageUIDescriptor</code>, which has some default configuration for <code>PageData</code>:</p>
<pre><code class="lang-csharp">[<span class="hljs-meta">UIDescriptorRegistration</span>]
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">PageUIDescriptor</span> : <span class="hljs-title">UIDescriptor</span>&lt;<span class="hljs-title">PageData</span>&gt;, <span class="hljs-title">IEditorDropBehavior</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">PageUIDescriptor</span>(<span class="hljs-params"></span>)
      : <span class="hljs-title">base</span>(<span class="hljs-params"><span class="hljs-string">"epi-iconObjectPage"</span></span>)</span>
    {
        IsPrimaryType = <span class="hljs-literal">true</span>;
        CommandIconClass = <span class="hljs-string">"epi-iconPage"</span>;
        AllowSelectItSelf = <span class="hljs-literal">true</span>;
        ContainerTypes = <span class="hljs-keyword">new</span> [] { <span class="hljs-keyword">typeof</span> (PageData) };
        EditorDropBehaviour = EditorDropBehavior.CreateLink;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">bool</span> AllowSelectItSelf { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">private</span> <span class="hljs-keyword">set</span>; }

    <span class="hljs-keyword">public</span> EditorDropBehavior EditorDropBehaviour { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
}
</code></pre>
<p>When the site starts it is uncertain if the default UI Descriptor or our custom one will be loaded first. Only the first one will be registered and initialized; others for the same specific type will be skipped and a debug message will be written to the logs.</p>
<h2 id="heading-a-solution">A solution</h2>
<p>One way around this issue is to create an initialization module and modify the already registered and initialized UI Descriptors.</p>
<pre><code class="lang-csharp">[<span class="hljs-meta">InitializableModule</span>]
[<span class="hljs-meta">ModuleDependency(typeof(DataInitialization))</span>]
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">PageDataDefaultViewsInitialization</span> : <span class="hljs-title">IInitializableModule</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Initialize</span>(<span class="hljs-params">InitializationEngine context</span>)</span>
    {
        <span class="hljs-comment">// Get the UIDescriptorRegistry instance</span>
        <span class="hljs-keyword">var</span> registry = context.Locate.Advanced.GetInstance&lt;UIDescriptorRegistry&gt;();

        <span class="hljs-comment">// Get the UIDescriptor for PageData</span>
        <span class="hljs-keyword">var</span> descriptor = registry.UIDescriptors
            .FirstOrDefault(x =&gt; x.ForType == <span class="hljs-keyword">typeof</span>(PageData));

        <span class="hljs-comment">// Abort if it didn't exist</span>
        <span class="hljs-keyword">if</span> (descriptor == <span class="hljs-literal">null</span>)
            <span class="hljs-keyword">return</span>;

        <span class="hljs-comment">// Modify the descriptor as you please</span>
        descriptor.DefaultView = CmsViewNames.AllPropertiesView;
        descriptor.PublishView = CmsViewNames.AllPropertiesView;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Uninitialize</span>(<span class="hljs-params">InitializationEngine context</span>)</span>
    {

    }
}
</code></pre>
<p>The code is rather simple. We are just getting the <code>UIDescriptorRegistry</code> instance and then getting the first UIDescriptor for <code>PageData</code> (if there is any). If it exists we then modify it however we please, as we would have done in our custom <code>UIDescriptor</code>.</p>
<blockquote>
<p>Accessing the <code>UIDescriptorRegistry.UIDescriptors</code> property is what triggers the loading/initialization of all the UI Descriptors.</p>
</blockquote>
<p>This approach can also be used if you need some more generic logic for customizing UI Descriptors, e.g. depending on type name or for 3rd party types that you don't control.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>There can only be one UI Descriptor per specific type/interface. If there are multiple descriptors only one will be registered and initialized; the others will be skipped. It looks like it depends on a race condition in the type scanning which descriptor will be loaded first, so it can change between site restarts.</p>
<p>One solution is to instead modify the registered UI Descriptors by finding the ones you care about from the <code>UIDescriptorRegistry</code>.</p>
<h4 id="heading-bonus-info">Bonus info</h4>
<p>The priority of UI Descriptors, i.e. which UI Descriptor is chosen for a specific type, is controlled by the (private) <code>UIDescriptorRegistry.TypeComparer</code>:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">int</span> <span class="hljs-title">Compare</span>(<span class="hljs-params">UIDescriptor x, UIDescriptor y</span>)</span>
{
    <span class="hljs-keyword">if</span> (x == y)
        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
    Type forType1 = x.ForType;
    Type forType2 = y.ForType;
    <span class="hljs-keyword">return</span> forType1.IsInterface &amp;&amp; !forType2.IsInterface || forType1.IsAssignableFrom(forType2) ? <span class="hljs-number">1</span> : <span class="hljs-number">-1</span>;
}
</code></pre>
<p>In short, the more specific your UI Descriptor is, the higher priority.</p>
<p>Let's say we the following classes and interfaces:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CustomPage</span> : <span class="hljs-title">BasePage</span>, <span class="hljs-title">ISomeInterface</span>
{
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">ISomeInterface</span> : <span class="hljs-title">IBase</span> { }
</code></pre>
<p>UI Descriptors for all those would be prioritized in this order:</p>
<ol>
<li><code>UIDescriptor&lt;CustomPage&gt;</code></li>
<li><code>UIDescriptor&lt;BasePage&gt;</code></li>
<li><code>UIDescriptor&lt;ISomeInterface&gt;</code></li>
<li><code>UIDescriptor&lt;IBase&gt;</code></li>
</ol>
<p>So, concrete types are above interfaces. Interfaces inheriting another interface before the inherited interface etc.</p>
]]></content:encoded></item><item><title><![CDATA[Sitecore 9 rule-based configuration and numbered roles]]></title><description><![CDATA[The other day I was digging around and stumbled upon an undocumented feature for the (somewhat) new rule-based configuration released with Sitecore 9.
You can append -{number} to the role definition (in <appSettings> in Web.config) and it will work a...]]></description><link>https://blog.krusen.dk/sitecore-config-numbered-roles</link><guid isPermaLink="true">https://blog.krusen.dk/sitecore-config-numbered-roles</guid><dc:creator><![CDATA[Søren Kruse]]></dc:creator><pubDate>Fri, 31 Aug 2018 05:14:25 GMT</pubDate><content:encoded><![CDATA[
<p>The other day I was digging around and stumbled upon an undocumented feature for the (somewhat) new <a target="_blank" href="https://doc.sitecore.net/sitecore_experience_platform/developing/developing_with_sitecore/customizing_server_configuration/rulebased_configuration">rule-based configuration</a> released with Sitecore 9.</p>
<p>You can append <code>-{number}</code> to the role definition (in <code>&lt;appSettings&gt;</code> in <code>Web.config</code>) and it will work as both the full role name and without the <code>-{number}</code> part, e.g. <code>ContentManagement-1</code> works as both <code>ContentManagement</code> and <code>ContentManagement-1</code>.</p>
<p>Web.config:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">cofiguration</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">appSettings</span>&gt;</span>
        <span class="hljs-comment">&lt;!-- The standard way --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">setting</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"role:define"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"ContentManagement"</span> /&gt;</span>

        <span class="hljs-comment">&lt;!-- Numbered version --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">setting</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"role:define"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"ContentManagement-1"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">appSettings</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">configuration</span>&gt;</span>
</code></pre>
<p>Any Sitecore config patch file:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">configuration</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">sitecore</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">settings</span>&gt;</span>
           <span class="hljs-comment">&lt;!-- Both approaches below will work with 'ContentManagement-1' role --&gt;</span>
           <span class="hljs-tag">&lt;<span class="hljs-name">setting</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"my.setting"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"1234"</span> <span class="hljs-attr">role:require</span>=<span class="hljs-string">"Content-Management"</span> /&gt;</span>
           <span class="hljs-tag">&lt;<span class="hljs-name">setting</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"my.setting"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"1234"</span> <span class="hljs-attr">role:require</span>=<span class="hljs-string">"Content-Management-1"</span> /&gt;</span>
       <span class="hljs-tag">&lt;/<span class="hljs-name">settings</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">sitecore</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">configuration</span>&gt;</span>
</code></pre>
<p>It's nothing too special and nothing you couldn't do before, but it's a bit simpler to configure if you have multiple servers with the same role, where one specific server needs specific settings - e.g. if only the primary CM server should have some feature enabled.
 </p>
]]></content:encoded></item><item><title><![CDATA[Sitecore release notes made searchable!]]></title><description><![CDATA[If you're like me you've probably (more than once) had to read/search through several pages of release notes to find out if the issue you are currently having (or a bug you have reported earlier) has been fixed in any of the latest Sitecore releases....]]></description><link>https://blog.krusen.dk/sitecore-release-notes-made-searchable</link><guid isPermaLink="true">https://blog.krusen.dk/sitecore-release-notes-made-searchable</guid><dc:creator><![CDATA[Søren Kruse]]></dc:creator><pubDate>Wed, 24 Jan 2018 13:05:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484568186/FJRVMsaEO.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[
<p>If you're like me you've probably (more than once) had to read/search through several pages of release notes to find out if the issue you are currently having (or a bug you have reported earlier) has been fixed in any of the latest Sitecore releases.</p>
<p>Well, at some point I got tired of that and also wanted to expand my Azure-knowledge and wanted to try out Azure Search for something - so I ended up making https://sitecorereleasenotes.com, go check it out.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484564674/mldNjd4yq.png" alt="chrome_2018-01-23_18-43-03" /></p>
<h2 id="heading-what-is-it">What is it?</h2>
<p>It's a site that allows you to search for words or issue numbers mentioned in the Sitecore XP release notes located on <a target="_blank" href="https://dev.sitecore.net/Downloads/Sitecore_Experience_Platform.aspx">https://dev.sitecore.net/Downloads/Sitecore_Experience_Platform.aspx</a>. That means all release notes from 8.0 and onward.</p>
<p>It will return a list of the 5 most relevant releases for your search query, showing what it matched and with a link to both the release notes and the download page.</p>
<p>It doesn't allow complicated/specialized queries but it works very well for issue numbers and most simple queries.</p>
<h2 id="heading-how-does-it-work">How does it work?</h2>
<p>It is rather simple, actually. It is just an Azure Function that crawls the downloads page daily and indexes all the release notes into Azure Search. The site itself is more or less just a simple interface to query the index and display the results nicely, running as an Azure Web App.</p>
<p>Most of the Azure services (Functions, Search, Web App/App Service) can use the free tier (or a very cheap one). It's also possible to use the free tier for the Web App, but I've gone with the B1 (Basic) for the SSL support, custom domain and the "Always On" options.</p>
<p>The crawling is scheduled to run daily, but it only takes ~15 seconds so it could be run more often - but Sitecore doesn't put out new releases THAT often and I can live with up to a one day delay.</p>
<h2 id="heading-how-can-i-get-involved">How can I get involved?</h2>
<p>The code is available on <a target="_blank" href="https://github.com/Krusen/SitecoreReleaseNotes">Github</a>. You are more than welcome to create an issue if you have any feature requests, or even better submit a pull request!</p>
<p>The code is not that pretty as it just barely got past the prototype stage, to a stage where I was comfortable showing it off to the public.</p>
<h2 id="heading-do-you-plan-on-improving-it">Do you plan on improving it?</h2>
<p>Maybe, it depends. I don't have any plans right now as it currently fills most of my own needs. I have plenty of ideas but there is only so much time in a day and it is competing with other more interesting stuff.</p>
<p>If it gains a lot of traction and interest I might get back into it at some point, but otherwise I hope it's useful for some people as it is now.
 </p>
]]></content:encoded></item><item><title><![CDATA[Sitecore 9 with Solr and SQL Server running in Docker]]></title><description><![CDATA[With Solr now being the default and recommended search provider in Sitecore 9 for all setups except XM1 (and required for xConnect) I wanted to look at how to run Solr with Docker.
My requirements/reasons for wanting to run Solr in a Docker container...]]></description><link>https://blog.krusen.dk/sitecore-9-with-solr-and-sql-in-docker</link><guid isPermaLink="true">https://blog.krusen.dk/sitecore-9-with-solr-and-sql-in-docker</guid><dc:creator><![CDATA[Søren Kruse]]></dc:creator><pubDate>Fri, 08 Dec 2017 09:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484472590/5CkI-pKfn2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[
<p>With Solr now being the default and recommended search provider in <strong>Sitecore 9</strong> for all setups except <strong>XM1</strong> (and required for <strong>xConnect</strong>) I wanted to look at how to run Solr with <strong>Docker</strong>.</p>
<p>My requirements/reasons for wanting to run Solr in a Docker container:</p>
<ul>
<li>Not having to install Java (nobody wants that these days)</li>
<li>Easy install of Solr "as a service" (I can't be the only one thinking it's a bit of a hassle to setup on windows, right?)</li>
<li>Run Solr only when needed</li>
<li>Run different versions of Solr (or quickly switch between versions)</li>
</ul>
<p>During my research and experiments I got to thinking about SQL Server as well. It is not too long ago that it started being supported on Linux and I found out that Microsoft have made some <a target="_blank" href="https://hub.docker.com/r/microsoft/mssql-server-linux/">SQL Server 2017 docker images</a> - so why not try and get Sitecore running with that as well?</p>
<h1 id="heading-overview">Overview</h1>
<p>I will go through the steps for configuring the different containers and getting <strong>Sitecore 9 XP0</strong> installed using the <strong>Sitecore Installation Framework (SIF)</strong> with both <strong>SQL Server 2017</strong> and <strong>Solr 6.6.2</strong> running in containers in <strong>Docker</strong>.</p>
<p>Prepare yourself, this is a long one...</p>
<ul>
<li>Why I chose Linux containers</li>
<li>Prerequisites</li>
<li><ol>
<li>Setting up the containers<ul>
<li>1.1 Building a custom image for the nginx HTTPS proxy</li>
</ul>
</li>
</ol>
</li>
<li><ol>
<li>Running the containers and importing the created certificate</li>
</ol>
</li>
<li><ol>
<li>Modify SIF config files</li>
</ol>
</li>
<li><ol>
<li>Create and run install script with SIF-less</li>
</ol>
</li>
<li><ol>
<li>Continue with the post-installation steps in Sitecore installation guide</li>
</ol>
</li>
<li>Closing notes</li>
<li>Troubleshooting</li>
<li>Additional resources</li>
</ul>
<p>I've made the files needed for the Docker setup available <a target="_blank" href="https://github.com/Krusen/docker-sqlserver-solr-secure">on GitHub</a>.</p>
<h1 id="heading-why-i-chose-linux-containers">Why I chose Linux containers</h1>
<p>Docker (on Windows 10) can run either <strong>Linux containers</strong> or <strong>Windows containers</strong> - but <strong>not both at the same time</strong>. I could have gone with Windows containers, which would have enabled me to also run IIS and potentially the xConnect service in containers as well, but I decided against that for several reasons.</p>
<p>There are more Linux images available and they just have a bigger community compared to Windows images as they have only been reasonably supported by Docker somewhat recently. I also think it's easier to create custom images in Linux using <code>apt-get</code> or <code>apk add</code> (and I know almost nothing about Linux) compared to windows where you usually download a file from a specific URL, unzip etc. all using the command line. Windows is just better suited for a GUI and it's just all a bit cumbersome.</p>
<p>Also, the Sitecore Installation Framework (SIF) tinkers with your local machine with regards to IIS websites, application pools and so on, so I would have had to customize that as well if I wanted to use SIF for the installation.</p>
<h1 id="heading-prerequisites">Prerequisites</h1>
<ul>
<li>Download and install <strong>Sitecore Installation Framework</strong> and <strong>Sitecore Fundamentals</strong> (they are listed on the <a target="_blank" href="https://dev.sitecore.net/Downloads/Sitecore_Experience_Platform/90/Sitecore_Experience_Platform_90_Initial_Release.aspx">Sitecore 9 download page</a>)</li>
<li>Download the <a target="_blank" href="https://dev.sitecore.net/Downloads/Sitecore_Experience_Platform/90/Sitecore_Experience_Platform_90_Initial_Release.aspx">Sitecore 9.0 XP Single (XP0) package</a> or which ever package is relevant for you.</li>
<li>Download and install <a target="_blank" href="https://www.docker.com/docker-windows">Docker</a></li>
</ul>
<p>You will need to configure Docker to have <strong>at least 3.25 GB memory available</strong> (required for SQL Server). Right click the tray icon and go to <strong>Settings</strong>. Go to the <strong>Advanced</strong> tab and adjust the slider for the available memory.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484464478/GT14roGn0.png" alt="docker-advanced-settings" /></p>
<h1 id="heading-1-setting-up-the-containers">1. Setting up the containers</h1>
<p>For my current setup we need 3 services running in Docker:</p>
<ul>
<li>Solr</li>
<li>SQL Server</li>
<li>nginx (proxying HTTPS for Solr)</li>
</ul>
<blockquote>
<p>Instead of the nginx proxy you could also create a custom image where you configure SSL for Solr, but I found this solution - using nginx - easier to setup.</p>
</blockquote>
<p>To set all this up we need to create a few files. We start by composing our services for the <code>docker-compose</code> command with a <code>docker-compose.yml</code> file.</p>
<h3 id="heading-docker-composeyml">docker-compose.yml</h3>
<pre><code class="lang-docker">version: '3'
services:

  sql2017:
    image: microsoft/mssql-server-linux:2017-latest
    ports:
      - "1433:1433"
    volumes:
      - ./Sqldata:/var/opt/mssql
    environment:
      ACCEPT_EULA: "Y"
      SA_PASSWORD: Qwerty123

  solr662:
    image: solr:6.6.2
    ports:
      - "8983" # Only exposes the port to other services
    volumes:
      - ./Solrdata:/solrhome
    environment:
      SOLR_HOME: /solrhome
      INIT_SOLR_HOME: "yes"

  proxy:
    build: 
      context: .
      args: 
        SERVER_NAME: solr
    image: nginx-solr-proxy
    ports:
      - "8983:443"
    volumes:
      - ./Certs:/certs
    environment:
      SERVER_NAME: solr
      PROXY_PASS: http://solr662:8983
      PROXY_REDIRECT: http://solr662/solr/ https://solr:8983/solr/
    depends_on:
      - solr662
</code></pre>
<p>What all this does is configure 3 services: <code>sql2017</code>, <code>solr662</code> and <code>proxy</code>. Each services specifies an image (<code>proxy</code> actually builds its own, more on that in a bit), exposes some ports, mounts some folders so we can persist data and configures some relevant environment variables.</p>
<ul>
<li><strong>sql2017</strong><ul>
<li>Use the official <code>microsoft/mssql-server-linux</code> image, tag <code>2017-latest</code></li>
<li>Bind port <code>1433</code> on host machine to port <code>1433</code></li>
<li>Mount the folder <code>./Sqldata</code> to where the databases are stored inside the container</li>
</ul>
</li>
<li><strong>solr662</strong><ul>
<li>Use the official <code>solr</code> image, tag <code>6.6.2</code></li>
<li>Expose port <code>8983</code> only to the other services</li>
<li>Mount the folder <code>./Solrdata</code> to the Solr home folder inside the container</li>
</ul>
</li>
<li><strong>proxy</strong><ul>
<li>Build a new image (uses the <code>Dockerfile</code> file as explained later) with name <code>nginx-solr-proxy</code> and use this image</li>
<li>Bind port <code>8983</code> on host machine to port <code>443</code></li>
<li>Mount the folder <code>./Certs</code>. This folder will contain the SSL certificate used by the proxy. This will need to be installed into your root certificate store to be trusted (Chrome will start complain because it's not correctly singed by a CA, but SIF will work).</li>
</ul>
</li>
</ul>
<p><strong>NOTE:</strong> This setup requires you to add <code>127.0.0.1 solr</code> to your <strong>hosts</strong> file. If you want to use another hostname just change the value of the <code>SERVER_NAME</code> variable both under <code>build:</code> and <code>environment:</code> and change the hostname of the last part of the <code>PROXY_REDIRECT</code> environment variable to match, e.g. <code>PROXY_REDIRECT: http://solr662/solr/ https://YOUR_CUSTOM_HOSTNAME:8983/solr/</code>.</p>
<p>Later on, when the services are up and running, you will have to install the <code>snakeoil.cer</code> certificate located in the mounted <code>./Certs</code> folder.</p>
<h2 id="heading-11-building-a-custom-image-for-the-nginx-https-proxy">1.1 Building a custom image for the nginx HTTPS proxy</h2>
<p>For the nginx proxy we need to customize the barebone nginx image to include a newly created SSL certificate and configure nginx to our needs. This can be done in many ways and my way probably isn't the best way (it can definitely be improved), but it works pretty in my opinion. In any case it's a good starting point.</p>
<p>To do this we need three files:</p>
<ul>
<li><strong>Dockerfile</strong> - specifies how to build the image</li>
<li><strong>docker-entrypoint.sh</strong> - run each time the image is run</li>
<li><strong>.dockerignore</strong> - ignores files not needed by <strong>Dockerfile</strong></li>
</ul>
<h3 id="heading-dockerfile">Dockerfile</h3>
<pre><code class="lang-docker">FROM nginx:mainline-alpine

ARG SERVER_NAME=solr

ENV SSL_CERTIFICATE=/etc/ssl/certs/snakeoil.cer
ENV SSL_CERTIFICATE_KEY=/etc/ssl/private/snakeoil.key
RUN apk add --no-cache openssl \
    &amp;&amp; openssl ecparam -out ${SSL_CERTIFICATE_KEY} -name prime256v1 -genkey \
    &amp;&amp; openssl req -new -key ${SSL_CERTIFICATE_KEY} -x509 -sha256 -nodes \
        -days 3650 -subj "/CN=${SERVER_NAME}" -out ${SSL_CERTIFICATE}

RUN rm /etc/nginx/conf.d/*.conf

COPY . /

ENTRYPOINT ["/docker-entrypoint.sh"]
</code></pre>
<h3 id="heading-dockerignore">.dockerignore</h3>
<pre><code class="lang-docker">**/*
!docker-entrypoint.sh
</code></pre>
<p>What this does is pull the official <code>nginx</code> image with the tag <code>mainline-alpine</code> (the <strong>alpine</strong> version has a smaller footprint) and uses this as the baseline for our new image.</p>
<p>Then we are creating the certificate and key with the specified <code>SERVER_NAME</code> (as specified in <code>docker-compose.yml</code> or defaulting to <code>solr</code>) as the subject of the certificate.</p>
<p>Then we clear out the default nginx config files, copy everything in the current directory (that is not ignored by <code>.dockerignore</code>, i.e. only the <code>docker-entrypoint.sh</code> is copied).</p>
<p>At last we specify the script to run on startup, <code>docker-entrypoint.sh</code>.</p>
<h3 id="heading-docker-entrypointsh">docker-entrypoint.sh</h3>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/sh</span>

mkdir /certs -p
cp /etc/ssl/certs/snakeoil.cer /certs/
cp /etc/ssl/private/snakeoil.key /certs/

cat &gt; /etc/nginx/conf.d/proxy.conf &lt;&lt; EOT
map \<span class="hljs-variable">$http_upgrade</span> \<span class="hljs-variable">$connection_upgrade</span> {
    default upgrade;
    <span class="hljs-string">''</span>      close;
}

server {
    listen 443 ssl default;

    server_name <span class="hljs-variable">${SERVER_NAME:-_}</span>;
    ssl_certificate /etc/ssl/certs/snakeoil.cer;
    ssl_certificate_key /etc/ssl/private/snakeoil.key;

    location / {
        client_body_buffer_size <span class="hljs-variable">${CLIENT_BODY_BUFFER_SIZE:-128k}</span>;
        client_max_body_size <span class="hljs-variable">${CLIENT_MAX_BODY_SIZE:-16m}</span>;
        proxy_set_header Host <span class="hljs-variable">${PROXY_HOST:-\$host}</span>;
        proxy_set_header X-Forwarded-Proto \<span class="hljs-variable">$scheme</span>;
        proxy_set_header X-Forwarded-Port \<span class="hljs-variable">$server_port</span>;
        proxy_set_header X-Forwarded-For \<span class="hljs-variable">$proxy_add_x_forwarded_for</span>;
        proxy_pass <span class="hljs-variable">${PROXY_PASS:-http://upstream}</span>;
        proxy_redirect <span class="hljs-variable">${PROXY_REDIRECT:-default}</span>;
        proxy_http_version 1.1;
        proxy_set_header Upgrade \<span class="hljs-variable">$http_upgrade</span>;
        proxy_set_header Connection \<span class="hljs-variable">$connection_upgrade</span>;
        proxy_buffering <span class="hljs-variable">${PROXY_BUFFERING:-off}</span>;
        proxy_connect_timeout <span class="hljs-variable">${PROXY_CONNECT_TIMEOUT:-60s}</span>;
        proxy_read_timeout <span class="hljs-variable">${PROXY_READ_TIMEOUT:-180s}</span>;
        proxy_send_timeout <span class="hljs-variable">${PROXY_SEND_TIMEOUT:-60s}</span>;
    }
}

server {
    listen 80 default;

    server_name <span class="hljs-variable">${SERVER_NAME:-_}</span>;
    <span class="hljs-built_in">return</span> 301 https://\<span class="hljs-variable">$server_name</span>\<span class="hljs-variable">$request_uri</span>;
}
EOT

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Starting nginx"</span>
<span class="hljs-built_in">exec</span> nginx -g <span class="hljs-string">'daemon off;'</span>
</code></pre>
<blockquote>
<p><strong>NOTE:</strong> Make sure this file is saved with unix-style line endings <code>LF</code> and not Windows-style <code>CRLF</code></p>
</blockquote>
<p>The entrypoint script just configures nginx and copies the certificate to the <code>certs</code> folder so you can easily access it and import it into your root certificate store.</p>
<h2 id="heading-2-running-the-containers-and-importing-the-created-certificate">2. Running the containers and importing the created certificate</h2>
<p>To build our custom image and run the services we configured in <code>docker-compose.yml</code> simply run the following command in the same folder as your <code>docker-compose.yml</code>, <code>Dockerfile</code> etc.</p>
<pre><code class="lang-docker">docker-compose up -d
</code></pre>
<blockquote>
<p>If you leave out the <code>-d</code> parameter it will attach to the containers and show log output.</p>
</blockquote>
<p>It should result in something like this:</p>
<pre><code class="lang-docker">Building proxy
Step 1/8 : FROM nginx:mainline-alpine
 ---&gt; 5c6da346e3d6
Step 2/8 : ARG SERVER_NAME=solr
 ---&gt; Using cache
 ---&gt; 83967fbb9479
Step 3/8 : ENV SSL_CERTIFICATE /etc/ssl/certs/snakeoil.cer
 ---&gt; Using cache
 ---&gt; 82b6dfcb6d13
Step 4/8 : ENV SSL_CERTIFICATE_KEY /etc/ssl/private/snakeoil.key
 ---&gt; Using cache
 ---&gt; 5e89eeaa6573
Step 5/8 : RUN apk add --no-cache openssl     &amp;&amp; openssl ecparam -out ${SSL_CERTIFICATE_KEY} -name prime256v1 -genkey     &amp;&amp; openssl req -new -key ${SSL_CERTIFICATE_KEY} -x509 -sha256 -nodes         -days 3650 -subj "/CN=${SERVER_NAME}" -out ${SSL_CERTIFICATE}
 ---&gt; Using cache
 ---&gt; b6e33bf3b7e4
Step 6/8 : RUN rm /etc/nginx/conf.d/*.conf
 ---&gt; Using cache
 ---&gt; 8def646dfe62
Step 7/8 : COPY . /
 ---&gt; Using cache
 ---&gt; 2ca0fb012838
Step 8/8 : ENTRYPOINT /docker-entrypoint.sh
 ---&gt; Using cache
 ---&gt; 66b5af8fe6fd
Successfully built 66b5af8fe6fd
Successfully tagged nginx-solr-proxy:latest
Creating docker_solr662_1 ...
Creating docker_sql2017_1 ...
Creating docker_sql2017_1
Creating docker_solr662_1 ... done
Creating docker_proxy_1 ...
Creating docker_sql2017_1 ... done
</code></pre>
<p>The first part of the container name will use the name of the current folder, <code>docker</code> in my case.</p>
<p>You should now see three new folders:</p>
<ul>
<li><code>Sqldata</code></li>
<li><code>Solrdata</code></li>
<li><code>Certs</code></li>
</ul>
<p>Import the certificate <code>snakeoil.cer</code> from the <code>Certs</code> folder into your root  certificates store. Without this the Sitecore Installation Framework (SIF) will not trust the server and be unable to create the Solr cores etc. as part of the installation.</p>
<h1 id="heading-3-modify-sif-config-files">3. Modify SIF config files</h1>
<p>As we don't have a Solr service installed we need to modify the SIF config files. We  have to remove the <code>StopSolr</code> and <code>StartSolr</code> tasks from the following config files:</p>
<ul>
<li><code>xconnect-solr.json</code></li>
<li><code>sitecore-solr.json</code></li>
</ul>
<p>They are logically located in the <code>Tasks</code> section. You can comment them out or delete them completely. Here is an example from the <code>xconnect-solr.json</code> file:</p>
<pre><code class="lang-json"><span class="hljs-comment">// ...</span>

<span class="hljs-string">"Tasks"</span>: {
    <span class="hljs-comment">// Tasks are separate units of work in a configuration.</span>
    <span class="hljs-comment">// Each task is an action that will be completed when Install-SitecoreConfiguration is called.</span>
    <span class="hljs-comment">// By default, tasks are applied in the order they are declared.</span>
    <span class="hljs-comment">// Tasks may reference Parameters, Variables, and config functions. </span>

    <span class="hljs-comment">// "StopSolr": {</span>
    <span class="hljs-comment">//     // Stops the Solr service if it is running.</span>
    <span class="hljs-comment">//     "Type": "ManageService",</span>
    <span class="hljs-comment">//     "Params": {</span>
    <span class="hljs-comment">//         "Name": "[parameter('SolrService')]",</span>
    <span class="hljs-comment">//         "Status": "Stopped",</span>
    <span class="hljs-comment">//         "PostDelay": 1000</span>
    <span class="hljs-comment">//     }</span>
    <span class="hljs-comment">// },</span>

    <span class="hljs-comment">// ...</span>
}

<span class="hljs-comment">// ...</span>
</code></pre>
<p>Because we only mounted the <strong>Solr home folder</strong> instead of the whole <strong>Solr installation directory</strong> we also have to change the <code>Solr.Server</code> variable to be <code>[variable('Solr.FullRoot')]</code> in the files mentioned above. It should look like below.</p>
<pre><code class="lang-json"><span class="hljs-comment">// ...</span>
<span class="hljs-string">"Solr.Server"</span>: <span class="hljs-string">"[variable('Solr.FullRoot')]"</span>,
<span class="hljs-comment">// ...</span>
</code></pre>
<h1 id="heading-4-create-and-run-install-script-with-sif-less">4. Create and run install script with SIF-less</h1>
<p><a target="_blank" href="https://twitter.com/RAhnemann">Rob Ahnemann</a> has created this great tool called SIF-less to make it easier to specify the parameters for a SIF install and also to check that everything is setup correctly beforehand.</p>
<p>Check out his <a target="_blank" href="http://www.rockpapersitecore.com/2017/10/introducing-sif-less-for-easy-sitecore-9-installation/">initial blog post</a> and <a target="_blank" href="http://www.rockpapersitecore.com/2017/11/sif-less-version-0-5-0-more-requirements-checks/">the follow up</a>. SIF-less can be downloaded from his <a target="_blank" href="https://bitbucket.org/RAhnemann/sif-less/overview">Bitbucket repository</a> or from this <a target="_blank" href="https://bitbucket.org/RAhnemann/sif-less/downloads/SIFLess.zip">direct link</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484465928/Ek5t7JjR0.png" alt="sif-less" /></p>
<p>Above are the settings I used. A few notes to be aware of:</p>
<pre><code>- <span class="hljs-keyword">Use</span> <span class="hljs-string">'localhost,1433'</span> <span class="hljs-keyword">as</span> <span class="hljs-keyword">SQL</span> <span class="hljs-keyword">Server</span> (<span class="hljs-keyword">including</span> the ´<span class="hljs-string">'´s) otherwise the PowerShell script will not parse it as two separate values and fail
- Point **Solr Folder** to the mounted `Solrdata` folder
- **Solr Service** can be ignored (might fail if empty, I haven'</span>t tried)
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484467836/CW1vzEa2S.png" alt="sif-less-test" /></p>
<p>All tests except <strong>Solr Config Sets Exists</strong> and <strong>Solr Service Exists</strong> should be green.</p>
<p>Click the <strong>Generate Files</strong> button and run the generated <code>.ps1</code> file (something like <code>SIFless-EZ-1511282466.ps1</code>) to begin the installation.</p>
<p>The installation should hopefully complete without any issues, if not let me know in the comments.</p>
<h1 id="heading-5-continue-with-the-post-installation-steps-in-sitecore-installation-guide">5. Continue with the post-installation steps in Sitecore installation guide</h1>
<p>You should finish off your install by following the post-installation steps in the installation guide, starting in chapter 6.</p>
<p>It's mostly the default stuff of rebuilding Search Indexes and the Link Database, deploying Marketing Definitions etc., but step 6.1 requires you to add a recognized user to the xDB Shard Databases.</p>
<p>They have included a nifty script to help you with that. Just change the <code>DatabasePrefix</code> to match the prefix you used for your installation. You also have to turn on <strong>SQLCMD Mode</strong> from the <strong>Query</strong> menu to be able to successfully run the script.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484469189/UhnlsyHhS.png" alt="sqlcmd-mode" /></p>
<pre><code class="lang-sql">:SETVAR DatabasePrefix sc90 
:SETVAR UserName collectionuser 
:SETVAR Password Test12345 
:SETVAR ShardMapManagerDatabaseNameSuffix _Xdb.Collection.ShardMapManager 
:SETVAR Shard0DatabaseNameSuffix _Xdb.Collection.Shard0 
:SETVAR Shard1DatabaseNameSuffix _Xdb.Collection.Shard1 
GO 

IF(SUSER_ID('$(UserName)') IS NULL)
<span class="hljs-keyword">BEGIN</span>
    <span class="hljs-keyword">CREATE</span> LOGIN [$(UserName)] <span class="hljs-keyword">WITH</span> <span class="hljs-keyword">PASSWORD</span> = <span class="hljs-string">'$(Password)'</span>;
<span class="hljs-keyword">END</span>;
GO 

<span class="hljs-keyword">USE</span> [$(DatabasePrefix)$(ShardMapManagerDatabaseNameSuffix)] 

<span class="hljs-keyword">IF</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">EXISTS</span> (<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> sys.database_principals <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">name</span> = N<span class="hljs-string">'$(UserName)'</span>)
<span class="hljs-keyword">BEGIN</span>
    <span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">USER</span> [$(UserName)] <span class="hljs-keyword">FOR</span> LOGIN [$(UserName)]
        <span class="hljs-keyword">GRANT</span> <span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">ON</span> <span class="hljs-keyword">SCHEMA</span> :: __ShardManagement <span class="hljs-keyword">TO</span> [$(UserName)]
        <span class="hljs-keyword">GRANT</span> <span class="hljs-keyword">EXECUTE</span> <span class="hljs-keyword">ON</span> <span class="hljs-keyword">SCHEMA</span> :: __ShardManagement <span class="hljs-keyword">TO</span> [$(UserName)]
<span class="hljs-keyword">END</span>;
GO 

<span class="hljs-keyword">USE</span> [$(DatabasePrefix)$(Shard0DatabaseNameSuffix)]  

<span class="hljs-keyword">IF</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">EXISTS</span> (<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> sys.database_principals <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">name</span> = N<span class="hljs-string">'$(UserName)'</span>)
<span class="hljs-keyword">BEGIN</span>
    <span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">USER</span> [$(UserName)] <span class="hljs-keyword">FOR</span> LOGIN [$(UserName)]
        EXEC [xdb_collection].[GrantLeastPrivilege] @UserName = <span class="hljs-string">'$(UserName)'</span>
<span class="hljs-keyword">END</span>;
GO 

<span class="hljs-keyword">USE</span> [$(DatabasePrefix)$(Shard1DatabaseNameSuffix)]  

<span class="hljs-keyword">IF</span> <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">EXISTS</span> (<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> sys.database_principals <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">name</span> = N<span class="hljs-string">'$(UserName)'</span>)
<span class="hljs-keyword">BEGIN</span>
    <span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">USER</span> [$(UserName)] <span class="hljs-keyword">FOR</span> LOGIN [$(UserName)]
        EXEC [xdb_collection].[GrantLeastPrivilege] @UserName = <span class="hljs-string">'$(UserName)'</span>
<span class="hljs-keyword">END</span>; 
GO
</code></pre>
<h1 id="heading-closing-notes">Closing notes</h1>
<p>This ended up being quite a long blog post. It took me quite some time to put all the pieces together to get everything running, but a lot of that was because I know almost nothing about either Docker nor Linux.</p>
<p>In the end I think the required setup/files are actually pretty simple though, considering what is actually being done. All the files can be found <a target="_blank" href="https://github.com/Krusen/docker-sqlserver-solr-secure">on GitHub</a>.</p>
<p>One thing I specifically would like to improve on in the future is the whole SSL certificate setup, which still requires some manual steps and is not fully trusted in the browser.</p>
<p>I hope you enjoyed it all and got it working! If you have any comments, questions or suggestions for improvements please let me know in the comments section.</p>
<h1 id="heading-troubleshooting">Troubleshooting</h1>
<p><strong>Getting "exec user process caused "no such file or directory"" when starting nginx container</strong></p>
<p>Make sure the <code>docker-entrypoint.sh</code> file is saved with unix-style line endings <code>LF</code> and not Windows-style <code>CRLF</code>.</p>
<p>https://forums.docker.com/t/standard-init-linux-go-175-exec-user-process-caused-no-such-file/20025/3</p>
<h1 id="heading-additional-resources">Additional resources</h1>
<ul>
<li>https://hub.docker.com/r/microsoft/mssql-server-linux/</li>
<li><p>https://docs.microsoft.com/en-us/sql/linux/quickstart-install-connect-docker</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[MongoDB, C# and DateTimeOffset]]></title><description><![CDATA[The MongoDB driver for C#/.NET  can currently be serialized/deserialized in three different ways - as an array, object or string.
You can control the BSON representation of your property by adding the [BsonRepresentation] attribute or set it on your ...]]></description><link>https://blog.krusen.dk/c-mongodb-serialization-of-datetimeoffset</link><guid isPermaLink="true">https://blog.krusen.dk/c-mongodb-serialization-of-datetimeoffset</guid><dc:creator><![CDATA[Søren Kruse]]></dc:creator><pubDate>Wed, 20 Sep 2017 14:32:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484128030/DH-OW-dvY.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[
<p>The <a target="_blank" href="https://docs.mongodb.com/ecosystem/drivers/csharp/">MongoDB driver for C#/.NET</a>  can currently be serialized/deserialized in three different ways - as an array, object or string.</p>
<p>You can control the BSON representation of your property by adding the <code>[BsonRepresentation]</code> attribute or set it on your class map.</p>
<pre><code class="lang-csharp">[<span class="hljs-meta">BsonRepresentation(BsonType.String)</span>]
<span class="hljs-keyword">public</span> DateTimeOffset EventStart { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
</code></pre>
<p>As mentioned the <a target="_blank" href="https://github.com/mongodb/mongo-csharp-driver/blob/master/src/MongoDB.Bson/Serialization/Serializers/DateTimeOffsetSerializer.cs">DateTimeOffsetSerializer</a> supports three different representation types:</p>
<ul>
<li><code>BsonType.Array</code> (default)</li>
<li><code>BsonType.Document</code></li>
<li><code>BsonType.String</code></li>
</ul>
<h2 id="heading-array-representation-default">Array representation (default)</h2>
<p>By default <code>DateTimeOffset</code> is serialized as an array consisting of the ticks and the offset in minutes.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Serialization code for BsonType.Array</span>
bsonWriter.WriteStartArray();
bsonWriter.WriteInt64(<span class="hljs-keyword">value</span>.Ticks);
bsonWriter.WriteInt32((<span class="hljs-keyword">int</span>)<span class="hljs-keyword">value</span>.Offset.TotalMinutes);
bsonWriter.WriteEndArray();

<span class="hljs-comment">// Example JSON output</span>
<span class="hljs-comment">// [NumberLong("636415154304356493"), 120]</span>
</code></pre>
<p>This is probably the reason you are here right now. This is different than <code>DateTime</code> which is stored as a BSON date (<code>ISODate("2017-09-20T12:46:53.552Z")</code>) and it makes it harder to query manually and harder to read.</p>
<p>I'm sure there's a good reason why this was made the default, but I'm not exactly sure why.</p>
<h2 id="heading-string-representation">String representation</h2>
<p>The string representation is more recognizable to most people and probably what you are looking for.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Serialization code for BsonType.String</span>
bsonWriter.WriteString(JsonConvert.ToString(<span class="hljs-keyword">value</span>));

<span class="hljs-comment">// Example JSON output</span>
<span class="hljs-comment">// "2017-09-20T14:47:37.8324739+02:00"</span>
</code></pre>
<h2 id="heading-document-representation">Document representation</h2>
<p>The last of the three options is the document representation, which is more or less a combination of the array and string representation combined in an object (document).</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Serialization code for BsonType.Document</span>
bsonWriter.WriteStartDocument();
bsonWriter.WriteDateTime(<span class="hljs-string">"DateTime"</span>, BsonUtils.ToMillisecondsSinceEpoch(<span class="hljs-keyword">value</span>.UtcDateTime));
bsonWriter.WriteInt64(<span class="hljs-string">"Ticks"</span>, <span class="hljs-keyword">value</span>.Ticks);
bsonWriter.WriteInt32(<span class="hljs-string">"Offset"</span>, (<span class="hljs-keyword">int</span>)<span class="hljs-keyword">value</span>.Offset.TotalMinutes);
bsonWriter.WriteEndDocument();

<span class="hljs-comment">// Example JSON output</span>
<span class="hljs-comment">// {</span>
<span class="hljs-comment">//     "DateTime": ISODate("2017-09-20T12:56:06.642Z"),</span>
<span class="hljs-comment">//     "Ticks": NumberLong("636415161666429142"),</span>
<span class="hljs-comment">//     "Offset": 120</span>
<span class="hljs-comment">// }</span>
</code></pre>
 ]]></content:encoded></item><item><title><![CDATA[Octopus C# script step not finishing unawaited async Tasks]]></title><description><![CDATA[You might find yourself wanting to start an async Task either through Task.Run(() => ...) or something like Task DoSomethingAsync() or Task.Delay() where you don't want to await the completion of the task. You just want the step to complete and the t...]]></description><link>https://blog.krusen.dk/octopus-csharp-unawaited-async-tasks</link><guid isPermaLink="true">https://blog.krusen.dk/octopus-csharp-unawaited-async-tasks</guid><dc:creator><![CDATA[Søren Kruse]]></dc:creator><pubDate>Fri, 15 Sep 2017 05:40:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484122528/yaYzOEnO-.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[
<p>You might find yourself wanting to start an async <code>Task</code> either through <code>Task.Run(() =&gt; ...)</code> or something like <code>Task DoSomethingAsync()</code> or <code>Task.Delay()</code> where you don't want to await the completion of the task. You just want the step to complete and the task to continue running in the background. But it wont work.</p>
<p>In my situation I wanted to hit a URL 10 minutes after the Octopus deployment was completed and I didn't want the deployment to "hang" for 10 minutes seemingly still deploying.</p>
<p>I tried several different methods, like mentioned in the beginning, but the tasks were never run to completion.</p>
<p>I'm pretty sure I know why this happens, although I haven't actually confirmed it. I'm assuming Octopus fires up a new ScriptCS process with our C# script as the input. When our script reaches the end, i.e. not awaiting any tasks etc., then the process exits and any unfinished tasks goes with it.</p>
<h2 id="heading-alternative-solution-using-azure">Alternative solution using Azure</h2>
<p>I ended up with sort of an alternative solution using Azure Functions and Queue Storage which is free (or close to) for most solutions that don't require a lot of throughput.</p>
<p>It's pretty simple and in short it consists of an HTTP endpoint which adds (delayed) a message to the queue, and then a function with a queue trigger which executes the message. In Octopus I then just call the HTTP endpoint to trigger a delayed action and that's that.</p>
<p>I'll leave it at that and leave the details of the Azure stuff to a future blog post.
 </p>
]]></content:encoded></item><item><title><![CDATA[ErgastApiClient - C# library for querying the Ergast Developer API (Formula 1 data)]]></title><description><![CDATA[The Ergast Developer API (http://ergast.com/mrd/) is an awesome (experimental) web service which provides a historical record of Formula 1 data for non-commercial purposes. The API contains data all the back to the beginning in 1950.
Some time ago I ...]]></description><link>https://blog.krusen.dk/ergastapiclient-csharp-library</link><guid isPermaLink="true">https://blog.krusen.dk/ergastapiclient-csharp-library</guid><dc:creator><![CDATA[Søren Kruse]]></dc:creator><pubDate>Fri, 08 Sep 2017 05:59:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484116154/ieUC778an.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[
<p>The Ergast Developer API (http://ergast.com/mrd/) is an awesome (experimental) web service which provides a historical record of Formula 1 data for non-commercial purposes. The API contains data all the back to the beginning in 1950.</p>
<p>Some time ago I wanted to query some of this data and make some charts of lap times, gap to leader etc. from the latest F1 races, but I couldn't find any .NET library for it. I could have just made some simply calls to the specific endpoints I needed, but I like to make libraries, soo...</p>
<p>I still haven't gotten around to the chart part, but at least I've finished the library.</p>
<p>The library can be installed from NuGet - search for <code>ErgastApiClient</code> or install it through the Package Manger Console:</p>
<pre><code>PM<span class="hljs-operator">&gt;</span> Install<span class="hljs-operator">-</span>Package ErgastApiClient
</code></pre><p>If you are not a programmer but want to query the data anyway you can use the <a target="_blank" href="http://ergast.com/mrd/query">manual interface</a>.</p>
<h2 id="heading-using-the-library">Using the library</h2>
<p>The library is pretty simple to use. Create (and reuse) an <code>ErgastClient</code> and then create one of the many request types:</p>
<ul>
<li><code>RaceResultsRequest</code></li>
<li><code>LapTimesRequest</code></li>
<li><code>PitStopsRequest</code></li>
<li><code>CircuitInfoRequest</code></li>
<li><code>DriverInfoRequest</code></li>
<li><code>DriverStandingsRequest</code></li>
<li>...</li>
</ul>
<p>You then use the client to execute the request and it will return a matching response type. The client takes care of caching for you, so you don't query the Ergast web service unnecessarily.</p>
<p>Below is a complete example of doing a <code>RaceResultsRequest</code>.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Relevant imports</span>
<span class="hljs-keyword">using</span> ErgastApi.Client;
<span class="hljs-keyword">using</span> ErgastApi.Ids;
<span class="hljs-keyword">using</span> ErgastApi.Requests;

<span class="hljs-comment">// The client should be stored and reused during the lifetime of your application</span>
<span class="hljs-keyword">var</span> client = <span class="hljs-keyword">new</span> ErgastClient();

<span class="hljs-comment">// All request properties are optional (except 'Season' if 'Round' is set)</span>
<span class="hljs-keyword">var</span> request = <span class="hljs-keyword">new</span> RaceResultsRequest
{
    Season = <span class="hljs-string">"2017"</span>,     <span class="hljs-comment">// or Seasons.Current for current season</span>
    Round = <span class="hljs-string">"11"</span>,        <span class="hljs-comment">// or Rounds.Last or Rounds.Next for last or next round</span>
    DriverId = <span class="hljs-string">"vettel"</span>, <span class="hljs-comment">// or Drivers.SebastianVettel</span>

    Limit = <span class="hljs-number">30</span>      <span class="hljs-comment">// Limit the number of results returned</span>
    Offset = <span class="hljs-number">0</span>      <span class="hljs-comment">// Result offset (used for paging)</span>
};

<span class="hljs-comment">// RaceResultsRequest returns a RaceResultsResponse</span>
<span class="hljs-comment">// Other requests returns other response types</span>
RaceResultsResponse response = <span class="hljs-keyword">await</span> client.GetResponseAsync(request);

<span class="hljs-comment">// We know it's only a single race, round 11</span>
<span class="hljs-keyword">var</span> race = response.Races.First();

race.Round;                <span class="hljs-comment">// 11</span>
race.RaceName;             <span class="hljs-comment">// Hungarian Grand Prix</span>
race.Circuit.CircuitName;  <span class="hljs-comment">// Hungaroring</span>

<span class="hljs-comment">// There is only one driver in the results - Vettel</span>
<span class="hljs-comment">// Otherwise the results would be ordered by finishing position</span>
<span class="hljs-keyword">var</span> vettel = race.Results[<span class="hljs-number">0</span>];

vettel.Driver.Code;           <span class="hljs-comment">// VET</span>
vettel.FastestLap.LapNumber;  <span class="hljs-comment">// 69</span>
vettel.Position;              <span class="hljs-comment">// 1 (finishing position)</span>
</code></pre>
<p>The <code>RaceResultsResponse</code> contains a list of races matching the query. In this example there is only the one race (Round 11, Hungary, 2017). Each race contains info about the race, the circuit, time of the event etc. and of course the race results.</p>
<p>Each result (in this case there is only Vettel) contains info about the driver, finishing position, starting position (<code>Grid</code>), fastest lap etc.</p>
<p>The above example is the equivalent of <a target="_blank" href="http://ergast.com/api/f1/2017/11/drivers/vettel/results">this</a> manual query. You can also see <a target="_blank" href="http://ergast.com/api/f1/2017/11/drivers/vettel/results.json">the actual JSON data</a> by adding <code>.json</code> to the URL of the manual request.</p>
<h2 id="heading-source-code">Source code</h2>
<p>The source code is available on <a target="_blank" href="https://github.com/Krusen/ErgastApi.Net">GitHub</a> which also has some more examples of how you can use the library/Ergast API.</p>
<p>If you encounter any bugs or have a feature request, please create an issue on <a target="_blank" href="https://github.com/Krusen/ErgastApi.Net/issues">GitHub</a>. Pull Requests are also very welcome.
 </p>
]]></content:encoded></item><item><title><![CDATA[Octopus Script Step Error: "Common Language Runtime detected an invalid program"]]></title><description><![CDATA[You might run into the following error when deploying with Octopus and one of your tasks is executing a C# script (ScriptCS) on the target machine.

ERROR: Script execution failed. [InvalidProgramException] Common Language Runtime detected an invalid...]]></description><link>https://blog.krusen.dk/octopus-scriptcs-error-common-language-runtime</link><guid isPermaLink="true">https://blog.krusen.dk/octopus-scriptcs-error-common-language-runtime</guid><dc:creator><![CDATA[Søren Kruse]]></dc:creator><pubDate>Thu, 07 Sep 2017 11:34:19 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484108880/na1Ucvfyq.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[
<p>You might run into the following error when deploying with Octopus and one of your tasks is executing a C# script (ScriptCS) on the target machine.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484106750/SdUgfLq2n5.png" alt="octopus script error" /></p>
<pre><code>ERROR: Script execution failed. [InvalidProgramException] Common <span class="hljs-keyword">Language</span> Runtime detected an invalid program.
<span class="hljs-keyword">Exit</span> code: <span class="hljs-number">1</span>
The remote script failed <span class="hljs-keyword">with</span> <span class="hljs-keyword">exit</span> code <span class="hljs-number">1</span>
</code></pre><p>This is most likely because .NET 4.5.2 is not installed on the machine. If you install that the error should go away.</p>
<p>There's a bit more info available on the following links:</p>
<ul>
<li>https://github.com/dotnet/corefx/issues/320</li>
<li><p>https://github.com/dotnet/corefx/pull/687</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Filtering index searches by item security with correct paging and total results count]]></title><description><![CDATA[Sitecore ContentSearch indexes does not check item security by default, but it can be enabled with a configuration setting by changing the value of  /sitecore/contentSearch/indexConfigurations/defaultSearchSecurityOption from DisableSecurityCheck to ...]]></description><link>https://blog.krusen.dk/filtering-index-searches-item-security</link><guid isPermaLink="true">https://blog.krusen.dk/filtering-index-searches-item-security</guid><dc:creator><![CDATA[Søren Kruse]]></dc:creator><pubDate>Wed, 19 Jul 2017 11:22:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484098912/WfAoSHMl0.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[
<p><strong>Sitecore ContentSearch</strong> indexes does not check item security by default, but it can be enabled with a configuration setting by changing the value of  <code>/sitecore/contentSearch/indexConfigurations/defaultSearchSecurityOption</code> from <code>DisableSecurityCheck</code> to <code>EnableSecurityCheck</code>. However, it does not really work with paging of the results (i.e skip/take) or the total search result count.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">sitecore</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">contentSearch</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">indexConfigurations</span>&gt;</span>
      <span class="hljs-comment">&lt;!-- DEFAULT SEARCH SECURITY OPTION
            This setting is the default search security option that will be used if
            the search security option is not specified during the creation of search context.
            The accepted values are DisableSecurityCheck and EnableSecurityCheck.
      --&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">defaultSearchSecurityOption</span>&gt;</span>DisableSecurityCheck<span class="hljs-tag">&lt;/<span class="hljs-name">defaultSearchSecurityOption</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">indexConfigurations</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">contentSearch</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">sitecore</span>&gt;</span>
</code></pre>
<p>The check is performed when enumerating the results (after the search has already been done) by fetching each item from Sitecore and then checking the item security and skipping those items that are not accessible to the current user.</p>
<p>That means if there are 10 results in total and you want to get the first 5, but none of those 5 are readable to the current user, then you get an empty list - even though there are actually more results. The <code>TotalSearchResults</code> will also return <code>10</code> even though those  first 5 are not readable. Not optimal.</p>
<h2 id="heading-my-solution">My Solution</h2>
<p>I've come up with a better solution. It's somewhat limited and specifically tailored to the needs we had at the time as it is not really practical to store all access rights for all users and roles for all items in the index. It's all a compromise between complexity, search/indexing speed and the size of the index itself.</p>
<p><strong>Supported features</strong></p>
<ul>
<li>Direct user security</li>
<li>Direct role security</li>
<li>Inherited role security</li>
</ul>
<p><strong>Unsupported features</strong></p>
<ul>
<li>Inherited user security</li>
</ul>
<h2 id="heading-overview">Overview</h2>
<p>The solution consists of a few different elements.</p>
<ol>
<li>A computed field that stores the access rights we need</li>
<li>An interface that has a property for the computed field</li>
<li><strong>[optional]</strong> Extension methods to easily filter by security when querying an index</li>
<li><strong>[optional]</strong> An attribute to automatically filter by security when using the attributed <code>SearchResultItem</code> in queries</li>
</ol>
<h2 id="heading-step-1-computed-field">Step 1: Computed field</h2>
<p>Most of the logic happens in this computed field that we need to create. To be able to filter the results at query time we need to store some information in the index about which users and roles that have access to each item.</p>
<p>Overview of what we are doing in the computed field:</p>
<ol>
<li>Check if the <strong>Everyone</strong> role has access and if so just store <code>"everyone"</code></li>
<li>Get all roles in the <strong>sitecore</strong> domain that matches <code>RoleRegex</code></li>
<li>Create a list of all those matching roles that are allowed to read the item</li>
<li>Get a list of all user accounts that have access rights specified directly on the item and are allowed to read it</li>
<li>Return a combined list of those roles and users that have access to the item</li>
</ol>
<p>You might need to modify this a bit to match your needs, e.g. if your roles are not in the <strong>sitecore</strong> domain.</p>
<p><strong>*Note:</strong> The more roles that match the regex, the longer time the indexing will take as it has to check security for each role and this is done for each indexed item.*</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> System.Collections.Generic;
<span class="hljs-keyword">using</span> System.Linq;
<span class="hljs-keyword">using</span> System.Text.RegularExpressions;
<span class="hljs-keyword">using</span> Sitecore.Configuration;
<span class="hljs-keyword">using</span> Sitecore.ContentSearch;
<span class="hljs-keyword">using</span> Sitecore.ContentSearch.ComputedFields;
<span class="hljs-keyword">using</span> Sitecore.Data.Items;
<span class="hljs-keyword">using</span> Sitecore.Security.Accounts;
<span class="hljs-keyword">using</span> Sitecore.Security.Domains;
<span class="hljs-keyword">using</span> Sitecore.SecurityModel;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Sandbox.Search.ComputedFields</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ReadableTo</span> : <span class="hljs-title">IComputedIndexField</span>
    {
        <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Modify to match your needs!</span>
        <span class="hljs-comment">// The more matching roles the longer indexing will take.</span>
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">string</span> RoleDomain = <span class="hljs-string">"sitecore"</span>;
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">readonly</span> Regex RoleRegex = <span class="hljs-keyword">new</span> Regex(<span class="hljs-string">".*"</span>);

        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> FieldName { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> ReturnType { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">object</span> <span class="hljs-title">ComputeFieldValue</span>(<span class="hljs-params">IIndexable indexable</span>)</span>
        {
            Item item = indexable <span class="hljs-keyword">as</span> SitecoreIndexableItem;

            <span class="hljs-keyword">if</span> (item == <span class="hljs-literal">null</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;

            <span class="hljs-keyword">using</span> (<span class="hljs-keyword">new</span> SecurityStateSwitcher(SecurityState.Enabled))
            {
                <span class="hljs-keyword">if</span> (item.Security.CanRead(Account.FromName(<span class="hljs-string">"Everyone"</span>, AccountType.Role)))
                    <span class="hljs-keyword">return</span> <span class="hljs-string">"everyone"</span>;
            }

            <span class="hljs-comment">// Get roles in 'sitecore' domain matching the regex and check security (including inheritance)</span>
            <span class="hljs-comment">// More roles equals longer indexing time as security is checked for each role</span>
            <span class="hljs-keyword">var</span> roles = Domain.GetDomain(RoleDomain)
                .GetRoles()
                .Where(x =&gt; RoleRegex.IsMatch(x.Name));

            <span class="hljs-keyword">var</span> allowedRoles = <span class="hljs-keyword">new</span> List&lt;<span class="hljs-keyword">string</span>&gt;();
            <span class="hljs-keyword">using</span> (<span class="hljs-keyword">new</span> SecurityStateSwitcher(SecurityState.Enabled))
            {
                <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> role <span class="hljs-keyword">in</span> roles)
                {
                    <span class="hljs-keyword">if</span> (item.Security.CanRead(role))
                        allowedRoles.Add(role.Name);
                }
            }

            <span class="hljs-comment">// Get accounts (users/roles) with directly specified security</span>
            <span class="hljs-keyword">var</span> allowedAccounts =
                item.Security.GetAccessRules().Helper
                    .GetAccounts()
                    .Where(x =&gt; item.Security.CanRead(x))
                    .Select(x =&gt; x.Name);

            <span class="hljs-keyword">return</span> allowedRoles.Concat(allowedAccounts);
        }
    }
}
</code></pre>
<h3 id="heading-index-configuration">Index configuration</h3>
<p>We then need to add this new computed field to the <strong>index configuration</strong> for each index we want to use this with, so that we can use it when querying the index.</p>
<pre><code class="lang-xml"><span class="hljs-comment">&lt;!-- Add under /fieldMap/fieldNames in your index configuration --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">field</span> <span class="hljs-attr">fieldName</span>=<span class="hljs-string">"ReadableTo"</span> <span class="hljs-attr">storageType</span>=<span class="hljs-string">"NO"</span> <span class="hljs-attr">indexType</span>=<span class="hljs-string">"TOKENIZED"</span> <span class="hljs-attr">vectorType</span>=<span class="hljs-string">"NO"</span> <span class="hljs-attr">boost</span>=<span class="hljs-string">"1f"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"System.String"</span>     <span class="hljs-attr">settingType</span>=<span class="hljs-string">"Sitecore.ContentSearch.LuceneProvider.LuceneSearchFieldConfiguration, Sitecore.ContentSearch.LuceneProvider"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">analyzer</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"Sitecore.ContentSearch.LuceneProvider.Analyzers.LowerCaseKeywordAnalyzer, Sitecore.ContentSearch.LuceneProvider"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">field</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Add under computed fields (/fields[@hint='raw:AddComputedIndexField']) in your index configuration --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">field</span> <span class="hljs-attr">fieldName</span>=<span class="hljs-string">"ReadableTo"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"Sandbox.Search.ComputedFields.ReadableTo, Sandbox.Search"</span> /&gt;</span>
</code></pre>
<h2 id="heading-step-2-interface">Step 2: Interface</h2>
<p>Next up we need an interface with a property matching our new computed field. This is not strictly necessary, but it enables us to create an attribute and some extension methods to more easily use the new feature. If you don't need those extra features then you can just add a property named <code>ReadableTo</code> (or whatever you named it in the index configuration) to your <code>SearchResultItem</code>.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> System.Collections.Generic;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Sandbox.Search</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IIndexSecuritySupport</span>
    {
        IEnumerable&lt;<span class="hljs-keyword">string</span>&gt; ReadableTo { <span class="hljs-keyword">get</span>; }
    }
}
</code></pre>
<h2 id="heading-step-3-extension-methods-optional">Step 3: Extension methods (optional)</h2>
<p>To make life easier for ourselves we can add two extension methods - one for the current user and one for a specific user.</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-title">IQueryable</span>&lt;<span class="hljs-title">TItem</span>&gt; <span class="hljs-title">FilterReadable</span>&lt;<span class="hljs-title">TItem</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> IQueryable&lt;TItem&gt; queryable</span>) <span class="hljs-keyword">where</span> TItem : IIndexSecuritySupport
<span class="hljs-title">IQueryable</span>&lt;<span class="hljs-title">TItem</span>&gt; <span class="hljs-title">FilterReadable</span>&lt;<span class="hljs-title">TItem</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> IQueryable&lt;TItem&gt; queryable, User user</span>) <span class="hljs-keyword">where</span> TItem : IIndexSecuritySupport</span>
</code></pre>
<p>These will filter our <code>IQueryable&lt;TItem&gt;</code> to only items readable by either the current or the specified user respectively.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> System;
<span class="hljs-keyword">using</span> System.Collections.Generic;
<span class="hljs-keyword">using</span> System.Linq;
<span class="hljs-keyword">using</span> System.Linq.Expressions;
<span class="hljs-keyword">using</span> System.Reflection;
<span class="hljs-keyword">using</span> System.Text.RegularExpressions;
<span class="hljs-keyword">using</span> Sitecore.Configuration;
<span class="hljs-keyword">using</span> Sitecore.ContentSearch.Linq;
<span class="hljs-keyword">using</span> Sitecore.ContentSearch.Linq.Utilities;
<span class="hljs-keyword">using</span> Sitecore.Diagnostics;
<span class="hljs-keyword">using</span> Sitecore.Security.Accounts;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Sandbox.Search</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">QueryableSecurityExtensions</span>
    {
        <span class="hljs-comment">// This should match the regex in you computed field</span>
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">readonly</span> Regex RoleRegex = <span class="hljs-keyword">new</span> Regex(<span class="hljs-string">$".*"</span>);

        <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">readonly</span> Type IndexSecurityType = <span class="hljs-keyword">typeof</span>(IIndexSecuritySupport);

        <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">readonly</span> MethodInfo EnumerableContainsMethod;
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">readonly</span> PropertyInfo ReadableToProperty;

        <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-title">QueryableSecurityExtensions</span>(<span class="hljs-params"></span>)</span>
        {
            <span class="hljs-comment">// Enumerable.Contains&lt;string&gt;(IEnumerable&lt;string&gt;, string)</span>
            EnumerableContainsMethod =
                <span class="hljs-keyword">typeof</span>(Enumerable).GetMethods()
                    .Single(m =&gt; m.Name == <span class="hljs-string">"Contains"</span> &amp;&amp; m.GetParameters().Length == <span class="hljs-number">2</span>)
                    .MakeGenericMethod(<span class="hljs-keyword">typeof</span>(<span class="hljs-keyword">string</span>));

            <span class="hljs-comment">// IIndexSecuritySupport.ReadableTo</span>
            ReadableToProperty = <span class="hljs-keyword">typeof</span>(IIndexSecuritySupport).GetProperty(<span class="hljs-keyword">nameof</span>(IIndexSecuritySupport.ReadableTo));
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-title">IQueryable</span>&lt;<span class="hljs-title">TItem</span>&gt; <span class="hljs-title">FilterReadable</span>&lt;<span class="hljs-title">TItem</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> IQueryable&lt;TItem&gt; queryable</span>) <span class="hljs-keyword">where</span> TItem : IIndexSecuritySupport</span>
        {
            <span class="hljs-keyword">return</span> FilterReadable(queryable, User.Current);
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-title">IQueryable</span>&lt;<span class="hljs-title">TItem</span>&gt; <span class="hljs-title">FilterReadable</span>&lt;<span class="hljs-title">TItem</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">this</span> IQueryable&lt;TItem&gt; queryable, User user</span>) <span class="hljs-keyword">where</span> TItem : IIndexSecuritySupport</span>
        {
            Assert.ArgumentNotNull(queryable, <span class="hljs-keyword">nameof</span>(queryable));
            Assert.ArgumentNotNull(user, <span class="hljs-keyword">nameof</span>(user));
            Assert.IsTrue(IndexSecurityType.IsAssignableFrom(<span class="hljs-keyword">typeof</span>(TItem)), <span class="hljs-string">$"Queryable type must implement the '<span class="hljs-subst">{IndexSecurityType.Name}</span>' interface."</span>);

            <span class="hljs-keyword">var</span> roles =
                user.Roles.Where(x =&gt; RoleRegex.IsMatch(x.Name))
                    .Select(x =&gt; x.Name)
                    .ToList();

            roles.Add(user.Name);

            <span class="hljs-keyword">var</span> parameterExpression = Expression.Parameter(<span class="hljs-keyword">typeof</span>(TItem), <span class="hljs-string">"param"</span>);
            <span class="hljs-keyword">var</span> memberExpression = Expression.MakeMemberAccess(parameterExpression, ReadableToProperty);

            <span class="hljs-keyword">var</span> everyone = GetContainsConstantPredicate&lt;TItem&gt;(<span class="hljs-string">"everyone"</span>, parameterExpression, memberExpression);
            <span class="hljs-keyword">var</span> containsAny = GetContainsAnyPredicate&lt;TItem&gt;(roles, parameterExpression, memberExpression);

            <span class="hljs-keyword">return</span> queryable.Filter(everyone.Or(containsAny));
        }

        <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-title">Expression</span>&lt;<span class="hljs-title">Func</span>&lt;<span class="hljs-title">TItem</span>, <span class="hljs-title">bool</span>&gt;&gt; <span class="hljs-title">GetContainsAnyPredicate</span>&lt;<span class="hljs-title">TItem</span>&gt;(<span class="hljs-params">IEnumerable&lt;<span class="hljs-keyword">string</span>&gt; values, ParameterExpression parameterExpression, MemberExpression memberExpression</span>)</span>
        {
            <span class="hljs-keyword">var</span> containsAnyPredicate = PredicateBuilder.False&lt;TItem&gt;();
            <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> <span class="hljs-keyword">value</span> <span class="hljs-keyword">in</span> values)
            {
                <span class="hljs-keyword">var</span> containsExpression =
                    Expression.Lambda&lt;Func&lt;TItem, <span class="hljs-keyword">bool</span>&gt;&gt;(
                        Expression.Call(EnumerableContainsMethod, memberExpression, Expression.Constant(<span class="hljs-keyword">value</span>)),
                        parameterExpression);
                containsAnyPredicate = containsAnyPredicate.Or(containsExpression);
            }
            <span class="hljs-keyword">return</span> containsAnyPredicate;
        }

        <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-title">Expression</span>&lt;<span class="hljs-title">Func</span>&lt;<span class="hljs-title">TItem</span>, <span class="hljs-title">bool</span>&gt;&gt; <span class="hljs-title">GetContainsConstantPredicate</span>&lt;<span class="hljs-title">TItem</span>&gt;(<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">value</span>, ParameterExpression parameter, MemberExpression member</span>)</span>
        {
            <span class="hljs-keyword">return</span>
                Expression.Lambda&lt;Func&lt;TItem, <span class="hljs-keyword">bool</span>&gt;&gt;(
                    Expression.Call(EnumerableContainsMethod, member, Expression.Constant(<span class="hljs-keyword">value</span>)), parameter);
        }
    }
}
</code></pre>
<p>Without the extension methods we would have to do this everytime:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> user = Sitecore.Context.User;

<span class="hljs-keyword">var</span> names =
    user.Roles.Where(x =&gt; RoleRegex.IsMatch(x.Name))
        .Select(x =&gt; x.Name)
        .ToList();

names.Add(user.Name);

<span class="hljs-keyword">var</span> containsAnyFilter = PredicateBuilder.False&lt;ArticleSearchResultItem&gt;();
<span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> name <span class="hljs-keyword">in</span> names)
{
    containsAnyFilter = containsAnyFilter.Or(x =&gt; x.ReadableTo.Contains(name));
}

query.Where(x =&gt; x.Something == <span class="hljs-string">"abcdef"</span>)
     .Filter(x =&gt; x.ReadableTo.Contains(<span class="hljs-string">"everyone"</span>) || containsAnyFilter)
</code></pre>
<p>Now we can just do this:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Returns only indexed items readable to the current user</span>
query.Where(x =&gt; x.Something == <span class="hljs-string">"abcdef"</span>).FilterReadable();

<span class="hljs-comment">// Returns only indexed items readable to 'extranet\SomeUser'</span>
<span class="hljs-keyword">var</span> user = User.FromName(<span class="hljs-string">"extranet\\SomeUser"</span>, <span class="hljs-literal">false</span>);
query.Where(x =&gt; x.Something == <span class="hljs-string">"abcdef"</span>).FilterReadable(user);
</code></pre>
<h2 id="heading-step-4-predefined-query-attribute-for-searchresultitem-optional">Step 4: Predefined query attribute for SearchResultItem (optional)</h2>
<p>Sitecore allows us to use the <code>[PredefinedQuery]</code> attribute on classes to apply predefined queries when querying an index using that type. This attribute allows us to add constant filters. An example could be to always filter by a specific template ID:</p>
<pre><code class="lang-csharp">[<span class="hljs-meta">PredefinedQuery(<span class="hljs-meta-string">"TemplateID"</span>, ComparisonType.Equal, <span class="hljs-meta-string">"{7FAFEDF6-9438-4CAD-9E04-3FCD89206D2F}"</span>, typeof(ID)</span>]
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ArticleSearchResultItem</span> : <span class="hljs-title">SearchResultItem</span>
{
    <span class="hljs-comment">// ...</span>
}

<span class="hljs-comment">// Now you don't have to add this every time you want to search for articles:</span>
<span class="hljs-comment">// .Where(x =&gt; x.TemplateID == new ID("{7FAFEDF6-9438-4CAD-9E04-3FCD89206D2F}"))</span>
</code></pre>
<p>It is also possible to make our own with our own logic by creating a class inheriting the <code>IPredefinedQueryAttribute</code> interface. This allows us to create an attribute that makes sure that only items readable to the current user is returned when querying the index using types marked with that attribute.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> System;
<span class="hljs-keyword">using</span> System.Linq;
<span class="hljs-keyword">using</span> Sitecore.ContentSearch;
<span class="hljs-keyword">using</span> Sitecore.ContentSearch.Diagnostics;
<span class="hljs-keyword">using</span> Sitecore.ContentSearch.Linq.Parsing;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">Sandbox.Search</span>
{
    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;summary&gt;</span></span>
    <span class="hljs-comment"><span class="hljs-doctag">///</span> Automatically applies filtering on security to queries using the attributed class.</span>
    <span class="hljs-comment"><span class="hljs-doctag">///</span> <span class="hljs-doctag">&lt;/summary&gt;</span></span>
    [<span class="hljs-meta">AttributeUsage(AttributeTargets.Class, Inherited = false)</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ApplySecurityAttribute</span> : <span class="hljs-title">Attribute</span>, <span class="hljs-title">IPredefinedQueryAttribute</span>
    {
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">readonly</span> Type IndexSecurityType = <span class="hljs-keyword">typeof</span> (IIndexSecuritySupport);

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">IQueryable</span>&lt;<span class="hljs-title">TItem</span>&gt; <span class="hljs-title">ApplyFilter</span>&lt;<span class="hljs-title">TItem</span>&gt;(<span class="hljs-params">IQueryable&lt;TItem&gt; queryable, IIndexValueFormatter valueFormatter</span>)</span>
        {
            <span class="hljs-keyword">if</span> (!IndexSecurityType.IsAssignableFrom(<span class="hljs-keyword">typeof</span> (TItem)))
            {
                SearchLog.Log.Warn(<span class="hljs-string">$"The type '<span class="hljs-subst">{<span class="hljs-keyword">typeof</span> (TItem).FullName}</span>' does not implement the '<span class="hljs-subst">{IndexSecurityType.Name}</span>' interface so security filtering is not being applied."</span>);
                <span class="hljs-keyword">return</span> queryable;
            }

            <span class="hljs-comment">// The casts looks hacky but it works</span>
            <span class="hljs-keyword">return</span> queryable
                .Cast&lt;IIndexSecuritySupport&gt;()
                .FilterReadable() <span class="hljs-comment">// Our extension method from step 3</span>
                .Cast&lt;TItem&gt;();
        }
    }
}
</code></pre>
<p>Then we just apply this to our custom <code>SearchResultItem</code> class:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Your search result item also needs to inherit the IIndexSecuritySupport interface</span>
[<span class="hljs-meta">ApplySecurity</span>]
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ArticleSearchResultItem</span> : <span class="hljs-title">SearchResultItem</span>, <span class="hljs-title">IIndexSecuritySupport</span>
{
}
</code></pre>
<p>Now we don't need to remember to add the <code>FilterReadable()</code> call to queries using the <code>ArticleSearchResultItem</code> type.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// This is now the same as 'query.Where(x =&gt; x.Something == "abcdef").FilterReadable()'</span>
query.Where(x =&gt; x.Something == <span class="hljs-string">"abcdef"</span>);
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>So that's it. It looks a lot more complex than it really is.</p>
<p>There are two reasons why I'm not handling inherited user security. Well, first off - we didn't need it. But besides that, as far as I know it's not possible to check for inherited access rights without checking if each individual user has any inherited rights - and that would have to be done for <strong>every user</strong> on your site.</p>
<p><em>Let me know if you have any issues with this or comments in general.</em>
 </p>
]]></content:encoded></item><item><title><![CDATA[Sitecore Social Connected Exception: "Application in args should not be null"]]></title><description><![CDATA[You might run into this exception when trying to log in using one of the social connectors that is part of the Sitecore Social Connected module (Facebook, Twitter, LinkedIn, Google+)
ERROR Sitecore.Social: Application in args should not be null
Excep...]]></description><link>https://blog.krusen.dk/sitecore-social-application-in-args-should-not-be-null</link><guid isPermaLink="true">https://blog.krusen.dk/sitecore-social-application-in-args-should-not-be-null</guid><dc:creator><![CDATA[Søren Kruse]]></dc:creator><pubDate>Wed, 05 Jul 2017 14:13:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484091810/fVe_4FlHN.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[
<p>You might run into this exception when trying to log in using one of the social connectors that is part of the Sitecore Social Connected module (Facebook, Twitter, LinkedIn, Google+)</p>
<pre><code>ERROR Sitecore.Social: Application in args should not be null
Exception: Sitecore.Social.NetworkProviders.Exceptions.AuthException
Message: Exception of <span class="hljs-keyword">type</span> <span class="hljs-string">'Sitecore.Social.NetworkProviders.Exceptions.AuthException'</span> was thrown.
Source: Sitecore.Social.NetworkProviders
   at Sitecore.Social.NetworkProviders.Exceptions.Analyzers.ArgsExceptionAnalyzer.Analyze(AuthArgs args)
   at Sitecore.Social.Client.Connector.SocialLogin.ProcessRequest(HttpContext httpContext)
</code></pre><p>I ran into this exception the other day and was a bit confused at it had been working fine.</p>
<p>It turns out a change had been made to our setup to always include the language as the first part in the URL - and if it was missing it would redirect to the correct URL including the language part.</p>
<p>When you click on one of the Social Connector buttons to log in, the module makes a <code>POST</code> request to <code>/Social/TwitterConnector/Login</code> (or the equivalent for the other connectors). These use standard MVC to generate a form which points to the <strong>Login</strong> method on the corresponding controller.</p>
<pre><code><span class="hljs-meta">@using</span> (Html.BeginForm(<span class="hljs-string">"Login"</span>, <span class="hljs-literal">null</span>, <span class="hljs-keyword">new</span> { area = <span class="hljs-string">"Social"</span> }, FormMethod.Post, <span class="hljs-keyword">new</span> { style = <span class="hljs-string">"display:inline"</span> }))
{
  <span class="hljs-meta">@Html</span>.HiddenFor(<span class="hljs-function"><span class="hljs-params">model</span> =&gt;</span> model.Parameters)

  &lt;input <span class="hljs-keyword">type</span>=<span class="hljs-string">"image"</span> title=<span class="hljs-string">'@Model.ToolTip'</span> style=<span class="hljs-string">"margin:0 1px"</span> src=<span class="hljs-string">"@Url.Content(Model.Icon)"</span> /&gt;
}
</code></pre><p>The redirect logic that was setup was also redirecting <code>POST</code> requests, but redirected <code>POST</code> requests turn into <code>GET</code> and also no longer include the form parameters.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>So what can we learn from all this?</p>
<p><strong>Do not redirect <code>POST</code> requests. Please.</strong>
 </p>
]]></content:encoded></item><item><title><![CDATA[Sitecore MVC: StackOverflowException when returning views instead of partial views]]></title><description><![CDATA[If you end up getting a StackOverflowException in one of your controllers when using MVC with Sitecore it might be because you are returning View() instead of PartialView().
If you want to return View() in your controller then you either need to set ...]]></description><link>https://blog.krusen.dk/sitecore-mvc-stackoverflowexception-when-returning-view</link><guid isPermaLink="true">https://blog.krusen.dk/sitecore-mvc-stackoverflowexception-when-returning-view</guid><dc:creator><![CDATA[Søren Kruse]]></dc:creator><pubDate>Wed, 31 May 2017 11:42:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484085163/Gsccb2S9i.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[
<p>If you end up getting a <code>StackOverflowException</code> in one of your controllers when using MVC with Sitecore it might be because you are returning <code>View()</code> instead of <code>PartialView()</code>.</p>
<p>If you want to return <code>View()</code> in your controller then you either need to set layout to null/empty string on the view itself or add it to <code>_ViewStart.cshtml</code> - otherwise you will end up with an infinite loop.</p>
<pre><code class="lang-aspnet">@{
    Layout = "";
}
</code></pre>
<p>An alternative is to make sure you don't have a <code>_ViewStart.cshtml</code> file with your main layout specified.</p>
<p>The loop happens because of placeholders in the main layout file. If one of the renderings in a placeholder returns a view with <code>View()</code> - instead of a partial view with <code>PartialView()</code> - then it will try to load the layout file, which will then load the renderings in the placeholders, which will then load the layout file and so on.</p>
<p>As mentioned to avoid this issue you can just return <code>PartialView()</code> instead as that does not try to load the layout again.
 </p>
]]></content:encoded></item><item><title><![CDATA[Collection of small useful javascript functions]]></title><description><![CDATA[Every once in a while I'll be working on some minor javascript stuff and need some little nifty function that is usually available through whatever javascript framework being used - be it lodash, jQuery, angular or something else - but I can't or don...]]></description><link>https://blog.krusen.dk/simple-javascript-pad-left-method-debounce</link><guid isPermaLink="true">https://blog.krusen.dk/simple-javascript-pad-left-method-debounce</guid><dc:creator><![CDATA[Søren Kruse]]></dc:creator><pubDate>Wed, 31 May 2017 10:27:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484077568/I9nsu9gfr.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[
<p>Every once in a while I'll be working on some minor javascript stuff and need some little nifty function that is usually available through whatever javascript framework being used - be it lodash, jQuery, angular or something else - but I can't or don't want/need to use one of those.</p>
<p>In those situation I usually end up searching StackOverflow for the solution and most likely have to test a few of them to find the best and most modern version.</p>
<p>To help my self I've decided to save some of them for ease of access and future use, so here goes:</p>
<ul>
<li>Pad left</li>
<li>Debounce</li>
</ul>
<h2 id="heading-pad-left">Pad left</h2>
<p>This will add a character to the left of the input value until the total length of the value is the specified width.</p>
<p>This is useful for stuff like right-aligning text and padding numbers with leading zeros.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> padLeft = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">value, width, char</span>) </span>{
    char = (char !== <span class="hljs-literal">undefined</span>) ? char : <span class="hljs-string">" "</span>;
    width = (<span class="hljs-keyword">typeof</span> width === <span class="hljs-string">"number"</span>) ? width : <span class="hljs-built_in">parseInt</span>(width);
    value = <span class="hljs-built_in">String</span>(value);
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">Array</span>(<span class="hljs-number">1</span> + width - value.length).join(char) + value;
}
</code></pre>
<p>This works with both strings and numbers for input. <strong>Please note that negative numbers is not handled correctly.</strong></p>
<h4 id="heading-examples">Examples</h4>
<pre><code class="lang-javascript"><span class="hljs-comment">// Right-aligning text</span>
padLeft(<span class="hljs-string">"Blue"</span>, <span class="hljs-number">10</span>, <span class="hljs-string">" "</span>)
padLeft(<span class="hljs-string">"Orange"</span>, <span class="hljs-number">10</span>, <span class="hljs-string">" "</span>)

<span class="hljs-comment">// Result:</span>
<span class="hljs-comment">//      Blue</span>
<span class="hljs-comment">//    Orange</span>
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-comment">// Padding numbers with leading zeros</span>
padLeft(<span class="hljs-number">5</span>, <span class="hljs-number">3</span>, <span class="hljs-number">0</span>)
padLeft(<span class="hljs-number">42</span>, <span class="hljs-number">3</span>, <span class="hljs-number">0</span>)
padLeft(<span class="hljs-number">137</span>, <span class="hljs-number">3</span>, <span class="hljs-number">0</span>)

<span class="hljs-comment">// Result:</span>
<span class="hljs-comment">// 005</span>
<span class="hljs-comment">// 042</span>
<span class="hljs-comment">// 137</span>
</code></pre>
<h2 id="heading-debounce">Debounce</h2>
<p>Debouncing means waiting a set amount of time before executing a specified function.</p>
<p>This is useful in many different situations, for example an autosuggest feature where you only want to load suggestion after the user is done typing instead of continuously after each keypress.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// 'wait' is time in milliseconds</span>
<span class="hljs-keyword">var</span> debounce = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">func, wait</span>) </span>{
    <span class="hljs-keyword">var</span> timeout;
    <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">var</span> context = <span class="hljs-built_in">this</span>, args = <span class="hljs-built_in">arguments</span>;
        <span class="hljs-built_in">clearTimeout</span>(timeout);
        timeout = <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            func.apply(context, args);
        }, wait || <span class="hljs-number">0</span>);
    };
}
</code></pre>
<h4 id="heading-examples">Examples</h4>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> loadSuggestions = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Load suggestions from web service</span>
}

<span class="hljs-comment">// debounce(..) returns a new function.</span>
<span class="hljs-comment">// You have to save and reuse the returned function for it to work as expected.</span>
<span class="hljs-keyword">var</span> loadSuggestionsDebounce = debounce(loadSuggestions, <span class="hljs-number">250</span>);

<span class="hljs-keyword">var</span> textfield = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"textfield"</span>);
textfield.addEventListener(<span class="hljs-string">"keypress"</span>, loadSuggestionsDebounce);
</code></pre>
 ]]></content:encoded></item><item><title><![CDATA[Sitecore 8 Web Forms For Marketers (WFFM) email settings cheat sheet]]></title><description><![CDATA[I've just been working with WFFM a bit - migrating forms from Sitecore 6.5 - and had to also set it up to use TLS for the mail server.
This post is basically just a cheat sheet of the email options that can be configured and where you can configure t...]]></description><link>https://blog.krusen.dk/sitecore-8-wffm-email-settings-cheat-sheet</link><guid isPermaLink="true">https://blog.krusen.dk/sitecore-8-wffm-email-settings-cheat-sheet</guid><dc:creator><![CDATA[Søren Kruse]]></dc:creator><pubDate>Tue, 07 Feb 2017 07:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484070974/YPMRiV6naE.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[
<p>I've just been working with WFFM a bit - migrating forms from Sitecore 6.5 - and had to also set it up to use TLS for the mail server.</p>
<p>This post is basically just a cheat sheet of the email options that can be configured and where you can configure them.</p>
<p><a target="_blank" href="https://doc.sitecore.net/web_forms_for_marketers/working_with_actions_and_validations/save_actions/specify_different_smtp_settings_for_the_send_email_message_save_action">The official documentation</a> explains the basics like mail server and credentials etc. but it's missing a few bits.</p>
<h2 id="heading-the-send-email-message-save-action-parameters">The 'Send Email Message' save action parameters</h2>
<p>On the item <code>/sitecore/system/Modules/Web Forms for Marketers/Settings/Actions/Save Actions/Send Email Message</code> in the <strong>Parameters</strong> field you can specify values (as XML) for the following settings:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">Host</span>&gt;</span>smtp.domain.com<span class="hljs-tag">&lt;/<span class="hljs-name">Host</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">Port</span>&gt;</span>587<span class="hljs-tag">&lt;/<span class="hljs-name">Port</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">Login</span>&gt;</span>user@domain.com<span class="hljs-tag">&lt;/<span class="hljs-name">Login</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">Password</span>&gt;</span>b<span class="hljs-tag">&lt;/<span class="hljs-name">Password</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">From</span>&gt;</span>user@domain.com<span class="hljs-tag">&lt;/<span class="hljs-name">From</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">EnableSsl</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">EnableSsl</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">IsBodyHtml</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">IsBodyHtml</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">IsIncludeAttachments</span>&gt;</span>false<span class="hljs-tag">&lt;/<span class="hljs-name">IsIncludeAttachments</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Not mentioned in official docs but should work as well --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">Subject</span>&gt;</span>Default subject<span class="hljs-tag">&lt;/<span class="hljs-name">Subject</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">Mail</span>&gt;</span>Default email body<span class="hljs-tag">&lt;/<span class="hljs-name">Mail</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">CC</span>&gt;</span>user@domain.com<span class="hljs-tag">&lt;/<span class="hljs-name">CC</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">BCC</span>&gt;</span>user@domain.com<span class="hljs-tag">&lt;/<span class="hljs-name">BCC</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">LocalFrom</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">LocalFrom</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">RecipientGateway</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">RecipientGateway</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">FromPhone</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">FromPhone</span>&gt;</span>
</code></pre>
<h2 id="heading-settings-from-config-files">Settings from config files</h2>
<p>It's only a subset of these settings that can be specified in config files. Values specified on the save action item itself will override any values from config files. Settings like <strong>EnableSsl</strong>, <strong>IsBodyHtml</strong> and <strong>IsIncludeAttachments</strong> can sadly only be specified on the save action although it should be somewhat trivial to change this, potentially by hooking into the <code>processMessage</code> pipeline.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">configuration</span> <span class="hljs-attr">xmlns:patch</span>=<span class="hljs-string">"http://www.sitecore.net/xmlconfig/"</span> <span class="hljs-attr">xmlns:set</span>=<span class="hljs-string">"http://www.sitecore.net/xmlconfig/set/"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">sitecore</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">settings</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">setting</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"MailServer"</span> <span class="hljs-attr">set:value</span>=<span class="hljs-string">"smtp.domain.com"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">setting</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"MailServerPort  "</span> <span class="hljs-attr">set:value</span>=<span class="hljs-string">"587"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">setting</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"MailServerUserName"</span> <span class="hljs-attr">set:value</span>=<span class="hljs-string">"user@domain.com"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">setting</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"MailServerPassword"</span> <span class="hljs-attr">set:value</span>=<span class="hljs-string">"b"</span> /&gt;</span>

      <span class="hljs-comment">&lt;!-- Corresponds to &lt;From&gt; - default sender address --&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">setting</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"Analytics.EMailFromAddress"</span> <span class="hljs-attr">set:value</span>=<span class="hljs-string">"user@domain.com"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">settings</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">sitecore</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">configuration</span>&gt;</span>
</code></pre>
<h2 id="heading-note-when-upgrading-from-sitecore-65">Note when upgrading from Sitecore 6.5</h2>
<p>Most of the forms created with the earlier version of WFFM had <code>&lt;Host&gt;</code> and <code>&lt;From&gt;</code> parameters with the default values specified on the form itself in the <strong>Save Actions</strong> field. These were overriding anything specified in either config files or on the save action item. To fix this we had to manually edit the XML of the <strong>Save Actions</strong> field on all the forms.</p>
<p>The old forms also had a reference to the old <strong>Save to database</strong> save action (that no longer exists after 8.0) which we also had to remove.</p>
<p>I created <a target="_blank" href="https://gist.github.com/Krusen/42b49e7df2657ba6935caa19b6b94d20">this <code>.aspx</code> page/script</a> to do this for us - <strong>use at your own risk!</strong>
 </p>
]]></content:encoded></item><item><title><![CDATA[Sitecore MVC Exception on Content Delivery servers]]></title><description><![CDATA[If you use MVC and follow Sitecore's guidelines with regards to which config files should be enabled/disabled on CD servers you might run into this exception:
InvalidOperationException: No route in the route table matches the supplied values.

The is...]]></description><link>https://blog.krusen.dk/sitecore-mvc-exception-no-route-in-the-route-table</link><guid isPermaLink="true">https://blog.krusen.dk/sitecore-mvc-exception-no-route-in-the-route-table</guid><dc:creator><![CDATA[Søren Kruse]]></dc:creator><pubDate>Wed, 01 Feb 2017 07:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484063299/DXRQtdVrq.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[
<p>If you use MVC and follow Sitecore's guidelines with regards to which config files should be enabled/disabled on CD servers you might run into this exception:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">InvalidOperationException:</span> <span class="hljs-literal">No</span> <span class="hljs-string">route</span> <span class="hljs-string">in</span> <span class="hljs-string">the</span> <span class="hljs-string">route</span> <span class="hljs-string">table</span> <span class="hljs-string">matches</span> <span class="hljs-string">the</span> <span class="hljs-string">supplied</span> <span class="hljs-string">values.</span>
</code></pre>
<h2 id="heading-the-issue">The issue</h2>
<p>This can happen when you have deleted/disabled the <strong>Sitecore.Speak.Mvc.config</strong>, which Sitecore recommends you do on Content Deliver servers, and use the default MVC helper methods <code>@Html.Action</code> and <code>@Html.RenderAction</code> in your renderings.</p>
<p>For some reason those methods requires a route containing the pattern <code>{controller}/{action}</code> to work. These are part of the default route in a standard MVC project, but usually not in a Sitecore project.</p>
<p>But then why does it work until we delete/disable <strong>Sitecore.Speak.Mvc.config</strong>?</p>
<p>Because that config files adds a processor to the <code>initialize</code> pipeline.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">initialize</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">processor</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"Sitecore.Mvc.Pipelines.Initialize.InitializeCommandRoute, Sitecore.Speak.Client"</span> <span class="hljs-attr">patch:before</span>=<span class="hljs-string">"processor[@type='Sitecore.Mvc.Pipelines.Loader.InitializeRoutes, Sitecore.Mvc']"</span>/&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">initialize</span>&gt;</span>
</code></pre>
<p>This processor registers the following routes:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">RegisterRoutes</span>(<span class="hljs-params">RouteCollection routes, PipelineArgs args</span>)</span>
{
    <span class="hljs-keyword">string</span> commandRoutePrefix = SpeakSettings.Mvc.CommandRoutePrefix;
    routes.MapRoute(<span class="hljs-string">"Sitecore.Speak.Commands"</span>, commandRoutePrefix + <span class="hljs-string">"{controller}/{action}"</span>);
    routes.MapRoute(<span class="hljs-string">"Sitecore.Speak"</span>, <span class="hljs-string">"sitecore/shell/api/sitecore/{controller}/{action}"</span>);
}
</code></pre>
<p>So when you delete/disable this config file, those routes do no longer get registered.</p>
<h2 id="heading-how-to-fix-it">How to fix it</h2>
<p>It's pretty simple to fix. You just have to add a route containing the <code>{controller}/{action}</code> pattern in your own processor in the <code>initialize</code> pipeline.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Something like this</span>
RouteTable.Routes.MapRoute(
    <span class="hljs-string">"Bogus-Required-Route"</span>,
    <span class="hljs-string">"bogus-required-route/{controller}/{action}"</span>,
);
</code></pre>
<p>I'm not sure if the route would overwrite Sitecore's route handling, so to be sure I would use a distinct path for the route that you are sure to never match a page URL for your site.</p>
<p>If you want to prevent the <strong>action method</strong> from being invoked as a result of  a user request you can add the <code>[ChildActionOnly]</code> attribute to it.</p>
<h2 id="heading-the-config-enable-disable-spreadsheet">The Config Enable-Disable spreadsheet</h2>
<p>If for some reason, like me, you can never find the download link for the <strong>Config Enable-Disable spreadsheet</strong>, then you can find them on <a target="_blank" href="https://doc.sitecore.net/sitecore_experience_platform/setting_up__maintaining/xdb/configuring_servers/configure_a_content_delivery_server">this page</a>.
 </p>
]]></content:encoded></item><item><title><![CDATA[Infinite loop with language fallback and non-standard named standard values item]]></title><description><![CDATA[Enable item-level language fallback and have a non-standard named __Standard Values item and you're going to have bad time - specifically a StackOverflowException. Those are notoriously hard to troubleshoot. Trust me...
Apparently the name of the sta...]]></description><link>https://blog.krusen.dk/infinite-loop-with-language-fallback-and-standard-values</link><guid isPermaLink="true">https://blog.krusen.dk/infinite-loop-with-language-fallback-and-standard-values</guid><dc:creator><![CDATA[Søren Kruse]]></dc:creator><pubDate>Fri, 27 Jan 2017 07:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1653484457653/jkjb5GAj6.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[
<p>Enable item-level language fallback and have a <strong>non-standard named</strong> <code>__Standard Values</code> item and you're going to have bad time - specifically a <code>StackOverflowException</code>. Those are <strong>notoriously hard</strong> to troubleshoot. Trust me...</p>
<p>Apparently the name of the standard values item, <code>__Standard Values</code>, is <strong>hardcoded</strong> inside <strong>Sitecore</strong> in several places - which makes sense as the item isn't otherwise discernible.</p>
<p>When <strong>item-level language fallback</strong> is enabled and you try to retrieve an item, it checks if item fallback is enabled on the <strong>item itself</strong> (checkbox field, part of the standard fields).</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">bool</span> <span class="hljs-title">IsItemFallbackEnabled</span>(<span class="hljs-params">Item item</span>)</span>
{
    <span class="hljs-keyword">if</span> (item == <span class="hljs-literal">null</span>)
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;

    <span class="hljs-keyword">if</span> (StandardValuesManager.IsStandardValuesHolder(item))
        <span class="hljs-keyword">return</span> item.Fields[FieldIDs.EnableItemFallback].GetValue(<span class="hljs-literal">false</span>) == <span class="hljs-string">"1"</span>;

    <span class="hljs-keyword">using</span> (<span class="hljs-keyword">new</span> LanguageFallbackItemSwitcher(<span class="hljs-keyword">new</span> <span class="hljs-keyword">bool</span>?(<span class="hljs-literal">false</span>))) 
    {
        <span class="hljs-keyword">return</span> item.Fields[FieldIDs.EnableItemFallback].GetValue(<span class="hljs-literal">true</span>, <span class="hljs-literal">true</span>, <span class="hljs-literal">false</span>) == <span class="hljs-string">"1"</span>;
    }
}
</code></pre>
<p>The call to <code>StandardValuesManager.IsStandardValuesHolder(item)</code> ends up doing this check:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">return</span> item.Name.Equals(<span class="hljs-string">"__Standard Values"</span>, StringComparison.OrdinalIgnoreCase);
</code></pre>
<p>So if the standard values item is <strong>not named exactly that</strong>, then it tries to get the field value again... and again... and again. You get the point.</p>
<p>This is probably not an issue you would run into very often, but it's always nice to be prepared. We ran into this issue with a client where we had installed an older version of the <a target="_blank" href="https://github.com/thecadams/301RedirectModule">301 Redirect Module</a> (version 1.3 if I remember correctly), which had standard values items with a hyphen instead of a space in the name - <code>__Standard-Values</code> instead of the correct <code>__Standard Values</code>.</p>
<p>You can no longer download version 1.3 and later versions do not have this problem. The module has also <strong>recently been updated</strong> with a lot of new features like <strong>Content Editor notifications</strong> and <strong>automatic generation of redirects</strong> when items are moved.</p>
<p>The inifinite loop issue has been reported to <strong>Sitecore Support</strong> and they have filed it as a bug with <strong>reference number 118166</strong>.
 </p>
]]></content:encoded></item></channel></rss>