<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://tech-fellow.eu/feed.xml" rel="self" type="application/atom+xml" /><link href="https://tech-fellow.eu/" rel="alternate" type="text/html" hreflang="en" /><updated>2025-02-02T22:47:33+02:00</updated><id>https://tech-fellow.eu/feed.xml</id><title type="html">Tech Fellow Blog</title><subtitle>wonders in IT world by technical fellow, web technologist</subtitle><entry><title type="html">Aspiring Optimizely</title><link href="https://tech-fellow.eu/2025/02/02/aspiring-optimizely/" rel="alternate" type="text/html" title="Aspiring Optimizely" /><published>2025-02-02T22:00:00+02:00</published><updated>2025-02-02T22:00:00+02:00</updated><id>https://tech-fellow.eu/2025/02/02/aspiring-optimizely</id><content type="html" xml:base="https://tech-fellow.eu/2025/02/02/aspiring-optimizely/"><![CDATA[<p>Adding .NET Aspire application host to your Optimizely project (even if it’s just for local development) is really a time-saver when it comes to setting up your local development environment, spinning up resources you need and tracing it during runtime.</p>

<p>You might ask - why do I need to add Aspire if I can just F5? True, but what is your SQL server strategy? How do you restore databases? How long it takes to setup environment on new machine?</p>

<p>Using Aspire hosting model - you save time for this all. Let’s dive into how to get started to add Aspire to you Optimizely project.</p>

<h2 id="adding-aspire">Adding Aspire</h2>

<p>Adding Aspire is as easy as create new project. I’ll use Visual Studio for this exercise.</p>

<ul>
  <li>first you need to open your Optimizely solution (I’ll use simple Alloy here targeted to <code class="language-plaintext highlighter-rouge">net8.0</code>)</li>
  <li>then you need to add new <strong>.NET Aspire Empty App</strong></li>
</ul>

<p><img src="/assets/img/2025/02/opti-aspire-1.png" alt="" /></p>

<ul>
  <li>Visual Studio will ask few questions</li>
  <li>then <code class="language-plaintext highlighter-rouge">*.AppHost</code> and <code class="language-plaintext highlighter-rouge">*.ServiceDefaults</code> projects should be added to your solution</li>
</ul>

<p><code class="language-plaintext highlighter-rouge">*.AppHost</code> is the actual startup project - host and orchestrator of the solution and <code class="language-plaintext highlighter-rouge">*.ServiceDefaults</code> is utility project which we gonna need to modify a bit to fit Optimizely setup.</p>

<h2 id="adding-sql-server">Adding SQL Server</h2>

<p>Now when we have application host, we can start adding dependency projects and/or services to our distributed application (Aspire calls it distributed - as it makes sense in the context when you are running multiple services for your solution at the same time).</p>

<ul>
  <li>first we need to add SQL Server NuGet package reference to Aspire host project</li>
</ul>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;PackageReference</span> <span class="na">Include=</span><span class="s">"Aspire.Hosting.SqlServer"</span> <span class="na">Version=</span><span class="s">"9.0.0"</span> <span class="nt">/&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This NuGet package ensures that we are able now to add SQL Server to our host.</p>

<ul>
  <li>now in <code class="language-plaintext highlighter-rouge">Program.cs</code> file we can add SQL Server as dependency for our host</li>
</ul>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="n">DistributedApplication</span><span class="p">.</span><span class="nf">CreateBuilder</span><span class="p">(</span><span class="n">args</span><span class="p">);</span>

<span class="kt">var</span> <span class="n">sql</span> <span class="p">=</span> <span class="n">builder</span>
    <span class="p">.</span><span class="nf">AddSqlServer</span><span class="p">(</span><span class="s">"alloy-sql"</span><span class="p">)</span>
    <span class="c1">// Configure the container to store data in a volume so that it persists across instances.</span>
    <span class="p">.</span><span class="nf">WithDataVolume</span><span class="p">()</span>
    <span class="p">.</span><span class="nf">WithLifetime</span><span class="p">(</span><span class="n">ContainerLifetime</span><span class="p">.</span><span class="n">Persistent</span><span class="p">);</span>

<span class="kt">var</span> <span class="n">db</span> <span class="p">=</span> <span class="n">sql</span><span class="p">.</span><span class="nf">AddDatabase</span><span class="p">(</span><span class="s">"EPiServerDB"</span><span class="p">,</span> <span class="n">databaseName</span><span class="p">:</span> <span class="s">"alloy-db-cms"</span><span class="p">);</span>

<span class="k">await</span> <span class="n">builder</span><span class="p">.</span><span class="nf">Build</span><span class="p">().</span><span class="nf">RunAsync</span><span class="p">();</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>To save even more time as you can see - I set server to <code class="language-plaintext highlighter-rouge">.WithLifetime(ContainerLifetime.Persistent)</code>. This is instructing Aspire not to kill Docker container and delete image, but preserve SQL Server instance across app launches.</p>

<p>Theoretically we are able to run our Aspire solution and see that SQL Server is started automatically and mapped to the solution.</p>

<p><img src="/assets/img/2025/02/opti-aspire-2.png" alt="" /></p>

<p>We can also check local Docker container list.</p>

<p><img src="/assets/img/2025/02/opti-aspire-3.png" alt="" /></p>

<p>However, connecting to SQL Server and checking databases, we can see that server is empty.</p>

<p><img src="/assets/img/2025/02/opti-aspire-4.png" alt="" /></p>

<p>Unfortunately SQL Server spin-up does not handle database creation automatically, so we gonna help Aspire here a bit.</p>

<h2 id="create-optimizely-cms-database-automatically">Create Optimizely CMS Database Automatically</h2>

<p>In order to create database automatically, we need couple scripts for our Docker image.</p>

<ul>
  <li>create new directory in <code class="language-plaintext highlighter-rouge">*.AppHost</code> project called <code class="language-plaintext highlighter-rouge">/sqlserverconfig</code> in project’s root directory</li>
  <li>mount that directory to the image with</li>
</ul>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="c1">// SQL doesn't support any auto-creation of databases or running scripts on startup so we have to do it manually.</span>
<span class="kt">var</span> <span class="n">sql</span> <span class="p">=</span> <span class="n">builder</span>
    <span class="p">.</span><span class="nf">AddSqlServer</span><span class="p">(</span><span class="s">"alloy-sql"</span><span class="p">)</span>
    <span class="c1">// Mount the init scripts directory into the container.</span>
    <span class="p">.</span><span class="nf">WithBindMount</span><span class="p">(</span><span class="s">@".\sqlserverconfig"</span><span class="p">,</span> <span class="s">"/usr/config"</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>create <code class="language-plaintext highlighter-rouge">entrypoint.sh</code> file in <code class="language-plaintext highlighter-rouge">/sqlserverconfig</code> directory which will execute database creation script</li>
</ul>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="c">#!/bin/bash</span>

<span class="c"># Start the script to create the DB and user</span>
/usr/config/configure-db.sh &amp;

<span class="c"># Start SQL Server</span>
/opt/mssql/bin/sqlservr
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>create <code class="language-plaintext highlighter-rouge">configure-db.sh</code> file in the same <code class="language-plaintext highlighter-rouge">/sqlserverconfig</code> directory</li>
</ul>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</pre></td><td class="rouge-code"><pre><span class="c">#!/bin/bash</span>

<span class="c"># set -x</span>

<span class="c"># Wait 120 seconds for SQL Server to start up by ensuring that</span>
<span class="c"># calling SQLCMD does not return an error code, which will ensure that sqlcmd is accessible</span>
<span class="c"># and that system and user databases return "0" which means all databases are in an "online" state</span>

<span class="nv">dbstatus</span><span class="o">=</span>1
<span class="nv">errcode</span><span class="o">=</span>1
<span class="nv">start_time</span><span class="o">=</span><span class="nv">$SECONDS</span>
<span class="nv">end_by</span><span class="o">=</span><span class="k">$((</span>start_time <span class="o">+</span> <span class="m">120</span><span class="k">))</span>

<span class="nb">echo</span> <span class="s2">"Starting check for SQL Server start-up at </span><span class="nv">$start_time</span><span class="s2">, will end at </span><span class="nv">$end_by</span><span class="s2">"</span>

<span class="k">while</span> <span class="o">[[</span> <span class="nv">$SECONDS</span> <span class="nt">-lt</span> <span class="nv">$end_by</span> <span class="o">&amp;&amp;</span> <span class="o">(</span> <span class="nv">$errcode</span> <span class="nt">-ne</span> 0 <span class="o">||</span> <span class="o">(</span> <span class="nt">-z</span> <span class="s2">"</span><span class="nv">$dbstatus</span><span class="s2">"</span> <span class="o">||</span> <span class="nv">$dbstatus</span> <span class="nt">-ne</span> 0 <span class="o">)</span> <span class="o">)</span> <span class="o">]]</span><span class="p">;</span> <span class="k">do
    </span><span class="nv">dbstatus</span><span class="o">=</span><span class="s2">"</span><span class="si">$(</span>/opt/mssql-tools/bin/sqlcmd <span class="nt">-h</span> <span class="nt">-1</span> <span class="nt">-t</span> 1 <span class="nt">-U</span> sa <span class="nt">-P</span> <span class="s2">"</span><span class="nv">$MSSQL_SA_PASSWORD</span><span class="s2">"</span> <span class="nt">-C</span> <span class="nt">-Q</span> <span class="s2">"SET NOCOUNT ON; Select SUM(state) from sys.databases"</span><span class="si">)</span><span class="s2">"</span>
    <span class="nv">errcode</span><span class="o">=</span><span class="nv">$?</span>
    <span class="nb">sleep </span>1
<span class="k">done

</span><span class="nv">elapsed_time</span><span class="o">=</span><span class="k">$((</span>SECONDS <span class="o">-</span> start_time<span class="k">))</span>
<span class="nb">echo</span> <span class="s2">"Stopped checking for SQL Server start-up after </span><span class="nv">$elapsed_time</span><span class="s2"> seconds (dbstatus=</span><span class="nv">$dbstatus</span><span class="s2">,errcode=</span><span class="nv">$errcode</span><span class="s2">,seconds=</span><span class="nv">$SECONDS</span><span class="s2">)"</span>

<span class="k">if</span> <span class="o">[[</span> <span class="nv">$dbstatus</span> <span class="nt">-ne</span> 0 <span class="o">]]</span> <span class="o">||</span> <span class="o">[[</span> <span class="nv">$errcode</span> <span class="nt">-ne</span> 0 <span class="o">]]</span><span class="p">;</span> <span class="k">then
    </span><span class="nb">echo</span> <span class="s2">"SQL Server took more than 120 seconds to start up or one or more databases are not in an ONLINE state"</span>
    <span class="nb">echo</span> <span class="s2">"dbstatus = </span><span class="nv">$dbstatus</span><span class="s2">"</span>
    <span class="nb">echo</span> <span class="s2">"errcode = </span><span class="nv">$errcode</span><span class="s2">"</span>
    <span class="nb">exit </span>1
<span class="k">fi</span>

<span class="c"># Loop through the .sql files in the /docker-entrypoint-initdb.d and execute them with sqlcmd</span>
<span class="k">for </span>f <span class="k">in</span> /docker-entrypoint-initdb.d/<span class="k">*</span>.sql
<span class="k">do
    </span><span class="nb">echo</span> <span class="s2">"Processing </span><span class="nv">$f</span><span class="s2"> file..."</span>
    /opt/mssql-tools/bin/sqlcmd <span class="nt">-S</span> localhost <span class="nt">-U</span> sa <span class="nt">-P</span> <span class="s2">"</span><span class="nv">$MSSQL_SA_PASSWORD</span><span class="s2">"</span> <span class="nt">-C</span> <span class="nt">-d</span> master <span class="nt">-i</span> <span class="s2">"</span><span class="nv">$f</span><span class="s2">"</span>
<span class="k">done</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This script basically ensures that SQL Server is up &amp; running and will execute all script files in <code class="language-plaintext highlighter-rouge">/docker-entrypoint-initdb.d/</code> directory in the image (which we gonna bind just in a moment)</p>

<ul>
  <li>add this script to the Docker image</li>
</ul>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">sql</span> <span class="p">=</span> <span class="n">builder</span>
    <span class="p">.</span><span class="nf">AddSqlServer</span><span class="p">(</span><span class="s">"alloy-sql"</span><span class="p">)</span>
    <span class="c1">// Mount the init scripts directory into the container.</span>
    <span class="p">.</span><span class="nf">WithBindMount</span><span class="p">(</span><span class="s">@".\sqlserverconfig"</span><span class="p">,</span> <span class="s">"/usr/config"</span><span class="p">)</span>
    <span class="c1">// Run the custom entrypoint script on startup.</span>
    <span class="p">.</span><span class="nf">WithEntrypoint</span><span class="p">(</span><span class="s">"/usr/config/entrypoint.sh"</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>create new directory <code class="language-plaintext highlighter-rouge">/App_Data/sqlserver</code> in in your Alloy CMS project</li>
  <li>create new file <code class="language-plaintext highlighter-rouge">init.sql</code> in that <code class="language-plaintext highlighter-rouge">/App_Data/sqlserver</code> directory</li>
</ul>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="c1">-- SQL Server init script</span>

<span class="c1">-- Create the AddressBook database</span>
<span class="n">IF</span> <span class="k">NOT</span> <span class="k">EXISTS</span> <span class="p">(</span><span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">sys</span><span class="p">.</span><span class="n">databases</span> <span class="k">WHERE</span> <span class="n">name</span> <span class="o">=</span> <span class="n">N</span><span class="s1">'alloy-db-cms'</span><span class="p">)</span>
<span class="k">BEGIN</span>
  <span class="k">CREATE</span> <span class="k">DATABASE</span> <span class="p">[</span><span class="n">alloy</span><span class="o">-</span><span class="n">db</span><span class="o">-</span><span class="n">cms</span><span class="p">];</span>
<span class="k">END</span><span class="p">;</span>
<span class="k">GO</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>and finally we need to add directory to Docker image</li>
</ul>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">sql</span> <span class="p">=</span> <span class="n">builder</span>
    <span class="p">.</span><span class="nf">AddSqlServer</span><span class="p">(</span><span class="s">"alloy-sql"</span><span class="p">)</span>
    <span class="c1">// Mount the init scripts directory into the container.</span>
    <span class="p">.</span><span class="nf">WithBindMount</span><span class="p">(</span><span class="s">@".\sqlserverconfig"</span><span class="p">,</span> <span class="s">"/usr/config"</span><span class="p">)</span>
    <span class="c1">// Mount the SQL scripts directory into the container so that the init scripts run.</span>
    <span class="p">.</span><span class="nf">WithBindMount</span><span class="p">(</span><span class="s">@"..\..\AlloyCms12New\App_Data\sqlserver"</span><span class="p">,</span> <span class="s">"/docker-entrypoint-initdb.d"</span><span class="p">)</span>
    <span class="c1">// Run the custom entrypoint script on startup.</span>
    <span class="p">.</span><span class="nf">WithEntrypoint</span><span class="p">(</span><span class="s">"/usr/config/entrypoint.sh"</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Overall file structure is following:</p>

<p><img src="/assets/img/2025/02/opti-aspire-5.png" alt="" /></p>

<p>Full SQL Server setup code:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="c1">// SQL doesn't support any auto-creation of databases or running scripts on startup so we have to do it manually.</span>
<span class="kt">var</span> <span class="n">sql</span> <span class="p">=</span> <span class="n">builder</span>
    <span class="p">.</span><span class="nf">AddSqlServer</span><span class="p">(</span><span class="s">"alloy-sql"</span><span class="p">)</span>
    <span class="c1">// Mount the init scripts directory into the container.</span>
    <span class="p">.</span><span class="nf">WithBindMount</span><span class="p">(</span><span class="s">@".\sqlserverconfig"</span><span class="p">,</span> <span class="s">"/usr/config"</span><span class="p">)</span>
    <span class="c1">// Mount the SQL scripts directory into the container so that the init scripts run.</span>
    <span class="p">.</span><span class="nf">WithBindMount</span><span class="p">(</span><span class="s">@"..\..\AlloyCms12New\App_Data\sqlserver"</span><span class="p">,</span> <span class="s">"/docker-entrypoint-initdb.d"</span><span class="p">)</span>
    <span class="c1">// Run the custom entrypoint script on startup.</span>
    <span class="p">.</span><span class="nf">WithEntrypoint</span><span class="p">(</span><span class="s">"/usr/config/entrypoint.sh"</span><span class="p">)</span>
    <span class="c1">// Configure the container to store data in a volume so that it persists across instances.</span>
    <span class="p">.</span><span class="nf">WithDataVolume</span><span class="p">()</span>
    <span class="p">.</span><span class="nf">WithLifetime</span><span class="p">(</span><span class="n">ContainerLifetime</span><span class="p">.</span><span class="n">Persistent</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now when we run the <code class="language-plaintext highlighter-rouge">*.AppHost</code> again - database named <code class="language-plaintext highlighter-rouge">alloy-cms-db</code> is automatically created.</p>

<p><img src="/assets/img/2025/02/opti-aspire-6.png" alt="" /></p>

<h2 id="adding-alloy-cms-project">Adding Alloy CMS Project</h2>

<p>Now we are ready to add Alloy CMS project to our Aspire host.
This is much easier than it sounds.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">db</span> <span class="p">=</span> <span class="n">sql</span><span class="p">.</span><span class="nf">AddDatabase</span><span class="p">(</span><span class="s">"EPiServerDB"</span><span class="p">,</span> <span class="n">databaseName</span><span class="p">:</span> <span class="s">"alloy-db-cms"</span><span class="p">);</span>
<span class="n">builder</span>
    <span class="p">.</span><span class="nf">AddProject</span><span class="p">(</span><span class="s">"alloy-cms"</span><span class="p">,</span> <span class="s">@"..\..\AlloyCms12New\AlloyCms12New.csproj"</span><span class="p">)</span>
    <span class="p">.</span><span class="nf">WithReference</span><span class="p">(</span><span class="n">db</span><span class="p">)</span>
    <span class="p">.</span><span class="nf">WaitFor</span><span class="p">(</span><span class="n">db</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Let’s build everything and run the host.</p>

<p><img src="/assets/img/2025/02/opti-aspire-7.png" alt="" /></p>

<p>As you can see - Alloy is up &amp; running and part of our distributed solution.</p>

<p>We are also able to see console logs as part of Aspire Dashboard.</p>

<p><img src="/assets/img/2025/02/opti-aspire-8.png" alt="" /></p>

<p>However, structured logs, traces and metrics are not found for this app.</p>

<p><img src="/assets/img/2025/02/opti-aspire-9.png" alt="" /></p>

<p>Now we need to do some tricks in ServiceDefaults project which was added by Aspire project template.</p>

<h2 id="adding-logging-and-tracing-via-service-defaults">Adding Logging and Tracing (via Service Defaults)</h2>

<p>If you check <code class="language-plaintext highlighter-rouge">*.ServiceDefaults</code> project you will see that all the extension methods to add logging and other magic to the project is for <code class="language-plaintext highlighter-rouge">IHostApplicationBuilder</code> which basically is <code class="language-plaintext highlighter-rouge">Microsoft.AspNetCore.Builder.WebApplicationBuilder</code>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="n">TBuilder</span> <span class="n">AddServiceDefaults</span><span class="p">&lt;</span><span class="n">TBuilder</span><span class="p">&gt;(</span><span class="k">this</span> <span class="n">TBuilder</span> <span class="n">builder</span><span class="p">)</span>
    <span class="k">where</span> <span class="n">TBuilder</span> <span class="p">:</span> <span class="n">IHostApplicationBuilder</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You can have access to this object when you are building web application using</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="n">WebApplication</span><span class="p">.</span><span class="nf">CreateBuilder</span><span class="p">(</span><span class="n">args</span><span class="p">);</span>
<span class="p">...</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>However, by default Optimizely is using older model - <code class="language-plaintext highlighter-rouge">Microsoft.Extensions.Hosting.IHostBuilder</code>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">Program</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">Main</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">args</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nf">CreateHostBuilder</span><span class="p">(</span><span class="n">args</span><span class="p">).</span><span class="nf">Build</span><span class="p">().</span><span class="nf">Run</span><span class="p">();</span>

    <span class="k">public</span> <span class="k">static</span> <span class="n">IHostBuilder</span> <span class="nf">CreateHostBuilder</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">args</span><span class="p">)</span> <span class="p">=&gt;</span>
        <span class="n">Host</span><span class="p">.</span><span class="nf">CreateDefaultBuilder</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
            <span class="p">.</span><span class="nf">ConfigureCmsDefaults</span><span class="p">()</span>
            <span class="p">.</span><span class="nf">ConfigureWebHostDefaults</span><span class="p">(</span><span class="n">webBuilder</span> <span class="p">=&gt;</span> <span class="n">webBuilder</span><span class="p">.</span><span class="n">UseStartup</span><span class="p">&lt;</span><span class="n">Startup</span><span class="p">&gt;());</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Using new hosting model is still work-in-progress and <a href="https://world.optimizely.com/forum/developer-forum/cms-12/thread-container/2022/5/-net-6-new-minimal-hosting-model-with-cms-12-giving-exception-at-startup/">not yet fully supported by Optimizely</a>.</p>

<p>Actually all it does is accessing <code class="language-plaintext highlighter-rouge">builder.Services</code> and configuring logging for the host.
We would need to do a bit of black magic for ServiceDefaults to get the same stuff into older hosting model.</p>

<ul>
  <li>create a copy of <code class="language-plaintext highlighter-rouge">Extensions.cs</code> file (I chose the most creative name I could figure out - <code class="language-plaintext highlighter-rouge">Extensions2.cs</code>).</li>
  <li>modify <code class="language-plaintext highlighter-rouge">AddServiceDefaults</code> method to extend <code class="language-plaintext highlighter-rouge">IServiceCollection services</code> instead of <code class="language-plaintext highlighter-rouge">TBuilder builder</code> (we also gonna need <code class="language-plaintext highlighter-rouge">IConfiguration</code> and <code class="language-plaintext highlighter-rouge">applicationName</code> as well)</li>
</ul>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="n">IServiceCollection</span> <span class="nf">AddServiceDefaults</span><span class="p">(</span><span class="k">this</span> <span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">,</span> <span class="n">IConfiguration</span> <span class="n">configuration</span><span class="p">,</span> <span class="kt">string</span> <span class="n">applicationName</span><span class="p">)</span>
<span class="p">{</span>
    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>fix compilation errors - instead of <code class="language-plaintext highlighter-rouge">builder.Service.</code> use <code class="language-plaintext highlighter-rouge">services.</code></li>
  <li>do the same changes for the rest of the methods</li>
  <li>use <code class="language-plaintext highlighter-rouge">applicationName</code> parameter in <code class="language-plaintext highlighter-rouge">ConfigureOpenTelemetry</code> method to configure tracing</li>
  <li>add <code class="language-plaintext highlighter-rouge">*.ServiceDefaults</code> project reference to AlloyCms project</li>
</ul>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>  <span class="nt">&lt;ItemGroup&gt;</span>
    <span class="nt">&lt;ProjectReference</span> <span class="na">Include=</span><span class="s">"..\AspireApp1\AspireApp1.ServiceDefaults\AspireApp1.ServiceDefaults.csproj"</span> <span class="nt">/&gt;</span>
  <span class="nt">&lt;/ItemGroup&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>inject <code class="language-plaintext highlighter-rouge">IConfiguration</code> in <code class="language-plaintext highlighter-rouge">Startup.cs</code></li>
</ul>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">Startup</span><span class="p">(</span><span class="n">IWebHostEnvironment</span> <span class="n">webHostingEnvironment</span><span class="p">,</span> <span class="n">IConfiguration</span> <span class="n">configuration</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>use service defaults to configure tracing and metrics for AlloyCms project</li>
</ul>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre>    <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="p">...</span>

        <span class="n">services</span><span class="p">.</span><span class="nf">AddServiceDefaults</span><span class="p">(</span><span class="n">configuration</span><span class="p">,</span> <span class="n">webHostingEnvironment</span><span class="p">.</span><span class="n">ApplicationName</span><span class="p">);</span>
    <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>and lastly configure logging for AlloyCms project (in <code class="language-plaintext highlighter-rouge">Program.cs</code> file)</li>
</ul>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="n">IHostBuilder</span> <span class="nf">CreateHostBuilder</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">args</span><span class="p">)</span> <span class="p">=&gt;</span>
    <span class="n">Host</span><span class="p">.</span><span class="nf">CreateDefaultBuilder</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">ConfigureCmsDefaults</span><span class="p">()</span>
        <span class="p">.</span><span class="nf">ConfigureLogging</span><span class="p">(</span><span class="n">builder</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="n">builder</span><span class="p">.</span><span class="nf">AddOpenTelemetry</span><span class="p">(</span><span class="n">logging</span> <span class="p">=&gt;</span>
            <span class="p">{</span>
                <span class="n">logging</span><span class="p">.</span><span class="n">IncludeFormattedMessage</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
                <span class="n">logging</span><span class="p">.</span><span class="n">IncludeScopes</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
            <span class="p">});</span>
        <span class="p">})</span>
        <span class="p">.</span><span class="nf">ConfigureWebHostDefaults</span><span class="p">(</span><span class="n">webBuilder</span> <span class="p">=&gt;</span> <span class="n">webBuilder</span><span class="p">.</span><span class="n">UseStartup</span><span class="p">&lt;</span><span class="n">Startup</span><span class="p">&gt;());</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="running-the-orchestrator">Running the Orchestrator</h2>

<p>Now we are able to run Alloy again and enjoy logging and tracing in Aspire Dashboard.</p>

<p><img src="/assets/img/2025/02/opti-aspire-10.png" alt="" /></p>

<p>We can also check out traces and structured logging.</p>

<p><img src="/assets/img/2025/02/opti-aspire-11.png" alt="" /></p>

<h2 id="checkout-the-source-code">Checkout the Source Code</h2>

<p>If you got lost in source code modification exercise - you can also checkout <a href="https://github.com/valdisiljuconoks/aspiring-optimizely">reference project</a> for any hints you may need.</p>

<p>Happy asping!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Aspire" /><category term="Optimizely" /><category term="Episerver" /><category term=".net" /><category term="c#" /><category term="aspire" /><category term="optimizely" /><category term="episerver" /><summary type="html"><![CDATA[Adding .NET Aspire application host to your Optimizely project (even if it’s just for local development) is really a time-saver when it comes to setting up your local development environment, spinning up resources you need and tracing it during runtime.]]></summary></entry><entry><title type="html">How to fix Azure.RequestFailedException - One of the request inputs is not valid. exception</title><link href="https://tech-fellow.eu/2024/04/21/azure-storage-one-of-inputs-is-not-valid/" rel="alternate" type="text/html" title="How to fix Azure.RequestFailedException - One of the request inputs is not valid. exception" /><published>2024-04-21T18:00:00+03:00</published><updated>2024-04-21T18:00:00+03:00</updated><id>https://tech-fellow.eu/2024/04/21/azure-storage-one-of-inputs-is-not-valid</id><content type="html" xml:base="https://tech-fellow.eu/2024/04/21/azure-storage-one-of-inputs-is-not-valid/"><![CDATA[<p>When you are working on APIs and want to secure access by using well-known header field names:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">HttpGet</span><span class="p">]</span>
<span class="p">[</span><span class="nf">Route</span><span class="p">(</span><span class="s">"verify-token"</span><span class="p">)]</span>
<span class="p">[</span><span class="nf">Produces</span><span class="p">(</span><span class="s">"application/json"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">ActionResult</span><span class="p">&gt;</span> <span class="nf">VerifyToken</span><span class="p">(</span>
    <span class="p">[</span><span class="nf">FromHeader</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"Authorization"</span><span class="p">)]</span> <span class="kt">string</span><span class="p">?</span> <span class="n">token</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">t</span> <span class="p">=</span> <span class="k">await</span> <span class="n">accessTokenRepository</span><span class="p">.</span><span class="nf">GetByTokenValueAsync</span><span class="p">(</span><span class="n">token</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">t</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="nf">Unauthorized</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="nf">Ok</span><span class="p">();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>From fist sight it might look like innocent API access control mechanism - get the token value from the header, verify against the storage - if not found, fail.</p>

<p>Code that looks for the token in storage is nothing fancy:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">AccessTokenEntity</span><span class="p">&gt;</span> <span class="nf">GetEntityByValueAsync</span><span class="p">(</span><span class="kt">string</span> <span class="k">value</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">query</span> <span class="p">=</span> <span class="nf">CreateTokenByValueFilter</span><span class="p">(</span><span class="k">value</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">client</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">GetTable</span><span class="p">();</span>
    <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="k">await</span> <span class="n">client</span><span class="p">.</span><span class="n">ExecuteQueryAsync</span><span class="p">&lt;</span><span class="n">AccessTokenEntity</span><span class="p">&gt;(</span><span class="n">query</span><span class="p">);</span>

    <span class="k">return</span> <span class="n">result</span><span class="p">.</span><span class="nf">FirstOrDefault</span><span class="p">();</span>
<span class="p">}</span>

<span class="k">private</span> <span class="k">static</span> <span class="kt">string</span> <span class="nf">CreateTokenByValueFilter</span><span class="p">(</span><span class="kt">string</span> <span class="k">value</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="n">TableClient</span><span class="p">.</span><span class="n">CreateQueryFilter</span><span class="p">&lt;</span><span class="n">AccessTokenEntity</span><span class="p">&gt;(</span>
        <span class="n">e</span> <span class="p">=&gt;</span> <span class="n">e</span><span class="p">.</span><span class="n">PartitionKey</span> <span class="p">==</span> <span class="n">AccessTokenEntity</span><span class="p">.</span><span class="n">PartitionKeyValue</span> <span class="p">&amp;&amp;</span> <span class="n">e</span><span class="p">.</span><span class="n">Token</span> <span class="p">==</span> <span class="k">value</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Even if you run your sample code locally against Azure Storage Emulator (aka <a href="https://learn.microsoft.com/en-us/azure/storage/common/storage-use-azurite?tabs=visual-studio%2Cblob-storage">azurite</a>) - everything might be working perfectly.</p>

<p>However, when you do deploy to actual Azure environment (or point your local environment to Azure Storage services) - you most probably will hit exception along these lines:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
</pre></td><td class="rouge-code"><pre>2024-04-19 12:24:04.473 +00:00 [ERR] Connection ID "....", Request ID "....": An unhandled exception was thrown by the application.
Azure.RequestFailedException: One of the request inputs is not valid.
RequestId:.....
Time:2024-04-19T12:24:04.4525536Z
Status: 400 (Bad Request)
ErrorCode: InvalidInput

Content:
{"odata.error":{"code":"InvalidInput","message":{"lang":"en-US","value":"One of the request inputs is not valid.\nRequestId:...\nTime:2024-04-19T12:24:04.4525536Z"}}}

Headers:
Cache-Control: no-cache
Transfer-Encoding: chunked
Server: Windows-Azure-Table/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: ...
x-ms-client-request-id: ...
x-ms-version: REDACTED
X-Content-Type-Options: REDACTED
Date: Fri, 19 Apr 2024 12:24:04 GMT
Content-Type: application/json;odata=minimalmetadata;streaming=true;charset=utf-8

   at Azure.Data.Tables.TableRestClient.QueryEntitiesAsync(String table, Nullable`1 timeout, String nextPartitionKey, String nextRowKey, QueryOptions queryOptions, CancellationToken cancellationToken)
   at Azure.Data.Tables.TableClient.&lt;&gt;c__DisplayClass55_0`1.&lt;&lt;QueryAsync&gt;b__0&gt;d.MoveNext()
--- End of stack trace from previous location ---
   at Azure.Core.PageableHelpers.FuncAsyncPageable`1.AsPages(String continuationToken, Nullable`1 pageSizeHint)+MoveNext()
   at Azure.Core.PageableHelpers.FuncAsyncPageable`1.AsPages(String continuationToken, Nullable`1 pageSizeHint)+System.Threading.Tasks.Sources.IValueTaskSource&lt;System.Boolean&gt;.GetResult()
   ...
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="the-solution">The Solution</h2>

<p>I did not capture network traffic and did not analyze it (as I assume that outgoing request might be the same as running locally), but removing header binding and receiving token value by url:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">HttpGet</span><span class="p">]</span>
<span class="p">[</span><span class="nf">Route</span><span class="p">(</span><span class="s">"verify-token"</span><span class="p">)]</span>
<span class="p">[</span><span class="nf">Produces</span><span class="p">(</span><span class="s">"application/json"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">ActionResult</span><span class="p">&gt;</span> <span class="nf">VerifyToken</span><span class="p">(</span><span class="kt">string</span><span class="p">?</span> <span class="n">token</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">t</span> <span class="p">=</span> <span class="k">await</span> <span class="n">accessTokenRepository</span><span class="p">.</span><span class="nf">GetByTokenValueAsync</span><span class="p">(</span><span class="n">token</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">t</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="nf">Unauthorized</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="nf">Ok</span><span class="p">();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>or binding to another header field:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">HttpGet</span><span class="p">]</span>
<span class="p">[</span><span class="nf">Route</span><span class="p">(</span><span class="s">"verify-token"</span><span class="p">)]</span>
<span class="p">[</span><span class="nf">Produces</span><span class="p">(</span><span class="s">"application/json"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">ActionResult</span><span class="p">&gt;</span> <span class="nf">VerifyToken</span><span class="p">(</span>
    <span class="p">[</span><span class="nf">FromHeader</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"Token"</span><span class="p">)]</span> <span class="kt">string</span><span class="p">?</span> <span class="n">token</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">t</span> <span class="p">=</span> <span class="k">await</span> <span class="n">accessTokenRepository</span><span class="p">.</span><span class="nf">GetByTokenValueAsync</span><span class="p">(</span><span class="n">token</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">t</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="nf">Unauthorized</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="nf">Ok</span><span class="p">();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>solves the problem.</p>

<p>I did not see that coming!</p>

<p>Happy coding!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="Azure" /><category term="Table Storage" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="azure" /><summary type="html"><![CDATA[When you are working on APIs and want to secure access by using well-known header field names:]]></summary></entry><entry><title type="html">Change Url Dynamically for GraphQL Client (Strawberry Shake)</title><link href="https://tech-fellow.eu/2024/04/08/strawberry-shake-change-url-dynamically/" rel="alternate" type="text/html" title="Change Url Dynamically for GraphQL Client (Strawberry Shake)" /><published>2024-04-08T15:00:00+03:00</published><updated>2024-04-08T15:00:00+03:00</updated><id>https://tech-fellow.eu/2024/04/08/strawberry-shake-change-url-dynamically</id><content type="html" xml:base="https://tech-fellow.eu/2024/04/08/strawberry-shake-change-url-dynamically/"><![CDATA[<p><a href="https://strawberry.rocks/">Strawberry client</a> package is a great library if you need to talk to some GraphQL endpoints.</p>

<p>Sometimes you need to decide of different endpoint address depending on some condition or even do it fully dynamically (during runtime per call).</p>

<p>So let’s assume that we have two different endpoint addresses that we would need to switch between depending on some condition.</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="p">{</span><span class="w">
    </span><span class="nl">"AppConfig"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"NormalEndpointBaseAddress"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://normal-server.com"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"DebugEndpointBaseAddress"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://debug-server.com"</span><span class="w">
    </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>In our case we had to switch between endpoints depending on incoming request parameters - one endpoint was used in “normal” and other in “debug” mode.
Mode switch is just a simple payload parameter in the request:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="p">{</span><span class="w">
    </span><span class="err">....</span><span class="w">
    </span><span class="nl">"isDebugMode"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>When you add Strawberry client to your service collection, it returns <code class="language-plaintext highlighter-rouge">IClientBuilder&lt;T&gt;</code> type which in turn has <code class="language-plaintext highlighter-rouge">ConfigureHttpClient()</code> extension:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="n">services</span>
    <span class="p">.</span><span class="nf">AddSomeGraphQLServiceClient</span><span class="p">()</span>        <span class="c1">// name of the method depends on the Strawberry config for your service</span>
    <span class="p">.</span><span class="nf">ConfigureHttpClient</span><span class="p">((</span><span class="n">provider</span><span class="p">,</span> <span class="n">client</span><span class="p">)</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
    <span class="p">});</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Inside <code class="language-plaintext highlighter-rouge">ConfigureHttpClient()</code> we can make a decision what endpoint base address will be.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="n">services</span>
    <span class="p">.</span><span class="nf">AddSomeGraphQLServiceClient</span><span class="p">()</span>
    <span class="p">.</span><span class="nf">ConfigureHttpClient</span><span class="p">((</span><span class="n">provider</span><span class="p">,</span> <span class="n">client</span><span class="p">)</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="c1">// if no one set the mode -&gt; running in normal mode</span>
        <span class="kt">var</span> <span class="n">isDebug</span> <span class="p">=</span> <span class="n">ContextProvider</span><span class="p">.</span><span class="nf">GetState</span><span class="p">()?.</span><span class="n">IsDebugMode</span> <span class="p">??</span> <span class="k">false</span><span class="p">;</span>
        <span class="kt">var</span> <span class="n">appConfig</span> <span class="p">=</span> <span class="n">provider</span><span class="p">.</span><span class="n">GetRequiredService</span><span class="p">&lt;</span><span class="n">IOptions</span><span class="p">&lt;</span><span class="n">AppConfig</span><span class="p">&gt;&gt;().</span><span class="n">Value</span><span class="p">;</span>

        <span class="n">client</span><span class="p">.</span><span class="n">BaseAddress</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">Uri</span><span class="p">(!</span><span class="n">isDebug</span> <span class="p">?</span> <span class="n">appConfig</span><span class="p">.</span><span class="n">NormalEndpointBaseAddress</span> <span class="p">:</span> <span class="n">appConfig</span><span class="p">.</span><span class="n">DebugEndpointBaseAddress</span><span class="p">);</span>
    <span class="p">});</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now we need to look inside <code class="language-plaintext highlighter-rouge">ContextProvider</code> and understand what is that.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">ContextProvider</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">static</span> <span class="k">readonly</span> <span class="n">AsyncLocal</span><span class="p">&lt;</span><span class="n">CustomExecutionContext</span><span class="p">&gt;</span> <span class="n">State</span> <span class="p">=</span> <span class="k">new</span><span class="p">();</span>

    <span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">SetDebugMode</span><span class="p">(</span><span class="kt">bool</span> <span class="n">state</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">State</span><span class="p">.</span><span class="n">Value</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">CustomExecutionContext</span><span class="p">(</span><span class="n">state</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">static</span> <span class="n">CustomExecutionContext</span><span class="p">?</span> <span class="nf">GetState</span><span class="p">()</span> <span class="p">=&gt;</span> <span class="n">State</span><span class="p">.</span><span class="n">Value</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">CustomExecutionContext</span><span class="p">(</span><span class="kt">bool</span> <span class="n">state</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">bool</span> <span class="n">IsDebugMode</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="n">state</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Key takeaway here is <code class="language-plaintext highlighter-rouge">AsyncLocal&lt;T&gt;</code> - it is a structure will survive async operations and will always point you to the correct instance of the custom execution context.</p>

<p>Next thing we can implement is action filter and detect is incoming request contains debug mode flag and set it accordingly.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="n">builder</span><span class="p">.</span><span class="n">Services</span>
    <span class="p">.</span><span class="nf">AddControllersWithViews</span><span class="p">(</span><span class="n">options</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">options</span><span class="p">.</span><span class="n">Filters</span><span class="p">.</span><span class="n">Add</span><span class="p">&lt;</span><span class="n">DebugModeDetectorFilter</span><span class="p">&gt;();</span>
    <span class="p">});</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And filter itself:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">DebugModeDetectorFilter</span> <span class="p">:</span> <span class="n">IActionFilter</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">OnActionExecuting</span><span class="p">(</span><span class="n">ActionExecutingContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">argument</span> <span class="k">in</span> <span class="n">context</span><span class="p">.</span><span class="n">ActionArguments</span><span class="p">.</span><span class="nf">Select</span><span class="p">(</span><span class="n">a</span> <span class="p">=&gt;</span> <span class="n">a</span><span class="p">.</span><span class="n">Value</span><span class="p">).</span><span class="nf">Where</span><span class="p">(</span><span class="n">v</span> <span class="p">=&gt;</span> <span class="n">v</span> <span class="k">is</span> <span class="n">BaseServiceRequestDto</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">argument</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="c1">// set debug mode in state - this will be used later in Strawberry HttpClient configuration to set correct service base address</span>
                <span class="n">ContextProvider</span><span class="p">.</span><span class="nf">SetDebugMode</span><span class="p">(((</span><span class="n">BaseServiceRequestDto</span><span class="p">)</span><span class="n">argument</span><span class="p">).</span><span class="n">IsDebugMode</span> <span class="p">??</span> <span class="k">false</span><span class="p">);</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">OnActionExecuted</span><span class="p">(</span><span class="n">ActionExecutedContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>In our solution every single request DTO object has base class <code class="language-plaintext highlighter-rouge">BaseServiceRequestDto</code> - then we can reuse the same common payload parameters for every single request if we need to.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">using</span> <span class="nn">TypeGen.Core.TypeAnnotations</span><span class="p">;</span>

<span class="p">[</span><span class="n">ExportTsInterface</span><span class="p">]</span>
<span class="k">public</span> <span class="k">abstract</span> <span class="k">class</span> <span class="nc">BaseServiceRequestDto</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">TsOptional</span><span class="p">]</span>
    <span class="k">public</span> <span class="kt">bool</span><span class="p">?</span> <span class="n">IsDebugMode</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>With this in place - now every time front-end will send in <code class="language-plaintext highlighter-rouge">isDebugMode: true</code> field - back-end will use <code class="language-plaintext highlighter-rouge">https://debug-server.com</code> as base address for GraphQL services.</p>

<p>Happy coding!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term=".net" /><category term="c#" /><category term="open source" /><summary type="html"><![CDATA[Strawberry client package is a great library if you need to talk to some GraphQL endpoints.]]></summary></entry><entry><title type="html">DbLocalizationProvider v8.0 Released</title><link href="https://tech-fellow.eu/2024/02/28/localization-provider-v8-released/" rel="alternate" type="text/html" title="DbLocalizationProvider v8.0 Released" /><published>2024-02-28T15:00:00+02:00</published><updated>2024-02-28T15:00:00+02:00</updated><id>https://tech-fellow.eu/2024/02/28/localization-provider-v8-released</id><content type="html" xml:base="https://tech-fellow.eu/2024/02/28/localization-provider-v8-released/"><![CDATA[<p>I’m pleased to announce that Localization Provider v8.0 is finally out.</p>

<p>Again - took a bit longer than expected :)</p>

<h2 id="whats-new">What’s new?</h2>

<ul>
  <li>.NET8 set as default target</li>
  <li>Added provider model for external translation services</li>
  <li>Various bug fixes</li>
  <li>Some performance improvements</li>
  <li><code class="language-plaintext highlighter-rouge">ConfigurationContext</code> now supports config configuration as well (you can change some settings after you have added and configured default settings for localization provider). This is very useful in unit test scenarios when you need to adjust some settings for specific test.</li>
  <li>Improved resource key comparison, gaining a bit of performance in hot paths</li>
  <li>Added pagination in Admin UI</li>
  <li>Security improvements (by default upgrading insecure connections)</li>
  <li>Dependencies upgrade</li>
</ul>

<h2 id="cloud-translator">Cloud Translator</h2>

<p>If your editors are having timing issues translating the content it’s now possible to add cloud based translators and leverage power of cloud.</p>

<p>Currently supported translators:</p>

<ul>
  <li>Azure <a href="https://learn.microsoft.com/en-us/azure/ai-services/translator/translator-overview">Cognitive Services</a></li>
  <li>Epicweb.Optimizely.AIAssistant. <a href="https://optimizely.blog/2025/01/introducing-ai-assistance-for-dblocalizationprovider/">More info here</a></li>
</ul>

<p>First you will need to install Azure Cognitive AI integration package:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>dotnet add package LocalizationProvider.Translator.Azure
</pre></td></tr></tbody></table></code></pre></div></div>

<p>To enable Microsoft Azure Cognitive Services as translator for Localization Provider follow these steps:</p>

<ul>
  <li>Create Cognitive Services instance in Azure</li>
  <li>Copy <strong>Access Key</strong> and <strong>Region</strong></li>
</ul>

<p><img src="/assets/img/2024/02/auto-translate-1.png" alt="" /></p>

<ul>
  <li>Add Azure Cognitive Services registration to your Localization Provider setup code:</li>
</ul>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">services</span><span class="p">.</span><span class="nf">AddDbLocalizationProvider</span><span class="p">(</span><span class="n">x</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">x</span><span class="p">.</span><span class="nf">UseAzureCognitiveServices</span><span class="p">(</span><span class="s">"{access-key}"</span><span class="p">,</span> <span class="s">"{region}"</span><span class="p">);</span>

        <span class="c1">// rest of the provider configuration...</span>
    <span class="p">});</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You should better read values from <code class="language-plaintext highlighter-rouge">appsettings.json</code> file or any other secure storage of your choice (like <a href="https://azure.microsoft.com/en-us/products/key-vault">Azure KeyVault</a>).</p>

<p>After you have configured cloud translator successfully, editors will have easy and fast way to translate resources with a magic wand.</p>

<p><img src="/assets/img/2024/02/auto-translate-2.png" alt="" /></p>

<h3 id="post-configuration">Post Configuration</h3>

<p>It is also possible to perform post configuration (after you have called <code class="language-plaintext highlighter-rouge">AddDbLocalizationProvider()</code>) of the localization provider.
This is useful when you are unit testing your web app, after Startup code is executed and you want to make sure that some post configuration settings are applied for your unit tests to execute correctly.</p>

<p><strong>NB!</strong> Please note, that it is <em>not</em> possible to configure any types, scanners or anything else that is added to the DI container during <code class="language-plaintext highlighter-rouge">AddDbLocalizationProvider()</code> call. This limitation is due to fact that types are added to DI container and post configuration is called afterwards (when <code class="language-plaintext highlighter-rouge">IServiceProvider</code> is already built).</p>

<p>To post configure localization provider you have to follow standard <a href="https://learn.microsoft.com/en-us/dotnet/core/extensions/options">.NET Options</a> pattern:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">Startup</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="p">...</span>

        <span class="n">services</span><span class="p">.</span><span class="nf">AddDbLocalizationProvider</span><span class="p">(</span><span class="n">cfg</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="p">...</span>
        <span class="p">});</span>

        <span class="c1">// post configuring provider</span>
        <span class="n">services</span><span class="p">.</span><span class="n">Configure</span><span class="p">&lt;</span><span class="n">ConfigurationContext</span><span class="p">&gt;(</span><span class="n">ctx</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="n">ctx</span><span class="p">.</span><span class="n">EnableInvariantCultureFallback</span> <span class="p">=</span> <span class="k">false</span><span class="p">;</span>
        <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="pagination-in-adminui">Pagination in AdminUI</h2>

<p>This feature should be turned on if you are experiencing performance issues in AdminUI (page load times, resource update times, etc).</p>

<p>To enable pagination - set <code class="language-plaintext highlighter-rouge">EnableDbSearch</code> to <code class="language-plaintext highlighter-rouge">true</code>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="n">services</span><span class="p">.</span><span class="nf">AddDbLocalizationProviderAdminUI</span><span class="p">(</span><span class="n">x</span> <span class="p">=&gt;</span>
<span class="p">{</span>
    <span class="c1">// enable "server-side" pagination</span>
    <span class="n">x</span><span class="p">.</span><span class="n">EnableDbSearch</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>

    <span class="c1">// optionally you can set number of resources</span>
    <span class="c1">// to return when pagination is enabled</span>
    <span class="n">x</span><span class="p">.</span><span class="n">PageSize</span> <span class="p">=</span> <span class="m">50</span><span class="p">;</span>

    <span class="c1">// rest of the configuration...</span>
<span class="p">});</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>When pagination is enabled, AdminUI by default will not load any resources. The only way to get resources in result - would be to execute search specifying any part of the resource key.</p>

<h2 id="contributing">Contributing</h2>

<p>IF you liked the library and want to make it even better - consider contributing. The best place to start is to checkout out <a href="https://github.com/valdisiljuconoks/LocalizationProvider/issues">the issue list</a> for the packages.</p>

<h2 id="got-idea">Got Idea?</h2>

<p>IF you got any idea how to improve  the library, or what features are you missing the most, consider leaving feedback on <a href="https://github.com/valdisiljuconoks/LocalizationProvider/issues">the issue list</a>.</p>

<p>As always - happy coding, happy localizing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="Localization" /><category term="Localization Provider" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization" /><category term="localization provider" /><summary type="html"><![CDATA[I’m pleased to announce that Localization Provider v8.0 is finally out.]]></summary></entry><entry><title type="html">New Day, New Start</title><link href="https://tech-fellow.eu/2024/01/01/new-day-new-start/" rel="alternate" type="text/html" title="New Day, New Start" /><published>2024-01-01T20:00:00+02:00</published><updated>2024-01-01T20:00:00+02:00</updated><id>https://tech-fellow.eu/2024/01/01/new-day-new-start</id><content type="html" xml:base="https://tech-fellow.eu/2024/01/01/new-day-new-start/"><![CDATA[<p>Starting with 2024 new year, I decided to move to another platform and another domain.</p>

<p>From now on I’ll be living on <a href="https://tech-fellow.eu">tech-fellow.eu</a> which is proudly powered by <a href="https://pages.github.com/">GitHub Pages</a>.</p>

<p>All the historical content is being moved over. I’ll do my best to update external links pointing to old site. If you come across any that do does not work, please DM me!</p>

<p>Many thanks and happy coding!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Blogging" /><category term="Personal" /><category term="blogging" /><category term="personal" /><summary type="html"><![CDATA[Starting with 2024 new year, I decided to move to another platform and another domain.]]></summary></entry><entry><title type="html">How to Build Interceptor with built-in Microsoft DI - IServiceProvider</title><link href="https://tech-fellow.eu/2023/04/05/interceptors-with-built-in-iservicecollection/" rel="alternate" type="text/html" title="How to Build Interceptor with built-in Microsoft DI - IServiceProvider" /><published>2023-04-05T15:00:00+03:00</published><updated>2023-04-05T15:00:00+03:00</updated><id>https://tech-fellow.eu/2023/04/05/interceptors-with-built-in-iservicecollection</id><content type="html" xml:base="https://tech-fellow.eu/2023/04/05/interceptors-with-built-in-iservicecollection/"><![CDATA[<p><strong>Service Interception</strong> is known as an altering process to make it look like service instance is delivered to the calling site by contract, but it could altered and totally another type might be hidden by the interface.</p>

<p>Interception of the services is not a built-in feature of ServiceProvider (aka Microsoft Dependency Injection framework).
However it’s quite simple to implement one yourself. This blog post describes how to implement one and use it.</p>

<h2 id="registration-api-prototype">Registration API Prototype</h2>
<p>Registration of the interceptor should be made when service collection is built. At this point service registrations is just a list of the service descriptors specifying implementing type, registered type, lifetime and other characteristics of the service.</p>

<p>Let’s start with prototype code how consumers would register interceptors in service collection:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="n">WebApplication</span><span class="p">.</span><span class="nf">CreateBuilder</span><span class="p">(</span><span class="n">args</span><span class="p">);</span>

<span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="n">AddTransient</span><span class="p">&lt;</span><span class="n">IEngine</span><span class="p">,</span> <span class="n">TheEngine</span><span class="p">&gt;();</span>
<span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="n">Intercept</span><span class="p">&lt;</span><span class="n">IEngine</span><span class="p">,</span> <span class="n">EngineWithTelemetry</span><span class="p">&gt;();</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This extension method should register new service interceptor - <code class="language-plaintext highlighter-rouge">EngineWithTelemetry</code> implementing <code class="language-plaintext highlighter-rouge">IEngine</code> interface and “behaving” according to the interface.</p>

<p>Whoever would request instance of <code class="language-plaintext highlighter-rouge">IEngine</code> would get <code class="language-plaintext highlighter-rouge">EngineWithTelemetry</code>.</p>

<p>Usually signature of the interceptor service constructor requires an instance of “intercepted” service (you can call it <code class="language-plaintext highlighter-rouge">inner</code> to make things more clear).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="nf">EngineWithTelemetry</span><span class="p">(</span><span class="n">IEngine</span> <span class="n">inner</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">_inner</span> <span class="p">=</span> <span class="n">inner</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now we have interceptor and intercepted services. What happens in interceptor is your logic, but usually following requirements deem to look for interceptors:</p>

<ul>
  <li>logging</li>
  <li>telemetry</li>
  <li>some data stream correlation requirements</li>
  <li>caching</li>
  <li>auditing</li>
  <li>etc.</li>
</ul>

<p>One of the easiest ways to implement these requirements is to implement cross-cutting concern and apply implicitly to required services.</p>

<p>This also makes it possible not to change original service’s source code and not flood it with different responsibilities to do many things not entirely related to the service itself.</p>

<p>Also regarding constructor of the interceptor - it should of course also support other injections (not only intercepted service). So following code should work as well (assuming that <code class="language-plaintext highlighter-rouge">ITelemetryClient</code> is registered service in IoC):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="nf">EngineWithTelemetry</span><span class="p">(</span><span class="n">IEngine</span> <span class="n">inner</span><span class="p">,</span> <span class="n">ITelemetryClient</span> <span class="n">telemetryClient</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">_inner</span> <span class="p">=</span> <span class="n">inner</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="implementation">Implementation</h2>
<p>Now let’s get back to the interceptor registration and get it implemented.
This is our prototype method:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="n">IServiceCollection</span> <span class="n">Intercept</span><span class="p">&lt;</span><span class="n">TService</span><span class="p">,</span> <span class="n">TInterceptor</span><span class="p">&gt;(</span><span class="k">this</span> <span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Remember that service registration while container is built - is just a list of descriptors that are easily adjustable (or replaced completely).</p>

<p>First of all we need to check if there are any registrations of the service to intercept, if not - we can safely return.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">targetServices</span> <span class="p">=</span> <span class="n">services</span><span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">s</span> <span class="p">=&gt;</span> <span class="n">s</span><span class="p">.</span><span class="n">ServiceType</span> <span class="p">==</span> <span class="k">typeof</span><span class="p">(</span><span class="n">TService</span><span class="p">)).</span><span class="nf">ToList</span><span class="p">();</span>

<span class="k">if</span> <span class="p">(!</span><span class="n">targetServices</span><span class="p">.</span><span class="nf">Any</span><span class="p">())</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="n">services</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Next we need to iterate over list of target service registrations and understand if we have implementation factory for the service or not - having factory it is required to invoke that to get instance of the intercepted service.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">service</span> <span class="k">in</span> <span class="n">targetServices</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">ix</span> <span class="p">=</span> <span class="n">services</span><span class="p">.</span><span class="nf">IndexOf</span><span class="p">(</span><span class="n">service</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">service</span><span class="p">.</span><span class="n">ImplementationFactory</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="p">...</span>
    <span class="p">}</span>
    <span class="k">else</span>
    <span class="p">{</span>
        <span class="p">...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now when we have access to the intercepted service descriptor - we need to <strong>REPLACE</strong> it.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">if</span> <span class="p">(</span><span class="n">service</span><span class="p">.</span><span class="n">ImplementationFactory</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">services</span><span class="p">[</span><span class="n">ix</span><span class="p">]</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ServiceDescriptor</span><span class="p">(</span>
        <span class="k">typeof</span><span class="p">(</span><span class="n">TService</span><span class="p">),</span>
        <span class="n">provider</span> <span class="p">=&gt;</span> <span class="n">ActivatorUtilities</span><span class="p">.</span><span class="nf">CreateInstance</span><span class="p">(</span>
            <span class="n">provider</span><span class="p">,</span>
            <span class="k">typeof</span><span class="p">(</span><span class="n">TInterceptor</span><span class="p">),</span>
            <span class="n">ActivatorUtilities</span><span class="p">.</span><span class="nf">GetServiceOrCreateInstance</span><span class="p">(</span><span class="n">provider</span><span class="p">,</span> <span class="n">service</span><span class="p">.</span><span class="n">ImplementationType</span><span class="p">)),</span>
        <span class="n">service</span><span class="p">.</span><span class="n">Lifetime</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So what happens here? Short description:</p>

<ul>
  <li>we replace existing service descriptor with the new one</li>
  <li>new descriptor registers the same type (<code class="language-plaintext highlighter-rouge">typeof(TService)</code>) in service collection</li>
  <li>new descriptor will use <code class="language-plaintext highlighter-rouge">ActivatorUtilities.CreateInstance</code> to create an instance of the interceptor (<code class="language-plaintext highlighter-rouge">typeof(TInterceptor)</code>)</li>
  <li>original service instance is created with help of <code class="language-plaintext highlighter-rouge">ActivatorUtilities.GetServiceOrCreateInstance(provider, service.ImplementationType)</code></li>
  <li>and it is passed as parameter to the constructor of the interceptor (thus we are able to receive <code class="language-plaintext highlighter-rouge">inner</code> instance of the original service)</li>
</ul>

<p>Very similar code also for the case with implementing factory for the intercepted service:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="k">if</span> <span class="p">(</span><span class="n">service</span><span class="p">.</span><span class="n">ImplementationFactory</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
    <span class="p">...</span>
<span class="p">}</span>
<span class="k">else</span>
<span class="p">{</span>
    <span class="n">services</span><span class="p">[</span><span class="n">ix</span><span class="p">]</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ServiceDescriptor</span><span class="p">(</span>
        <span class="k">typeof</span><span class="p">(</span><span class="n">TService</span><span class="p">),</span>
        <span class="n">provider</span> <span class="p">=&gt;</span> <span class="n">ActivatorUtilities</span><span class="p">.</span><span class="nf">CreateInstance</span><span class="p">(</span>
            <span class="n">provider</span><span class="p">,</span>
            <span class="k">typeof</span><span class="p">(</span><span class="n">TInterceptor</span><span class="p">),</span>
            <span class="n">service</span><span class="p">.</span><span class="n">ImplementationFactory</span><span class="p">.</span><span class="nf">Invoke</span><span class="p">(</span><span class="n">provider</span><span class="p">)),</span>
        <span class="n">service</span><span class="p">.</span><span class="n">Lifetime</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>But here we have to invoke <code class="language-plaintext highlighter-rouge">service.ImplementationFactory.Invoke(provider)</code> to the instance of the original service.</p>

<p>Whole interceptor service registration implementation for completeness:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="n">IServiceCollection</span> <span class="n">Intercept</span><span class="p">&lt;</span><span class="n">TService</span><span class="p">,</span> <span class="n">TInterceptor</span><span class="p">&gt;(</span><span class="k">this</span> <span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">targetServices</span> <span class="p">=</span> <span class="n">services</span><span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">s</span> <span class="p">=&gt;</span> <span class="n">s</span><span class="p">.</span><span class="n">ServiceType</span> <span class="p">==</span> <span class="k">typeof</span><span class="p">(</span><span class="n">TService</span><span class="p">)).</span><span class="nf">ToList</span><span class="p">();</span>

    <span class="k">if</span> <span class="p">(!</span><span class="n">targetServices</span><span class="p">.</span><span class="nf">Any</span><span class="p">())</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">services</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">service</span> <span class="k">in</span> <span class="n">targetServices</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">ix</span> <span class="p">=</span> <span class="n">services</span><span class="p">.</span><span class="nf">IndexOf</span><span class="p">(</span><span class="n">service</span><span class="p">);</span>

        <span class="k">if</span> <span class="p">(</span><span class="n">service</span><span class="p">.</span><span class="n">ImplementationFactory</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">services</span><span class="p">[</span><span class="n">ix</span><span class="p">]</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ServiceDescriptor</span><span class="p">(</span>
                <span class="k">typeof</span><span class="p">(</span><span class="n">TService</span><span class="p">),</span>
                <span class="n">provider</span> <span class="p">=&gt;</span> <span class="n">ActivatorUtilities</span><span class="p">.</span><span class="nf">CreateInstance</span><span class="p">(</span>
                    <span class="n">provider</span><span class="p">,</span>
                    <span class="k">typeof</span><span class="p">(</span><span class="n">TInterceptor</span><span class="p">),</span>
                    <span class="n">ActivatorUtilities</span><span class="p">.</span><span class="nf">GetServiceOrCreateInstance</span><span class="p">(</span><span class="n">provider</span><span class="p">,</span> <span class="n">service</span><span class="p">.</span><span class="n">ImplementationType</span><span class="p">)),</span>
                <span class="n">service</span><span class="p">.</span><span class="n">Lifetime</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="k">else</span>
        <span class="p">{</span>
            <span class="c1">// register descriptor for the service with factory</span>
            <span class="n">services</span><span class="p">[</span><span class="n">ix</span><span class="p">]</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ServiceDescriptor</span><span class="p">(</span>
                <span class="k">typeof</span><span class="p">(</span><span class="n">TService</span><span class="p">),</span>
                <span class="n">provider</span> <span class="p">=&gt;</span> <span class="n">ActivatorUtilities</span><span class="p">.</span><span class="nf">CreateInstance</span><span class="p">(</span>
                    <span class="n">provider</span><span class="p">,</span>
                    <span class="k">typeof</span><span class="p">(</span><span class="n">TInterceptor</span><span class="p">),</span>
                    <span class="n">service</span><span class="p">.</span><span class="n">ImplementationFactory</span><span class="p">.</span><span class="nf">Invoke</span><span class="p">(</span><span class="n">provider</span><span class="p">)),</span>
                <span class="n">service</span><span class="p">.</span><span class="n">Lifetime</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="n">services</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Happy intercepting!
[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="C#" /><category term=".NET" /><category term="Dependency Injection" /><category term="IoC" /><category term="Containers" /><category term="Interceptor" /><category term="c#" /><category term=".net" /><category term="dependency injection" /><category term="containers" /><summary type="html"><![CDATA[Service Interception is known as an altering process to make it look like service instance is delivered to the calling site by contract, but it could altered and totally another type might be hidden by the interface.]]></summary></entry><entry><title type="html">Overview of some of the less-known Optimizely Add-Ons</title><link href="https://tech-fellow.eu/2023/03/06/overview-of-less-known-optimizely-add-ons/" rel="alternate" type="text/html" title="Overview of some of the less-known Optimizely Add-Ons" /><published>2023-03-06T10:30:00+02:00</published><updated>2023-03-06T10:30:00+02:00</updated><id>https://tech-fellow.eu/2023/03/06/overview-of-less-known-optimizely-add-ons</id><content type="html" xml:base="https://tech-fellow.eu/2023/03/06/overview-of-less-known-optimizely-add-ons/"><![CDATA[<p>We have more than seven hundred packages (717) on Optimizely NuGet feed. Official Optimizely packages are part of this number, but the majority is community driven open-source packages enhancing and extending the platform, services and developer, administrator or editor experiences. It’s a lot. And there is a great community behind this number.</p>

<p>I had a chance to talk more about Optimizely Add-Ons at last <a href="https://world.optimizely.com/community/optimizely-dev-happy-hours/happy-hour-emea/">Optimizely Happy Hour</a>.</p>

<p>If you want to go through the list at a slower speed, this blog post is covering topics and packages touched on in the session.</p>

<p>I ran through all the packages on the feed and selected some of less-known (either one I haven’t seen/heard myself or with low download count). Read a bit about the package, added value and purpose of the package. I chose to filter only packages targeting .NET5 and above.</p>

<p>I could not select every single package and review it here, but I picked interesting ones and grouped them 4 categories:</p>
<ul>
  <li><a href="#general-framework">General / Framework</a>
    <ul>
      <li><a href="#source-analyzers">Source Analyzers</a></li>
      <li><a href="#settings">Settings</a></li>
      <li><a href="#extension-methods">Extension Methods</a></li>
      <li><a href="#health-check">Health Check</a></li>
      <li><a href="#warm-up">Warm-up</a></li>
      <li><a href="#session">Session</a></li>
      <li><a href="#azure-explorer">Azure Explorer</a></li>
      <li><a href="#event-transports">Event Transports</a></li>
    </ul>
  </li>
  <li><a href="#cms-12">CMS 12</a>
    <ul>
      <li><a href="#timespan">TimeSpan</a></li>
      <li><a href="#extended-external-links">Extended External Links</a></li>
      <li><a href="#pdf-preview">PDF Preview</a></li>
      <li><a href="#grouping-headers">Grouping Headers</a></li>
      <li><a href="#better-content-areas">Better Content Areas</a></li>
      <li><a href="#enhanced-property-list">Enhanced Property List</a></li>
      <li><a href="#generic-linkitem-collection">Generic LinkItem Collection</a></li>
      <li><a href="#custom-quick-navigation">Custom Quick Navigation</a></li>
      <li><a href="#content-type-usage">Content Type Usage</a></li>
      <li><a href="#unpublish">Unpublish</a></li>
      <li><a href="#content-security-policy-csp">Content Security Policy (CSP)</a></li>
      <li><a href="#access-rights-audit-log">Access Rights Audit Log</a></li>
    </ul>
  </li>
  <li><a href="#commerce-14">Commerce 14</a>
    <ul>
      <li><a href="#currency-exchange-rates">Currency Exchange Rates</a></li>
      <li><a href="#geolocation-tools">Geolocation Tools</a></li>
      <li><a href="#product-feed">Product Feed</a></li>
    </ul>
  </li>
  <li><a href="#dangerous-powerful-packages">“Dangerous” (Powerful) Packages</a>
    <ul>
      <li><a href="#sql-studio">SQL Studio</a></li>
      <li><a href="#developer-tools">Developer Tools</a></li>
      <li><a href="#developer-console">Developer Console</a></li>
    </ul>
  </li>
</ul>

<h1 id="general--framework">General / Framework</h1>
<h2 id="source-analyzers">Source Analyzers</h2>
<p>Source analyzer package allows you to get runtime exceptions quicker and exposes those as compile time errors.</p>

<p><img src="/assets/img/2023/03/addons-1.png" alt="addons-1" /></p>

<p>Simply type the following command in your prompt, and you’re ready to go!</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package Stekeblad.Optimizely.Analyzers
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Once installed, this package scans your source and runs analyzers throwing errors in your face.</p>

<p><img src="/assets/img/2023/03/addons-1-1.png" alt="addons-1-1" /></p>

<h2 id="settings">Settings</h2>
<p>Settings package allows you to store various settings, configuration parameters or even maybe arguments to scheduled job as part of content repository.
It will provide familiar editorial UI for administrators or powerful editors to create and maintain settings.</p>

<p><img src="/assets/img/2023/03/addons-2.png" alt="addons-2" /></p>

<p>Install the package by:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package AddOn.Episerver.Settings
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Once installed, you need to define your model for the settings “container”.</p>

<p><img src="/assets/img/2023/03/addons-2-1.png" alt="addons-2-1" /></p>

<p>The new section will show up to create or maintain your setting values using well-known editorial UI from Optimizely.</p>

<p><img src="/assets/img/2023/03/addons-2-2.png" alt="addons-2-2" /></p>

<p>Retrieval of the setting values is very easy - just inject <code class="language-plaintext highlighter-rouge">ISettingsService</code> (similar API as for <code class="language-plaintext highlighter-rouge">IContentLoader</code>) and retrieve settings by the type parameter.</p>

<p><img src="/assets/img/2023/03/addons-2-3.png" alt="addons-2-3" /></p>

<p>We see this as great addition when you need to parametrize scheduled job execution and need to provide different parameter values (and preferably do this without restart of the site).</p>

<h2 id="extension-methods">Extension Methods</h2>
<p>There are 2 packages worth looking at if you would like to improve productivity for your developers. Some of the methods overlap, but overall - both packages can be installed and used simultaneously.</p>

<p>The first package is from Blend Interactive.</p>

<p><img src="/assets/img/2023/03/addons-3.png" alt="addons-3" /></p>

<p>Installation is as simple as the rest of the packages:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package Blend.Optimizely
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And another package is from Geta Digital.</p>

<p><img src="/assets/img/2023/03/addons-4.png" alt="addons-4" /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package Geta.Optimizely.Extensions
</pre></td></tr></tbody></table></code></pre></div></div>

<p>There are many extension methods for BCL (Base Class Library) types and also for Optimizely content and related types.</p>

<p><img src="/assets/img/2023/03/addons-4-1.png" alt="addons-4-1" /></p>

<p>Browse around and see which ones you like and use most.</p>

<h2 id="health-check">Health Check</h2>
<p>It’s always a good idea to keep your site in-check. Health check package from Optimizely could be used to implement health endpoints and utilize those in your infrastructure monitoring routines.</p>

<p><img src="/assets/img/2023/03/addons-5.png" alt="addons-5" /></p>

<p>Throw this command at your prompt to get package installed.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package EPiServer.Cms.HealthCheck
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You need to register CMS endpoints in the pipeline.</p>

<p><img src="/assets/img/2023/03/addons-5-1.png" alt="addons-5-1" /></p>

<p>Under the hood it’s plugged into standard ASP.NET Core health check pipeline and uses <code class="language-plaintext highlighter-rouge">ISchemaUpdater</code> to get database version. Database version is read by executing stored procedure. So essentially health endpoint is checking if site can read database and if connection is successfully established.
You can also implement your own health checks and add to the collection to verify something specific your project needs.</p>

<h2 id="warm-up">Warm-up</h2>
<p>During cold weather we need to warm-up to keep us alive. However, in your Optimizely site you can use warm-up package to prepare site to serve requests to the end-users. Using warm-up package from Optimizely.</p>

<p><img src="/assets/img/2023/03/addons-6.png" alt="addons-6" /></p>

<p>Installation:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package EPiServer.Cms.Warmup
</pre></td></tr></tbody></table></code></pre></div></div>

<p>By adding package to the site, it will register callback to <code class="language-plaintext highlighter-rouge">IApplicationLifetime.ApplicationStarted</code> event and will fire off requests to all sites’ root url found in configuration.</p>

<p><img src="/assets/img/2023/03/addons-6-1.png" alt="addons-6-1" /></p>

<p>You can also add additional paths for the warmup package to hint during startup. This is useful if you have special cache preparation endpoints and similar actions exposed to prepare your site before it’s ready to serve.
And also you can add “Warmup Health Check” - to double check that warm-up procedure has been executed successfully.</p>

<h2 id="session">Session</h2>
<p>Sometimes you need to keep a track of device or a user. Optimizely offers you small utility package to keep track of user’s sessions.</p>

<p><img src="/assets/img/2023/03/addons-7.png" alt="addons-7" /></p>

<p>As usual - paste this in your favorite command prompt:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package EPiServer.Session
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/2023/03/addons-7-1.png" alt="addons-7-1" /></p>

<p>The default implementation of the session storage uses browser cookies to transfer session identifier to the server.</p>

<h2 id="azure-explorer">Azure Explorer</h2>
<p>Usually when you run your site in DXP you have Azure Storage Account attached to the site to keep your assets safe. It’s quite rare but still - it might be necessity to browse around and review storage content. Sometimes even maybe upload something that needs to be access from the project.</p>

<p><img src="/assets/img/2023/03/addons-8.png" alt="addons-8" /></p>

<p>For this, head over to your command prompt and install Mark’s Storage Explorer package:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package EPiServer.Azure.StorageExplorer
</pre></td></tr></tbody></table></code></pre></div></div>

<p>After installation your will have new admin section to access the addon.</p>

<p><img src="/assets/img/2023/03/addons-8-1.png" alt="addons-8-1" /></p>

<p>Storage Explorer user interface allows to download or upload files to the blob storage. Comes very handy in case of emergency.</p>

<h2 id="event-transports">Event Transports</h2>
<p>If you want to emit or receive events using other transport type as <code class="language-plaintext highlighter-rouge">ServiceBus</code> (by default in DXP) you have few options available:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">StefanOlsen.Optimizely.Events.Sockets</code></li>
  <li><code class="language-plaintext highlighter-rouge">EPiServer.Events.MassTransit</code></li>
  <li>or <code class="language-plaintext highlighter-rouge">StefanOlsen.Optimizely.Events.Redis</code></li>
</ul>

<h1 id="cms-12">CMS 12</h1>
<h2 id="timespan">TimeSpan</h2>
<p>It’s much easier to work with data types (<code class="language-plaintext highlighter-rouge">TimeSpan</code>) that you really need and not subtract something every time you get property value (<code class="language-plaintext highlighter-rouge">DateTime</code>) to get to the actual value you need.</p>

<p>Using following command in your prompt to get <code class="language-plaintext highlighter-rouge">TimeSpan</code> data type with nice editorial interface as part of your content type definition:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package Advanced.CMS.TimeProperty
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/2023/03/addons-9.png" alt="addons-9" /></p>

<p>You can now define content property as <code class="language-plaintext highlighter-rouge">TimeSpan</code>.</p>

<p><img src="/assets/img/2023/03/addons-9-1.png" alt="addons-9-1" /></p>

<p>And also set value using time selector in editorial user interface.</p>

<p><img src="/assets/img/2023/03/addons-9-2.png" alt="addons-9-2" /></p>

<h2 id="extended-external-links">Extended External Links</h2>
<p>If you need to keep track of all outgoing external links in your site, you can expose all external links in a single list.</p>

<p><img src="/assets/img/2023/03/addons-10-2.png" alt="addons-10-2" /></p>

<p>Head over to NuGet feed and install <code class="language-plaintext highlighter-rouge">ExtendedExternalLinks</code> package:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package ExtendedExternalLinks
</pre></td></tr></tbody></table></code></pre></div></div>

<p>It will give you a widget to summarize all your external links in the site and link to the content reference where it’s used.</p>

<p><img src="/assets/img/2023/03/addons-10-1-1.png" alt="addons-10-1-1" /></p>

<h2 id="pdf-preview">PDF Preview</h2>
<p>If you site is working with PDF documents and editors asking if they could preview those directly in Optimizely editorial user interface? Now you can just install PDF Preview package and you are good to go!</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package EPiServer.PdfPreview
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/2023/03/addons-11-1.png" alt="addons-11-1" /></p>

<h2 id="grouping-headers">Grouping Headers</h2>
<p>When you have too many properties under single group (“tab” in editorial user interface), you can use this package to group properties under logical group in the same tab.</p>

<p><img src="/assets/img/2023/03/addons-12-2.png" alt="addons-12-2" /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package Advanced.CMS.GroupingHeader
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then you need to decorate your group’s first element (rest of the properties will follow the same semantics and will be added to the group).</p>

<p><img src="/assets/img/2023/03/addons-12-1-1.png" alt="addons-12-1-1" /></p>

<p>In editorial interface now all properties under this group are together with nice group header to inform editor what kind of content properties are located in this group.</p>

<p><img src="/assets/img/2023/03/addons-12-2-1.png" alt="addons-12-2-1" /></p>

<h2 id="better-content-areas">Better Content Areas</h2>
<p>We have at least two packages that tries to make content areas better by 2 cents.</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">AddOn.Optimizely.ContentAreaLayout</code></li>
  <li>and <code class="language-plaintext highlighter-rouge">TechFellow.Optimizely.AdvancedContentArea</code></li>
</ul>

<h3 id="contentarealayout">ContentAreaLayout</h3>
<p><code class="language-plaintext highlighter-rouge">ContentAreaLayout</code> plugin does exactly what it states - controlling layout of the content area.</p>

<p><img src="/assets/img/2023/03/addons-13.png" alt="addons-13" /></p>

<p>Installation is super simple, as usual, punch this into your command line:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package AddOn.Optimizely.ContentAreaLayout
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Next step is to define your block type which will act as controller for the following blocks and will determine the width of the blocks they occupy in the row.</p>

<p><img src="/assets/img/2023/03/addons-13-1.png" alt="addons-13-1" /></p>

<p>Now you have to create new instance of the block and drop it in the content area (before the blocks you would like to control width of).</p>

<p><img src="/assets/img/2023/03/addons-13-2.png" alt="addons-13-2" /></p>

<p>And lastly - you can see how layout block is controlling the width taken by following blocks in the content area.</p>

<p><img src="/assets/img/2023/03/addons-13-3.png" alt="addons-13-3" /></p>

<p>Using this plugin you can create powerful content area layouts and avoid of the mistakes that editors might make.</p>

<h3 id="advancedcontentarea">AdvancedContentArea</h3>
<p>If you would like to give more options of the editors to choose layout themselves, then <code class="language-plaintext highlighter-rouge">AdvancedContentArea</code> might help you with this challenge.</p>

<p><img src="/assets/img/2023/03/addons-14.png" alt="addons-14" /></p>

<p>Install it via command line:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package TechFellow.Optimizely.AdvancedContentArea
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You register plugin in your project, add necessary <code class="language-plaintext highlighter-rouge">DisplayOptions</code> and you are pretty much ready to go.</p>

<p><img src="/assets/img/2023/03/addons-14-1.png" alt="addons-14-1" /></p>

<p>Now editors have option to specify display option by themselves and setup content area in the way they need it to be.</p>

<p><img src="/assets/img/2023/03/addons-14-2.png" alt="addons-14-2" /></p>

<p>Checking DOM later on, you can see that content area renderer added all required classes to look and work nicely in Bootstrap grid system.</p>

<p><img src="/assets/img/2023/03/addons-14-3.png" alt="addons-14-3" /></p>

<p><strong>psst!</strong> <code class="language-plaintext highlighter-rouge">AdvancedContentArea</code> can be used also to control layout of your Optimizely Forms elements.</p>

<p><img src="/assets/img/2023/03/addons-14-4.png" alt="addons-14-4" /></p>

<h2 id="enhanced-property-list">Enhanced Property List</h2>
<p>Built-in property list is nice and all, but it’s missing two important features - able to render image and content reference.</p>

<p><img src="/assets/img/2023/03/addons-15.png" alt="addons-15" /></p>

<p>This package is exactly about to fix it.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package DoubleJay.Epi.EnhancedPropertyList
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Imagine that we do have content in property list which has image and content reference.</p>

<p><img src="/assets/img/2023/03/addons-15-1.png" alt="addons-15-1" /></p>

<p>By default, rendering row of this content type in property list, might not resolve image and content reference nicely.</p>

<p><img src="/assets/img/2023/03/addons-15-2.png" alt="addons-15-2" /></p>

<p>Now, changing descriptor of the field, we can fix this issue.</p>

<p><img src="/assets/img/2023/03/addons-15-3.png" alt="addons-15-3" /></p>

<p>Images and content references are rendered correctly now in the list:</p>

<p><img src="/assets/img/2023/03/addons-15-4.png" alt="addons-15-4" /></p>

<h2 id="generic-linkitem-collection">Generic LinkItem Collection</h2>
<p>When you list item collection and need some small tweaks or extension, it’s hard. This package might help you to get around.</p>

<p><img src="/assets/img/2023/03/addons-16.png" alt="addons-16" /></p>

<p>This generic link item collection package, author is solving problem about not being able to extend link item collection property.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package Geta.Optimizely.GenericLinks
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You need to define content type that will expand <code class="language-plaintext highlighter-rouge">LinkItem</code> and type in additional properties you would need to save on <code class="language-plaintext highlighter-rouge">LinkItem</code>.</p>

<p><img src="/assets/img/2023/03/addons-16-1.png" alt="addons-16-1" /></p>

<p>You need to use new link collection content type in your content definition.</p>

<p><img src="/assets/img/2023/03/addons-16-2.png" alt="addons-16-2" /></p>

<p>And now, editorial user interface has changed a bit for item editor.</p>

<p><img src="/assets/img/2023/03/addons-16-3.png" alt="addons-16-3" /></p>

<p>As you can see, now editors are able to supply <code class="language-plaintext highlighter-rouge">LinkItem</code> with additional properties if needed.</p>

<h2 id="custom-quick-navigation">Custom Quick Navigation</h2>
<p>If your project has a lot of shortcuts to other systems or you just might want to see available favorites always available at your fingertips, install <code class="language-plaintext highlighter-rouge">Quick Navigation</code> extension package.</p>

<p><img src="/assets/img/2023/03/addons-17.png" alt="addons-17" /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package Epicweb.Optimizely.QuickNavExtension
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/2023/03/addons-17-1.png" alt="addons-17-1" /></p>

<p>And now you quick navigation menu turned into unrecognizable :)</p>

<p><img src="/assets/img/2023/03/addons-17-2.png" alt="addons-17-2" /></p>

<h2 id="content-type-usage">Content Type Usage</h2>
<p>There are few packages that try to address this specific challenge - “Where this content is used?”</p>

<p><img src="/assets/img/2023/03/addons-18.png" alt="addons-18" /></p>

<p>Try out content usage package.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package Eshn.ContentTypeUsage
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If will answer almost all type usage questions you might have.</p>

<p><img src="/assets/img/2023/03/addons-18-1.png" alt="addons-18-1" /></p>

<h2 id="unpublish">Unpublish</h2>
<p>Super tiny, but super useful package - gives you an option to unpublish your content.</p>

<p><img src="/assets/img/2023/03/addons-19.png" alt="addons-19" /></p>

<p>Renders new menu item in the publish menu. Nothing more, nothing less :)</p>

<p><img src="/assets/img/2023/03/addons-19-1.png" alt="addons-19-1" /></p>

<h2 id="content-security-policy-csp">Content Security Policy (CSP)</h2>
<p>It’s important to keep your site healthy. This also includes <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP">content security policy</a>.
Before this package, usually I would add middle-ware or something which could affect my outgoing responses and add required CSP fields. I would need to build some configuration storage where to keep CSP settings, etc.
However, this is already taken care of and you can just install the package and enjoy your time off.</p>

<p><img src="/assets/img/2023/03/addons-20.png" alt="addons-20" /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package Jhoose.Security.Admin
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And now you are able to specify and maintain all CSP directives and configuration accordingly.</p>

<p><img src="/assets/img/2023/03/addons-20-1.png" alt="addons-20-1" /></p>

<p>Nice plugin to keep your sites secure.</p>

<h2 id="access-rights-audit-log">Access Rights Audit Log</h2>
<p>Talking about security, it’s also important to audit changes in your site and be informed about any abnormal activity.</p>

<p>For this reason there is also great package to keep track of access right changes for the content.</p>

<p><img src="/assets/img/2023/03/addons-21.png" alt="addons-21" /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package Swapcode.Optimizely.AuditLog
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Package hooks into access right changes pipeline and writes events to built-in “Change Log”.</p>

<p><img src="/assets/img/2023/03/addons-21-1.png" alt="addons-21-1" /></p>

<p>Nice addition to keep your site secure.</p>
<h1 id="commerce-14">Commerce 14</h1>
<p>For the Commerce part there are not actually that many packages yet. So it’s space we all need to fill :)
Anyways I picked some of interesting packages worth mentioning.</p>

<h2 id="currency-exchange-rates">Currency Exchange Rates</h2>
<p>When you are working with multi-currency sites, it’s good to have exchange rates for currencies loaded and ready to use. By default, this functionality is not something that is built-in into the platform. But you can use addon to extend platform functionality and load necessary currency exchange rates automatically.</p>

<p>Paste this into your command line:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package EPi.Libraries.Commerce.ExchangeRates
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/2023/03/addons-22.png" alt="addons-22" /></p>

<p>Also you need to decide which source for the currency rate exchange system you will use to download data. Addon supports two sources:</p>

<ul>
  <li>Fixer</li>
  <li>Currency Layer</li>
</ul>

<p>There will be another package that you will need to install to get access to the exchange rates source data.</p>

<p><code class="language-plaintext highlighter-rouge">EPi.Libraries.Commerce.ExchangeRates</code> will register scheduled job to load list of currencies and download and import list of exchange rates.</p>

<p><img src="/assets/img/2023/03/addons-22-1.png" alt="addons-22-1" /></p>

<p>After job is ran, relative currency (ones used in the site) exchange rates will be downloaded and imported into the database.</p>

<p><img src="/assets/img/2023/03/addons-22-2.png" alt="addons-22-2" /></p>

<h2 id="geolocation-tools">Geolocation Tools</h2>
<p>Continuing multi-currency topic, most of the times you will also have to handle multi-market functionality. Very often requirement is to select “closest” market based on end-user data (IP address mostly).</p>

<p>You can get help from this package:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package Geta.Optimizely.GeolocationTools.Commerce
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/2023/03/addons-23.png" alt="addons-23" /></p>

<p>Using this package you will be able to automatically select market based on end-user location.</p>

<p><img src="/assets/img/2023/03/addons-23-1.png" alt="addons-23-1" /></p>

<p>So again, functionality that is often requested by our customers is exposed and packed as reusable extension to the platform.</p>

<h2 id="product-feed">Product Feed</h2>
<p>Working with Commerce projects one of the standard requirement is to expose catalog data in one or another format for external consumption. Whether it’s Google Product Feed or external service pulling in CSV format, or any other way - <code class="language-plaintext highlighter-rouge">ProductFeed</code> package got you covered.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package Geta.Optimizely.ProductFeed
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/2023/03/addons-24.png" alt="addons-24" /></p>

<p><code class="language-plaintext highlighter-rouge">ProductFeed</code> package is highly customizable and extended, so it should suit your needs.</p>

<p>You can plugin various mappers and loaders and what’s not to enable and build your exposure pipeline the way you need it to be.</p>

<p><img src="/assets/img/2023/03/addons-24-1.png" alt="addons-24-1" /></p>

<p>After running scheduled job to build feed, it’s available for consumption.</p>

<p><img src="/assets/img/2023/03/addons-24-2.png" alt="addons-24-2" /></p>

<h1 id="dangerous-powerful-packages">“Dangerous” (Powerful) Packages</h1>
<p>Packages and Addons in this category are coming with great power (and great responsibility).
<strong>DISCLAIMER</strong>: Use packages enlisted in this section on your own risk!</p>

<h2 id="sql-studio">SQL Studio</h2>
<p>When you need back-door access to your database to perform some nasty clean-up action, or updating something in batch or fix the data - one way to achieve this is to have SQL Studio addon installed and accessible.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package Gulla.Episerver.SqlStudio
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/2023/03/addons-25.png" alt="addons-25" /></p>

<p>This addon allows you to access database directly and execute queries or commands for your convenience.</p>

<p><img src="/assets/img/2023/03/addons-25-1.png" alt="addons-25-1" /></p>

<p>Package is configurable to allow only certain keywords and commands (preventing accidental damage to the database). These settings should be reviewed and approved before deployed to production (or any other environment).</p>

<h2 id="developer-tools">Developer Tools</h2>
<p>Another tool for advanced users and administrators is <code class="language-plaintext highlighter-rouge">DeveloperTools</code>. This package allows to look into the application state, review startup times, check environment variables and even content of dependency injection container.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package EPiServer.DeveloperTools
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/2023/03/addons-26.png" alt="addons-26" /></p>

<p>Set of available tools in <code class="language-plaintext highlighter-rouge">DeveloperTools</code> package is growing and community is adding more and more useful tools there.</p>

<p><img src="/assets/img/2023/03/addons-26-1.png" alt="addons-26-1" /></p>

<h2 id="developer-console">Developer Console</h2>
<p>Last, but not least - keep an eye on Allan’s work.
One of the package that is scheduled soon to be released - <code class="language-plaintext highlighter-rouge">DeveloperConsole</code> (<a href="https://github.com/CodeArtDK/CodeArt.Optimizely.DeveloperConsole">link to the repo</a>).</p>

<p><img src="/assets/img/2023/03/addons-27.png" alt="addons-27" /></p>

<p>This is basically PowerShell in your Optimizely site.</p>

<h1 id="feed-browser">Feed Browser</h1>
<p>Also, if you are wondering around NuGet feed and exploring what addons and packages are available on the feed, head over to David’s <a href="https://www.david-tec.com/optimizely-nuget-feed-explorer/">feed explorer</a> for more elegant browsing experience :)</p>

<p><img src="/assets/img/2023/03/addons-28.png" alt="addons-28" /></p>

<h1 id="summary">Summary</h1>
<p>We have more than 700 packages on the feed. Most of the packages have been delivered by our beloved community and tireless community members and <a href="https://world.optimizely.com/omvp/">OMVPs</a>.</p>

<p>Bit shout to everyone improving Optimizely platform everyday!</p>

<p>Happy coding!
[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><category term="open source" /><summary type="html"><![CDATA[We have more than seven hundred packages (717) on Optimizely NuGet feed. Official Optimizely packages are part of this number, but the majority is community driven open-source packages enhancing and extending the platform, services and developer, administrator or editor experiences. It’s a lot. And there is a great community behind this number.]]></summary></entry><entry><title type="html">Optimizely Advanced ContentArea Renderer for Forms is Back!</title><link href="https://tech-fellow.eu/2023/02/11/optimizely-forms-advanced-contentarea-renderer-is-back/" rel="alternate" type="text/html" title="Optimizely Advanced ContentArea Renderer for Forms is Back!" /><published>2023-02-11T17:00:00+02:00</published><updated>2023-02-11T17:00:00+02:00</updated><id>https://tech-fellow.eu/2023/02/11/optimizely-forms-advanced-contentarea-renderer-is-back</id><content type="html" xml:base="https://tech-fellow.eu/2023/02/11/optimizely-forms-advanced-contentarea-renderer-is-back/"><![CDATA[<p>Advanced Content Area Renderer is now available for Optimizely content. However, it would be nice to apply display options to Optimizely Forms elements as well.</p>

<p><img src="/assets/img/2023/02/acar-forms-1.png" alt="" /></p>

<h2 id="background">Background</h2>

<p><code class="language-plaintext highlighter-rouge">Optimizely.Forms</code> are more or less closed for modification and extensions. Templates are bundled together with the package and copied into your <code class="language-plaintext highlighter-rouge">modules/</code> folder.
To get Advanced Content Area Renderer working together <code class="language-plaintext highlighter-rouge">Optimizely.Forms</code> we will need to modify forms container element view template. We have to change just a single line, but still - this is something that needs to be kept in mind when upgrading forms packages again.</p>

<h2 id="getting-started">Getting Started</h2>

<ul>
  <li>First of all, we will need to pull down <code class="language-plaintext highlighter-rouge">AdvancedContentArea</code> package for <code class="language-plaintext highlighter-rouge">Optimizely.Forms</code>.</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package TechFellow.Optimizely.AdvancedContentArea.Forms
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is a small library that is available as part of <a href="https://github.com/valdisiljuconoks/optimizely-advanced-contentarea">AdvancedContentArea</a> project.</p>

<ul>
  <li>
    <p>Second, extract built-in forms container block element template for modification. Template is located at <code class="language-plaintext highlighter-rouge">{web-project-root}\modules\_protected\EPiServer.Forms\EPiServer.Forms.zip</code>. Look for <code class="language-plaintext highlighter-rouge">\Views\ElementBlocks\Components\FormContainerBlock\FormContainerBlock.cshtml</code> file inside this <code class="language-plaintext highlighter-rouge">.zip</code> file.</p>
  </li>
  <li>
    <p>Copy this <code class="language-plaintext highlighter-rouge">.cshtml</code> file to your web project’s shared components views folder: <code class="language-plaintext highlighter-rouge">{web-project}\Views\Shared\ElementBlocks\Components\FormContainerBlock</code> (create a folder if it does not exist).</p>
  </li>
</ul>

<h2 id="modify-the-template">Modify the Template</h2>

<p>To get things working we have to modify built-in template for <code class="language-plaintext highlighter-rouge">Optimizely.Forms</code> container element. As it seems like straightforward and easy way to customize - this approach has <strong>huge downside</strong> - you have to keep in mind that updating <code class="language-plaintext highlighter-rouge">Optimizely.Forms</code> pacakge, template might be changed and your copied / modified template might not be compatible anymore with new <code class="language-plaintext highlighter-rouge">Optimizely.Forms</code> version. In such case - just copy over again new version of the template and do the same modifications as before.</p>

<p>Now we need to add two things to the template:</p>

<p>a) add required <code class="language-plaintext highlighter-rouge">using</code> (<code class="language-plaintext highlighter-rouge">Ln 18</code>):</p>

<pre><code class="language-razor">...
@using TechFellow.Optimizely.AdvancedContentArea.Forms
...
</code></pre>

<p>b) then we need to go to <code class="language-plaintext highlighter-rouge">Ln 98</code> and change from this:</p>

<pre><code class="language-razor">Html.RenderElementsInStep(step.i, step.value.Elements);
</code></pre>

<p>to this:</p>

<pre><code class="language-razor">Html.RenderFormElements(step.i, step.value.Elements, Model);
</code></pre>

<p><img src="/assets/img/2023/02/acar-forms-4.png" alt="" /></p>

<p>This is extension method coming from <code class="language-plaintext highlighter-rouge">TechFellow.Optimizely.AdvancedContentArea.Forms</code> package.</p>

<p>Or alternatively - you can <a href="https://github.com/valdisiljuconoks/optimizely-advanced-contentarea/blob/master/samples/AlloySampleSite/Views/Shared/ElementBlocks/Components/FormContainerBlock/FormContainerBlock.cshtml">download this file</a> from GitHub repo test project.</p>

<p>You may ask - why this is needed? Basically - original code was iterating over forms elements collection and calling content renderer directly in the loop. There is almost no place for customization and replacement (maybe I’m wrong - please comment, if you know better way to avoid these modifications). I’m overriding this method with my own implementation - also passing in <code class="language-plaintext highlighter-rouge">Model</code> e.g. <code class="language-plaintext highlighter-rouge">FormContainerBlock</code>.
In this case <code class="language-plaintext highlighter-rouge">Model</code> is needed because we need to access original <code class="language-plaintext highlighter-rouge">ContentAreaItem</code> that was used as form element base to get selected display options by the editor. By knowing which display option was selected, library can wrap form element in new markup element with configured classes.</p>

<h2 id="result">Result</h2>

<p>By referencing this small package - editors now are able to use display options also for Optimizely form elements on-page edit mode:</p>

<p><img src="/assets/img/2023/02/acar-forms-1-1.png" alt="" /></p>

<p>The following markup for this particular form element will be applied according to <code class="language-plaintext highlighter-rouge">DisplayOptions</code> settings:</p>

<p><img src="/assets/img/2023/02/acar-forms-5.png" alt="" /></p>

<p>If you have any issues, problems, or feedback - please, leave it on <a href="https://github.com/valdisiljuconoks/optimizely-advanced-contentarea/issues">GitHub repo</a>.
<br /></p>

<p>Happy forming!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><category term="open source" /><summary type="html"><![CDATA[Advanced Content Area Renderer is now available for Optimizely content. However, it would be nice to apply display options to Optimizely Forms elements as well.]]></summary></entry><entry><title type="html">Optimizely Advanced ContentArea Renderer is Back!</title><link href="https://tech-fellow.eu/2023/01/23/optimizely-advanced-contentarea-render-is-back/" rel="alternate" type="text/html" title="Optimizely Advanced ContentArea Renderer is Back!" /><published>2023-01-23T09:00:00+02:00</published><updated>2023-01-23T09:00:00+02:00</updated><id>https://tech-fellow.eu/2023/01/23/optimizely-advanced-contentarea-render-is-back</id><content type="html" xml:base="https://tech-fellow.eu/2023/01/23/optimizely-advanced-contentarea-render-is-back/"><![CDATA[<p>If you have used <a href="https://nuget.optimizely.com/package/?id=EPiBootstrapArea">EPiBootstrapArea</a> package - then back in those days we had an opportunity to render Episerver <code class="language-plaintext highlighter-rouge">ContentArea</code> items with different <code class="language-plaintext highlighter-rouge">DisplayOptions</code> based on Twitter’s Bootstrap <a href="https://getbootstrap.com/docs/4.0/layout/grid/">framework grid system</a>.</p>

<p><code class="language-plaintext highlighter-rouge">EPiBootstrapArea</code> over the years lost its connection to Bootstrap framework and became general purpose advanced <code class="language-plaintext highlighter-rouge">ContentArea</code> renderer (with an option to set Boostrap grid system’s well-known classes).</p>

<p>Recently I got a call from fellow <a href="https://world.optimizely.com/omvp/">OMVP</a> asking about whether they would be able to upgrade CMS11 project using <code class="language-plaintext highlighter-rouge">EPiBootstrapArea</code> package to CMS12. At that time I had no plans to upgrade it (as I saw that demand for Bootstrap package was declining).
However, upgrade path was not that hard. So I decided to give it a shot.</p>

<p>As I wanted to get rid of Bootstrap “heritage” - this was a good timing to rename the package. So let me introduce <code class="language-plaintext highlighter-rouge">Optimizely.AdvancedContentArea</code>.</p>

<h2 id="getting-started">Getting Started</h2>

<p>You need to install package from Optimizely’s NuGet <a href="https://nuget.optimizely.com/package/?id=TechFellow.Optimizely.AdvancedContentArea">feed</a> to start using Advanced ContentArea renderer:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet add package TechFellow.Optimizely.AdvancedContentArea
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Next you would need to configure renderer by adding it to the application and specifying display options:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">Startup</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">services</span><span class="p">.</span><span class="nf">AddAdvancedContentArea</span><span class="p">(</span><span class="n">o</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="n">o</span><span class="p">.</span><span class="n">DisplayOptions</span> <span class="p">=</span> <span class="n">DisplayOptions</span><span class="p">.</span><span class="n">Default</span><span class="p">;</span>
        <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Or you can add your own diplsay options:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">Startup</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">services</span><span class="p">.</span><span class="nf">AddAdvancedContentArea</span><span class="p">(</span><span class="n">o</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="n">o</span><span class="p">.</span><span class="n">DisplayOptions</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">DisplayModeFallback</span><span class="p">&gt;</span>
            <span class="p">{</span>
                <span class="k">new</span><span class="p">()</span>
                <span class="p">{</span>
                    <span class="n">Id</span> <span class="p">=</span> <span class="s">"three-fifth"</span><span class="p">,</span>
                    <span class="n">Name</span> <span class="p">=</span> <span class="s">"Three fifth (3/5)"</span><span class="p">,</span>
                    <span class="n">Tag</span> <span class="p">=</span> <span class="s">"displaymode-three-fifth"</span><span class="p">,</span>
                    <span class="n">ExtraExtraLargeScreenWidth</span> <span class="p">=</span> <span class="m">7</span><span class="p">,</span>
                    <span class="n">ExtraExtraLargeScreenCssClassPattern</span> <span class="p">=</span> <span class="s">"col-three-fifth-xxl-{0}"</span><span class="p">,</span>
                    <span class="n">ExtraLargeScreenWidth</span> <span class="p">=</span> <span class="m">7</span><span class="p">,</span>
                    <span class="n">ExtraLargeScreenCssClassPattern</span> <span class="p">=</span> <span class="s">"col-three-fifth-xl-{0}"</span><span class="p">,</span>
                    <span class="n">LargeScreenWidth</span> <span class="p">=</span> <span class="m">7</span><span class="p">,</span>
                    <span class="n">LargeScreenCssClassPattern</span> <span class="p">=</span> <span class="s">"col-three-fifth-lg-{0}"</span><span class="p">,</span>
                    <span class="n">MediumScreenWidth</span> <span class="p">=</span> <span class="m">12</span><span class="p">,</span>
                    <span class="n">MediumScreenCssClassPattern</span> <span class="p">=</span> <span class="s">"col-three-fifth-md-{0}"</span><span class="p">,</span>
                    <span class="n">SmallScreenWidth</span> <span class="p">=</span> <span class="m">12</span><span class="p">,</span>
                    <span class="n">SmallScreenCssClassPattern</span> <span class="p">=</span> <span class="s">"col-three-fifth-sm-{0}"</span><span class="p">,</span>
                    <span class="n">ExtraSmallScreenWidth</span> <span class="p">=</span> <span class="m">12</span><span class="p">,</span>
                    <span class="n">ExtraSmallScreenCssClassPattern</span> <span class="p">=</span> <span class="s">"col-three-fifth-xs-{0}"</span><span class="p">,</span>
                    <span class="n">Icon</span> <span class="p">=</span> <span class="s">"epi-icon__layout--three-fifth"</span>
                <span class="p">}</span>
            <span class="p">};</span>
        <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="configuration">Configuration</h2>

<p>Following configuration options are available:</p>

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Default</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">DisplayOptions</code></td>
      <td>Empty list</td>
      <td>Specify list of display options available for the renderer. Later editors will be able to choose any of these options while creating content and specifying dispay option for blocks.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">RowSupportEnabled</code></td>
      <td><code class="language-plaintext highlighter-rouge">false</code></td>
      <td>Configure if advanced content area renderer should support row option.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">AutoAddRow</code></td>
      <td><code class="language-plaintext highlighter-rouge">false</code></td>
      <td>Configure renderer to add automatically <code class="language-plaintext highlighter-rouge">row</code> CSS class to each new row <code class="language-plaintext highlighter-rouge">div</code> element.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">ItemStartRenderCallback</code></td>
      <td><code class="language-plaintext highlighter-rouge">null</code></td>
      <td>Callback to use to modify start tag for the content area items.</td>
    </tr>
  </tbody>
</table>

<h2 id="available-built-in-display-options">Available Built-in Display Options</h2>

<p>Following display options are available by default (via <code class="language-plaintext highlighter-rouge">DisplayOptions.Default</code>):</p>
<ul>
  <li>“Full width (1/1)” (<code class="language-plaintext highlighter-rouge">displaymode-full</code>).</li>
  <li>“Half width (1/2)” (<code class="language-plaintext highlighter-rouge">displaymode-half</code>).</li>
  <li>“One-third width (1/3)” (<code class="language-plaintext highlighter-rouge">displaymode-one-third</code>).</li>
  <li>“Two-thirds width (2/3)” (<code class="language-plaintext highlighter-rouge">displaymode-two-thirds</code>).</li>
  <li>“One-quarter width (1/4)” (<code class="language-plaintext highlighter-rouge">displaymode-one-quarter</code>).</li>
  <li>“Three-quarter width (3/4)” (<code class="language-plaintext highlighter-rouge">displaymode-three-quarters</code>).</li>
</ul>

<h2 id="usage">Usage</h2>

<p>Once you have configured available display options for your Optimizely Content Areas, usage is pretty straight forward - just choose appropriate display options for each item in the area:</p>

<p><img src="/assets/img/2023/01/display-modes.png" alt="" /></p>

<h3 id="display-option-fallbacks">Display Option Fallbacks</h3>
<p>For every display option there are 6 fallback width for various screen sizes based on Bootstrap grid system. According to Bootstrap <a href="https://getbootstrap.com/docs/5.2/layout/breakpoints/">specification</a> following screen sizes are defined:</p>
<ul>
  <li>Extra extra large screen (&gt;= 1400px, <code class="language-plaintext highlighter-rouge">-xxl-</code>)</li>
  <li>Extra large screen (&gt;= 1200px, <code class="language-plaintext highlighter-rouge">-xl-</code>)</li>
  <li>Large screen (&gt;= 992px, <code class="language-plaintext highlighter-rouge">-lg-</code>)</li>
  <li>Medium devices (&gt;= 768px, <code class="language-plaintext highlighter-rouge">-md-</code>)</li>
  <li>Small devices (&gt;= 576px, <code class="language-plaintext highlighter-rouge">-sm-</code>)</li>
  <li>Extra small devices (&lt; 576px, <em>None</em>)</li>
</ul>

<p>These numbers are added at the end of Bootstrap grid system class (for instance 12 for Large screen -&gt; <code class="language-plaintext highlighter-rouge">'col-lg-12'</code>)</p>

<table>
  <thead>
    <tr>
      <th>Display Mode Name</th>
      <th>Extra small devices</th>
      <th>Small devices (sm)</th>
      <th>Medium devices (md)</th>
      <th>Large screen (lg)</th>
      <th>Extra large screen (xl)</th>
      <th>Extra extra large screen (xxl)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Full width</td>
      <td>12</td>
      <td>12</td>
      <td>12</td>
      <td>12</td>
      <td>12</td>
      <td>12</td>
    </tr>
    <tr>
      <td>Half width</td>
      <td>12</td>
      <td>12</td>
      <td>6</td>
      <td>6</td>
      <td>6</td>
      <td>6</td>
    </tr>
    <tr>
      <td>One third</td>
      <td>12</td>
      <td>12</td>
      <td>6</td>
      <td>4</td>
      <td>4</td>
      <td>4</td>
    </tr>
    <tr>
      <td>Two thirds</td>
      <td>12</td>
      <td>12</td>
      <td>6</td>
      <td>8</td>
      <td>8</td>
      <td>8</td>
    </tr>
    <tr>
      <td>One quarter</td>
      <td>12</td>
      <td>12</td>
      <td>6</td>
      <td>3</td>
      <td>3</td>
      <td>3</td>
    </tr>
    <tr>
      <td>Three quarters</td>
      <td>12</td>
      <td>12</td>
      <td>6</td>
      <td>9</td>
      <td>9</td>
      <td>9</td>
    </tr>
  </tbody>
</table>

<p>Eventually if you choose <code class="language-plaintext highlighter-rouge">Half-width (1/2)</code> display option for a block of type <code class="language-plaintext highlighter-rouge">EditorialBlockWithHeader</code> following markup will be generated:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"block editorialblockwithheader col-lg-6 col-md-6 col-sm-12 col-xs-12 displaymode-half"</span><span class="nt">&gt;</span>
    ...
<span class="nt">&lt;/div&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Breakdown of added classes:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">block</code> : generic class added to identify a block</li>
  <li><code class="language-plaintext highlighter-rouge">{block-name}</code> : name of the block type is added (in this case <code class="language-plaintext highlighter-rouge">EditorialBlockWithHeader</code>)</li>
  <li><code class="language-plaintext highlighter-rouge">col-xs-12</code> : block will occupy whole width of the screen on extra small devices</li>
  <li><code class="language-plaintext highlighter-rouge">col-sm-12</code> : block will occupy whole width of the screen on small devices</li>
  <li><code class="language-plaintext highlighter-rouge">col-md-6</code> : block will occupy one half of the screen on medium devices</li>
  <li><code class="language-plaintext highlighter-rouge">col-lg-6</code> : block will occupy one half of the screen on desktop</li>
  <li><code class="language-plaintext highlighter-rouge">displaymode-half</code> : chosen display option <code class="language-plaintext highlighter-rouge">tag</code> is added</li>
</ul>

<h2 id="more-info">More Info?</h2>

<p>If you want to learn more - please visit <a href="https://github.com/valdisiljuconoks/optimizely-advanced-contentarea#advanced-features">library’s GitHub page</a>.</p>

<p>Happy rendering!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><category term="open source" /><summary type="html"><![CDATA[If you have used EPiBootstrapArea package - then back in those days we had an opportunity to render Episerver ContentArea items with different DisplayOptions based on Twitter’s Bootstrap framework grid system.]]></summary></entry><entry><title type="html">Optimizely DeveloperTools are back!</title><link href="https://tech-fellow.eu/2022/12/13/developertools-are-back/" rel="alternate" type="text/html" title="Optimizely DeveloperTools are back!" /><published>2022-12-13T12:00:00+02:00</published><updated>2022-12-13T12:00:00+02:00</updated><id>https://tech-fellow.eu/2022/12/13/developertools-are-back</id><content type="html" xml:base="https://tech-fellow.eu/2022/12/13/developertools-are-back/"><![CDATA[<p>Experimental project with handy tools for developers is back for Optimizely v12.</p>

<h1 id="disclaimer">DISCLAIMER!</h1>
<p>Remember, use at your own risk - this is <strong>not</strong> a supported product!</p>

<h2 id="current-features">Current Features</h2>

<ul>
  <li>View contents of the Dependency Injection container</li>
  <li>View Content Type sync state between Code and DB</li>
  <li>View rendering templates for content types</li>
  <li>View ASP.NET routes</li>
  <li>View loaded assemblies in AppDomain</li>
  <li>View startup time for initialization modules</li>
  <li>View remote event statistics, provider and servers</li>
  <li>View all registered view engines</li>
  <li>View local object cache content (with option to remove items)</li>
  <li>View initialization module dependencies as graph</li>
</ul>

<h2 id="getting-started">Getting Started</h2>

<p>To get started with Optimizely developer tools - all you need to do is to add it to your project and use it :)</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
    <span class="p">...</span>
    <span class="n">services</span><span class="p">.</span><span class="nf">AddOptimizelyDeveloperTools</span><span class="p">();</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">void</span> <span class="nf">Configure</span><span class="p">(</span><span class="n">IApplicationBuilder</span> <span class="n">app</span><span class="p">,</span> <span class="n">IWebHostEnvironment</span> <span class="n">env</span><span class="p">)</span>
<span class="p">{</span>
    <span class="p">...</span>
    <span class="n">app</span><span class="p">.</span><span class="nf">UseOptimizelyDeveloperTools</span><span class="p">();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>When installed and configured - you must be part of the “Administrators” group to access the tool. New menu “Developer Tools” should appear in the top menu.</p>

<p><img src="/assets/img/2022/12/opti-devtools.png" alt="" /></p>

<h2 id="how-risky-it-is-to-install-on-production">How Risky it is to install on production?</h2>
<p>You can read more in-depth analysis of toolset and it’s side-effects <a href="https://tech-fellow.ghost.io/2019/02/14/how-risky-are-episerver-developertools-on-production-environment/">here</a>.</p>

<h2 id="try-it-out">Try It Out!</h2>
<p>Download the latest build on <a href="https://nuget.optimizely.com/package/?id=EPiServer.DeveloperTools">NuGet</a> or <a href="https://github.com/episerver/DeveloperTools/releases">under releases</a></p>

<p><br /></p>

<p>Happy tooling!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><category term="open source" /><summary type="html"><![CDATA[Experimental project with handy tools for developers is back for Optimizely v12.]]></summary></entry><entry><title type="html">Import Your Localized Resources in v7.5</title><link href="https://tech-fellow.eu/2022/11/21/import-your-localized-resources-in-v7-5/" rel="alternate" type="text/html" title="Import Your Localized Resources in v7.5" /><published>2022-11-21T13:00:00+02:00</published><updated>2022-11-21T13:00:00+02:00</updated><id>https://tech-fellow.eu/2022/11/21/import-your-localized-resources-in-v7-5</id><content type="html" xml:base="https://tech-fellow.eu/2022/11/21/import-your-localized-resources-in-v7-5/"><![CDATA[<p>Import functionality has been delayed for several versions of <code class="language-plaintext highlighter-rouge">DbLocalizationProvider</code>. However, with the help of <a href="https://github.com/ruwen">community member</a> - this feature has finally been implemented!</p>

<p>“Import Resources” feature is now available in <a href="https://nuget.optimizely.com/package/?id=DbLocalizationProvider.AdminUI.EPiServer">v7.5</a>. It also gives you “Preview” before importing resources with an option to select only part of the changes detected from the import file.</p>

<p><img src="/assets/img/2022/11/locprovider-import.png" alt="" /></p>

<p>Feel free to send feedback or feature requests on <a href="https://github.com/valdisiljuconoks/LocalizationProvider">the project site</a>!</p>

<p>Happy importing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="Localization" /><category term="Localization Provider" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization" /><category term="localization provider" /><summary type="html"><![CDATA[Import functionality has been delayed for several versions of DbLocalizationProvider. However, with the help of community member - this feature has finally been implemented!]]></summary></entry><entry><title type="html">Dynamic Route in ASP.NET Core When MapDynamicControllerRoute Does Not Work</title><link href="https://tech-fellow.eu/2022/11/01/dynamic-route-in-asp-net-core-when/" rel="alternate" type="text/html" title="Dynamic Route in ASP.NET Core When MapDynamicControllerRoute Does Not Work" /><published>2022-11-01T10:00:00+02:00</published><updated>2022-11-01T10:00:00+02:00</updated><id>https://tech-fellow.eu/2022/11/01/dynamic-route-in-asp-net-core-when</id><content type="html" xml:base="https://tech-fellow.eu/2022/11/01/dynamic-route-in-asp-net-core-when/"><![CDATA[<h2 id="background">Background</h2>
<p>Creating one of the add-on for Optimizely I had to deal with challenge to register dynamically route for the API controller. Dynamic route here means that user is able to provide own url segment on top of which add-on user interface and supporting API service endpoints will be registered.</p>

<p>There have been also some <a href="https://github.com/valdisiljuconoks/localization-provider-epi/issues/150">bug reports</a> around this area. So we need to address this somehow.</p>

<p>Why this is needed? Add-on is used in content management systems where you as the author of add-on can’t control url and therefore your chosen url for add-on might collide with user content address.</p>

<p>Code sample is as following:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">services</span>
        <span class="p">.</span><span class="nf">AddDbLocalizationProviderAdminUI</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="n">_</span><span class="p">.</span><span class="n">RootUrl</span> <span class="p">=</span> <span class="s">"/localization-admin-ui"</span><span class="p">;</span>
        <span class="p">});</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">void</span> <span class="nf">Configure</span><span class="p">(</span><span class="n">IApplicationBuilder</span> <span class="n">app</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">app</span><span class="p">.</span><span class="nf">UseEndpoints</span><span class="p">(</span><span class="n">endpoints</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="c1">// other endpoint registration</span>
        <span class="p">..</span>

        <span class="n">endpoints</span><span class="p">.</span><span class="nf">MapDbLocalizationAdminUI</span><span class="p">();</span>
    <span class="p">});</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This should assure that add-on is available at <code class="language-plaintext highlighter-rouge">/localization-admin-ui</code>, which also requires supporting API services to be available under <code class="language-plaintext highlighter-rouge">localization-admin-ui/api/*</code> address.</p>

<p>You might be thinking that route pattern could be moved mapping method - <code class="language-plaintext highlighter-rouge">MapDbLocalizationAdminUI(string pattern)</code>. However this is not entirely possible due to fact that add-on setup and initialization code needs to know <code class="language-plaintext highlighter-rouge">RootUrl</code> way before it’s mapped at endpoint collection.</p>

<p>Dynamic route requirement means that we can’t use <code class="language-plaintext highlighter-rouge">[Route]</code> attribute on the API service controller as it requires compilation time constant for the route pattern.</p>

<p>So this is not possible:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">DbLocalizationProvider.AdminUI.AspNetCore</span><span class="p">;</span>

<span class="p">[</span><span class="nf">Route</span><span class="p">(</span><span class="n">RootUrl</span> <span class="p">+</span> <span class="s">"/api/service"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ServiceController</span> <span class="p">:</span> <span class="n">ControllerBase</span>
<span class="p">{</span>
    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="try-with-dependency-injection-for-attribute">Try with Dependency Injection for Attribute</h2>
<p>One of the approaches would be to pass in <code class="language-plaintext highlighter-rouge">UiConfigurationContext</code> where <code class="language-plaintext highlighter-rouge">RootUrl</code> property is located to the attribute somehow.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">DynamicRouteAttribute</span> <span class="p">:</span> <span class="n">RouteAttribute</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">DynamicRouteAttribute</span><span class="p">(</span><span class="kt">string</span> <span class="n">pattern</span><span class="p">)</span>
        <span class="p">:</span> <span class="k">base</span><span class="p">(</span><span class="n">pattern</span><span class="p">,</span> <span class="p">???)</span>
    <span class="p">{</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="nf">DynamicRouteAttribute</span><span class="p">(</span><span class="kt">string</span> <span class="n">pattern</span><span class="p">,</span> <span class="n">UiConfigurationContext</span> <span class="n">context</span><span class="p">)</span>
        <span class="p">:</span> <span class="k">base</span><span class="p">(</span><span class="n">context</span><span class="p">.</span><span class="n">RootUrl</span> <span class="p">+</span> <span class="n">pattern</span><span class="p">)</span>
    <span class="p">{</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="p">[</span><span class="nf">DynamicRoute</span><span class="p">(</span><span class="s">"/api/service"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ServiceController</span> <span class="p">:</span> <span class="n">ControllerBase</span>
<span class="p">{</span>
    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This would allow us to use ordinary route attribute with route pattern and also respect user’s configuration for the root address of the add-on. Dependency Injection for an attribute is against all good practices to split <a href="https://blog.ploeh.dk/2014/06/13/passive-attributes/">meta-data and behavior</a> and should not be used.</p>

<p>Also as add-on (library) author you have no idea how to access <code class="language-plaintext highlighter-rouge">UiConfigurationContext</code> from the attribute context. <code class="language-plaintext highlighter-rouge">UiConfigurationContext</code> is added to service collection (dependency injection container) but we have limited options how to access it here. We could use some static <code class="language-plaintext highlighter-rouge">ServiceLocator</code>, <code class="language-plaintext highlighter-rouge">IServiceProvider</code> or any other method - but that would require some actions from hosting project setup code, like - preserving service factory somehow and use it later.</p>

<p>However this is against all best practices and requires some static context. Not very “dependency injection-ish”.</p>

<p>Let’s try another approach.</p>

<h2 id="mapping-route-with-dynamiccontrollerroute">Mapping Route with DynamicControllerRoute</h2>
<p>There is a way to dynamically change matched route before it’s handled. This is done by <code class="language-plaintext highlighter-rouge">MapDynamicControllerRoute()</code>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">Configure</span><span class="p">(</span><span class="n">IApplicationBuilder</span> <span class="n">app</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">app</span><span class="p">.</span><span class="nf">UseEndpoints</span><span class="p">(</span><span class="n">endpoints</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="c1">// other endpoint registration</span>
        <span class="p">..</span>

        <span class="n">endpoints</span><span class="p">.</span><span class="nf">MapDbLocalizationAdminUI</span><span class="p">();</span>
    <span class="p">});</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">static</span> <span class="n">IEndpointRouteBuilder</span> <span class="nf">MapDbLocalizationAdminUI</span><span class="p">(</span>
    <span class="k">this</span> <span class="n">IEndpointRouteBuilder</span> <span class="n">builder</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">context</span> <span class="p">=</span> <span class="n">builder</span><span class="p">.</span><span class="n">ServiceProvider</span><span class="p">.</span><span class="n">GetService</span><span class="p">&lt;</span><span class="n">UiConfigurationContext</span><span class="p">&gt;();</span>

    <span class="n">builder</span><span class="p">.</span><span class="n">MapDynamicControllerRoute</span><span class="p">&lt;</span><span class="n">AdminUIDynamicRouteValueTransformer</span><span class="p">&gt;(</span><span class="n">context</span><span class="p">.</span><span class="n">RootUrl</span> <span class="p">+</span> <span class="s">"/api/service/{action}"</span><span class="p">);</span>

    <span class="k">return</span> <span class="n">builder</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Here we are transforming incoming route on <code class="language-plaintext highlighter-rouge">context.RootUrl + "/api/service/*"</code> route. Transformer does nothing fancy - just sets correct controller for the request:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="k">public</span>  <span class="k">class</span> <span class="nc">AdminUIDynamicRouteValueTransformer</span><span class="p">:</span> <span class="n">DynamicRouteValueTransformer</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">UiConfigurationContext</span> <span class="n">_context</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">AdminUIDynamicRouteValueTransformer</span><span class="p">(</span><span class="n">UiConfigurationContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_context</span> <span class="p">=</span> <span class="n">context</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">override</span> <span class="n">ValueTask</span><span class="p">&lt;</span><span class="n">RouteValueDictionary</span><span class="p">&gt;</span> <span class="nf">TransformAsync</span><span class="p">(</span>
        <span class="n">HttpContext</span> <span class="n">httpContext</span><span class="p">,</span> <span class="n">RouteValueDictionary</span> <span class="n">values</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">values</span><span class="p">[</span><span class="s">"controller"</span><span class="p">]</span> <span class="p">=</span> <span class="s">"Service"</span><span class="p">;</span>
        <span class="k">return</span> <span class="k">new</span> <span class="n">ValueTask</span><span class="p">&lt;</span><span class="n">RouteValueDictionary</span><span class="p">&gt;(</span><span class="n">values</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This looks OK’ish. Transformer is created via dependency injection, so we can get to our services in normal way.</p>

<p>However, problems start when you install other citizens to the project who also does route registration - <a href="https://docs.developers.optimizely.com/commerce/v1.3.0-service-api-developer-guide/docs">Optimizely Service API</a> in this case.</p>

<p>Exception is somewhat odd, but I coudn’t figure out where exactly was the problem.</p>

<p><img src="/assets/img/2022/09/route-exception-1.png" alt="" /></p>

<p>My speculation - <code class="language-plaintext highlighter-rouge">ServiceController</code> does not have <code class="language-plaintext highlighter-rouge">[Route]</code> attribute but is still selected via dynamic controller route transformer. In result - interfering with “normal” API service attribute-based registrations. I don’t know.</p>

<p>If you have any idea - please comment! Thx</p>

<h2 id="applicationmodel-to-the-rescue">ApplicationModel to the Rescue</h2>
<p>There is another approach how to influence application behavior after runtime has finished building behavioral model for the application (scanning and registering different parts of the application).</p>

<p>When application starts up there is a phase in the pipeline - build application model. This is process when runtime decides how application should behave - what controllers we have, actions for each controller, parameters, etc.
To influence this phase we can use <code class="language-plaintext highlighter-rouge">IApplicationModelProvider</code> interface. First we need to register this in IoC. Best location - when service collection is built:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="n">IDbLocalizationProviderAdminUIBuilder</span> <span class="nf">AddDbLocalizationProviderAdminUI</span><span class="p">(</span>
    <span class="k">this</span> <span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">,</span>
    <span class="n">Action</span><span class="p">&lt;</span><span class="n">UiConfigurationContext</span><span class="p">&gt;</span> <span class="n">setup</span> <span class="p">=</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
    <span class="p">...</span>
    <span class="n">services</span><span class="p">.</span><span class="nf">TryAddEnumerable</span><span class="p">(</span><span class="n">ServiceDescriptor</span><span class="p">.</span><span class="n">Transient</span>
                              <span class="p">&lt;</span><span class="n">IApplicationModelProvider</span><span class="p">,</span> <span class="n">ServiceControllerDynamicRouteProvider</span><span class="p">&gt;());</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And dynamic route model provider:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">ServiceControllerDynamicRouteProvider</span> <span class="p">:</span> <span class="n">IApplicationModelProvider</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">UiConfigurationContext</span> <span class="n">_context</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">ServiceControllerDynamicRouteProvider</span><span class="p">(</span><span class="n">UiConfigurationContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_context</span> <span class="p">=</span> <span class="n">context</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">OnProvidersExecuting</span><span class="p">(</span><span class="n">ApplicationModelProviderContext</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">OnProvidersExecuted</span><span class="p">(</span><span class="n">ApplicationModelProviderContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">serviceControllerModel</span> <span class="p">=</span>
            <span class="n">context</span><span class="p">.</span><span class="n">Result</span><span class="p">.</span><span class="n">Controllers</span><span class="p">.</span><span class="nf">FirstOrDefault</span><span class="p">(</span><span class="n">c</span> <span class="p">=&gt;</span> <span class="n">c</span><span class="p">.</span><span class="n">ControllerType</span><span class="p">.</span><span class="nf">IsAssignableFrom</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">ServiceController</span><span class="p">)));</span>

        <span class="k">if</span> <span class="p">(</span><span class="n">serviceControllerModel</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">return</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="kt">var</span> <span class="n">selectorModel</span> <span class="p">=</span> <span class="n">serviceControllerModel</span><span class="p">.</span><span class="n">Selectors</span><span class="p">.</span><span class="nf">FirstOrDefault</span><span class="p">();</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">selectorModel</span> <span class="k">is</span> <span class="p">{</span> <span class="n">AttributeRouteModel</span><span class="p">:</span> <span class="p">{</span> <span class="p">}</span> <span class="p">})</span>
        <span class="p">{</span>
            <span class="n">selectorModel</span><span class="p">.</span><span class="n">AttributeRouteModel</span><span class="p">.</span><span class="n">Template</span> <span class="p">=</span> <span class="n">_context</span><span class="p">.</span><span class="n">RootUrl</span> <span class="p">+</span> <span class="s">"/api/service"</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="kt">int</span> <span class="n">Order</span> <span class="p">=&gt;</span> <span class="p">-</span><span class="m">1000</span> <span class="p">+</span> <span class="m">10</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Here are few important things to mention:</p>

<ul>
  <li>it does not really matter whether you do configuration on <code class="language-plaintext highlighter-rouge">OnProvidersExecuted</code> or <code class="language-plaintext highlighter-rouge">OnProvidersExecuting</code></li>
  <li>however it’s important to keep correct <code class="language-plaintext highlighter-rouge">Order</code> of the part model provider. Default application model provider execution order is set to <code class="language-plaintext highlighter-rouge">-1000</code>. If you set anything beyond this - it will be executed first. So increasing by <code class="language-plaintext highlighter-rouge">10</code> - we can be sure that our model will be executed after the default one. This reminds me of delicate poking of middle-wares to get the correct order.</li>
</ul>

<p>So when the default application model provider has been executed - all controllers have been scanned and registered. Each controller has also meta-data about how to reach out this controller - thus controller’s <code class="language-plaintext highlighter-rouge">Selectors</code>. We have an opportunity to mutate this selector data to change routing for our <code class="language-plaintext highlighter-rouge">ServiceController</code>.</p>

<p>However this will require <code class="language-plaintext highlighter-rouge">ServiceController</code> to have <code class="language-plaintext highlighter-rouge">[Route]</code> attribute set - so the controller is registered in the application model. But we can set any pattern in the attribute - as it will be rewritten anyways.</p>

<pre><code class="language-csahrp">[Route("/localization-admin/api/service", Name = "LocAdminUIRoute")]
public class ServiceController : ControllerBase
{
    ...
}
</code></pre>

<p><br /></p>

<p>Happy routing!
[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><category term="open source" /><summary type="html"><![CDATA[Background Creating one of the add-on for Optimizely I had to deal with challenge to register dynamically route for the API controller. Dynamic route here means that user is able to provide own url segment on top of which add-on user interface and supporting API service endpoints will be registered.]]></summary></entry><entry><title type="html">Run BenchmarkDotNet in xUnit</title><link href="https://tech-fellow.eu/2022/11/01/run-benchmarks-in-xunit/" rel="alternate" type="text/html" title="Run BenchmarkDotNet in xUnit" /><published>2022-11-01T10:00:00+02:00</published><updated>2022-11-01T10:00:00+02:00</updated><id>https://tech-fellow.eu/2022/11/01/run-benchmarks-in-xunit</id><content type="html" xml:base="https://tech-fellow.eu/2022/11/01/run-benchmarks-in-xunit/"><![CDATA[<p>If you ever need to run <a href="https://benchmarkdotnet.org/articles/overview.html">BenchmarkDotNet</a> as part of the unit test (because sometimes it’s easier to just write unit tests instead of a dedicated app), you can use this wrapper around benchmark runner.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">Trait</span><span class="p">(</span><span class="s">"Category"</span><span class="p">,</span> <span class="s">"Unit"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">PerformanceTests</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">ITestOutputHelper</span> <span class="n">_output</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">PerformanceTests</span><span class="p">(</span><span class="n">ITestOutputHelper</span> <span class="n">output</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_output</span> <span class="p">=</span> <span class="n">output</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="p">[</span><span class="n">Fact</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">TestPerformance__HeavyMethod__ShouldAllocateNothing</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">logger</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">AccumulationLogger</span><span class="p">();</span>

        <span class="kt">var</span> <span class="n">config</span> <span class="p">=</span> <span class="n">ManualConfig</span><span class="p">.</span><span class="nf">Create</span><span class="p">(</span><span class="n">DefaultConfig</span><span class="p">.</span><span class="n">Instance</span><span class="p">)</span>
            <span class="p">.</span><span class="nf">AddLogger</span><span class="p">(</span><span class="n">logger</span><span class="p">)</span>
            <span class="p">.</span><span class="nf">WithOptions</span><span class="p">(</span><span class="n">ConfigOptions</span><span class="p">.</span><span class="n">DisableOptimizationsValidator</span><span class="p">);</span>

        <span class="n">BenchmarkRunner</span><span class="p">.</span><span class="n">Run</span><span class="p">&lt;</span><span class="n">HeavyBenchmarks</span><span class="p">&gt;(</span><span class="n">config</span><span class="p">);</span>

        <span class="c1">// write benchmark summary</span>
        <span class="n">_output</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="n">logger</span><span class="p">.</span><span class="nf">GetLog</span><span class="p">());</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="p">[</span><span class="n">MemoryDiagnoser</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">HeavyBenchmarks</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">Benchmark</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">ProcessRequest</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">sut</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">HeavyClass</span><span class="p">();</span>
        <span class="n">sut</span><span class="p">.</span><span class="nf">HeavyMethod</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Happy unit benchmarking!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Performance" /><category term="xUnit" /><category term="Testing" /><category term=".net" /><category term="c#" /><category term="performance" /><category term="xunit" /><category term="testing" /><summary type="html"><![CDATA[If you ever need to run BenchmarkDotNet as part of the unit test (because sometimes it’s easier to just write unit tests instead of a dedicated app), you can use this wrapper around benchmark runner.]]></summary></entry><entry><title type="html">GoogleProductFeed for Optimizely - Reloaded</title><link href="https://tech-fellow.eu/2022/04/22/googleproductfeed-for-optimizely-reloaded/" rel="alternate" type="text/html" title="GoogleProductFeed for Optimizely - Reloaded" /><published>2022-04-22T01:15:00+03:00</published><updated>2022-04-22T01:15:00+03:00</updated><id>https://tech-fellow.eu/2022/04/22/googleproductfeed-for-optimizely-reloaded</id><content type="html" xml:base="https://tech-fellow.eu/2022/04/22/googleproductfeed-for-optimizely-reloaded/"><![CDATA[<p>The previous version of GoogleProductFeed package for <a href="https://nuget.optimizely.com/package/?id=Geta.GoogleProductFeed&amp;ref=tech-fellow.eu">EPiServer</a> / <a href="https://nuget.optimizely.com/package/?id=Geta.Optimizely.GoogleProductFeed&amp;ref=tech-fellow.eu">Optimizely</a> had some inherited problems. In case you need a few product feed format “exports” of your catalog data - loading multiple times the same catalog content was one of the major issues. There are sites that have thousands of products and variations and loading them takes quite a bit of time.</p>

<p>Mainly performance and time it took to generate feed was the main problem with the previous version of the package. There were also cases when data needs to be “enriched” before it’s exposed to the public - like loading prices or checking the availability of the SKU. Sometimes enrichment can also take a long time. Doing this for each feed is a waste of resources if we put it mildly.</p>

<h2 id="geta-productfeed-for-optimizely">Geta ProductFeed for Optimizely</h2>

<p>So taking all known issues into account decision was to reload the package and refactor some of its internals to support a very similar concept for processing pipelines in factories.</p>

<p>With this approach, it’s now supported single load of the catalog content, single (or multiple) enrichment steps for loaded data, and one or many product feed endpoint exporters.</p>

<p>We have created a bunch of new packages - <a href="https://nuget.optimizely.com/package/?id=Geta.Optimizely.ProductFeed&amp;ref=tech-fellow.eu">Geta.Optimizely.ProductFeed</a> and <a href="https://nuget.optimizely.com/?q=geta.optimizely.productfeed&amp;s=Popular&amp;r=10&amp;f=All&amp;ref=tech-fellow.eu">friends</a>.</p>

<h3 id="getting-started">Getting Started</h3>

<p>Getting started with Geta product feed is pretty easy. You need to install core / shared package:</p>

<pre><code class="language-dotnetcli">&gt; dotnet install Geta.Optimizely.ProductFeed
</code></pre>

<p>And just configure it in <strong>Startup.cs</strong> file:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="n">services</span>
    <span class="p">.</span><span class="n">AddProductFeed</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">options</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="c1">// setup product feed config</span>
    <span class="p">});</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Here <code class="language-plaintext highlighter-rouge">T</code> is an entity to which generic <code class="language-plaintext highlighter-rouge">CatalogContentBase</code> class will be mapped to.</p>

<p>Feed generation is still implemented as Optimizely scheduled job (look for “ProductFeed - Create feeds”).</p>

<h3 id="processing-pipeline">Processing Pipeline</h3>

<p>During the processing pipeline there are a few key moments to be aware of (you can override any of these mentioned below):</p>

<ol>
  <li>Catalog Data Load - loads data from the Optimizely Commerce catalog.</li>
  <li>Catalog Data Map - loaded data usually comes in <code class="language-plaintext highlighter-rouge">CatalogContentBase</code> shape. This step allows mapping to <code class="language-plaintext highlighter-rouge">T</code> data type (mentioned in <code class="language-plaintext highlighter-rouge">AddProductFeed&lt;T&gt;()</code> method).</li>
  <li>Enrichments - When loaded data is mapped to a custom entity, the processing pipeline can start the work. Enrichments are responsible for loading some heavy data and adding necessary metadata to the <code class="language-plaintext highlighter-rouge">T</code> entity.</li>
  <li>Feed Exporters - exporters are responsible for generating feed content in a specific format and using specific feed entities.</li>
  <li>Feed entity Converter - converters are responsible for taking the projected entity (<code class="language-plaintext highlighter-rouge">T</code> mentioned in <code class="language-plaintext highlighter-rouge">AddProductFeed()</code>) and return a feed entity which will be used to store the actual product feed in the underlying storage.</li>
  <li>Storage Providers - right now we only have MSSQL storage implementation. But should be quite easy to implement the next one.</li>
</ol>

<h3 id="add-google-xml-product-feed">Add Google Xml Product Feed</h3>

<p>First you need to install Google Xml product feed package:</p>

<pre><code class="language-dotnetcli">&gt; dotnet add package Geta.Optimizely.ProductFeed.Google
</code></pre>

<p>Following code adds Google Xml product feed functionality to your site:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="n">services</span>
    <span class="p">.</span><span class="n">AddProductFeed</span><span class="p">&lt;</span><span class="n">MyCommerceProductRecord</span><span class="p">&gt;(</span><span class="n">options</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">options</span><span class="p">.</span><span class="n">ConnectionString</span> <span class="p">=</span> <span class="n">_configuration</span><span class="p">.</span><span class="nf">GetConnectionString</span><span class="p">(</span><span class="s">"EPiServerDB"</span><span class="p">);</span>
        <span class="n">options</span><span class="p">.</span><span class="n">SetEntityMapper</span><span class="p">&lt;</span><span class="n">EntityMapper</span><span class="p">&gt;();</span>

        <span class="n">options</span><span class="p">.</span><span class="n">AddEnricher</span><span class="p">&lt;</span><span class="n">FashionProductAvailabilityEnricher</span><span class="p">&gt;();</span>

        <span class="n">options</span><span class="p">.</span><span class="nf">AddGoogleXmlExport</span><span class="p">(</span><span class="n">d</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="n">d</span><span class="p">.</span><span class="n">FileName</span> <span class="p">=</span> <span class="s">"/google-feed"</span><span class="p">;</span>
            <span class="n">d</span><span class="p">.</span><span class="n">SetConverter</span><span class="p">&lt;</span><span class="n">GoogleXmlConverter</span><span class="p">&gt;();</span>
        <span class="p">});</span>
    <span class="p">});</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Few notes:</p>

<ol>
  <li>Loaded commerce catalog data will be mapped to <code class="language-plaintext highlighter-rouge">MyCommerceProductRecord</code> class.</li>
  <li><code class="language-plaintext highlighter-rouge">EntityMapper</code> will be used to do this mapping.</li>
  <li><code class="language-plaintext highlighter-rouge">FashionProductAvailabilityEnricher</code> will be used to process each <code class="language-plaintext highlighter-rouge">MyCommerceProductRecord</code> and set SKU availability by some criteria.</li>
  <li>Google Xml product feed entities will be generated using <code class="language-plaintext highlighter-rouge">GoogleXmlConverter</code> class.</li>
  <li>Feed data will be stored in MSSQL database under <code class="language-plaintext highlighter-rouge">"EPiServerDB"</code> connection string.</li>
  <li>Google Xml product feed will be mounted to <code class="language-plaintext highlighter-rouge">/google-feed</code> URL.</li>
</ol>

<p>Custom mapped entity class (<code class="language-plaintext highlighter-rouge">MyCommerceProductRecord</code>):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">MyCommerceProductRecord</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Code</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">DisplayName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Description</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Url</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Brand</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">ImageLink</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">bool</span> <span class="n">IsAvailable</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Custom entity mapper (<code class="language-plaintext highlighter-rouge">EntityMapper.cs</code>):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">EntityMapper</span> <span class="p">:</span> <span class="n">IEntityMapper</span><span class="p">&lt;</span><span class="n">MyCommerceProductRecord</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="n">MyCommerceProductRecord</span> <span class="nf">Map</span><span class="p">(</span><span class="n">CatalogContentBase</span> <span class="n">catalogConte</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="p">...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Enricher (<code class="language-plaintext highlighter-rouge">FashionProductAvailabilityEnricher.cs</code>):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">FashionProductAvailabilityEnricher</span> <span class="p">:</span>
    <span class="n">IProductFeedContentEnricher</span><span class="p">&lt;</span><span class="n">MyCommerceProductRecord</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="n">MyCommerceProductRecord</span> <span class="nf">Enrich</span><span class="p">(</span>
        <span class="n">MyCommerceProductRecord</span> <span class="n">sourceData</span><span class="p">,</span>
        <span class="n">CancellationToken</span> <span class="n">cancellationToken</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// enrich SKU availability</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Google Xml feed entity converter (<code class="language-plaintext highlighter-rouge">GoogleXmlConverter.cs</code>):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">GoogleXmlConverter</span> <span class="p">:</span> <span class="n">IProductFeedConverter</span><span class="p">&lt;</span><span class="n">MyCommerceProductRecord</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">object</span> <span class="nf">Convert</span><span class="p">(</span><span class="n">MyCommerceProductRecord</span> <span class="n">entity</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="k">new</span> <span class="n">Geta</span><span class="p">.</span><span class="n">Optimizely</span><span class="p">.</span><span class="n">ProductFeed</span><span class="p">.</span><span class="n">Google</span><span class="p">.</span><span class="n">Models</span><span class="p">.</span><span class="n">Entry</span>
        <span class="p">{</span>
            <span class="c1">// set properties for feed entity</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="add-csv-product-feed">Add CSV Product Feed</h3>

<p>Adding CSV export is quite easy as well.</p>

<pre><code class="language-dotnetcli">&gt; dotnet add package Geta.Optimizely.ProductFeed.Csv
</code></pre>

<p>Then add somewhat similar code to your <code class="language-plaintext highlighter-rouge">Startup.cs</code> file:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="n">services</span>
    <span class="p">.</span><span class="n">AddProductFeed</span><span class="p">&lt;</span><span class="n">MyCommerceProductRecord</span><span class="p">&gt;(</span><span class="n">options</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">options</span><span class="p">.</span><span class="n">ConnectionString</span> <span class="p">=</span> <span class="n">_configuration</span><span class="p">.</span><span class="nf">GetConnectionString</span><span class="p">(</span><span class="s">"EPiServerDB"</span><span class="p">);</span>
        <span class="n">options</span><span class="p">.</span><span class="n">SetEntityMapper</span><span class="p">&lt;</span><span class="n">EntityMapper</span><span class="p">&gt;();</span>

        <span class="n">options</span><span class="p">.</span><span class="n">AddEnricher</span><span class="p">&lt;</span><span class="n">FashionProductAvailabilityEnricher</span><span class="p">&gt;();</span>

        <span class="n">options</span><span class="p">.</span><span class="nf">AddCsvExport</span><span class="p">(</span><span class="n">d</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="n">d</span><span class="p">.</span><span class="n">FileName</span> <span class="p">=</span> <span class="s">"/csv-feed-1"</span><span class="p">;</span>
            <span class="n">d</span><span class="p">.</span><span class="n">SetConverter</span><span class="p">&lt;</span><span class="n">CsvConverter</span><span class="p">&gt;();</span>
            <span class="n">d</span><span class="p">.</span><span class="n">CsvEntityType</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="n">CsvEntry</span><span class="p">);</span>
        <span class="p">});</span>
    <span class="p">});</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>All processing pipeline logic is the same as for the Google Xml feed except following changes:</p>

<ol>
  <li>CSV product feed entity is set to <code class="language-plaintext highlighter-rouge">CsvEntity</code>.</li>
  <li>Feed entity is converted via <code class="language-plaintext highlighter-rouge">CsvConverter</code>.</li>
  <li>Feed is mounted to <code class="language-plaintext highlighter-rouge">/csv-feed-1</code> route.</li>
</ol>

<p>Custom CSV entity (<code class="language-plaintext highlighter-rouge">CsvEntity.cs</code>):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">CsvEntry</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Name</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Code</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">decimal</span> <span class="n">Price</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">bool</span> <span class="n">IsAvailable</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>CSV converter (<code class="language-plaintext highlighter-rouge">CsvConverter.cs</code>):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">CsvConverter</span> <span class="p">:</span> <span class="n">IProductFeedConverter</span><span class="p">&lt;</span><span class="n">MyCommerceProductRecord</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">object</span> <span class="nf">Convert</span><span class="p">(</span><span class="n">MyCommerceProductRecord</span> <span class="n">entity</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="k">new</span> <span class="n">CsvEntry</span>
        <span class="p">{</span>
            <span class="c1">// set properties for the entity</span>
        <span class="p">};</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>CSV feed will have a header row generated out-of-the-box based on properties in <code class="language-plaintext highlighter-rouge">CsvEntity</code> class.</p>

<p>Currently, there is no option to disable this functionality. If you need one - please file an issue in GitHub <a href="https://github.com/Geta/geta-optimizely-productfeed/issues?ref=tech-fellow.eu">repo</a>.</p>

<h2 id="under-the-hood">Under the Hood</h2>

<p>General pipeline look &amp; feel is shown in the picture below.</p>

<p>Job starts with <strong>loading</strong> the data from the Optimizely catalog. Then <strong>mapping</strong> to the custom entity. <strong>Enriching</strong> it with some additional data (if needed). And then exporting to different formats via different <strong>exports</strong> and <strong>converters</strong>. Lastly stored feed is <strong>exposed</strong> via mounted route.</p>

<p><img src="/assets/img/2022/04/productfeed-1.png" alt="" /></p>

<p>High level mapping between setup code and the processing pipeline is shown in the image below.</p>

<p><img src="/assets/img/2022/04/productfeed-2-2.png" alt="" /></p>

<p>Happy product feeding!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="google product feed" /><category term="xml" /><category term="csv" /><summary type="html"><![CDATA[The previous version of GoogleProductFeed package for EPiServer / Optimizely had some inherited problems. In case you need a few product feed format “exports” of your catalog data - loading multiple times the same catalog content was one of the major issues. There are sites that have thousands of products and variations and loading them takes quite a bit of time.]]></summary></entry><entry><title type="html">How to Configure Microsoft.Extensions.Logging in Optimizely CMS11</title><link href="https://tech-fellow.eu/2022/02/10/how-to-configure-microsoft-extensions-logging-in-optimizely-cms11/" rel="alternate" type="text/html" title="How to Configure Microsoft.Extensions.Logging in Optimizely CMS11" /><published>2022-02-10T00:00:00+02:00</published><updated>2022-02-10T00:00:00+02:00</updated><id>https://tech-fellow.eu/2022/02/10/how-to-configure-microsoft-extensions-logging-in-optimizely-cms11</id><content type="html" xml:base="https://tech-fellow.eu/2022/02/10/how-to-configure-microsoft-extensions-logging-in-optimizely-cms11/"><![CDATA[<p>You might be thinking that <code class="language-plaintext highlighter-rouge">Microsoft.Extensions.Logging</code> and related packages are useful only for .NET Core and above. That’s not entirely true. While <code class="language-plaintext highlighter-rouge">Microsoft.Extensions.Logging</code> is target .NET Standard it’s possible to use it even on .NET Framework 4.x. This is de-facto logging library that class libraries should use at very least. Where Optimizely (ex. Episerver) CMS11 (running on .NET Framework) would collide with anything from the “new world” (.NET5)?</p>

<p><img src="/assets/img/2022/02/ms.logging-in-cms11-1.png" alt="ms.logging-in-cms11-1" /></p>

<p>We do have many shared libraries across our codebase. As by design and name states - class libraries contain business logic and other sweet stuff. Main goal is to reuse and share the same business login across many rutimes and platforms as possible (and applicable).</p>

<p>Few years ago we refactored our shared class libraries to use <code class="language-plaintext highlighter-rouge">Common.Logging</code> as logging abstractions. That would allow us to reduce dependency on <code class="language-plaintext highlighter-rouge">log4net</code> coming from CMS platform. The same class libraries are using in other projects in our solution. Some of them even on .NET 6. To get everything in order and no exception during runtime - we had to pull in also <code class="language-plaintext highlighter-rouge">Common.Logging</code> dependency to get things working properly.</p>

<p>Depending on runtime (ASP.NET Core or Azure Runtime, or whatever) you might get to work with different logging abstractions and therefore you have to make sure that all moving parts are working properly together and there are all required adapters registered.</p>

<p>It is time for us to say good-bye to <code class="language-plaintext highlighter-rouge">Common.Logging</code>.</p>

<p>However if we throw out <code class="language-plaintext highlighter-rouge">Common.Logging</code> from our shared libraries and use <code class="language-plaintext highlighter-rouge">Microsoft.Extensions.Logging</code> abstractions, how can we be sure that we are not losing log entries when library will be used in CMS11 context where we have log4net and friends?</p>

<p>Therefore we have to trick DI container to pretend that it’s possible to create <code class="language-plaintext highlighter-rouge">ILogger&lt;T&gt;</code> instances when anyone from shared libraries is requesting instance of it.</p>

<h2 id="train-structuremap-about-msextensionslogging">Train StructureMap About MS.Extensions.Logging</h2>

<p>First thing we have to do is to tell StructureMap what to do about <code class="language-plaintext highlighter-rouge">ILogger&lt;T&gt;</code> open generic (when someone requests this dependency).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">DependencyResolverInitialization</span> <span class="p">:</span> <span class="n">IConfigurableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureContainer</span><span class="p">(</span><span class="n">ServiceConfigurationContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">context</span><span class="p">.</span><span class="n">ConfigurationComplete</span> <span class="p">+=</span> <span class="p">(</span><span class="n">o</span><span class="p">,</span> <span class="n">e</span><span class="p">)</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="n">context</span><span class="p">.</span><span class="nf">StructureMap</span><span class="p">().</span><span class="nf">Configure</span><span class="p">(</span><span class="n">cfg</span> <span class="p">=&gt;</span>
            <span class="p">{</span>
                <span class="n">cfg</span><span class="p">.</span><span class="nf">For</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">ILogger</span><span class="p">&lt;&gt;)).</span><span class="nf">Use</span><span class="p">(</span><span class="k">new</span> <span class="nf">LoggerAdapterFactory</span><span class="p">());</span>
            <span class="p">});</span>
        <span class="p">};</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Type <code class="language-plaintext highlighter-rouge">LoggerAdapterFactory</code> is special StructureMap type that will instruct DI library what to do next.</p>

<p>It is of type <code class="language-plaintext highlighter-rouge">Instance</code> that is used by the library when StructureMap will have to “close” open generic.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">LoggerAdapterFactory</span> <span class="p">:</span> <span class="n">Instance</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">override</span> <span class="n">Instance</span> <span class="nf">CloseType</span><span class="p">(</span><span class="n">Type</span><span class="p">[]</span> <span class="n">types</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">instanceType</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="n">LoggerInstance</span><span class="p">&lt;&gt;).</span><span class="nf">MakeGenericType</span><span class="p">(</span><span class="n">types</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">Activator</span><span class="p">.</span><span class="nf">CreateInstance</span><span class="p">(</span><span class="n">instanceType</span><span class="p">)</span> <span class="k">as</span> <span class="n">Instance</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">// ignore</span>
    <span class="k">public</span> <span class="k">override</span> <span class="n">IDependencySource</span> <span class="nf">ToDependencySource</span><span class="p">(</span><span class="n">Type</span> <span class="n">pluginType</span><span class="p">)</span> <span class="p">{</span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">NotImplementedException</span><span class="p">();</span> <span class="p">}</span>

    <span class="c1">// this is just for the debugging</span>
    <span class="k">public</span> <span class="k">override</span> <span class="kt">string</span> <span class="n">Description</span> <span class="p">=&gt;</span> <span class="s">"Build ILogger&lt;T&gt; with LoggerAdapterFactory"</span><span class="p">;</span>

    <span class="c1">// what types this instance handles</span>
    <span class="k">public</span> <span class="k">override</span> <span class="n">Type</span> <span class="n">ReturnedType</span> <span class="p">=&gt;</span> <span class="k">typeof</span><span class="p">(</span><span class="n">ILogger</span><span class="p">&lt;&gt;);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We are “outsorcing” actual creation of the logger classes to <code class="language-plaintext highlighter-rouge">LoggerInstance</code>.
Let’s take a look at <code class="language-plaintext highlighter-rouge">LoggerInstance</code>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">LoggerInstance</span><span class="p">&lt;</span><span class="n">TCategoryName</span><span class="p">&gt;</span> <span class="p">:</span> <span class="n">LambdaInstance</span><span class="p">&lt;</span><span class="n">ILogger</span><span class="p">&lt;</span><span class="n">TCategoryName</span><span class="p">&gt;&gt;</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">LoggerInstance</span><span class="p">()</span>
        <span class="p">:</span> <span class="k">base</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="k">new</span> <span class="n">ExtensionsLogger</span><span class="p">&lt;</span><span class="n">TCategoryName</span><span class="p">&gt;())</span> <span class="p">{</span> <span class="p">}</span>

    <span class="c1">// just made debugging easier</span>
    <span class="k">public</span> <span class="k">override</span> <span class="kt">string</span> <span class="n">Description</span> <span class="p">=&gt;</span>
        <span class="s">"via LoggerInstance&lt;"</span> <span class="p">+</span> <span class="k">typeof</span><span class="p">(</span><span class="n">TCategoryName</span><span class="p">).</span><span class="n">Name</span> <span class="p">+</span> <span class="s">"&gt;"</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Everytime StructureMap will see <code class="language-plaintext highlighter-rouge">ILogger&lt;T&gt;</code> dependency it will use these 2 types to construct instance of the requested dependency.</p>

<p>And <code class="language-plaintext highlighter-rouge">ExtensionsLogger</code> is actual bridge between <code class="language-plaintext highlighter-rouge">MS.Extensions.Logging</code> logger and <code class="language-plaintext highlighter-rouge">ILogger</code> from Optimizely CMS.</p>

<h2 id="implement-the-bridge">Implement the Bridge</h2>

<p>Actual implementation of logging bridge is quite simple -&gt; we just have to translate calls from <code class="language-plaintext highlighter-rouge">Microsoft.Extensions.Logging</code> to Optimizely logger API.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">ExtensionsLogger</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;</span> <span class="p">:</span> <span class="n">ILogger</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">EPiServer</span><span class="p">.</span><span class="n">Logging</span><span class="p">.</span><span class="n">ILogger</span> <span class="n">_innerLogger</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">ExtensionsLogger</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">_innerLogger</span> <span class="p">=</span> <span class="n">LogManager</span><span class="p">.</span><span class="nf">GetLogger</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">T</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="n">Log</span><span class="p">&lt;</span><span class="n">TState</span><span class="p">&gt;(</span><span class="n">LogLevel</span> <span class="n">logLevel</span><span class="p">,</span> <span class="n">EventId</span> <span class="n">eventId</span><span class="p">,</span> <span class="n">TState</span> <span class="n">state</span><span class="p">,</span> <span class="n">Exception</span> <span class="n">exception</span><span class="p">,</span>
        <span class="n">Func</span><span class="p">&lt;</span><span class="n">TState</span><span class="p">,</span> <span class="n">Exception</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;</span> <span class="n">formatter</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">switch</span> <span class="p">(</span><span class="n">logLevel</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">case</span> <span class="n">LogLevel</span><span class="p">.</span><span class="n">Trace</span><span class="p">:</span>
                <span class="n">_innerLogger</span><span class="p">.</span><span class="nf">Trace</span><span class="p">(</span><span class="nf">formatter</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">exception</span><span class="p">));</span>
                <span class="k">break</span><span class="p">;</span>
            <span class="k">case</span> <span class="n">LogLevel</span><span class="p">.</span><span class="n">Debug</span><span class="p">:</span>
                <span class="n">_innerLogger</span><span class="p">.</span><span class="nf">Debug</span><span class="p">(</span><span class="nf">formatter</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">exception</span><span class="p">));</span>
                <span class="k">break</span><span class="p">;</span>
            <span class="k">case</span> <span class="n">LogLevel</span><span class="p">.</span><span class="n">Information</span><span class="p">:</span>
                <span class="n">_innerLogger</span><span class="p">.</span><span class="nf">Information</span><span class="p">(</span><span class="nf">formatter</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">exception</span><span class="p">));</span>
                <span class="k">break</span><span class="p">;</span>
            <span class="k">case</span> <span class="n">LogLevel</span><span class="p">.</span><span class="n">Warning</span><span class="p">:</span>
                <span class="n">_innerLogger</span><span class="p">.</span><span class="nf">Warning</span><span class="p">(</span><span class="nf">formatter</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">exception</span><span class="p">));</span>
                <span class="k">break</span><span class="p">;</span>
            <span class="k">case</span> <span class="n">LogLevel</span><span class="p">.</span><span class="n">Error</span><span class="p">:</span>
                <span class="n">_innerLogger</span><span class="p">.</span><span class="nf">Error</span><span class="p">(</span><span class="nf">formatter</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">exception</span><span class="p">));</span>
                <span class="k">break</span><span class="p">;</span>
            <span class="k">case</span> <span class="n">LogLevel</span><span class="p">.</span><span class="n">Critical</span><span class="p">:</span>
                <span class="n">_innerLogger</span><span class="p">.</span><span class="nf">Critical</span><span class="p">(</span><span class="nf">formatter</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">exception</span><span class="p">));</span>
                <span class="k">break</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="kt">bool</span> <span class="nf">IsEnabled</span><span class="p">(</span><span class="n">LogLevel</span> <span class="n">logLevel</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">switch</span> <span class="p">(</span><span class="n">logLevel</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">case</span> <span class="n">LogLevel</span><span class="p">.</span><span class="n">Trace</span><span class="p">:</span>
                <span class="k">return</span> <span class="n">_innerLogger</span><span class="p">.</span><span class="nf">IsTraceEnabled</span><span class="p">();</span>
            <span class="k">case</span> <span class="n">LogLevel</span><span class="p">.</span><span class="n">Debug</span><span class="p">:</span>
                <span class="k">return</span> <span class="n">_innerLogger</span><span class="p">.</span><span class="nf">IsDebugEnabled</span><span class="p">();</span>
            <span class="k">case</span> <span class="n">LogLevel</span><span class="p">.</span><span class="n">Information</span><span class="p">:</span>
                <span class="k">return</span> <span class="n">_innerLogger</span><span class="p">.</span><span class="nf">IsInformationEnabled</span><span class="p">();</span>
            <span class="k">case</span> <span class="n">LogLevel</span><span class="p">.</span><span class="n">Warning</span><span class="p">:</span>
                <span class="k">return</span> <span class="n">_innerLogger</span><span class="p">.</span><span class="nf">IsWarningEnabled</span><span class="p">();</span>
            <span class="k">case</span> <span class="n">LogLevel</span><span class="p">.</span><span class="n">Error</span><span class="p">:</span>
                <span class="k">return</span> <span class="n">_innerLogger</span><span class="p">.</span><span class="nf">IsErrorEnabled</span><span class="p">();</span>
            <span class="k">case</span> <span class="n">LogLevel</span><span class="p">.</span><span class="n">Critical</span><span class="p">:</span>
                <span class="k">return</span> <span class="n">_innerLogger</span><span class="p">.</span><span class="nf">IsCriticalEnabled</span><span class="p">();</span>
        <span class="p">}</span>

        <span class="k">return</span> <span class="k">false</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">// no support for scopes for now</span>
    <span class="k">public</span> <span class="n">IDisposable</span> <span class="n">BeginScope</span><span class="p">&lt;</span><span class="n">TState</span><span class="p">&gt;(</span><span class="n">TState</span> <span class="n">state</span><span class="p">)</span> <span class="p">{</span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">NotImplementedException</span><span class="p">();</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As we know category name (or <code class="language-plaintext highlighter-rouge">&lt;T&gt;</code> parameter for <code class="language-plaintext highlighter-rouge">ILogger</code>) we can ask <code class="language-plaintext highlighter-rouge">LogManager</code> to give us logger of that type: <code class="language-plaintext highlighter-rouge">LogManager.GetLogger(typeof(T));</code>.
This will ensure that log entries are decorated with correct category.</p>

<h2 id="sample-usage">Sample Usage</h2>

<p>After configuring this properly in your app, you can ask for <code class="language-plaintext highlighter-rouge">ILogger&lt;T&gt;</code> dependnecy
 directly in your controller constructor, or you use class library that does this. It doesn’t matter. Infrastructure is set up properly and logging is working as expected:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">StartPageController</span> <span class="p">:</span> <span class="n">PageControllerBase</span><span class="p">&lt;</span><span class="n">StartPage</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">ILogger</span><span class="p">&lt;</span><span class="n">StartPageController</span><span class="p">&gt;</span> <span class="n">_logger</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">StartPageController</span><span class="p">(</span><span class="n">ILogger</span><span class="p">&lt;</span><span class="n">StartPageController</span><span class="p">&gt;</span> <span class="n">logger</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_logger</span> <span class="p">=</span> <span class="n">logger</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">ActionResult</span> <span class="nf">Index</span><span class="p">(</span><span class="n">StartPage</span> <span class="n">currentPage</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_logger</span><span class="p">.</span><span class="nf">LogInformation</span><span class="p">(</span><span class="s">"TEST FROM START PAGE"</span><span class="p">);</span>

        <span class="p">...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">ILogger&lt;T&gt;</code> interface is coming from <code class="language-plaintext highlighter-rouge">Microsoft.Extensions.Logging</code> namespace.</p>

<p><img src="/assets/img/2022/02/ms.logging-in-cms11-2.png" alt="ms.logging-in-cms11-2" /></p>

<p>After couple of seconds log entries show up also in log files (you will need to configure different settings from default ones to see also <code class="language-plaintext highlighter-rouge">Information</code> severity entries).</p>

<p><img src="/assets/img/2022/02/ms.logging-in-cms11-3.png" alt="ms.logging-in-cms11-3" /></p>

<p>Happy coding!</p>

<p>Smooth migrating to .NET5!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="DeveloperTools" /><category term="Logging" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="logging" /><summary type="html"><![CDATA[You might be thinking that Microsoft.Extensions.Logging and related packages are useful only for .NET Core and above. That’s not entirely true. While Microsoft.Extensions.Logging is target .NET Standard it’s possible to use it even on .NET Framework 4.x. This is de-facto logging library that class libraries should use at very least. Where Optimizely (ex. Episerver) CMS11 (running on .NET Framework) would collide with anything from the “new world” (.NET5)?]]></summary></entry><entry><title type="html">How To Easily Exhaust SNAT Sockets in Your Azure Function</title><link href="https://tech-fellow.eu/2022/01/29/how-to-easily-exhaust-snat-sockets-in-your-application/" rel="alternate" type="text/html" title="How To Easily Exhaust SNAT Sockets in Your Azure Function" /><published>2022-01-29T00:15:00+02:00</published><updated>2022-01-29T00:15:00+02:00</updated><id>https://tech-fellow.eu/2022/01/29/how-to-easily-exhaust-snat-sockets-in-your-application</id><content type="html" xml:base="https://tech-fellow.eu/2022/01/29/how-to-easily-exhaust-snat-sockets-in-your-application/"><![CDATA[<p>So here we are again - late Friday evening, some sort of hotel lobby music in my headphones (I miss travel) and this chart on my screen. I’m reaching for my keyboard to type “studio” in my <a href="https://github.com/microsoft/PowerToys?ref=tech-fellow.ghost.io">PowerToys</a> power-run bar. We are running out of network sockets to talk to any service, any API - basically anything. We are at SNAT port exhaustion.</p>

<h2 id="queue-is-full">Queue is Full</h2>

<p>It started out of sudden. Yes, we were in the middle of packing up for the release and there were quite of things to be released. So must be in between the lines of the new code. But there were many new things.</p>

<p>We noticed that out of the blue sky our azure functions started to fail with a somewhat weird error message:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>2022-01-28 08:32:11.282 +00:00 [ERR] An unhandled exception has occurred while executing the request.
Microsoft.Data.SqlClient.SqlException (0x80131904): A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: TCP Provider, error: 0 - An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full.)
 ---&gt; System.ComponentModel.Win32Exception (10055): An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full.
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Yeah, maybe SQL server is dead (or it’s doing some circus tricks as we are scaling and taking backups from time to time).</p>

<p>But then after some time, other services start to fail. This time access to Azure Storage tables:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre>2022-01-28 08:33:38.583 +00:00 [ERR] HTTP GET /api/... responded 500 in 33791.4264 ms
Microsoft.Azure.Cosmos.Table.StorageException: An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full. (mytable.table.core.windows.net:443)
 ---&gt; System.Net.Http.HttpRequestException: An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full. (mytable.table.core.windows.net:443)
 ---&gt; System.Net.Sockets.SocketException (10055): An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full.
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This time error message is exactly the same: An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full.</p>

<p>Error message quickly leads to <a href="https://github.com/Azure/Azure-Functions/issues/1127?ref=tech-fellow.ghost.io">similar issue</a> others have experienced. Someone is using too much..</p>

<h2 id="looking-for-analysis-report-in-portal">Looking For Analysis Report in Portal</h2>

<p>Microsoft Azure portal provides really useful reporting and analysis tools to get started with the issue.</p>

<p>This is done via “Diagnose and solve problems” section in your function app. Choose “Availability and Performance” and then “SNAT Port Exhaustion”.</p>

<p><img src="/assets/img/2022/01/snat-report.png" alt="" /></p>

<p>We can also even see a number of connections fail.</p>

<p><img src="/assets/img/2022/01/Screenshot-2022-01-28-195148-1.png" alt="" /></p>

<p>But unfortunately Azure for some reason is not able to show which endpoints are failing.</p>

<p><img src="/assets/img/2022/01/Screenshot-2022-01-28-195213.png" alt="" /></p>

<h2 id="analyzing-the-dump">Analyzing the Dump</h2>

<p>We need to take a dump (memory) to move forward.</p>

<p>This is super easy done via “Diagnose and solve problems” section in your function app. Choose “Diagnostics tools” and then “Collect Memory Dump”.</p>

<p><img src="/assets/img/2022/01/menu.png" alt="" /></p>

<p>Let’s see what’s inside the dump.</p>

<p><strong>Visual Studio</strong> is just a perfect tool for the job of analyzing memory. After opening .dmp file you have to choose “Debug Managed Memory”. It will take time. I’ve been analyzing memory dumps of size 14GB. Meanwhile, I could prepare my coffee. Twice.</p>

<p>First view what Visual Studio is opening shows heap view - basically, all top objects that reside in memory and GC is not able to wipe them off.</p>

<p><img src="/assets/img/2022/01/top-types-in-mem.png" alt="" /></p>

<p><strong>Timer</strong>, <strong>TimeQueueTimer</strong>, <strong>Amqp</strong>, <strong>EventHandler</strong> and other types are WAAAYYY OFF above the normal count for a healthy application.</p>

<p><img src="/assets/img/2022/01/amqp.png" alt="" /></p>

<p>5k Amqp sessions to Azure ServiceBus?? There definitely is something wrong going on.</p>

<p>Let’s inspect some of the instances..</p>

<p>Inspecting some first couple sessions - everything seems to be just fine, functions who need access to ServiceBus - is having a session.</p>

<p>Then I opened up some 29xxx th instance (which is way off the range).</p>

<p><img src="/assets/img/2022/01/amqp-session-instance.png" alt="" /></p>

<p>In order to understand to which SB topic/subscription this session is created, you should dig deeper and look for <strong>Links[x].Settings.Target</strong>.</p>

<p><img src="/assets/img/2022/01/amqp-session-target.png" alt="" /></p>

<p>Ok, now we know to which topic/subscription this session is pointing to. We can check out the function code.</p>

<h2 id="review-the-code">Review The Code</h2>

<p>Our function is opening the listener to ServiceBus and receiving the messages in batches, process those, execution ends. No, we don’t want to use binding here are we need to control the frequency of the function execution and not invoke every time a new message arrives on the topic.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="k">using</span> <span class="nn">Microsoft.Azure.ServiceBus</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">Microsoft.Azure.ServiceBus.Core</span><span class="p">;</span>

<span class="k">private</span> <span class="k">readonly</span> <span class="n">MessageReceiver</span> <span class="n">_messageReceiver</span><span class="p">;</span>

<span class="k">public</span> <span class="nf">Function1</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">_messageReceiver</span> <span class="p">=</span>
        <span class="k">new</span> <span class="nf">MessageReceiver</span><span class="p">(...,</span> <span class="n">EntityNameHelper</span><span class="p">.</span><span class="nf">FormatSubscriptionPath</span><span class="p">(...,</span> <span class="p">...));</span>
<span class="p">}</span>

<span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="s">"Pump"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">Run</span><span class="p">([</span><span class="nf">TimerTrigger</span><span class="p">(</span><span class="s">"*/15 * * * * *"</span><span class="p">)]</span> <span class="n">TimerInfo</span> <span class="n">myTimer</span><span class="p">,</span> <span class="n">ILogger</span> <span class="n">log</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">messages</span> <span class="p">=</span> <span class="k">await</span> <span class="n">_messageReceiver</span><span class="p">.</span><span class="nf">ReceiveAsync</span><span class="p">(...);</span>
    <span class="c1">// process the messages...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Looks kinda legit. Creates a new instance of the receiver, receives all messages from the topic subscription, processes them, and disposes receiver. During the next execution - the same.</p>

<p>However - we are missing one important detail here. We are <strong>NOT</strong> reusing connection to the ServiceBus, but instead - opening a new one <strong>EVERY</strong> time function executes.</p>

<p>According to best practices - you should strive to do pooling, reusing, or any sort of action to avoid socket exhaustion.</p>

<h2 id="fixing-the-code">Fixing The Code</h2>

<p>Let’s try to fix the code to avoid this problem.</p>

<h3 id="attempt-1">Attempt #1</h3>

<p>One way is to convert the message receiver to <code class="language-plaintext highlighter-rouge">static</code> field.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
</pre></td><td class="rouge-code"><pre><span class="k">using</span> <span class="nn">Microsoft.Azure.ServiceBus</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">Microsoft.Azure.ServiceBus.Core</span><span class="p">;</span>

<span class="k">private</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">_connectionString</span>
<span class="k">private</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">_topicName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="k">private</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">_subscriptionName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">};</span>

<span class="k">private</span> <span class="k">static</span> <span class="k">readonly</span> <span class="n">Lazy</span><span class="p">&lt;</span><span class="n">IMessageReceiver</span><span class="p">&gt;</span> <span class="n">_messageReceiver</span> <span class="p">=</span>
    <span class="k">new</span> <span class="n">Lazy</span><span class="p">&lt;</span><span class="n">IMessageReceiver</span><span class="p">&gt;(()</span> <span class="p">=&gt;</span>
        <span class="k">new</span> <span class="nf">MessageReceiver</span><span class="p">(</span>
          <span class="n">_connectionString</span><span class="p">,</span>
          <span class="n">EntityNameHelper</span><span class="p">.</span><span class="nf">FormatSubscriptionPath</span><span class="p">(</span><span class="n">_topicName</span><span class="p">,</span> <span class="n">_subscriptionName</span><span class="p">)));</span>

<span class="k">public</span> <span class="nf">Function1</span><span class="p">(</span><span class="n">YourServiceOptions</span> <span class="n">options</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">_serviceBusConnectionString</span> <span class="p">=</span> <span class="p">...;</span>
    <span class="n">_topicName</span> <span class="p">=</span> <span class="p">...;</span>
    <span class="n">_subscriptionName</span> <span class="p">=</span> <span class="p">...;</span>
<span class="p">}</span>

<span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="s">"Pump"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">Run</span><span class="p">([</span><span class="nf">TimerTrigger</span><span class="p">(</span><span class="s">"*/15 * * * * *"</span><span class="p">)]</span> <span class="n">TimerInfo</span> <span class="n">myTimer</span><span class="p">,</span> <span class="n">ILogger</span> <span class="n">log</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">messages</span> <span class="p">=</span> <span class="k">await</span> <span class="n">_messageReceiver</span><span class="p">.</span><span class="n">Value</span><span class="p">.</span><span class="nf">ReceiveAsync</span><span class="p">(...);</span>
    <span class="c1">// process the messages...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We are declaring a message receiver as static <code class="language-plaintext highlighter-rouge">Lazy&lt;T&gt;</code> meaning that it should be initialized once and then reused every time we request for a <code class="language-plaintext highlighter-rouge">Value</code>.</p>

<p>This works, but it’s considered to be <a href="https://rules.sonarsource.com/csharp/RSPEC-3963?ref=tech-fellow.eu">code smell</a>. Static fields should be initialized inline.</p>

<h3 id="attempt-2">Attempt #2</h3>

<p>A nicer way to get around this issue I found was to hide the message receiver behind some abstraction and configure this abstraction in your dependency container to be singleton per application.</p>

<p>Define the receiver:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">ServiceBusMessageReceiver</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">MessageReceiver</span> <span class="n">_receiver</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">EnturServiceBusMessageReceiver</span><span class="p">(</span><span class="kt">string</span> <span class="n">connectionString</span><span class="p">,</span> <span class="kt">string</span> <span class="n">topicName</span><span class="p">,</span> <span class="kt">string</span> <span class="n">subscriptionName</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_receiver</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">MessageReceiver</span><span class="p">(</span><span class="n">serviceBusConnectionString</span><span class="p">,</span>
                                        <span class="n">EntityNameHelper</span><span class="p">.</span><span class="nf">FormatSubscriptionPath</span><span class="p">(</span><span class="n">topicName</span><span class="p">,</span> <span class="n">subscriptionName</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">IList</span><span class="p">&lt;</span><span class="n">Message</span><span class="p">&gt;&gt;</span> <span class="nf">ReceiveAsync</span><span class="p">(</span><span class="kt">int</span> <span class="n">maxMessageCount</span><span class="p">,</span> <span class="n">TimeSpan</span> <span class="n">operationTimeout</span><span class="p">)</span> <span class="p">=&gt;</span>
        <span class="n">_receiver</span><span class="p">.</span><span class="nf">ReceiveAsync</span><span class="p">(</span><span class="n">maxMessageCount</span><span class="p">,</span> <span class="n">operationTimeout</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Configure DI container:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="n">services</span><span class="p">.</span><span class="nf">AddSingleton</span><span class="p">(</span><span class="n">sp</span> <span class="p">=&gt;</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">options</span> <span class="p">=</span> <span class="n">sp</span><span class="p">.</span><span class="n">GetRequiredService</span><span class="p">&lt;</span><span class="n">YourServiceOptions</span><span class="p">&gt;();</span>

    <span class="k">return</span> <span class="k">new</span> <span class="nf">ServiceBusMessageReceiver</span><span class="p">(</span>
        <span class="n">options</span><span class="p">.</span><span class="n">ServiceBusConnectionString</span><span class="p">,</span>
        <span class="n">options</span><span class="p">.</span><span class="n">TopicName</span><span class="p">,</span>
        <span class="n">options</span><span class="p">.</span><span class="n">SubscriptionName</span><span class="p">);</span>
<span class="p">});</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And then you are able to use this service as any other injected dependency.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">readonly</span> <span class="n">ServiceBusMessageReceiver</span> <span class="n">receiver</span><span class="p">;</span>

<span class="k">public</span> <span class="nf">Function1</span><span class="p">(</span><span class="n">ServiceBusMessageReceiver</span> <span class="n">receiver</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">_messageReceiver</span> <span class="p">=</span> <span class="n">receiver</span><span class="p">;</span>
<span class="p">}</span>

<span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="s">"Pump"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">Run</span><span class="p">([</span><span class="nf">TimerTrigger</span><span class="p">(</span><span class="s">"*/15 * * * * *"</span><span class="p">)]</span> <span class="n">TimerInfo</span> <span class="n">myTimer</span><span class="p">,</span> <span class="n">ILogger</span> <span class="n">log</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">messages</span> <span class="p">=</span> <span class="k">await</span> <span class="n">_messageReceiver</span><span class="p">.</span><span class="nf">ReceiveAsync</span><span class="p">(...);</span>
    <span class="c1">// process the messages...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="pit-of-success">Pit of Success</h2>

<p>This is of course is not functional architecture and there are no ports or adapters, but still - using the second approach (by defining your service as singleton dependency) you are falling into a <a href="https://blog.ploeh.dk/2016/03/18/functional-architecture-is-ports-and-adapters/?ref=tech-fellow.eu">pit of success</a> as there is less room for errors that developer can make, less room for how developer instantiates dependencies. Everything service needs get injected into it.</p>

<p>Now we are happy to stare at the stabilization line after the late-night patch..</p>

<p><img src="/assets/img/2022/01/stabilize.png" alt="" /></p>

<p>Happy coding! Stay safe!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="Azure" /><category term="Functions" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="debugging" /><category term="azure" /><category term="functions" /><summary type="html"><![CDATA[So here we are again - late Friday evening, some sort of hotel lobby music in my headphones (I miss travel) and this chart on my screen. I’m reaching for my keyboard to type “studio” in my PowerToys power-run bar. We are running out of network sockets to talk to any service, any API - basically anything. We are at SNAT port exhaustion.]]></summary></entry><entry><title type="html">DbLocalizationProvider v7 Out!</title><link href="https://tech-fellow.eu/2022/01/23/dblocalizationprovider-for-optimizely/" rel="alternate" type="text/html" title="DbLocalizationProvider v7 Out!" /><published>2022-01-23T23:15:00+02:00</published><updated>2022-01-23T23:15:00+02:00</updated><id>https://tech-fellow.eu/2022/01/23/dblocalizationprovider-for-optimizely</id><content type="html" xml:base="https://tech-fellow.eu/2022/01/23/dblocalizationprovider-for-optimizely/"><![CDATA[<h1 id="many-thanks">Many Thanks!</h1>

<p>As you can see v7.0 came quite heavily and took a long time before it saw daylight. It wouldn’t be possible without my supporters and QA volunteers. Many thanks to everyone who was involved in this release and for making sure that we hammer out as many bugs as we could discover. I know that there is more to discover around the codebase well hidden in the dark corners of the inherited legacy heritage.</p>

<p><img src="/assets/img/2022/01/v7-1.png" alt="" /></p>

<p>In this blog post I wanted to highlight some of the most obvious and visible changes to the library. As we jump to the next major version - this was good timing for me to finally materialize some of the pending break changes I was holding back for a very long time.</p>

<h1 id="general-changes-some-quite-hard-breaking-ones">General Changes (Some Quite Hard Breaking Ones)</h1>

<p>There are some general changes that are worth mentioning:</p>

<ul>
  <li>Everything is re-targeted to <strong>.NET 5.0</strong>.</li>
  <li>ASP.NET (old .NET Framework Runtime) package has been <strong>dropped</strong>. It’s still around on the NuGet feed but is not actively developed anymore.</li>
  <li><strong>No more static properties</strong> - all stack has been refactored to use DI (finally!).</li>
  <li>New types showed up <code class="language-plaintext highlighter-rouge">ICommandExecutor</code> and <code class="language-plaintext highlighter-rouge">IQueryExecutor</code>. You can now access resources in a programmatic way if you need to. Just ask your favorite DI container for these dependencies.</li>
</ul>

<h2 id="namespace-changes">Namespace Changes</h2>

<p>The following types have changed their living space:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">[LocalizedModelAttribute]</code> moved to <code class="language-plaintext highlighter-rouge">DbLocalizationProvider.Abstractions</code> namespace</li>
  <li><code class="language-plaintext highlighter-rouge">[LocalizedResourceAttribute]</code> moved to <code class="language-plaintext highlighter-rouge">DbLocalizationProvider.Abstractions</code> namespace</li>
  <li><code class="language-plaintext highlighter-rouge">[ResourceKeyAttribute]</code> moved to <code class="language-plaintext highlighter-rouge">DbLocalizationProvider.Abstractions</code> namespace</li>
  <li>Moved <code class="language-plaintext highlighter-rouge">Translate(this Enum target, ...)</code> to <code class="language-plaintext highlighter-rouge">ILocalizationProvider.Translate(this Enum target, ...)</code></li>
</ul>

<h2 id="list-of-packages">List of Packages</h2>

<p>Below you can find the list of packages that now library or maybe we should call it platform ;) contains:</p>

<table>
  <thead>
    <tr>
      <th>Package</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">LocalizationProvider.Abstractions</code></td>
      <td>Contains all the high-level abstractions required for the libraries.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">LocalizationProvider</code></td>
      <td>Main core package containing resource scanners, generic CQRS stuff, <br />localization service, etc.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">LocalizationProvider.AdminUI.Models</code></td>
      <td>Data model for AdminUI service API endpoints. <br />Can be used to extend and create new AdminUI integrations.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">LocalizationProvider.AspNetCore</code></td>
      <td>Main core package to integrate into ASP.NET Core (.NET 5.0) runtime.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">LocalizationProvider.Storage.AzureTables</code></td>
      <td>If you need to store resources and translations in Azure Table storage.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">LocalizationProvider.Storage.PostgreSql</code></td>
      <td>Storage implementation for some fancy and geeky Linux fans.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">LocalizationProvider.Storage.SqlServer</code></td>
      <td>Standard implementation of the MSSQL storage.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">LocalizationProvider.AdminUI.AspNetCore</code></td>
      <td>AdminUI integration package for ASP.NET Core (.NET 5.0).</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">LocalizationProvider.Csv</code></td>
      <td>Export support for CSV format.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">LocalizationProvider.AdminUI.AspNetCore.Csv</code></td>
      <td>AdminUI integaration for CSV format exporter.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">LocalizationProvider.Xliff</code></td>
      <td>Export support for XLIFF format.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">LocalizationProvider.AdminUI.AspNetCore.Xliff</code></td>
      <td>AdminUI integaration for XLIFF format exporter.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">DbLocalizationProvider.EPiServer</code></td>
      <td>If you are running on Optimizely, you can use this package to integrate <br />DbLocalizationProvider into Optimizely runtime.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">DbLocalizationProvider.AdminUI.EPiServer</code></td>
      <td>Integrate AdminUI into Optimizely runtime.</td>
    </tr>
  </tbody>
</table>

<h2 id="configuration">Configuration</h2>

<ul>
  <li>Removed static methods such as:</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>ConfigurationContext.Setup()
ConfigurationContext.Current
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>Renamed fallback cultures property:</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>ConfigurationContext.FallbackCultures
</pre></td></tr></tbody></table></code></pre></div></div>

<p>to</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>ConfigurationContext.FallbackLanguages
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="data-model">Data Model</h2>

<ul>
  <li><code class="language-plaintext highlighter-rouge">LocalizationResource.Translations</code> from <code class="language-plaintext highlighter-rouge">ICollection&lt;LocalizationResourceTranslation&gt;</code> to <code class="language-plaintext highlighter-rouge">LocalizationResourceTranslationCollection</code></li>
  <li>introduced <code class="language-plaintext highlighter-rouge">IResourceRepository</code> - for easier storage implementations</li>
  <li>moved <code class="language-plaintext highlighter-rouge">DiscoveredResource</code> from <code class="language-plaintext highlighter-rouge">DbLocalizationProvider.Sync</code> to <code class="language-plaintext highlighter-rouge">DbLocalizationProvider.Abstractions</code></li>
  <li>removed <code class="language-plaintext highlighter-rouge">GetAllTranslations</code> query</li>
</ul>

<h2 id="storage">Storage</h2>

<h3 id="implementing-custom-storage-provider">Implementing Custom Storage Provider</h3>

<p><code class="language-plaintext highlighter-rouge">IResourceRepository</code> repository interface to be implemented by any storage implementation. So now if you are considering adding new storage implementation - this is the only interface you might need to provide an implementation for (with the rest of the schema sync stuff if any).</p>

<h3 id="new-implementation---azure-tables">New Implementation - Azure Tables</h3>
<p>For those who are running on low-end budgets and SQL Server is just overkill, there is a new storage implementation - Microsoft Azure Storage tables.</p>

<p>Just install the package:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="err">&gt;</span><span class="w"> </span><span class="n">dotnet</span><span class="w"> </span><span class="nx">add</span><span class="w"> </span><span class="nx">package</span><span class="w"> </span><span class="nx">LocalizationProvider.Storage.AzureTables</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>And then (in your <code class="language-plaintext highlighter-rouge">Startup.cs</code>):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">services</span>
        <span class="p">.</span><span class="nf">AddDbLocalizationProvider</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="c1">// ..</span>

             <span class="n">ctx</span><span class="p">.</span><span class="nf">UseAzureTables</span><span class="p">(</span><span class="s">"..."</span><span class="p">);</span>
       <span class="p">});</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h1 id="adminui-for-net-runtime">AdminUI for .NET Runtime</h1>

<h2 id="configuration-changes">Configuration Changes</h2>

<p>In favor of no static stuff <code class="language-plaintext highlighter-rouge">UiConfigurationContext.Current</code> property has been removed.</p>

<h2 id="restricting-access">Restricting Access</h2>

<p>Following properties have been removed in favor of lambda to configure access policy:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">UiConfigurationContext.AuthorizedAdminRoles</code> - list of roles with administrator access;</li>
  <li><code class="language-plaintext highlighter-rouge">UiConfigurationContext.AuthorizedEditorRoles</code> - list of roles with editor access;</li>
</ul>

<p>Now you can just define access policy:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="n">services</span><span class="p">.</span><span class="nf">AddDbLocalizationProviderAdminUI</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
<span class="p">{</span>
    <span class="n">_</span><span class="p">.</span><span class="n">AccessPolicyOptions</span> <span class="p">=</span> <span class="n">builder</span> <span class="p">=&gt;</span>
        <span class="n">builder</span><span class="p">.</span><span class="nf">AddRequirements</span><span class="p">(</span><span class="k">new</span> <span class="nf">RolesAuthorizationRequirement</span><span class="p">(</span><span class="k">new</span> <span class="p">[]</span> <span class="p">{</span> <span class="s">"test"</span> <span class="p">}));</span>
<span class="p">});</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If none is set - by default only users with <code class="language-plaintext highlighter-rouge">Administrators</code> role have access to AdminUI.</p>

<h2 id="some-new-features">Some New Features</h2>

<p>AdminUI along the way got some shiny blings.</p>

<ul>
  <li>
    <p>Sticky header - if you have reaaally long list of resources - now the table header will stick to the top of the page for you to easier understand which language are you going to edit.</p>
  </li>
  <li>
    <p>List of available languages - now you can select which languages you would like to see in AdminUI. This might be handy if you have many languages available on the site but you want to work only with a subset of those.</p>
  </li>
  <li>
    <p>Added support for CSV and XLIFF export formats:</p>
  </li>
</ul>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">services</span>
    <span class="p">.</span><span class="nf">AddDbLocalizationProviderAdminUI</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="c1">// setup adminui</span>
    <span class="p">})</span>
    <span class="p">.</span><span class="nf">AddCsvSupport</span><span class="p">()</span>
    <span class="p">.</span><span class="nf">AddXliffSupport</span><span class="p">();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h1 id="optimizely-runtime">Optimizely Runtime</h1>

<h2 id="configuration-1">Configuration</h2>

<p>You have to call <code class="language-plaintext highlighter-rouge">.AddOptimizely()</code> and <code class="language-plaintext highlighter-rouge">.AddOptimizelyAdminUI()</code> methods (along with additional configuration and setup) to add provider and administrative user interface to your Optimizely application.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">services</span>
        <span class="p">.</span><span class="nf">AddDbLocalizationProvider</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="c1">// ..</span>
       <span class="p">})</span>
       <span class="p">.</span><span class="nf">AddOptimizely</span><span class="p">();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">services</span>
    <span class="p">.</span><span class="nf">AddDbLocalizationProviderAdminUI</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="c1">// setup adminui</span>
    <span class="p">})</span>
    <span class="p">.</span><span class="nf">AddOptimizelyAdminUI</span><span class="p">();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>More info - <a href="https://github.com/valdisiljuconoks/localization-provider-epi/blob/release/docs/getting-started-epi.md">getting-started-epi.md</a></p>

<h2 id="available-languages">Available Languages</h2>

<p>Now a list of available languages is fetched from the Optimizely language repository. Sequence and title of the language set by editors are also respected and languages in AdminUI are sorted according to the sequence.</p>

<h2 id="current-language-ex-cultureinfocurrentuiculture">Current Language (ex. CultureInfo.CurrentUICulture)</h2>

<p>For a long time localization provider was relying on <code class="language-plaintext highlighter-rouge">CultureInfo.CurrentUICulture</code> property to determine in which language resource translation should be fetched. While this was working OK in pure .NET applications, Optimizely has way more advanced contexts and edge-cases on how language could be selected and which one is the current one.</p>

<p>Now library respects current language (preview in edit mode with a different language selected is now properly supported).</p>

<h1 id="azure-functions-runtime">Azure Functions Runtime</h1>

<p>No big changes here - integration with Azure Function runtime works as it should be.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre>[assembly: FunctionsStartup(typeof(Startup))]

namespace funcapp
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddDbLocalizationProvider(...);
        }
    }
}
</pre></td></tr></tbody></table></code></pre></div></div>

<h1 id="roadmap-for-the-v71">Roadmap for the v7.1</h1>

<ul>
  <li>Retarget to .NET 6.0 (once Optimizely platform will start supporting it)</li>
  <li>Implement “Import” functionality in AdminUI</li>
  <li>Smaller editorial features to make life easier for editors</li>
  <li>Implement “New Resource” feature to manually create resources</li>
  <li>“Delete All” command in AdminUI to TNTify all resources</li>
</ul>

<p><br /></p>
<p>Happy coding! Keep up a good work!</p>

<p>Stay safe!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="Localization" /><category term="Localization Provider" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization" /><category term="localization provider" /><summary type="html"><![CDATA[Many Thanks!]]></summary></entry><entry><title type="html">Avoid Lock - Pointing Two WebJobs to The Same Azure Storage Account</title><link href="https://tech-fellow.eu/2021/11/16/avoid-lock-pointing-2-webjobs-to-the-same-azure-storage-account/" rel="alternate" type="text/html" title="Avoid Lock - Pointing Two WebJobs to The Same Azure Storage Account" /><published>2021-11-16T22:30:00+02:00</published><updated>2021-11-16T22:30:00+02:00</updated><id>https://tech-fellow.eu/2021/11/16/avoid-lock-pointing-2-webjobs-to-the-same-azure-storage-account</id><content type="html" xml:base="https://tech-fellow.eu/2021/11/16/avoid-lock-pointing-2-webjobs-to-the-same-azure-storage-account/"><![CDATA[<p>Yes yes, while the whole world around us is serverless (read “servers running on thin air”), we are still running on concrete servers and utilizing real CPUs.</p>

<p>Recently we had a requirement to run multiple copies of our webjobs in parallel (with different settings and configuration) doing similar but different work. Webjobs runtime uses <code class="language-plaintext highlighter-rouge">Singleton</code> lock approach to coordinate the execution of the job across the farm (if you have scaled-out your application). This is the way how runtime avoids duplicate executions of the same job. Webjobs runtime uses Azure storage blobs to accomplish a locking mechanism across multiple nodes in your cluster.</p>

<p>We wanted to skip extra storage account creation for the copy of the webjobs, but instead - we would like to use the same account because webjobs are doing completely different tasks and it’s OK if they run simultaneously. But when you point both copies of the job to the same storage account one of the jobs will not be able to acquire the lock and therefore will stall until another job will release the lock.</p>

<p><img src="/assets/img/2021/11/image.png" alt="" /></p>

<p>We had to handle this somehow and workaround “single host” limitation.</p>

<h2 id="surfing-webjob-host-source-code-to-find-the-lock-source">Surfing WebJob Host Source Code to Find The Lock Source</h2>

<p>We would need to find who is in charge of issuing the locks and who is responsible for generating the path for the locks (<code class="language-plaintext highlighter-rouge">ba0d.../Keeper.ScheduledJob.Run.Listener</code>).</p>

<p>When you configure your webjob runtime, you are adding a couple of services to the <code class="language-plaintext highlighter-rouge">IServiceCollection</code> via <code class="language-plaintext highlighter-rouge">IHostBuilder</code> extension method.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">HostBuilder</span><span class="p">();</span>
<span class="n">builder</span><span class="p">.</span><span class="nf">ConfigureWebJobs</span><span class="p">((</span><span class="n">context</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">b</span><span class="p">.</span><span class="nf">AddAzureStorageCoreServices</span><span class="p">();</span>
        <span class="n">b</span><span class="p">.</span><span class="nf">AddAzureStorage</span><span class="p">();</span>
        <span class="n">b</span><span class="p">.</span><span class="nf">AddTimers</span><span class="p">();</span>

        <span class="p">...</span>
    <span class="p">})</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">AddTimers()</code> method plays important role in this game.</p>

<p>If you look inside - then at the end <code class="language-plaintext highlighter-rouge">JobHostService</code> is added as <a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-6.0&amp;tabs=visual-studio&amp;ref=tech-fellow.eu">background service</a>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="n">services</span><span class="p">.</span><span class="nf">TryAddEnumerable</span><span class="p">(</span><span class="n">ServiceDescriptor</span><span class="p">.</span><span class="n">Singleton</span><span class="p">&lt;</span><span class="n">IHostedService</span><span class="p">,</span> <span class="n">JobHostService</span><span class="p">&gt;());</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Let’s look inside <code class="language-plaintext highlighter-rouge">JobHostService</code>. Some bla bla housekeeping things and call to <code class="language-plaintext highlighter-rouge">((IJobHost)_jobHost).StartAsync(cancellationToken)</code>.</p>

<p>Let’s see what job host is doing..</p>

<p>During the initialization <code class="language-plaintext highlighter-rouge">IJobHost</code> creates <code class="language-plaintext highlighter-rouge">JobHostContext</code> where all the information about found functions - yes, in webjobs context each webjob is actually called “Function” - no doubt that explains why Azure Functions SDK is based on Azure WebJobs SDK ;)</p>

<p>Each function is represented by <code class="language-plaintext highlighter-rouge">FunctionDescriptor</code> - very similar concept as MVC does controller/action thingy and how context is represented in various filters for example those could be plugged into the pipeline.</p>

<p>Job host context has function descriptors, logger factory and what’s not.</p>

<p>Part of the host context creation (<code class="language-plaintext highlighter-rouge">JobHostContextFactory</code>) factory also creates various instances of <code class="language-plaintext highlighter-rouge">IListener</code> which in turn is responsible for triggering (executing) functions when external initiator “appears” (for example in queue trigger case - when a message has been dropped in the queue).</p>

<p>Listeners however are created via <code class="language-plaintext highlighter-rouge">HostListenerFactory</code> type. And one of the constructor arguments is <code class="language-plaintext highlighter-rouge">SingletonManager singletonManager</code>. Type sounds familiar. Let’s take a closer look at what it does.</p>

<p><code class="language-plaintext highlighter-rouge">HostListenerFactory</code> is responsible for creating all instances of <code class="language-plaintext highlighter-rouge">IListener</code> for found functions. We have only a single function (webjob) in the project:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">Run</span><span class="p">(</span>
    <span class="p">[</span><span class="nf">TimerTrigger</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">ScheduledJobTrigger</span><span class="p">),</span> <span class="n">RunOnStartup</span> <span class="p">=</span> <span class="k">true</span><span class="p">)]</span>
    <span class="n">TimerInfo</span> <span class="n">timerInfo</span><span class="p">)</span>
<span class="p">{</span>
    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Job host has knowledge about every single function found in the project. Apart of the function metadata, the function descriptor has info also about what type of listener is required for the function to run.</p>

<p>Our job is triggered on a timer (CRON expression at the end). Remember about that <code class="language-plaintext highlighter-rouge">AddTimers()</code> method and the beginning of the post? Well, let’s see what it does actually:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="n">IWebJobsBuilder</span> <span class="nf">AddTimers</span><span class="p">(</span><span class="k">this</span> <span class="n">IWebJobsBuilder</span> <span class="n">builder</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">builder</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">builder</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="n">builder</span><span class="p">.</span><span class="n">AddExtension</span><span class="p">&lt;</span><span class="n">TimersExtensionConfigProvider</span><span class="p">&gt;()</span>
        <span class="p">.</span><span class="n">BindOptions</span><span class="p">&lt;</span><span class="n">TimersOptions</span><span class="p">&gt;();</span>
    <span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="n">AddSingleton</span><span class="p">&lt;</span><span class="n">ScheduleMonitor</span><span class="p">,</span> <span class="n">StorageScheduleMonitor</span><span class="p">&gt;();</span>

    <span class="k">return</span> <span class="n">builder</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Nothing really much of it. But <code class="language-plaintext highlighter-rouge">TimersExtensionConfigProvider</code> is important here.</p>

<p><code class="language-plaintext highlighter-rouge">Microsoft.Azure.WebJobs.Extensions.Extensions.Timers.TimersExtensionConfigProvider</code>provides info to the host and runtime what exactly are timer triggers and how to get more information about them - like what kind of listener is required for the timers to go off and kick the job. This knowledge transfer in WebJobs world is called “binding rules”. And the type that carries this info for the timers is <code class="language-plaintext highlighter-rouge">TimerTriggerAttributeBindingProvider</code> who essentially is informing runtime that <code class="language-plaintext highlighter-rouge">TimerTriggerBinding</code> should be used if the host needs info about timers and what kind of listener they need.</p>

<p><code class="language-plaintext highlighter-rouge">ITriggerBinding</code> interface (which is implemented by <code class="language-plaintext highlighter-rouge">TimerTriggerBinding</code>) has the method - <code class="language-plaintext highlighter-rouge">CreateListenerAsync</code>. For the timers listener is <code class="language-plaintext highlighter-rouge">Microsoft.Azure.WebJobs.Extensions.Timers.Listeners.TimerListener</code>.</p>

<p>Let’s look at the listener:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">Singleton</span><span class="p">(</span><span class="n">Mode</span> <span class="p">=</span> <span class="n">SingletonMode</span><span class="p">.</span><span class="n">Listener</span><span class="p">)]</span>
<span class="k">internal</span> <span class="k">sealed</span> <span class="k">partial</span> <span class="k">class</span> <span class="nc">TimerListener</span> <span class="p">:</span> <span class="n">IListener</span>
<span class="p">{</span>
    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Well, here we are - this listener is requiring <code class="language-plaintext highlighter-rouge">Singleton</code> which has to be acquired before firing off this trigger.</p>

<p>Let’s jump back to <code class="language-plaintext highlighter-rouge">HostListenerFactory</code>. When it’s asked to create a new listener, there is a check for the <code class="language-plaintext highlighter-rouge">Singleton</code> attribute. If that’s present - the original listener is wrapped in <code class="language-plaintext highlighter-rouge">SingletonListener</code> to ensure that lock is acquired before starting the inner listener. <code class="language-plaintext highlighter-rouge">SingletonListener</code> is using <code class="language-plaintext highlighter-rouge">SingletonManager</code> to actually get the lock from the Azure storage blob.</p>

<p>What’s inside <code class="language-plaintext highlighter-rouge">SingletonManager</code>?</p>

<p>Loads of stuff.. and <code class="language-plaintext highlighter-rouge">FormatLockId(...)</code>. This sounds right. Let’s see what’s there.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="nf">FormatLockId</span><span class="p">(</span><span class="n">FunctionDescriptor</span> <span class="n">descr</span><span class="p">,</span> <span class="n">SingletonScope</span> <span class="n">scope</span><span class="p">,</span> <span class="kt">string</span> <span class="n">hostId</span><span class="p">,</span> <span class="kt">string</span> <span class="n">scopeId</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="kt">string</span><span class="p">.</span><span class="nf">IsNullOrEmpty</span><span class="p">(</span><span class="n">hostId</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="s">"hostId"</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="kt">string</span> <span class="n">lockId</span> <span class="p">=</span> <span class="kt">string</span><span class="p">.</span><span class="n">Empty</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">scope</span> <span class="p">==</span> <span class="n">SingletonScope</span><span class="p">.</span><span class="n">Function</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">lockId</span> <span class="p">+=</span> <span class="n">descr</span><span class="p">.</span><span class="n">FullName</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">if</span> <span class="p">(!</span><span class="kt">string</span><span class="p">.</span><span class="nf">IsNullOrEmpty</span><span class="p">(</span><span class="n">scopeId</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(!</span><span class="kt">string</span><span class="p">.</span><span class="nf">IsNullOrEmpty</span><span class="p">(</span><span class="n">lockId</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="n">lockId</span> <span class="p">+=</span> <span class="s">"."</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="n">lockId</span> <span class="p">+=</span> <span class="n">scopeId</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="n">lockId</span> <span class="p">=</span> <span class="kt">string</span><span class="p">.</span><span class="nf">Format</span><span class="p">(</span><span class="n">CultureInfo</span><span class="p">.</span><span class="n">InvariantCulture</span><span class="p">,</span> <span class="s">"{0}/{1}"</span><span class="p">,</span> <span class="n">hostId</span><span class="p">,</span> <span class="n">lockId</span><span class="p">);</span>

    <span class="k">return</span> <span class="n">lockId</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is most important line there <code class="language-plaintext highlighter-rouge">lockId = string.Format(CultureInfo.InvariantCulture, "{0}/{1}", hostId, lockId);</code></p>

<p>Locks consists of two segments:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">hostId</code> - passed in as an argument</li>
  <li><code class="language-plaintext highlighter-rouge">lockId</code> - type full name (FQDN) and <code class="language-plaintext highlighter-rouge">scopeId</code> (if has one)</li>
</ul>

<p>Seems legit. Let’s see where <code class="language-plaintext highlighter-rouge">hostId</code> is coming from.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="k">internal</span> <span class="kt">string</span> <span class="n">HostId</span>
<span class="p">{</span>
    <span class="k">get</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">_hostId</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">_hostId</span> <span class="p">=</span> <span class="n">_hostIdProvider</span><span class="p">.</span><span class="nf">GetHostIdAsync</span><span class="p">(</span><span class="n">CancellationToken</span><span class="p">.</span><span class="n">None</span><span class="p">).</span><span class="n">Result</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">_hostId</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>NB! I hope Microsoft engineers are super sure what they are doing when call <code class="language-plaintext highlighter-rouge">.Result</code> of the <code class="language-plaintext highlighter-rouge">HostId</code> producing <code class="language-plaintext highlighter-rouge">Task</code>.</p>

<p>So as it turns out - there is such an extension as <code class="language-plaintext highlighter-rouge">IHostIdProvider</code>. If webjob is scaled out to multiple instances and timers need singleton lock - there should be something that generates “the same” host id for both of these jobs. Something that is the same for all webjobs of the same source project. Let’s see what does <code class="language-plaintext highlighter-rouge">IHostIdProvider</code>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="kt">string</span> <span class="nf">ComputeHostId</span><span class="p">()</span>
<span class="p">{</span>
    <span class="c1">// Search through all types for the first job method.</span>
    <span class="c1">// The reason we have to do this rather than attempt to use the entry assembly</span>
    <span class="c1">// (Assembly.GetEntryAssembly) is because that doesn't work for WebApps, and the</span>
    <span class="c1">// SDK supports both WebApp and Console app hosts.</span>
    <span class="n">MethodInfo</span> <span class="n">firstJobMethod</span> <span class="p">=</span> <span class="k">null</span><span class="p">;</span>
    <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">type</span> <span class="k">in</span> <span class="n">_typeLocator</span><span class="p">.</span><span class="nf">GetTypes</span><span class="p">())</span>
    <span class="p">{</span>
        <span class="n">firstJobMethod</span> <span class="p">=</span> <span class="n">FunctionIndexer</span><span class="p">.</span><span class="nf">GetJobMethods</span><span class="p">(</span><span class="n">type</span><span class="p">).</span><span class="nf">FirstOrDefault</span><span class="p">();</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">firstJobMethod</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="c1">// Compute hash and map to Guid</span>
    <span class="c1">// If the job host doesn't yet have any job methods (e.g. it's a new project)</span>
    <span class="c1">// then a default ID is generated</span>
    <span class="kt">string</span> <span class="n">hostName</span> <span class="p">=</span> <span class="n">firstJobMethod</span><span class="p">?.</span><span class="n">DeclaringType</span><span class="p">.</span><span class="n">Assembly</span><span class="p">.</span><span class="n">FullName</span> <span class="p">??</span> <span class="s">"Unknown"</span><span class="p">;</span>
    <span class="n">Guid</span> <span class="n">id</span><span class="p">;</span>
    <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">md5</span> <span class="p">=</span> <span class="n">MD5</span><span class="p">.</span><span class="nf">Create</span><span class="p">())</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">hash</span> <span class="p">=</span> <span class="n">md5</span><span class="p">.</span><span class="nf">ComputeHash</span><span class="p">(</span><span class="n">Encoding</span><span class="p">.</span><span class="n">UTF8</span><span class="p">.</span><span class="nf">GetBytes</span><span class="p">(</span><span class="n">hostName</span><span class="p">));</span>
        <span class="n">id</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">Guid</span><span class="p">(</span><span class="n">hash</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="n">id</span><span class="p">.</span><span class="nf">ToString</span><span class="p">(</span><span class="s">"N"</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Well this makes total sense now. It generates <code class="language-plaintext highlighter-rouge">Guid</code> out of hash produced by the hosting assembly’s full name. If you run the same webjob instance on another node - it will produce the same <code class="language-plaintext highlighter-rouge">Guid</code> - resulting in failure to acquire lock - and thus skipping the execution. Which is perfectly fine. But not in our case :)</p>

<p>We need to add some extra salt to distinguish between one and another webjob hosts.</p>

<h3 id="generating-unique-lock-path-by-overriding-hostid">Generating Unique Lock Path by Overriding HostId</h3>

<p>As it turned out - we have to inject another <code class="language-plaintext highlighter-rouge">HostIdProvider</code> to get a unique host id and therefore be able to run more than a single webjob instance of the same source project.</p>

<p>For us, there is a configuration knob in the settings file that dictates which job it is (set by automatic deployment pipeline for us). We could use this to add some salt to the <code class="language-plaintext highlighter-rouge">hostId</code> generation process.</p>

<p>Let’s implement our own host id provider:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">HostTypeIdProvider</span> <span class="p">:</span> <span class="n">IHostIdProvider</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="kt">string</span> <span class="n">_hostType</span><span class="p">;</span>
    <span class="k">private</span> <span class="kt">string</span> <span class="n">_hostId</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">HostTypeIdProvider</span><span class="p">(</span><span class="kt">string</span> <span class="n">hostType</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_hostType</span> <span class="p">=</span> <span class="n">hostType</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">Task</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;</span> <span class="nf">GetHostIdAsync</span><span class="p">(</span><span class="n">CancellationToken</span> <span class="n">cancellationToken</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_hostId</span> <span class="p">??=</span> <span class="nf">ComputeHostId</span><span class="p">();</span>

        <span class="k">return</span> <span class="n">Task</span><span class="p">.</span><span class="nf">FromResult</span><span class="p">(</span><span class="n">_hostId</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="kt">string</span> <span class="nf">ComputeHostId</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">hostName</span> <span class="p">=</span> <span class="s">"Keeper-"</span> <span class="p">+</span> <span class="n">_hostType</span><span class="p">;</span>
        <span class="n">Guid</span> <span class="n">id</span><span class="p">;</span>
        <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">md5</span> <span class="p">=</span> <span class="n">MD5</span><span class="p">.</span><span class="nf">Create</span><span class="p">())</span>
        <span class="p">{</span>
            <span class="kt">var</span> <span class="n">hash</span> <span class="p">=</span> <span class="n">md5</span><span class="p">.</span><span class="nf">ComputeHash</span><span class="p">(</span><span class="n">Encoding</span><span class="p">.</span><span class="n">UTF8</span><span class="p">.</span><span class="nf">GetBytes</span><span class="p">(</span><span class="n">hostName</span><span class="p">));</span>
            <span class="n">id</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">Guid</span><span class="p">(</span><span class="n">hash</span><span class="p">);</span>
        <span class="p">}</span>

        <span class="k">return</span> <span class="n">id</span><span class="p">.</span><span class="nf">ToString</span><span class="p">(</span><span class="s">"N"</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And the only thing left is to inject this into the webjobs runtime. As most of the things nowadays are retrieved from IoC - it’s super easy:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">Main</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">args</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">HostBuilder</span><span class="p">();</span>
    <span class="n">builder</span><span class="p">.</span><span class="nf">ConfigureWebJobs</span><span class="p">((</span><span class="n">context</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="n">b</span><span class="p">.</span><span class="nf">AddAzureStorageCoreServices</span><span class="p">();</span>
            <span class="n">b</span><span class="p">.</span><span class="nf">AddAzureStorage</span><span class="p">();</span>
            <span class="n">b</span><span class="p">.</span><span class="nf">AddTimers</span><span class="p">();</span>

            <span class="kt">var</span> <span class="n">c</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">JobConfig</span><span class="p">();</span>
            <span class="n">context</span><span class="p">.</span><span class="n">Configuration</span><span class="p">.</span><span class="nf">GetSection</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">JobConfig</span><span class="p">)).</span><span class="nf">Bind</span><span class="p">(</span><span class="n">c</span><span class="p">);</span>

            <span class="n">b</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="n">AddSingleton</span><span class="p">&lt;</span><span class="n">IHostIdProvider</span><span class="p">&gt;(</span><span class="k">new</span> <span class="nf">HostTypeIdProvider</span><span class="p">(</span><span class="n">c</span><span class="p">.</span><span class="n">HostType</span> <span class="p">??</span> <span class="s">"Unknown"</span><span class="p">));</span>
        <span class="p">});</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So now we are able to run two (or even more) instances of our webjobs using the same Azure storage account. Each of them produces different <code class="language-plaintext highlighter-rouge">hostId</code> and therefore also different lock <code class="language-plaintext highlighter-rouge">path</code>. That allows each of them to acquire the singleton lock and start execution of the job functions.</p>

<h3 id="summary">Summary</h3>

<p>This is more like a note for me - when you are creating libraries or frameworks, please think about consumers of your masterpiece and how they will be able to override and change your opinionated approach or architecture :)</p>

<p>Happy coding!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="Azure" /><category term="WebJobs" /><category term="Background Services" /><category term="Dependency Injection" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="debugging" /><category term="azure" /><category term="webjobs" /><summary type="html"><![CDATA[Yes yes, while the whole world around us is serverless (read “servers running on thin air”), we are still running on concrete servers and utilizing real CPUs.]]></summary></entry><entry><title type="html">How-to Pack Your Shell Module for Optimizely Content Cloud</title><link href="https://tech-fellow.eu/2021/09/03/how-to-pack-your-shell-module-for-optimizely-content-cloud/" rel="alternate" type="text/html" title="How-to Pack Your Shell Module for Optimizely Content Cloud" /><published>2021-09-03T20:00:00+03:00</published><updated>2021-09-03T20:00:00+03:00</updated><id>https://tech-fellow.eu/2021/09/03/how-to-pack-your-shell-module-for-optimizely-content-cloud</id><content type="html" xml:base="https://tech-fellow.eu/2021/09/03/how-to-pack-your-shell-module-for-optimizely-content-cloud/"><![CDATA[<p>Optimizely Content Cloud is approaching fast and partners are working on getting modules out on the feed for the rest of us to test.</p>

<p>As you know - Optimizely vNext is targeting .NET 5 and with this fundamental platform change - there are few changes also how packaging of the module’s assets should be done.</p>

<p>This blog post should cover the most common tasks for you to pack properly Optimizely Content Cloud module.</p>

<p>Thanks to <a href="https://world.optimizely.com/System/Users-and-profiles/Community-Profile-Card/?userId=c739f674-8f6f-e111-968f-0050568d002c">Mark</a> and <a href="https://world.optimizely.com/System/Users-and-profiles/Community-Profile-Card/?userId=e6d9e7b4-1069-4217-81b4-1b2346a0150a">Māris</a> for initial version and ideas around how to pack our stuff.</p>

<p>If your module has Views - story is simpler there. More details <a href="https://github.com/episerver/netcore-preview#compiled-views-for-shell-modules">here</a>.</p>

<h2 id="todo-list">Todo List</h2>
<p>During module packaging process there are few things that we need to do:</p>

<ul>
  <li>copy <code class="language-plaintext highlighter-rouge">module.config</code> any client-side assets to temporary directory (assets usually go into directory named after package version);</li>
  <li>if your module has client-side assets - you have to ensure that <code class="language-plaintext highlighter-rouge">module.config</code> file points to correct path (including version number) e.g.:</li>
</ul>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;module</span>
        <span class="na">loadFromBin=</span><span class="s">"false"</span>
        <span class="na">clientResourceRelativePath=</span><span class="s">"7.0.0-pre-0002"</span>
        <span class="err">...</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>pack everything up into <code class="language-plaintext highlighter-rouge">.zip</code> file</li>
</ul>

<p><strong>NB!</strong> Even if your module does not have any client-side assets - you still need to include <code class="language-plaintext highlighter-rouge">module.config</code> file in <code class="language-plaintext highlighter-rouge">.zip</code> file. Here is <a href="https://github.com/episerver/netcore-preview/issues/17">a tracking issue</a> (to install module without <code class="language-plaintext highlighter-rouge">module.config</code> file). And install module provider sounds hackish anyway :)</p>

<ul>
  <li>include <code class="language-plaintext highlighter-rouge">.zip</code> file in target NuGet package under specific paths.</li>
</ul>

<p>So let’s get started.</p>

<h2 id="the-pack-script">The Pack Script</h2>
<h3 id="0-create-build-file-and-include-in-project">0. Create Build File and Include in Project</h3>
<p>To get things unified and reusable - let’s define <code class="language-plaintext highlighter-rouge">.proj</code> file that we will include in <code class="language-plaintext highlighter-rouge">.csproj</code> file - for the project that requires to be packed.</p>

<p>Let’s name file <code class="language-plaintext highlighter-rouge">pack.proj</code> and place it in <code class="language-plaintext highlighter-rouge">src/</code> folder.</p>

<p>Now we can include that one in <code class="language-plaintext highlighter-rouge">.csproj</code> file:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&lt;Import Project="$(SolutionDir)\src\pack.proj" Condition="Exists('$(SolutionDir)\src\pack.proj')" /&gt;
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="1-copy-stuff-to-temp-directory">1. Copy Stuff To Temp Directory</h3>
<p>First we need to define what is temp directory</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;PropertyGroup&gt;</span>
    <span class="nt">&lt;TmpOutDir&gt;</span>$(SolutionDir)\tmp<span class="nt">&lt;/TmpOutDir&gt;</span>
<span class="nt">&lt;/PropertyGroup&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then we have to script how stuff is copied over to temp directory. This target will be called always after successful <code class="language-plaintext highlighter-rouge">Build</code> target invocation - basically when project is built.</p>

<p>This script assumes that your Optimizely client-side assets are in <code class="language-plaintext highlighter-rouge">module\</code> folder in project structure.</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre>  <span class="nt">&lt;Target</span> <span class="na">Name=</span><span class="s">"CreateZip"</span> <span class="na">AfterTargets=</span><span class="s">"Build"</span><span class="nt">&gt;</span>

    <span class="nt">&lt;MakeDir</span> <span class="na">Directories=</span><span class="s">"$(TmpOutDir)\content\$(Version)"</span> <span class="nt">/&gt;</span>

    <span class="nt">&lt;ItemGroup&gt;</span>
      <span class="nt">&lt;ClientResources</span> <span class="na">Include=</span><span class="s">"$(SolutionDir)\src\$(MSBuildProjectName)\module\ClientResources\**\*"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;/ItemGroup&gt;</span>

    <span class="nt">&lt;Copy</span> <span class="na">SourceFiles=</span><span class="s">"@(ClientResources)"</span> <span class="na">DestinationFiles=</span><span class="s">"@(ClientResources -&gt; '$(TmpOutDir)\content\$(Version)\ClientResources\%(RecursiveDir)%(Filename)%(Extension)')"</span> <span class="nt">/&gt;</span>

    <span class="nt">&lt;Copy</span> <span class="na">SourceFiles=</span><span class="s">"$(SolutionDir)\src\$(MSBuildProjectName)\module\module.config"</span> <span class="na">DestinationFolder=</span><span class="s">"$(TmpOutDir)\content"</span> <span class="nt">/&gt;</span>

  <span class="nt">&lt;/Target&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Notes:</p>

<ul>
  <li>we define <code class="language-plaintext highlighter-rouge">ClientResources</code> variable pointing to all files under <code class="language-plaintext highlighter-rouge">module/ClientResources</code> folder;</li>
  <li>copy over those in <code class="language-plaintext highlighter-rouge">tmp/content/{version}/</code></li>
  <li>copy over also <code class="language-plaintext highlighter-rouge">module.config</code> file un <code class="language-plaintext highlighter-rouge">tmp/content/</code> folder;</li>
</ul>

<h3 id="2-set-client-resource-relative-path">2. Set Client Resource Relative Path</h3>
<p>Before we pack them up - we need to set correct client-side asset relative path in <code class="language-plaintext highlighter-rouge">module.config</code> file. This could be done by <code class="language-plaintext highlighter-rouge">XmlPoke</code> task:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;XmlPoke</span>
    <span class="na">XmlInputPath=</span><span class="s">"$(TmpOutDir)\content\module.config"</span>
    <span class="na">Query=</span><span class="s">"/module/@clientResourceRelativePath"</span>
    <span class="na">Value=</span><span class="s">"$(Version)"</span> <span class="nt">/&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="3-zip-it-up">3. Zip It Up</h3>
<p>Now we are ready to zip it up and remove temp folder.</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;UsingTask</span> <span class="na">TaskName=</span><span class="s">"ZipDirectory"</span> <span class="na">TaskFactory=</span><span class="s">"RoslynCodeTaskFactory"</span> <span class="na">AssemblyFile=</span><span class="s">"$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;ParameterGroup&gt;</span>
    <span class="nt">&lt;InputPath</span> <span class="na">ParameterType=</span><span class="s">"System.String"</span> <span class="na">Required=</span><span class="s">"true"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;OutputFileName</span> <span class="na">ParameterType=</span><span class="s">"System.String"</span> <span class="na">Required=</span><span class="s">"true"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;OverwriteExistingFile</span> <span class="na">ParameterType=</span><span class="s">"System.Boolean"</span> <span class="na">Required=</span><span class="s">"false"</span> <span class="nt">/&gt;</span>
  <span class="nt">&lt;/ParameterGroup&gt;</span>
  <span class="nt">&lt;Task&gt;</span>
    <span class="nt">&lt;Using</span> <span class="na">Namespace=</span><span class="s">"System.IO"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;Using</span> <span class="na">Namespace=</span><span class="s">"System.IO.Compression"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;Code</span> <span class="na">Type=</span><span class="s">"Fragment"</span> <span class="na">Language=</span><span class="s">"cs"</span><span class="nt">&gt;</span>
      <span class="cp">&lt;![CDATA[
        if(this.OverwriteExistingFile) {
          File.Delete(this.OutputFileName);
        }

        ZipFile.CreateFromDirectory(this.InputPath, this.OutputFileName);
      ]]&gt;</span>
    <span class="nt">&lt;/Code&gt;</span>
  <span class="nt">&lt;/Task&gt;</span>
<span class="nt">&lt;/UsingTask&gt;</span>

<span class="nt">&lt;ZipDirectory</span>
  <span class="na">InputPath=</span><span class="s">"$(TmpOutDir)\content"</span>
  <span class="na">OutputFileName=</span><span class="s">"$(OutDir)\$(MSBuildProjectName).zip"</span>
  <span class="na">OverwriteExistingFile=</span><span class="s">"true"</span> <span class="nt">/&gt;</span>
 <span class="nt">&lt;RemoveDir</span> <span class="na">Directories=</span><span class="s">"$(TmpOutDir)"</span> <span class="nt">/&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">$(OutDir)</code> - points to target folder where project is being packed.</p>

<h3 id="4-include-zip-file-in-nuget-package">4. Include .zip File in NuGet Package</h3>
<p>In order to include <code class="language-plaintext highlighter-rouge">.zip</code> file in NuGet package we have to specify that file is part of the package and also specify its location within the package folder tree system. This is accomplished with help of <code class="language-plaintext highlighter-rouge">Pack</code> and <code class="language-plaintext highlighter-rouge">PackagePath</code> properties defined for the <code class="language-plaintext highlighter-rouge">Content</code>.</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;Target</span> <span class="na">Name=</span><span class="s">"CreateZip"</span> <span class="na">AfterTargets=</span><span class="s">"Build"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;MakeDir</span> <span class="na">Directories=</span><span class="s">"$(TmpOutDir)\content\$(Version)"</span> <span class="nt">/&gt;</span>
  <span class="nt">&lt;ItemGroup&gt;</span>
    <span class="nt">&lt;Content</span> <span class="na">Include=</span><span class="s">"$(OutDir)\$(MSBuildProjectName).zip"</span> <span class="nt">&gt;</span>
    <span class="nt">&lt;Pack&gt;</span>true<span class="nt">&lt;/Pack&gt;</span>
    <span class="nt">&lt;PackagePath&gt;</span>content\modules\_protected\$(MSBuildProjectName)\;contentFiles\any\net5.0\modules\_protected\$(MSBuildProjectName)\<span class="nt">&lt;/PackagePath&gt;</span>
<span class="nt">&lt;/Content&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>NB!</strong> Shell <code class="language-plaintext highlighter-rouge">.zip</code> files must be present in two locations:</p>

<ul>
  <li>under <code class="language-plaintext highlighter-rouge">content\modules\_protected\..</code></li>
  <li>and under <code class="language-plaintext highlighter-rouge">contentFiles\any\net5.0\modules\_protected\..</code></li>
</ul>

<h2 id="copy-module-files-on-host-project-build">Copy Module Files On Host Project Build</h2>
<p>Here “host” project is consuming project - one where the package has been installed.</p>

<p>There is a catch. When you install NuGet package and want to include some files in the host project - files are added as “shortcuts”:</p>

<p><img src="/assets/img/2021/09/added-module-shortcut.png" alt="added-module-shortcut" /></p>

<p>Checking file properties you can see that files are added (as shortcut) from NuGet cache folder: <code class="language-plaintext highlighter-rouge">C:\Users\{user}\.nuget\packages\{module}\{version}\contentFiles\any\net5.0\modules\_protected\{module}\{module}.zip</code></p>

<p>Obviously this file is required to be present on the disk under project folder. We need additional file to get this file copied. We have to create <code class="language-plaintext highlighter-rouge">CopyZipFiles.targets</code> file. This file hook into different host project events and perform some actions. This time - we will copy over file <em>before</em> <code class="language-plaintext highlighter-rouge">Build</code> target.</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="cp">&lt;?xml version="1.0" encoding="utf-8"?&gt;</span>
<span class="nt">&lt;Project</span> <span class="na">xmlns=</span><span class="s">"http://schemas.microsoft.com/developer/msbuild/2003"</span> <span class="na">ToolsVersion=</span><span class="s">"4.0"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;ItemGroup&gt;</span>
    <span class="nt">&lt;SourceScripts</span>
      <span class="na">Include=</span><span class="s">"$(MSBuildThisFileDirectory)..\..\contentFiles\any\net5.0\modules\_protected\**\*.zip"</span><span class="nt">/&gt;</span>
  <span class="nt">&lt;/ItemGroup&gt;</span>

  <span class="nt">&lt;Target</span> <span class="na">Name=</span><span class="s">"CopyZipFiles"</span> <span class="na">BeforeTargets=</span><span class="s">"Build"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;Copy</span>
      <span class="na">SourceFiles=</span><span class="s">"@(SourceScripts)"</span>
      <span class="na">DestinationFolder=</span><span class="s">"$(MSBuildProjectDirectory)\modules\_protected\%(RecursiveDir)"</span>
<span class="nt">/&gt;</span>
  <span class="nt">&lt;/Target&gt;</span>
<span class="nt">&lt;/Project&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Here we basically take all files in NuGet package <code class="language-plaintext highlighter-rouge">contentFiles\any\net5.0\modules\_protected\</code> folder and copy to host project file system.</p>

<p>For the package to be able to execute some actions “inside” host project context - this target file also needs to be included in NuGet package with specific name (same as package name) and under specific folder (<code class="language-plaintext highlighter-rouge">build</code>).</p>

<p>To achieve this - we can use <code class="language-plaintext highlighter-rouge">Pack</code> and <code class="language-plaintext highlighter-rouge">PackagePath</code> settings:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;ItemGroup&gt;</span>
  <span class="nt">&lt;Content</span> <span class="na">Include=</span><span class="s">"$(SolutionDir)\src\$(MSBuildProjectName)\CopyZipFiles.targets"</span> <span class="nt">&gt;</span>
    <span class="nt">&lt;Pack&gt;</span>true<span class="nt">&lt;/Pack&gt;</span>
    <span class="nt">&lt;PackagePath&gt;</span>build\net5.0\$(MSBuildProjectName).targets<span class="nt">&lt;/PackagePath&gt;</span>
  <span class="nt">&lt;/Content&gt;</span>
<span class="nt">&lt;/ItemGroup&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="resulting-nuget-package">Resulting NuGet Package</h2>
<p>Packaging process is exactly the same as for any other .NET project:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet pack
</pre></td></tr></tbody></table></code></pre></div></div>

<p>At the end NuGet package should look something like this:</p>

<p><img src="/assets/img/2021/09/package.png" alt="package" /></p>

<p>I hope you will use other package ID as shown above :) otherwise we might collide..</p>

<h2 id="sample-working-project">Sample Working Project</h2>
<p>Localization Provider beta version for upcoming Optimizely version is using this approach. Here is reference to <a href="https://github.com/valdisiljuconoks/localization-provider-epi/tree/main/src/DbLocalizationProvider.AdminUI.EPiServer">GitHub repo</a>.</p>

<h2 id="full-file-versions">Full File Versions</h2>
<h3 id="the-pack-script-1">The Pack Script</h3>
<p>Here is full pack script file for completeness:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
</pre></td><td class="rouge-code"><pre><span class="cp">&lt;?xml version="1.0" encoding="utf-8"?&gt;</span>

<span class="nt">&lt;Project</span> <span class="na">xmlns=</span><span class="s">"http://schemas.microsoft.com/developer/msbuild/2003"</span> <span class="na">ToolsVersion=</span><span class="s">"15.0"</span><span class="nt">&gt;</span>

  <span class="nt">&lt;UsingTask</span> <span class="na">TaskName=</span><span class="s">"ZipDirectory"</span> <span class="na">TaskFactory=</span><span class="s">"RoslynCodeTaskFactory"</span> <span class="na">AssemblyFile=</span><span class="s">"$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;ParameterGroup&gt;</span>
      <span class="nt">&lt;InputPath</span> <span class="na">ParameterType=</span><span class="s">"System.String"</span> <span class="na">Required=</span><span class="s">"true"</span> <span class="nt">/&gt;</span>
      <span class="nt">&lt;OutputFileName</span> <span class="na">ParameterType=</span><span class="s">"System.String"</span> <span class="na">Required=</span><span class="s">"true"</span> <span class="nt">/&gt;</span>
      <span class="nt">&lt;OverwriteExistingFile</span> <span class="na">ParameterType=</span><span class="s">"System.Boolean"</span> <span class="na">Required=</span><span class="s">"false"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;/ParameterGroup&gt;</span>
    <span class="nt">&lt;Task&gt;</span>
      <span class="nt">&lt;Using</span> <span class="na">Namespace=</span><span class="s">"System.IO"</span> <span class="nt">/&gt;</span>
      <span class="nt">&lt;Using</span> <span class="na">Namespace=</span><span class="s">"System.IO.Compression"</span> <span class="nt">/&gt;</span>
      <span class="nt">&lt;Code</span> <span class="na">Type=</span><span class="s">"Fragment"</span> <span class="na">Language=</span><span class="s">"cs"</span><span class="nt">&gt;</span>
        <span class="cp">&lt;![CDATA[
          if(this.OverwriteExistingFile) {
            File.Delete(this.OutputFileName);
          }
          ZipFile.CreateFromDirectory(this.InputPath, this.OutputFileName);
        ]]&gt;</span>
      <span class="nt">&lt;/Code&gt;</span>
    <span class="nt">&lt;/Task&gt;</span>
  <span class="nt">&lt;/UsingTask&gt;</span>

  <span class="nt">&lt;PropertyGroup&gt;</span>
    <span class="nt">&lt;SolutionDir</span> <span class="na">Condition=</span><span class="s">"$(SolutionDir) == ''"</span><span class="nt">&gt;</span>$(MSBuildProjectDirectory)\..\<span class="nt">&lt;/SolutionDir&gt;</span>
    <span class="nt">&lt;TmpOutDir&gt;</span>$(SolutionDir)\tmp<span class="nt">&lt;/TmpOutDir&gt;</span>
  <span class="nt">&lt;/PropertyGroup&gt;</span>

  <span class="nt">&lt;Target</span> <span class="na">Name=</span><span class="s">"CreateZip"</span> <span class="na">AfterTargets=</span><span class="s">"Build"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;MakeDir</span> <span class="na">Directories=</span><span class="s">"$(TmpOutDir)\content\$(Version)"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;ItemGroup&gt;</span>
      <span class="nt">&lt;ClientResources</span> <span class="na">Include=</span><span class="s">"$(SolutionDir)\src\$(MSBuildProjectName)\module\ClientResources\**\*"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;/ItemGroup&gt;</span>
    <span class="nt">&lt;Copy</span> <span class="na">SourceFiles=</span><span class="s">"$(SolutionDir)\src\$(MSBuildProjectName)\module\module.config"</span> <span class="na">DestinationFolder=</span><span class="s">"$(TmpOutDir)\content"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;Copy</span> <span class="na">SourceFiles=</span><span class="s">"@(ClientResources)"</span> <span class="na">DestinationFiles=</span><span class="s">"@(ClientResources -&gt; '$(TmpOutDir)\content\$(Version)\ClientResources\%(RecursiveDir)%(Filename)%(Extension)')"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;XmlPoke</span> <span class="na">XmlInputPath=</span><span class="s">"$(TmpOutDir)\content\module.config"</span> <span class="na">Query=</span><span class="s">"/module/@clientResourceRelativePath"</span> <span class="na">Value=</span><span class="s">"$(Version)"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;ZipDirectory</span>
      <span class="na">InputPath=</span><span class="s">"$(TmpOutDir)\content"</span>
      <span class="na">OutputFileName=</span><span class="s">"$(OutDir)\$(MSBuildProjectName).zip"</span>
      <span class="na">OverwriteExistingFile=</span><span class="s">"true"</span> <span class="nt">/&gt;</span>

    <span class="c">&lt;!-- &lt;RemoveDir Directories="$(TmpOutDir)" /&gt; --&gt;</span>
  <span class="nt">&lt;/Target&gt;</span>

  <span class="nt">&lt;ItemGroup&gt;</span>
    <span class="nt">&lt;Content</span> <span class="na">Include=</span><span class="s">"$(OutDir)\$(MSBuildProjectName).zip"</span> <span class="nt">&gt;</span>
      <span class="nt">&lt;Pack&gt;</span>true<span class="nt">&lt;/Pack&gt;</span>
      <span class="nt">&lt;PackagePath&gt;</span>content\modules\_protected\$(MSBuildProjectName)\;contentFiles\any\net5.0\modules\_protected\$(MSBuildProjectName)\<span class="nt">&lt;/PackagePath&gt;</span>
    <span class="nt">&lt;/Content&gt;</span>
    <span class="nt">&lt;Content</span> <span class="na">Include=</span><span class="s">"$(SolutionDir)\src\$(MSBuildProjectName)\CopyZipFiles.targets"</span> <span class="nt">&gt;</span>
      <span class="nt">&lt;Pack&gt;</span>true<span class="nt">&lt;/Pack&gt;</span>
      <span class="nt">&lt;PackagePath&gt;</span>build\net5.0\$(MSBuildProjectName).targets<span class="nt">&lt;/PackagePath&gt;</span>
    <span class="nt">&lt;/Content&gt;</span>
  <span class="nt">&lt;/ItemGroup&gt;</span>
<span class="nt">&lt;/Project&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="copy-zip-file-script">Copy Zip File Script</h3>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="cp">&lt;?xml version="1.0" encoding="utf-8"?&gt;</span>
<span class="nt">&lt;Project</span> <span class="na">xmlns=</span><span class="s">"http://schemas.microsoft.com/developer/msbuild/2003"</span> <span class="na">ToolsVersion=</span><span class="s">"4.0"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;ItemGroup&gt;</span>
    <span class="nt">&lt;SourceScripts</span>
      <span class="na">Include=</span><span class="s">"$(MSBuildThisFileDirectory)..\..\contentFiles\any\net5.0\modules\_protected\**\*.zip"</span><span class="nt">/&gt;</span>
  <span class="nt">&lt;/ItemGroup&gt;</span>

  <span class="nt">&lt;Target</span> <span class="na">Name=</span><span class="s">"CopyZipFiles"</span> <span class="na">BeforeTargets=</span><span class="s">"Build"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;Copy</span>
      <span class="na">SourceFiles=</span><span class="s">"@(SourceScripts)"</span>
      <span class="na">DestinationFolder=</span><span class="s">"$(MSBuildProjectDirectory)\modules\_protected\%(RecursiveDir)"</span>
<span class="nt">/&gt;</span>
  <span class="nt">&lt;/Target&gt;</span>
<span class="nt">&lt;/Project&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Happy packaging!
[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><category term="open source" /><summary type="html"><![CDATA[Optimizely Content Cloud is approaching fast and partners are working on getting modules out on the feed for the rest of us to test.]]></summary></entry><entry><title type="html">What New APIs Are Coming in Optimizely Content Cloud vNext?</title><link href="https://tech-fellow.eu/2021/08/19/whats-new-coming-in-optimizely-vnext/" rel="alternate" type="text/html" title="What New APIs Are Coming in Optimizely Content Cloud vNext?" /><published>2021-08-19T01:10:00+03:00</published><updated>2021-08-19T01:10:00+03:00</updated><id>https://tech-fellow.eu/2021/08/19/whats-new-coming-in-optimizely-vnext</id><content type="html" xml:base="https://tech-fellow.eu/2021/08/19/whats-new-coming-in-optimizely-vnext/"><![CDATA[<h2 id="intro">Intro</h2>
<p>I was wondering what new assemblies and public APIs are coming in new version of Content Management System from Optimizely (ex. EPiServer).
I took standard AlloyTech site created via Episerver VS integration plugin (for CMS11) and <a href="https://github.com/episerver/netcore-preview">.NET Core Preview</a> site (<strong>v12.0.1-pre-022064</strong>) and ran some comparison script I hacked together at evening.</p>

<h2 id="assemblies">Assemblies</h2>
<p>These are brand new assemblies coming in CMS v12 (aka Optimizely Content Clound). Note that package and assmeblies names still contain prefix “EPiServer”. This is by design and it will make sure that upgrade process is much smoother.</p>

<ul>
  <li>EPiServer.CMS</li>
  <li>EPiServer.Cms.AspNetCore</li>
  <li>EPiServer.Cms.AspNetCore.HtmlHelpers</li>
  <li>EPiServer.Cms.AspNetCore.Mvc</li>
  <li>EPiServer.Cms.AspNetCore.Routing</li>
  <li>EPiServer.Cms.AspNetCore.Templating</li>
  <li>EPiServer.Cms.UI.Admin</li>
  <li>EPiServer.Cms.UI.VisitorGroups</li>
  <li>EPiServer.Framework.AspNetCore</li>
  <li>EPiServer.Hosting</li>
</ul>

<p>Assemblies left in CMS 11:</p>

<ul>
  <li>EPiServer.Cms.AspNet</li>
  <li>EPiServer.Configuration</li>
  <li>EPiServer.Data.Cache</li>
  <li>EPiServer.Framework.AspNet</li>
  <li>EPiServer.LinkAnalyzer</li>
  <li>EPiServer.Web.WebControls</li>
</ul>

<p><img src="/assets/img/2021/08/asm.png" alt="asm" /></p>

<p>This is full list comparison:</p>

<p><img src="/assets/img/2021/08/asm-full.png" alt="asm-full" /></p>

<h2 id="new-public-types">New Public Types</h2>
<p>Here it’s interesting to compare what new types have showned up in assemblies that are still present from CMS11.</p>

<p>Some of the types have been moved from <code class="language-plaintext highlighter-rouge">Internal</code> (CMS11) to public namespace (CMS12). Also some of types have been moved from one assembly to another (for example, <code class="language-plaintext highlighter-rouge">EPiServer.Web.QuickNavigatorMenu</code> defined in <code class="language-plaintext highlighter-rouge">EPiServer.Cms.AspNet.dll</code> moved to <code class="language-plaintext highlighter-rouge">EPiServer.Shell.UI</code>).</p>

<p>Some of the types have been transformed from <code class="language-plaintext highlighter-rouge">internal</code> to <code class="language-plaintext highlighter-rouge">public</code>.</p>

<p>I haven’t been digging deeper for each of the type and it’s goal in the platform.</p>

<p>Below you can find all new types in CMS12 but defined or moved to assemblies that exist CMS11 as well:</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><category term="open source" /><summary type="html"><![CDATA[Intro I was wondering what new assemblies and public APIs are coming in new version of Content Management System from Optimizely (ex. EPiServer). I took standard AlloyTech site created via Episerver VS integration plugin (for CMS11) and .NET Core Preview site (v12.0.1-pre-022064) and ran some comparison script I hacked together at evening.]]></summary></entry><entry><title type="html">Fixing 99% CPU usage in gRPC service</title><link href="https://tech-fellow.eu/2021/08/05/99-cpu-usage-in-grpc-service/" rel="alternate" type="text/html" title="Fixing 99% CPU usage in gRPC service" /><published>2021-08-05T00:15:00+03:00</published><updated>2021-08-05T00:15:00+03:00</updated><id>https://tech-fellow.eu/2021/08/05/99-cpu-usage-in-grpc-service</id><content type="html" xml:base="https://tech-fellow.eu/2021/08/05/99-cpu-usage-in-grpc-service/"><![CDATA[<h2 id="setting-the-crime-scene">Setting the Crime Scene</h2>
<p>We are back again in gRPC service and this time we will be working on another performance issue. These kind of issues comes under the radar very easily when you are dealing with long-lived, high performant and heavily used service that is running for ages. Back in old days it was easy to set recycling options for IIS and all of the sudden your memory, CPU or any other issues are auto-magically gone. Here in our case - gRPC service has to run for days, weeks, maybe even months without any interruptions. Maintaining service with these constraints becomes frankly interesting and challenging.</p>

<h2 id="observing-the-issue">Observing the Issue</h2>
<p>This time we had to deal with super high CPU usage by our gRPC service.
We were expecting to see normal behavior and resource usage by the service - something like this over the time:</p>

<p><img src="/assets/img/2021/08/cpu-99-normal.png" alt="cpu-99-normal" /></p>

<p>But, after <strong>few days</strong> of uptime - we were stuck with this picture from Task Manager:</p>

<p><img src="/assets/img/2021/08/cpu-99-abnormal.png" alt="cpu-99-abnormal" /></p>

<p>Interesting fact here is that this behavior starts to appear only after running for a few days. Which means that something is leaking somewhere and it leaks only under specific concrete conditions.</p>

<h2 id="collecting-trace">Collecting Trace</h2>
<p>What we can start with - collecting some traces from the running process. For this to happen - we have to install <a href="https://docs.microsoft.com/en-us/dotnet/core/diagnostics/">.NET Diagnostic Tools</a>.</p>

<p>Let’s start with counters.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet tool install --global dotnet-counters
</pre></td></tr></tbody></table></code></pre></div></div>

<p>First, we need to find applicable process ID for the gRPC service.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet-counters ps
</pre></td></tr></tbody></table></code></pre></div></div>
<p><img src="/assets/img/2021/08/dotnet-counters-ps.png" alt="dotnet-counters-ps" /></p>

<p>When found we can start counter monitor to see some of the indicators without collecting any process data yet.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet-counters monitor --refresh-interval 1 -p 4352
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This opens old school command prompt style diagnostics panel.</p>

<p><img src="/assets/img/2021/08/99cpu-1-1.png" alt="99cpu-1-1" /></p>

<p>Counters are collected every second (set by <code class="language-plaintext highlighter-rouge">refresh-interval</code> argument) and values are displayed on the screen.</p>

<p>Looking at counter data over the time - we saw that allocation rate increases, CPU usage increases, GC numbers go up.</p>

<p>But overall ~450MB allocation per second is not a good sign of healthy service (unless you expect it and the service is designed for that).</p>

<p>Next step is to collect some data that we could use to analyze in more details what’s going on and where to start to look for the issue root cause.</p>

<p>For this - we will need another global tool.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet tool install --global dotnet-trace
</pre></td></tr></tbody></table></code></pre></div></div>

<p>After trace tool is installed we can start collecting sample data (recommended us to run this tool exactly when you have observed issues with the application):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet-trace collect -p 4352 --providers Microsoft-DotNETCore-SampleProfiler
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Let it run for some time (I was collecting data for about 1 minute). After you complete trace session <code class="language-plaintext highlighter-rouge">trace.nettrace</code> file will be written to the disk (tool will let you know exact location).</p>

<p>I usually copy over trace file along with whole application directory to some local machine so I can analyze uninterrupted and off from production environment.</p>

<h2 id="analyzing-trace-using-perfview">Analyzing Trace Using PerfView</h2>
<p>Once we have all the files on local machine you will see following screen after opening trace file with PerfView.</p>

<p><img src="/assets/img/2021/08/cpu-99-pv-start.png" alt="cpu-99-pv-start" /></p>

<p>This is landing page of the PerfView.</p>

<p><code class="language-plaintext highlighter-rouge">Thread Time (with StartStop Activities) Stacks</code> is a good start to browse around collected data.</p>

<p>Double click on it and it will open more detailed view (I had to blur some of the method and type names not to expose project specific details).</p>

<p><img src="/assets/img/2021/08/cpu-99-pv-thread-time.png" alt="cpu-99-pv-thread-time" /></p>

<p>Next we can sort by <code class="language-plaintext highlighter-rouge">"Inc %"</code> column and inspect who is on top (<code class="language-plaintext highlighter-rouge">Inc %</code> - inclusive cost expressed as a percentage of the total cost of all samples).</p>

<p>Interesting that 1st “My Code” method which takes super huge amount of time during sampled period is <code class="language-plaintext highlighter-rouge">"PostProcess"</code> method from the <code class="language-plaintext highlighter-rouge">Quay</code> endpoint. CPU usage of <strong>45%</strong> for something so simple as processing 5000 items almost every second is <strong>REALLY</strong> suspicious.</p>

<p><img src="/assets/img/2021/08/cpu-99-pv-thread-postprocess.png" alt="cpu-99-pv-thread-postprocess" /></p>

<h2 id="revisiting-application-architecture">Revisiting Application Architecture</h2>
<p>So let’s revisit what is <code class="language-plaintext highlighter-rouge">Quay</code> endpoint and where it’s used.</p>

<p>We do have <code class="language-plaintext highlighter-rouge">SubscribeToQuays</code> endpoint method in our gRPC service. This method is responsible for the few things:</p>

<ul>
  <li>accepting request options describing what kind of data particular subscriber is interested in (<code class="language-plaintext highlighter-rouge">RequestOptions</code>). <code class="language-plaintext highlighter-rouge">RequestOptions</code> is a POCO class carrying various settings for the subscribe method invoke. For example, using options parameter I can subscribe to simple view of the quays - like name, coordinates and transport type for the quay;</li>
  <li>passing <code class="language-plaintext highlighter-rouge">RequestOptions</code> down to <code class="language-plaintext highlighter-rouge">ProfileStore</code> for profile calculation;</li>
  <li><code class="language-plaintext highlighter-rouge">ProfileStore</code> however is responsible to calculate combination of <code class="language-plaintext highlighter-rouge">RequestOptions</code> parameters and understand whether this is something brand new or we already have this profile in <code class="language-plaintext highlighter-rouge">ProfileStore</code>;</li>
  <li>List of generated profiles is stored in <code class="language-plaintext highlighter-rouge">ConcurrentDictionary&lt;&gt;</code> with key of <code class="language-plaintext highlighter-rouge">RequestOptions</code> itself.</li>
</ul>

<p>This is high level inner workings of the <code class="language-plaintext highlighter-rouge">ProfileStore</code>:</p>

<p><img src="/assets/img/2021/08/cpu-99-arch-profiles.png" alt="cpu-99-arch-profiles" /></p>

<p>When incoming data about transport positions (and other metrics) is received from ServiceBus <code class="language-plaintext highlighter-rouge">MessageReceiver</code> (variable <code class="language-plaintext highlighter-rouge">AllData</code>) - it is passed over to profile store for the individual profile data projection.
In order to keep performance at the required level - it was decided to clone <code class="language-plaintext highlighter-rouge">AllData</code> content and run various processors and filters for each profile’s copy of the data. This means that if we do have 3 distinct profiles in store - 3 copies of transport data will be created (each for every profile).
<code class="language-plaintext highlighter-rouge">RequestOptions</code> potential combinations of property values is low enough - so theoretically in our case max profile count can reach only 12. Knowing size of the <code class="language-plaintext highlighter-rouge">AllData</code> content and potential profile count - we made decision to copy data.</p>

<p><img src="/assets/img/2021/08/cpu-99-arch-profiles-data-processing.png" alt="cpu-99-arch-profiles-data-processing" /></p>

<p><strong>NB!</strong> We see that count of the profiles directly affects amount of used memory and required processing power to calculate projected transport data for that profile.</p>

<p>To illustrate <code class="language-plaintext highlighter-rouge">ProfileStore</code> responsibilities here is small code sample of how this should be working:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">RequestOptions</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">bool</span> <span class="n">IncludeCoordinates</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">bool</span> <span class="n">IncludeName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="n">TransportModeOptions</span> <span class="n">TransportModeOptions</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="k">new</span><span class="p">();</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">TransportModeOptions</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">bool</span> <span class="n">IncludeAll</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">ProfileStore</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="n">ConcurrentDictionary</span><span class="p">&lt;</span><span class="n">RequestOptions</span><span class="p">,</span> <span class="n">QuayProfile</span><span class="p">&gt;</span> <span class="n">_profiles</span>
        <span class="p">=</span> <span class="k">new</span><span class="p">(</span><span class="k">new</span> <span class="nf">RequestOptions</span><span class="p">());</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">RegisterProfile</span><span class="p">(</span><span class="n">RequestOptions</span> <span class="n">options</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(!</span><span class="n">_profiles</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="n">options</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="n">_profiles</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">new</span> <span class="nf">QuayDataProcessingProfile</span><span class="p">(</span><span class="n">options</span><span class="p">));</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="kt">int</span> <span class="n">ProfileCount</span> <span class="p">=&gt;</span> <span class="n">_profiles</span><span class="p">.</span><span class="nf">Count</span><span class="p">();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>In order to add proper support for <code class="language-plaintext highlighter-rouge">if (!_profiles.Contains(options))</code> we have to implement <code class="language-plaintext highlighter-rouge">IEqualityComparer&lt;RequestOptions&gt;</code> interface (we are constructing <code class="language-plaintext highlighter-rouge">ConcurrentDictionary&lt;&gt;</code> using our comparer).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">System.Collections.Generic</span>
<span class="p">{</span>
  <span class="k">public</span> <span class="k">interface</span> <span class="nc">IEqualityComparer</span><span class="p">&lt;</span><span class="k">in</span> <span class="n">T</span><span class="p">&gt;</span>
  <span class="p">{</span>
    <span class="kt">bool</span> <span class="nf">Equals</span><span class="p">(</span><span class="n">T</span><span class="p">?</span> <span class="n">x</span><span class="p">,</span> <span class="n">T</span><span class="p">?</span> <span class="n">y</span><span class="p">);</span>

    <span class="kt">int</span> <span class="nf">GetHashCode</span><span class="p">([</span><span class="n">DisallowNull</span><span class="p">]</span> <span class="n">T</span> <span class="n">obj</span><span class="p">);</span>
  <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is equality comparison implementation (or part of it):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">RequestOptions</span> <span class="p">:</span> <span class="n">IEqualityComparer</span><span class="p">&lt;</span><span class="n">RequestOptions</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">bool</span> <span class="n">IncludeCoordinates</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">bool</span> <span class="n">IncludeName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="n">TransportModeOptions</span> <span class="n">TransportModeOptions</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="k">new</span><span class="p">();</span>

    <span class="k">public</span> <span class="k">override</span> <span class="kt">bool</span> <span class="nf">Equals</span><span class="p">(</span><span class="kt">object</span> <span class="n">obj</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="nf">Equals</span><span class="p">((</span><span class="n">RequestOptions</span><span class="p">)</span><span class="n">obj</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="kt">bool</span> <span class="nf">Equals</span><span class="p">(</span><span class="n">RequestOptions</span> <span class="n">x</span><span class="p">,</span> <span class="n">RequestOptions</span> <span class="n">y</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="p">...</span>

        <span class="k">if</span> <span class="p">(!</span><span class="n">TransportModeOptions</span><span class="p">.</span><span class="nf">Equals</span><span class="p">(</span><span class="n">x</span><span class="p">.</span><span class="n">TransportModeOptions</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="k">return</span> <span class="k">false</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="k">return</span> <span class="k">true</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Basically we are comparing 2 objects and returning <code class="language-plaintext highlighter-rouge">true</code> if all the properties are the same; otherwise <code class="language-plaintext highlighter-rouge">false</code>.</p>

<p>Below is code fragment that should verify behavior of the <code class="language-plaintext highlighter-rouge">ProfileStore</code>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">Fact</span><span class="p">]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">RegisterTwoSimilarProfiles_ShouldBeOne</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">sut</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ProfileStore</span><span class="p">();</span>

    <span class="kt">var</span> <span class="n">p1</span> <span class="p">=</span> <span class="k">new</span> <span class="n">RequestOptions</span>
    <span class="p">{</span>
        <span class="n">IncludeCoordinates</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
        <span class="n">IncludeName</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
        <span class="n">TransportModeOptions</span> <span class="p">=</span>
        <span class="p">{</span>
            <span class="n">IncludeAll</span> <span class="p">=</span> <span class="k">false</span>
        <span class="p">}</span>
    <span class="p">};</span>

    <span class="kt">var</span> <span class="n">p2</span> <span class="p">=</span> <span class="k">new</span> <span class="n">RequestOptions</span>
    <span class="p">{</span>
        <span class="n">IncludeCoordinates</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
        <span class="n">IncludeName</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
        <span class="n">TransportModeOptions</span> <span class="p">=</span>
        <span class="p">{</span>
            <span class="n">IncludeAll</span> <span class="p">=</span> <span class="k">false</span>
        <span class="p">}</span>
    <span class="p">};</span>

    <span class="n">sut</span><span class="p">.</span><span class="nf">RegisterProfile</span><span class="p">(</span><span class="n">p1</span><span class="p">);</span>
    <span class="n">sut</span><span class="p">.</span><span class="nf">RegisterProfile</span><span class="p">(</span><span class="n">p2</span><span class="p">);</span>

    <span class="n">sut</span><span class="p">.</span><span class="n">ProfileCount</span><span class="p">.</span><span class="n">Should</span><span class="p">.</span><span class="nf">Be</span><span class="p">(</span><span class="m">1</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Unit tests were green! We are ready to roll further.</p>

<p>However from PerfView we see that we spend a lot of time preparing data for the profiles.</p>

<p>Next step should be to verify how much time takes to process incoming transport data for a profile.
After setting up infrastructure for that and running few sample runs - we saw that time is measured in milliseconds and CPU usage is not that high.</p>

<p>Now we have to ask ourselves two questions:</p>

<ul>
  <li>Why does data preparation for quay profiles take so much time?</li>
  <li>And why this happens only after few hours or even days of gRPC service uptime?</li>
</ul>

<p>To answer first question - during peak (or particularly hard time for the gRPC service) I took memory dump of the process. We could look into the memory footprints and maybe find something interesting there.</p>

<h2 id="analyzing-half-dead-process-memory-dump">Analyzing Half-Dead Process Memory Dump</h2>
<p>Btw, how to take a dump I described in previous post of these series <a href="/2021/05/23/analyzing-grpc-service-memdump-from-linux-based-docker-running-on-aci/">here</a>.</p>

<p>I already did that and opened <code class="language-plaintext highlighter-rouge">.dmp</code> file in Visual Studio 2022 Preview 2.1 (it’s quite snappy to be honest).</p>

<p>We have to start with <code class="language-plaintext highlighter-rouge">Debug Managed Memory</code>:</p>

<p><img src="/assets/img/2021/08/cpu-99-vs-debug.png" alt="cpu-99-vs-debug" /></p>

<p>It might take some time to calculate all GC roots and other information from the dump file - so be patient.</p>

<p><code class="language-plaintext highlighter-rouge">Parallel Stacks</code> is really useful view on the data - showing you what’s happening in your parallel code (<code class="language-plaintext highlighter-rouge">async</code> + <code class="language-plaintext highlighter-rouge">await</code> and friends).
Looking at parallel stack - I noticed that our famous <code class="language-plaintext highlighter-rouge">ProfileStore</code> is doing a lot of work and it’s spread across many (really many for that amount of data and potential count of profiles) threads.</p>

<p><img src="/assets/img/2021/08/cpu-99-vs-debug-ps.png" alt="cpu-99-vs-debug-ps" /></p>

<p>Data preparation happens in parallel for each profile - this can help speed up overall data slicing and profile projection preparation process.</p>

<p>But doing it over 29 threads (at the moment of dump collection) is <strong>WAY TOO MUCH</strong>!</p>

<p>So - related question is what about count of active profiles? To answer this question - we have to look into memory snapshot and find some details about <code class="language-plaintext highlighter-rouge">ProfileStore</code>.</p>

<p>Summary screen already is highlighting some of the details that might be interesting for us:</p>

<p><img src="/assets/img/2021/08/cpu-99-vs-mem-view.png" alt="cpu-99-vs-mem-view" /></p>

<p>Summary window (ordered by <code class="language-plaintext highlighter-rouge">Inclusive Size (Bytes)</code> column) shows that we do have <strong>146 instances</strong> of <code class="language-plaintext highlighter-rouge">QuayDataProfile</code> items. <code class="language-plaintext highlighter-rouge">QuayDataProfile</code> is basically value in <code class="language-plaintext highlighter-rouge">_profiles</code> dictionary.</p>

<p>This means that we have 146 active profiles!!! Which again is <strong>WAY TOO MUCH</strong> (like it’s even physically not possible to generate so much profiles)!</p>

<p>Let’s verify again by finding this dictionary somewhere on the stack:</p>

<p><img src="/assets/img/2021/08/cpu-99-vs-debug-stack.png" alt="cpu-99-vs-debug-stack" /></p>

<p>Ok, we have verified that we do have pretty high number of active profiles. Also keeping in mind that we do transport data snapshot clone for each profile and additionally we run some expensive processing pipeline - this might explain high  CPU usage. And we also saw that from the <code class="language-plaintext highlighter-rouge">Parallel Stack</code> window - that many threads are occupied with the same task.</p>

<p>Now we have to look deeper at how profiles are generated from <code class="language-plaintext highlighter-rouge">RequestOptions</code>.</p>

<p><img src="/assets/img/2021/08/cpu-99-arch-profiles-compare.png" alt="cpu-99-arch-profiles-compare" /></p>

<p>But.. but… unit tests <strong>WERE GREEN</strong>!!!</p>

<h2 id="returning-to-test-cases">Returning to Test Cases</h2>
<p>Ok, let’s return to our test suite.</p>

<p>This test is GREEN!</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">Fact</span><span class="p">]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">RegisterTwoSimilarProfiles_ShouldBeOne</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">sut</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ProfileStore</span><span class="p">();</span>

    <span class="kt">var</span> <span class="n">p1</span> <span class="p">=</span> <span class="k">new</span> <span class="n">RequestOptions</span>
    <span class="p">{</span>
        <span class="n">IncludeCoordinates</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
        <span class="n">IncludeName</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
        <span class="n">TransportModeOptions</span> <span class="p">=</span>
        <span class="p">{</span>
            <span class="n">IncludeAll</span> <span class="p">=</span> <span class="k">false</span>
        <span class="p">}</span>
    <span class="p">};</span>

    <span class="kt">var</span> <span class="n">p2</span> <span class="p">=</span> <span class="k">new</span> <span class="n">RequestOptions</span>
    <span class="p">{</span>
        <span class="n">IncludeCoordinates</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
        <span class="n">IncludeName</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
        <span class="n">TransportModeOptions</span> <span class="p">=</span>
        <span class="p">{</span>
            <span class="n">IncludeAll</span> <span class="p">=</span> <span class="k">false</span>
        <span class="p">}</span>
    <span class="p">};</span>

    <span class="n">sut</span><span class="p">.</span><span class="nf">RegisterProfile</span><span class="p">(</span><span class="n">p1</span><span class="p">);</span>
    <span class="n">sut</span><span class="p">.</span><span class="nf">RegisterProfile</span><span class="p">(</span><span class="n">p2</span><span class="p">);</span>

    <span class="n">sut</span><span class="p">.</span><span class="n">ProfileCount</span><span class="p">.</span><span class="n">Should</span><span class="p">.</span><span class="nf">Be</span><span class="p">(</span><span class="m">1</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Ok, let’s try to insert two different profiles:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">Fact</span><span class="p">]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">RegisterTwoDifferentProfiles_ShouldBeTwo</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">sut</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ProfileStore</span><span class="p">();</span>

    <span class="c1">// IncludeAll = false</span>
    <span class="kt">var</span> <span class="n">p1</span> <span class="p">=</span> <span class="k">new</span> <span class="n">RequestOptions</span>
    <span class="p">{</span>
        <span class="n">IncludeCoordinates</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
        <span class="n">IncludeName</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
        <span class="n">TransportModeOptions</span> <span class="p">=</span>
        <span class="p">{</span>
            <span class="n">IncludeAll</span> <span class="p">=</span> <span class="k">false</span>
        <span class="p">}</span>
    <span class="p">};</span>

    <span class="c1">// IncludeAll = true</span>
    <span class="kt">var</span> <span class="n">p2</span> <span class="p">=</span> <span class="k">new</span> <span class="n">RequestOptions</span>
    <span class="p">{</span>
        <span class="n">IncludeCoordinates</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
        <span class="n">IncludeName</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
        <span class="n">TransportModeOptions</span> <span class="p">=</span>
        <span class="p">{</span>
            <span class="n">IncludeAll</span> <span class="p">=</span> <span class="k">true</span>
        <span class="p">}</span>
    <span class="p">};</span>

    <span class="n">sut</span><span class="p">.</span><span class="nf">RegisterProfile</span><span class="p">(</span><span class="n">p1</span><span class="p">);</span>
    <span class="n">sut</span><span class="p">.</span><span class="nf">RegisterProfile</span><span class="p">(</span><span class="n">p2</span><span class="p">);</span>

    <span class="n">sut</span><span class="p">.</span><span class="n">ProfileCount</span><span class="p">.</span><span class="n">Should</span><span class="p">.</span><span class="nf">Be</span><span class="p">(</span><span class="m">2</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Again - test <strong>IS</strong> green! Whataheck? I’m assuming that distinct profile generation is working correctly..</p>

<p>After few minutes starring at screen and building in my mind various potential root causes for this issue, I realized that we do not have test case for inserting two identical profiles with <code class="language-plaintext highlighter-rouge">IncludeAll = true</code>.</p>

<p>Let’s create this test case then:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">Fact</span><span class="p">]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">RegisterTwoTheSameProfiles_WithIncludeAllTrue_ShouldBeOne</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">sut</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ProfileStore</span><span class="p">();</span>

    <span class="kt">var</span> <span class="n">p1</span> <span class="p">=</span> <span class="k">new</span> <span class="n">RequestOptions</span>
    <span class="p">{</span>
        <span class="n">IncludeCoordinates</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
        <span class="n">IncludeName</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
        <span class="n">TransportModeOptions</span> <span class="p">=</span>
        <span class="p">{</span>
            <span class="n">IncludeAll</span> <span class="p">=</span> <span class="k">true</span>
        <span class="p">}</span>
    <span class="p">};</span>

    <span class="kt">var</span> <span class="n">p2</span> <span class="p">=</span> <span class="k">new</span> <span class="n">RequestOptions</span>
    <span class="p">{</span>
        <span class="n">IncludeCoordinates</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
        <span class="n">IncludeName</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
        <span class="n">TransportModeOptions</span> <span class="p">=</span>
        <span class="p">{</span>
            <span class="n">IncludeAll</span> <span class="p">=</span> <span class="k">true</span>
        <span class="p">}</span>
    <span class="p">};</span>

    <span class="n">sut</span><span class="p">.</span><span class="nf">RegisterProfile</span><span class="p">(</span><span class="n">p1</span><span class="p">);</span>
    <span class="n">sut</span><span class="p">.</span><span class="nf">RegisterProfile</span><span class="p">(</span><span class="n">p2</span><span class="p">);</span>

    <span class="n">sut</span><span class="p">.</span><span class="n">ProfileCount</span><span class="p">.</span><span class="n">Should</span><span class="p">.</span><span class="nf">Be</span><span class="p">(</span><span class="m">1</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And <strong>KA-BOOM</strong>!!! Our test case is RED!</p>

<p><img src="/assets/img/2021/08/cpu-99-vs-debug-test-failed.png" alt="cpu-99-vs-debug-test-failed" /></p>

<p>This proves that you have to be careful with your assumptions about what those tests are covering.</p>

<h2 id="fixing-the-code">Fixing the Code</h2>
<p><code class="language-plaintext highlighter-rouge">RequestOptions</code> comparison was working correctly for <code class="language-plaintext highlighter-rouge">IncludeAll = false</code> but failed for <code class="language-plaintext highlighter-rouge">IncludeAll = true</code>.
There must be something wrong with instance comparison logic.</p>

<p>Let’s take a closer look.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">RequestOptions</span> <span class="p">:</span> <span class="n">IEqualityComparer</span><span class="p">&lt;</span><span class="n">RequestOptions</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">bool</span> <span class="n">IncludeCoordinates</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">bool</span> <span class="n">IncludeName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="n">TransportModeOptions</span> <span class="n">TransportModeOptions</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="k">new</span><span class="p">();</span>

    <span class="k">public</span> <span class="k">override</span> <span class="kt">bool</span> <span class="nf">Equals</span><span class="p">(</span><span class="kt">object</span> <span class="n">obj</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="nf">Equals</span><span class="p">((</span><span class="n">RequestOptions</span><span class="p">)</span><span class="n">obj</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="kt">bool</span> <span class="nf">Equals</span><span class="p">(</span><span class="n">RequestOptions</span> <span class="n">x</span><span class="p">,</span> <span class="n">RequestOptions</span> <span class="n">y</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="p">...</span>

        <span class="k">if</span> <span class="p">(!</span><span class="n">TransportModeOptions</span><span class="p">.</span><span class="nf">Equals</span><span class="p">(</span><span class="n">x</span><span class="p">.</span><span class="n">TransportModeOptions</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="k">return</span> <span class="k">false</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="k">return</span> <span class="k">true</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>At first look, seems quite OK-ish (yeah, we could do some code formatting and other nitties but overall logic seems to be correct)! We are comparing all properties of the passed in objects and if something is different - returning <code class="language-plaintext highlighter-rouge">false</code> flagging that instances differ.</p>

<p>But there is something wrong with <code class="language-plaintext highlighter-rouge">TransportModeOptions.IncludeAll</code> property..</p>

<p>“Look closer! Look cloooooser mate!” voice in my head started to shout louder and louder..</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="kt">bool</span> <span class="nf">Equals</span><span class="p">(</span><span class="n">RequestOptions</span> <span class="n">x</span><span class="p">,</span> <span class="n">RequestOptions</span> <span class="n">y</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">if</span> <span class="p">(!</span><span class="n">TransportModeOptions</span><span class="p">.</span><span class="nf">Equals</span><span class="p">(</span><span class="n">x</span><span class="p">.</span><span class="n">TransportModeOptions</span><span class="p">))</span>
    <span class="p">{</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>WTF??</strong> I took next glass of semi-sweet red wine at late night.. realizing that we were ignoring <code class="language-plaintext highlighter-rouge">y</code> in this comparison logic…</p>

<p>So what’s going on here?</p>

<p>We are comparing <strong><em>default</em></strong> value of <code class="language-plaintext highlighter-rouge">TransportModeOptions</code> property with value of argument <code class="language-plaintext highlighter-rouge">x</code> - <strong>completely</strong> ignoring passed in argument <code class="language-plaintext highlighter-rouge">y</code>. Meaning that every time we are adding profile with any values other than produced by <code class="language-plaintext highlighter-rouge">TransportModeOptions { get; set; } = new();</code> statement - we will get <code class="language-plaintext highlighter-rouge">false</code> as result of instance comparison logic.</p>

<p>This also answers our second question - “And why this happens only after few hours or even days of gRPC service uptime?”.</p>

<p>Requests with <code class="language-plaintext highlighter-rouge">IncludeAll = true</code> comes really rare from the consuming application. So number of profiles builds up over the time. Therefore immediate effects were not visible.</p>

<p>Fix for the mysterious issue is really simple (yet again - 1 liner):</p>

<p><img src="/assets/img/2021/08/cpu-99-vs-commit-compare.png" alt="cpu-99-vs-commit-compare" /></p>

<h2 id="fixing-the-code-for-real">Fixing the Code for Real</h2>
<p>What’s wrong with the code above? <code class="language-plaintext highlighter-rouge">RequestOptions</code> is doing too much. It’s holding data for the request AND also provides comparison logic.
Which also proves that code below looks a bit weird:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre>public class ProfileStore
{
    private ConcurrentDictionary&lt;RequestOptions, QuayProfile&gt; _profiles
        = new(new RequestOptions());

    public void RegisterProfile(RequestOptions options)
    {
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Why do I pass in <code class="language-plaintext highlighter-rouge">RequestOptions</code> instance when creating new <code class="language-plaintext highlighter-rouge">ConcurrentDictionary</code> (<code class="language-plaintext highlighter-rouge">= new(new RequestOptions())</code>)?</p>

<p>In my opinion better structure would be to “extract” comparison into separate class:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">QuayProcessorOptionsComparer</span> <span class="p">:</span> <span class="n">IEqualityComparer</span><span class="p">&lt;</span><span class="n">QuayProcessorOptions</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">bool</span> <span class="nf">Equals</span><span class="p">(</span><span class="n">QuayProcessorOptions</span> <span class="n">x</span><span class="p">,</span> <span class="n">QuayProcessorOptions</span> <span class="n">y</span><span class="p">)</span>
    <span class="p">{</span>

    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Which also gives cleaner <code class="language-plaintext highlighter-rouge">ConcurrentDictionary</code> instantiation code:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">readonly</span> <span class="n">ConcurrentDictionary</span><span class="p">&lt;</span><span class="n">QuayProcessorOptions</span><span class="p">,</span> <span class="n">QuayDataProfile</span><span class="p">&gt;</span>
    <span class="n">_profiles</span> <span class="p">=</span> <span class="k">new</span><span class="p">(</span><span class="k">new</span> <span class="nf">QuayProcessorOptionsComparer</span><span class="p">());</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Plus additional bonus would be getting compilation time error with original code:</p>

<p><img src="/assets/img/2021/08/cpu-99-fix.png" alt="cpu-99-fix" /></p>

<h2 id="lessons-learned">Lessons Learned</h2>

<ul>
  <li>Don’t assume anything when looking at unit test run results</li>
  <li>Review and revisit test cases and see for potentially uncovered cases (this might be fixed by using some data mocker like <code class="language-plaintext highlighter-rouge">AutoFixture</code> to stress test variations of the profiles and <code class="language-plaintext highlighter-rouge">ProfileStore</code> behavior when receiving such instances of <code class="language-plaintext highlighter-rouge">RequestOptions</code>).</li>
  <li>Constantly monitor your apps</li>
  <li>Learn the tools in your belt</li>
  <li>Be patient. Hard-core debugging is neither easy nor fast!</li>
</ul>

<p>Happy debugging!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="gRPC" /><category term="Debugging" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="grpc" /><category term="debugging" /><summary type="html"><![CDATA[Setting the Crime Scene We are back again in gRPC service and this time we will be working on another performance issue. These kind of issues comes under the radar very easily when you are dealing with long-lived, high performant and heavily used service that is running for ages. Back in old days it was easy to set recycling options for IIS and all of the sudden your memory, CPU or any other issues are auto-magically gone. Here in our case - gRPC service has to run for days, weeks, maybe even months without any interruptions. Maintaining service with these constraints becomes frankly interesting and challenging.]]></summary></entry><entry><title type="html">Discovering Most Stupid Mistake I Ever Made - Analyzing gRPC Service MemDump from Linux based Docker Running on ACI</title><link href="https://tech-fellow.eu/2021/05/24/analyzing-grpc-service-memdump-from-linux-based-docker-running-on-aci/" rel="alternate" type="text/html" title="Discovering Most Stupid Mistake I Ever Made - Analyzing gRPC Service MemDump from Linux based Docker Running on ACI" /><published>2021-05-24T01:05:00+03:00</published><updated>2021-05-24T01:05:00+03:00</updated><id>https://tech-fellow.eu/2021/05/24/analyzing-grpc-service-memdump-from-linux-based-docker-running-on-aci</id><content type="html" xml:base="https://tech-fellow.eu/2021/05/24/analyzing-grpc-service-memdump-from-linux-based-docker-running-on-aci/"><![CDATA[<p>This is yet another story from the series about <a href="/2021/05/building-real-time-public-transport-tracking-system-on-azure-part1/">building public transportation tracking system on Microsoft Azure</a>.</p>

<p>Here we are going to discover one of the most stupid mistake I could ever made in my career. The turning point was an informal conversation with the one and only <a href="https://twitter.com/TessFerrandez">Tess Ferrandez</a>.</p>

<h2 id="background">Background</h2>
<p>For those who were following this blog post series I will repeat here. We need to describe crime scene background.</p>

<p>Our public transportation tracking system is running on Microsoft Azure utilizing Web Jobs, Service Bus, Event Grid, gRPC for .NET, Azure Container Instances and many other services. Sometimes data flow chain might be pretty long and any link could break.</p>

<p>A quick recap of what we have in Azure for the gRPC service to operate:</p>

<ul>
  <li>data is collected on regular bases via Azure Functions</li>
  <li>then heavy lifting to do all required computations is done in WebJob</li>
  <li>WebJob drops newly generated snapshot on Service Bus topic</li>
  <li>gRPC listens on the Service Bus topic subscription</li>
  <li>Received data is prepared, filtered, sliced and broadcasted to connected clients</li>
</ul>

<p>Data flow is the application is somewhat along these lines:</p>

<p><img src="/assets/img/2021/05/arch.png" alt="arch" /></p>

<h2 id="the-problem">The Problem</h2>
<p>Over the time (usually couple days of uptime) gRPC service is not broadcasting data anymore to connected clients. New connection could be established - meaning that gRPC service is alive - but <strong>no new data is broadcasted</strong>. gRPC service restart helps. With the fresh start everything is back to normal until next occurrence. But that’s a treatment only till next time.</p>

<p>We are running gRPC service in Azure Container Instances. This means that we have to pack up diagnostics tooling along the Docker image and re-deploy the service.</p>

<h2 id="preparing-docker-image-with-net-diagnostic-tools">Preparing Docker Image with .NET Diagnostic Tools</h2>
<p>Adding .NET diagnostics tools to the docker image is simple as running bunch of copy commands.
Fortunately diagnostic tools are available as .NET <a href="https://docs.microsoft.com/en-us/dotnet/core/tools/global-tools">global tool</a> - meaning that installation is super easy and smooth.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre>FROM mcr.microsoft.com/dotnet/sdk:5.0-focal AS build

# install diagnostics tools
RUN dotnet tool install --tool-path /tools dotnet-trace
RUN dotnet tool install --tool-path /tools dotnet-counters
RUN dotnet tool install --tool-path /tools dotnet-dump
RUN dotnet tool install --tool-path /tools dotnet-gcdump

...

# copy diagnostics tools to final layer
FROM mcr.microsoft.com/dotnet/aspnet:5.0-focal AS final
WORKDIR /tools
COPY --from=build /tools .
</pre></td></tr></tbody></table></code></pre></div></div>

<p>With this fragment of <code class="language-plaintext highlighter-rouge">Dockerfile</code> following .NET diagnostics tools will be copied and available in Docker container which we are using for hosting gRPC service:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">dotnet-trace</code> - for collecting events from running process. More info <a href="https://docs.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-trace">here</a>.</li>
  <li><code class="language-plaintext highlighter-rouge">dotnet-counters</code> - if we would need to review and investigate counters on the image (like CPU or rate of exceptions thrown, etc); More info <a href="https://docs.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-counters">here</a>.</li>
  <li><code class="language-plaintext highlighter-rouge">dotnet-dump</code> - this is most important tool when you want to see what process has in memory. More info <a href="https://docs.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-dump">here</a>.</li>
  <li><code class="language-plaintext highlighter-rouge">dotnet-gcdump</code> - if you need to see what’s on GC mind or why still some of the objects are in memory and who needs those? More info <a href="https://docs.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-gcdump">here</a>.</li>
</ul>

<p>Not all of them will be used this time, but it’s always good to have right tools at your disposal when needed.</p>

<p>More information could be found <a href="https://docs.microsoft.com/en-us/dotnet/core/diagnostics/diagnostics-in-containers">here</a>.</p>

<p>Now that we have packed .NET diagnostics tools inside the image, we <a href="/assets/img/2021/01/21/building-real-time-public-transport-tracking-system-on-azure-part-6-packing-everything-up/">can redeploy</a> the image and run it again on ACI.</p>

<h2 id="mounting-volume-for-dumps">Mounting Volume for Dumps</h2>
<p>In order to run .NET diagnostics tools and analyze results offloaded from Docker container instance - we need to have permanent storage that is not part of Docker container file system. Otherwise on next restart file system of the container will be gone and fresh new will be mounted from container image.
To do so - we have utilize Azure Storage File Share service and use file share to mount it to Docker container and have a storage where we could move and store taken dumps.</p>

<p>Remember that volume mounting on ACI service is available <a href="https://docs.microsoft.com/en-us/azure/container-instances/container-instances-volume-azure-files#limitations">only for Linux</a> based images.</p>

<h3 id="creating-azure-storage-file-service">Creating Azure Storage File Service</h3>

<p><img src="/assets/img/2021/05/grpc-dump-storage-fileshare.png" alt="grpc-dump-storage-fileshare" /></p>

<h3 id="mount-file-share-to-docker-image">Mount File Share to Docker Image</h3>
<p>I’m using YAML files to deploy ACI containers - so we gonna edit a bit this beast.
First you need to define where you would like to mount attached volume (part of your container properties collection in your ACI YAML description file):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>  volumeMounts:
  - mountPath: /aci/logs/
    name: filesharevolume
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And then you can define from there this volume is coming from:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre>  volumes:
  - name: filesharevolume
    azureFile:
      sharename: grpc-dump-storage
      storageAccountName: grpccontainerfileshare
      storageAccountKey: 123...abc==
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Property <code class="language-plaintext highlighter-rouge">storageAccountKey</code> is just your storage SAS token (access key) and <code class="language-plaintext highlighter-rouge">sharename</code> is name of the share we just created.</p>

<p>Relevant YAML file fragments for completeness:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="rouge-code"><pre>api-version: 2018-10-01
location: westeurope
name: grpc-container
properties:
  containers:
  - name: grpc-app
    properties:
      volumeMounts:
      - mountPath: /aci/logs/
        name: filesharevolume
      ...
  osType: Linux
  volumes:
  - name: filesharevolume
    azureFile:
      sharename: grpc-dump-storage
      storageAccountName: grpccontainerfileshare
      storageAccountKey: 123...abc==
type: Microsoft.ContainerInstance/containerGroups
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="taking-memory-dumps">Taking Memory Dumps</h2>
<p>Now we have redeployed gRPC service with .NET diagnostics tools and new volume mapping.
By checking content of the <code class="language-plaintext highlighter-rouge">/tools</code> directory - see all included tools:</p>

<p><img src="/assets/img/2021/05/dotnet-tools-in-aci-console.png" alt="dotnet-tools-in-aci-console" /></p>

<p>We can see this mount is as expected - just yet another folder in the file system.</p>

<p><img src="/assets/img/2021/05/fileshare-in-aci-console.png" alt="fileshare-in-aci-console" /></p>

<h3 id="enlisting-applicable-processes">Enlisting Applicable Processes</h3>
<p>First thing we have to do is to list all applicable processes for memory dump. This is done by command:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>user@machine:/tools# dotnet-dump ps
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As result we see only single .NET process:</p>

<p><img src="/assets/img/2021/05/dotnet-dump-ps.png" alt="dotnet-dump-ps" /></p>

<h3 id="taking-a-dump">Taking a Dump</h3>
<p>In order to take a memory dump - it’s super easy:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>user@machine:/tools# ./dotnet-dump collect -p 1
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/2021/05/dotnet-dump-collect.png" alt="dotnet-dump-collect" /></p>

<p>Executing <code class="language-plaintext highlighter-rouge">collect</code> command dump tool will write dump file to the <code class="language-plaintext highlighter-rouge">/tools</code> directory.</p>

<p>Now we can move file to our shared mounted volume and later download to development machine to start analyze it further in Visual Studio.</p>

<p><strong>NB!</strong> You can also analyze it right there inside the docker image by executing:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>user@machine:/tools# ./dotnet-dump analyze core_20210523_053806
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/2021/05/dotnet-dump-analyze.png" alt="dotnet-dump-analyze" /></p>

<p>But I just prefer some user interface and more interactive environment compared to command-line interface.</p>

<h2 id="analyzing-dump-in-visual-studio">Analyzing Dump in Visual Studio</h2>
<p>It’s amazing that we can open and analyze process dumps taken from Linux based docker image directly in Visual Studio. Windbg is all nice and cool - but sometimes I’m just way too lazy and better spend some mouse clicks than typing and navigating through address space in command-line interface.</p>

<p>We can just open dump file in Visual Studio and it will gives familiar choices:</p>

<p><img src="/assets/img/2021/05/vs-open-dump-1.png" alt="vs-open-dump-1" /></p>

<p>When it comes to parallel / async code debugging experience - Parallel Stacks is invaluable tool to visualize what’s going on in your application.</p>

<p>This is state of the app when I took a memory dump when gRPC service was stalled.</p>

<p><img src="/assets/img/2021/05/pstacks.png" alt="pstacks" /></p>

<p>Btw, you can do the same also in command-line interface also (thanks to <a href="https://medium.com/criteo-engineering/how-to-extend-dotnet-dump-1-2-what-are-the-new-commands-2e3f92d06930">Christophe Nasarre</a> and friends at <a href="https://www.criteo.com/">Criteo</a>).</p>

<p><img src="/assets/img/2021/05/pstacks-cli.png" alt="pstacks-cli" /></p>

<h2 id="what-do-we-have-here">What Do We Have Here?</h2>
<p>We know that initial entrance for the data flow in gRPC service is via Service Bus receiver background service. Checking Parallel Stacks for the evidence - we can see that we do have <code class="language-plaintext highlighter-rouge">Task</code> awaiting state - which means that Service Bus receiver is alive and is just sitting and waiting for new messages to arrive:</p>

<p><img src="/assets/img/2021/05/pstacks-sb-alive.png" alt="pstacks-sb-alive" /></p>

<p>Next thing is to check what’s the status of the channels (<code class="language-plaintext highlighter-rouge">System.Threading.Channels.Channel&lt;T&gt;</code>) we used to communicate from Service Bus receiver to gRPC service.</p>

<p>Service Bus receiver has reference to all the channel abstractions (we use those just to hide dependency on <code class="language-plaintext highlighter-rouge">Channel&lt;T&gt;</code>).
It’s pretty simple abstraction:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">DefaultStreamChannel</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">Channel</span><span class="p">&lt;</span><span class="n">WorkItem</span><span class="p">&gt;</span> <span class="n">_channel</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">DefaultStreamChannel</span><span class="p">(</span><span class="n">IOptions</span><span class="p">&lt;</span><span class="n">AppConfig</span><span class="p">&gt;</span> <span class="n">config</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_channel</span> <span class="p">=</span> <span class="n">Channel</span><span class="p">.</span><span class="n">CreateBounded</span><span class="p">&lt;</span><span class="n">WorkItem</span><span class="p">&gt;(</span>
            <span class="k">new</span> <span class="nf">BoundedChannelOptions</span><span class="p">(</span><span class="n">config</span><span class="p">.</span><span class="n">Value</span><span class="p">.</span><span class="n">GrpcClientChannelBufferSize</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="n">AllowSynchronousContinuations</span> <span class="p">=</span> <span class="k">false</span><span class="p">,</span>
                <span class="n">SingleReader</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
                <span class="n">SingleWriter</span> <span class="p">=</span> <span class="k">false</span><span class="p">,</span>
                <span class="n">FullMode</span> <span class="p">=</span> <span class="n">BoundedChannelFullMode</span><span class="p">.</span><span class="n">DropOldest</span>
            <span class="p">});</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">ChannelReader</span><span class="p">&lt;</span><span class="n">WorkItem</span><span class="p">&gt;</span> <span class="n">Reader</span> <span class="p">=&gt;</span> <span class="n">_channel</span><span class="p">.</span><span class="n">Reader</span><span class="p">;</span>

    <span class="k">public</span> <span class="kt">bool</span> <span class="nf">Publish</span><span class="p">(</span><span class="n">WorkItem</span> <span class="n">data</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">_channel</span><span class="p">.</span><span class="n">Writer</span><span class="p">.</span><span class="nf">TryWrite</span><span class="p">(</span><span class="n">data</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So we can jump on awaiting <code class="language-plaintext highlighter-rouge">Task</code> and inspect channel states from there:</p>

<p><img src="/assets/img/2021/05/channels-state.png" alt="channels-state" /></p>

<p>We have defined buffer to be of size 5 items between Service Bus and gRPC.
As highlighted in the image above - it’s <strong>SUPER WEIRD</strong> that other channels are cleared but one of the them is stuck with 5 items in the buffer and are not processed.</p>

<h2 id="discovering-the-biggest-mistake-i-could-ever-make">Discovering The Biggest Mistake I Could Ever Make</h2>
<p>As we saw interesting is that channel capacity is taken, <code class="language-plaintext highlighter-rouge">Reader</code> is full and no new items being pushed through the channel. It’s weird indeed.</p>

<p>We have dedicated channel and dispatch background service for every data streams in gRPC. In order for data to flow Service Bus receiver, buffer channel in between, data dispatch background service should be working. We checked that Service Bus receiver is alive (we have awaiting task on new message to arrive) - however channels is full and no new messages are processed.</p>

<p>Next thing we can check - what about scheduled task for the reader side of the channel - <strong>AND THERE WAS NONE!</strong> No task for reader, nothing.. No evidence of dispatch background service existence!</p>

<p>Back to basics. I revisited facts what had collected so far:</p>

<ul>
  <li>data comes in from Service Bus topic</li>
  <li>SB message receiver is alive and posts messages to channel(-s)</li>
  <li>there is a dedicated background service for reading the channel</li>
  <li>message is processed and prepared for the broadcast</li>
  <li>then message is forwarded to message hub</li>
  <li>message hub has list of subscribers (gRPC connected clients)</li>
  <li>each subscriber receives message copy and is able to do the write to the stream</li>
</ul>

<p>There is somewhere an issue along these lines..</p>

<p>And then suddenly as from the clear skies - what if… just a thought.. what if there is an <strong>unhandled exception</strong> in that dedicated background service for the full channel??</p>

<p>Background services are initialized at startup and code that does this is pretty straightforward.</p>

<p>This is callstack from where initialization is called:</p>

<p><img src="/assets/img/2021/05/hosted-service-start-callstack.png" alt="hosted-service-start-callstack" /></p>

<p>Browsing <code class="language-plaintext highlighter-rouge">Microsoft.Extensions.Hosting</code> namespace understood that it’s just simple “find all <code class="language-plaintext highlighter-rouge">IHostedService</code> instances and call <code class="language-plaintext highlighter-rouge">StartAsync</code> method”. As we are inheriting from <code class="language-plaintext highlighter-rouge">BackgroundService</code> base class - we have to implement just <code class="language-plaintext highlighter-rouge">ExecuteAsync</code> method (which is called at <code class="language-plaintext highlighter-rouge">StartAsync</code> in <code class="language-plaintext highlighter-rouge">BackgroundService</code>).</p>

<p>If exception is thrown in background service (async code) - it’s basically <strong>swallowed</strong> by the runtime. There will be no clear evidence that exception was thrown, application will not be terminated.</p>

<p>Our gRPC service was made with huge flow - if any of subscribers will throw an exception - whole “broadcast” process is aborted and data is not pushed to any of the subscribers. Resulting in stuck gRPC service. The only cure is to restart the app. This is of course not accepted solution.</p>

<p>After experimenting with few code samples and try outs - we found out that the problem is located incoming dataset. We had an exception while we were preparing data for the broadcast (<code class="language-plaintext highlighter-rouge">int.Parse</code>). That’s why we had super weird behavior of the service - gRPC service failed “sometimes”. Like it could failed for 3 or 4 times a week. Sometimes more frequent sometimes less..</p>

<p>That all contributed to hard-to-find bug.</p>

<h2 id="hard-lesson-learned">Hard Lesson Learned</h2>
<p>I was super happy to discover this nasty little thing.
But I could not discover it alone. Informal chats, couple idea and just expressing your findings or suspicions out loud - will help A LOT!</p>

<p><img src="/assets/img/2021/05/twitter.png" alt="twitter" /></p>

<p>Thanks <a href="https://twitter.com/TessFerrandez">Tess</a> &amp; <a href="https://twitter.com/danielmarbach">Daniel</a>!!!</p>

<p><img src="/assets/img/2021/05/commit.png" alt="commit" /></p>

<p>It’s like 1 liner with huge impact!</p>

<p><img src="/assets/img/2021/05/commit-chages.png" alt="commit-chages" /></p>

<p>In summary: when you are dealing with async code - think through of exception handling process and dataflow. Beware that exceptions might be swallowed - leaving you wondering.. Application will continue to run with invalid state.</p>

<p>Btw, one of the easiest way to observe all first chance exceptions is to subscribe to the event in app domain:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="n">AppDomain</span><span class="p">.</span><span class="n">CurrentDomain</span><span class="p">.</span><span class="n">FirstChanceException</span> <span class="p">+=</span> <span class="n">OnFirstChanceException</span><span class="p">;</span>

<span class="k">private</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">OnFirstChanceException</span><span class="p">(</span><span class="kt">object</span> <span class="n">sender</span><span class="p">,</span> <span class="n">FirstChanceExceptionEventArgs</span> <span class="n">e</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// do some magic here</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Happy debugging!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="gRPC" /><category term="Debugging" /><category term="Azure" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="grpc" /><category term="debugging" /><category term="azure" /><summary type="html"><![CDATA[This is yet another story from the series about building public transportation tracking system on Microsoft Azure.]]></summary></entry><entry><title type="html">Implementing gRPC Auto-Reconnect on Timeout</title><link href="https://tech-fellow.eu/2021/04/10/implementing-grpc-auto-reconnect-on-timeout/" rel="alternate" type="text/html" title="Implementing gRPC Auto-Reconnect on Timeout" /><published>2021-04-10T23:10:00+03:00</published><updated>2021-04-10T23:10:00+03:00</updated><id>https://tech-fellow.eu/2021/04/10/implementing-grpc-auto-reconnect-on-timeout</id><content type="html" xml:base="https://tech-fellow.eu/2021/04/10/implementing-grpc-auto-reconnect-on-timeout/"><![CDATA[<p>In this blog post we are going to implement feature to reconnect to gRPC stream if specific timeout has elapsed and no new data has been received from the server.</p>

<p>Part of our real-time <a href="https://tech-fellow.eu/2019/12/08/building-real-time-public-transport-tracking-system-on-azure-part1/">public transportation tracking system</a> built on Microsoft Azure platform is also a gRPC service - providing near to the real-time data feed to the consuming parties. gRPC service is running as an experiment aside from <a href="https://dotnet.microsoft.com/apps/aspnet/signalr">SignalR</a> service which has been around for a while in our infrastructure.</p>

<p>Over the time we see that data size transferred on the wire reduced and battery consumption dropped by using gRPC instead of SignalR stream. Which is a good excuse for use to keep going with gRPC.</p>

<p>We are continuing to explore possibilities gRPC infrastructure has to offer. One of the great features of SignalR library is its built-in option to <a href="https://docs.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/handling-connection-lifetime-events#how-to-continuously-reconnect">automatically reconnect</a>. gRPC has somewhat similar feature - <a href="https://docs.microsoft.com/en-us/aspnet/core/grpc/retries?view=aspnetcore-5.0">“retry policy”</a>. However retry policy applies only to unary calls. In our case unary calls are more like auxiliary invokes service some classifiers or static data. In gRPC we are using server side streaming - meaning that we can’t use built-in retries and need to handle this ourselves.</p>

<p>One of the gRPC consuming applications is our own monitoring dashboard - where we are constantly consuming gRPC streams and any delays for receiving data packets means red code for us and the rescue team is most probably already on its way.
Monitoring dashboard is written in C# - so consuming gRPC service is super easy there.</p>

<h2 id="task-based-reconnect">Task-based Reconnect</h2>

<p>One of the first approach to implement retry was to fire off 2 tasks - one to receive packet on the stream from gRPC service, another - to control timeout. We would need to raise some sort of flag that no new data has been received for X amount of time, resulting in some alert action in monitoring system.</p>

<p>We gonna implement receiver as <code class="language-plaintext highlighter-rouge">BackgroundService</code> in .NET 5.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
</pre></td><td class="rouge-code"><pre><span class="k">protected</span> <span class="k">override</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">ExecuteAsync</span><span class="p">(</span><span class="n">CancellationToken</span> <span class="n">stoppingToken</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">stream</span> <span class="p">=</span> <span class="n">_subscriber</span><span class="p">.</span><span class="nf">GetStream</span><span class="p">();</span>
    <span class="n">Task</span><span class="p">&lt;</span><span class="kt">bool</span><span class="p">&gt;</span> <span class="n">nextDataTask</span><span class="p">;</span>

    <span class="k">while</span> <span class="p">(!</span><span class="n">stoppingToken</span><span class="p">.</span><span class="n">IsCancellationRequested</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">nextDataTask</span> <span class="p">=</span> <span class="n">stream</span><span class="p">.</span><span class="nf">MoveNext</span><span class="p">(</span><span class="n">stoppingToken</span><span class="p">);</span>

        <span class="c1">// wait for the incoming data within some threshold</span>
        <span class="c1">// if threshold will be exceeded - we will subscribe again to the stream to get new connection</span>
        <span class="kt">var</span> <span class="n">winningTask</span> <span class="p">=</span> <span class="k">await</span> <span class="n">Task</span><span class="p">.</span><span class="nf">WhenAny</span><span class="p">(</span><span class="n">nextDataTask</span><span class="p">,</span> <span class="n">Task</span><span class="p">.</span><span class="nf">Delay</span><span class="p">(</span><span class="n">_options</span><span class="p">.</span><span class="n">GrpcStreamTimeout</span><span class="p">,</span> <span class="n">stoppingToken</span><span class="p">));</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">winningTask</span> <span class="p">==</span> <span class="n">nextDataTask</span> <span class="p">&amp;&amp;</span> <span class="n">nextDataTask</span><span class="p">.</span><span class="n">IsCompletedSuccessfully</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="kt">var</span> <span class="n">gotNewItem</span> <span class="p">=</span> <span class="k">await</span> <span class="n">nextDataTask</span><span class="p">;</span>

            <span class="k">if</span> <span class="p">(</span><span class="n">gotNewItem</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="c1">// do some magic with `stream.Current` item</span>
            <span class="p">}</span>
        <span class="p">}</span>
        <span class="k">else</span>
        <span class="p">{</span>
            <span class="c1">// we are because winning task is timeout task</span>
            <span class="c1">// or next data task has failed</span>

            <span class="c1">// OPTIONAL: we can look inside next data task (`nextDataTask.Exception?`)</span>
            <span class="c1">// maybe there is an exception</span>
            <span class="c1">// that should be good practice to log it at least</span>

            <span class="c1">// other than that - we just subscribe once again to the stream</span>
            <span class="c1">// this will result in new connection and old one will be dropped</span>
            <span class="n">stream</span> <span class="p">=</span> <span class="n">_subscriber</span><span class="p">.</span><span class="nf">GetStream</span><span class="p">();</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And getting stream from the server is straight forward.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="n">IAsyncStreamReader</span><span class="p">&lt;</span><span class="n">DataItems</span><span class="p">&gt;</span> <span class="nf">GetStream</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">_channel</span> <span class="p">=</span> <span class="n">GrpcChannel</span><span class="p">.</span><span class="nf">ForAddress</span><span class="p">(...);</span>
    <span class="n">_client</span> <span class="p">=</span> <span class="k">new</span> <span class="n">GrpcDataFeed</span><span class="p">.</span><span class="nf">GrpcDataFeedClient</span><span class="p">(</span><span class="n">_channel</span><span class="p">);</span>
    <span class="n">_call</span> <span class="p">=</span> <span class="n">_client</span><span class="p">.</span><span class="nf">SubscribeToStream</span><span class="p">();</span>

    <span class="k">return</span> <span class="n">_call</span><span class="p">.</span><span class="n">ResponseStream</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Code works, but it looks messy.
Also would like to wait a bit before retrying again - just to give some time for the server to recover (in case of disaster).</p>

<h3 id="add-resilience-with-polly">Add Resilience with Polly</h3>

<p>To help complete this task - we can rely on some retry policy libraries. One of the most popular in .NET world is <a href="https://github.com/App-vNext/Polly">Polly</a>.</p>

<p>Here is the same code, but with Polly retry forever giving recovery window for 15 seconds before each retry.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
</pre></td><td class="rouge-code"><pre><span class="k">protected</span> <span class="k">override</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">ExecuteAsync</span><span class="p">(</span><span class="n">CancellationToken</span> <span class="n">stoppingToken</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">stream</span> <span class="p">=</span> <span class="n">_subscriber</span><span class="p">.</span><span class="nf">GetStream</span><span class="p">();</span>
    <span class="n">Task</span><span class="p">&lt;</span><span class="kt">bool</span><span class="p">&gt;</span> <span class="n">nextDataTask</span><span class="p">;</span>

    <span class="kt">var</span> <span class="n">policy</span> <span class="p">=</span> <span class="n">Policy</span>
        <span class="p">.</span><span class="n">Handle</span><span class="p">&lt;</span><span class="n">Exception</span><span class="p">&gt;()</span>
        <span class="p">.</span><span class="nf">WaitAndRetryForeverAsync</span><span class="p">(</span>
            <span class="n">attempt</span> <span class="p">=&gt;</span> <span class="n">TimeSpan</span><span class="p">.</span><span class="nf">FromSeconds</span><span class="p">(</span><span class="m">15</span><span class="p">),</span>
            <span class="p">(</span><span class="n">exception</span><span class="p">,</span> <span class="n">timespan</span><span class="p">)</span> <span class="p">=&gt;</span>
            <span class="p">{</span>
                <span class="n">_logger</span><span class="p">.</span><span class="nf">LogError</span><span class="p">(</span><span class="n">exception</span><span class="p">,</span> <span class="s">"Error handling gRPC stream. Reconnect."</span><span class="p">);</span>

                <span class="c1">// other than that - we just subscribe once again to the stream</span>
                <span class="c1">// this will result in new connection and old one will be dropped</span>

                <span class="n">stream</span> <span class="p">=</span> <span class="n">_subscriber</span><span class="p">.</span><span class="nf">GetStream</span><span class="p">();</span>
            <span class="p">});</span>

    <span class="k">while</span> <span class="p">(!</span><span class="n">stoppingToken</span><span class="p">.</span><span class="n">IsCancellationRequested</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">await</span> <span class="n">policy</span><span class="p">.</span><span class="nf">ExecuteAsync</span><span class="p">(</span><span class="k">async</span> <span class="p">()</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="n">nextDataTask</span> <span class="p">=</span> <span class="n">stream</span><span class="p">.</span><span class="nf">MoveNext</span><span class="p">(</span><span class="n">stoppingToken</span><span class="p">);</span>

            <span class="c1">// wait for the incoming data within some threshold</span>
            <span class="c1">// if threshold will be exceeded - we will subscribe again to the stream to get new connection</span>
            <span class="kt">var</span> <span class="n">winningTask</span> <span class="p">=</span> <span class="k">await</span> <span class="n">Task</span><span class="p">.</span><span class="nf">WhenAny</span><span class="p">(</span><span class="n">nextDataTask</span><span class="p">,</span> <span class="n">Task</span><span class="p">.</span><span class="nf">Delay</span><span class="p">(</span><span class="n">_options</span><span class="p">.</span><span class="n">GrpcStreamTimeout</span><span class="p">,</span> <span class="n">stoppingToken</span><span class="p">));</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">winningTask</span> <span class="p">==</span> <span class="n">nextDataTask</span> <span class="p">&amp;&amp;</span> <span class="n">nextDataTask</span><span class="p">.</span><span class="n">IsCompletedSuccessfully</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="kt">var</span> <span class="n">gotNewItem</span> <span class="p">=</span> <span class="k">await</span> <span class="n">nextDataTask</span><span class="p">;</span>

                <span class="k">if</span> <span class="p">(</span><span class="n">gotNewItem</span><span class="p">)</span>
                <span class="p">{</span>
                    <span class="n">_dataBuffer</span><span class="p">.</span><span class="nf">SetNewOptimizedStreamState</span><span class="p">(</span><span class="n">stream</span><span class="p">.</span><span class="n">Current</span><span class="p">);</span>
                <span class="p">}</span>
            <span class="p">}</span>
            <span class="k">else</span>
            <span class="p">{</span>
                <span class="c1">// we are because winning task is timeout task</span>
                <span class="c1">// or next data task has failed</span>

                <span class="c1">// we can look inside next data task (`nextDataTask.Exception?`)</span>
                <span class="c1">// maybe there is an exception</span>
                <span class="c1">// that should be good practice to log it at least</span>

                <span class="k">if</span> <span class="p">(</span><span class="n">nextDataTask</span><span class="p">.</span><span class="n">IsCompleted</span> <span class="p">&amp;&amp;</span> <span class="n">nextDataTask</span><span class="p">.</span><span class="n">Exception</span><span class="p">?.</span><span class="n">InnerException</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
                <span class="p">{</span>
                    <span class="k">throw</span> <span class="k">new</span> <span class="nf">Exception</span><span class="p">(</span><span class="s">"Error receiving data from gRPC endpoint."</span><span class="p">,</span> <span class="n">nextDataTask</span><span class="p">.</span><span class="n">Exception</span><span class="p">?.</span><span class="n">InnerException</span><span class="p">);</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="better-approach---cancellation-token-based-reconnect">Better Approach - Cancellation Token based Reconnect</h2>

<p>Task based code looks a bit messy. Think it could be improved.
Meanwhile we also can rewrite code to use async enumeration via <code class="language-plaintext highlighter-rouge">await foreach</code> statement.</p>

<p>This is the same logic but rewritten to use <code class="language-plaintext highlighter-rouge">CancellationToken</code> instead:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</pre></td><td class="rouge-code"><pre><span class="k">protected</span> <span class="k">override</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">ExecuteAsync</span><span class="p">(</span><span class="n">CancellationToken</span> <span class="n">stoppingToken</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">stream</span> <span class="p">=</span> <span class="n">_subscriber</span><span class="p">.</span><span class="nf">GetStream</span><span class="p">();</span>
    <span class="kt">var</span> <span class="n">cts</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">CancellationTokenSource</span><span class="p">(</span><span class="n">_options</span><span class="p">.</span><span class="n">GrpcStreamTimeout</span><span class="p">);</span>

    <span class="kt">var</span> <span class="n">policy</span> <span class="p">=</span> <span class="n">Policy</span>
        <span class="p">.</span><span class="n">Handle</span><span class="p">&lt;</span><span class="n">Exception</span><span class="p">&gt;()</span>
        <span class="p">.</span><span class="nf">WaitAndRetryForeverAsync</span><span class="p">(</span>
            <span class="n">attempt</span> <span class="p">=&gt;</span> <span class="n">TimeSpan</span><span class="p">.</span><span class="nf">FromSeconds</span><span class="p">(</span><span class="m">15</span><span class="p">),</span>
            <span class="p">(</span><span class="n">exception</span><span class="p">,</span> <span class="n">timespan</span><span class="p">)</span> <span class="p">=&gt;</span>
            <span class="p">{</span>
                <span class="n">_logger</span><span class="p">.</span><span class="nf">LogError</span><span class="p">(</span><span class="n">exception</span><span class="p">,</span> <span class="s">"Error handling gRPC stream. Reconnecting..."</span><span class="p">);</span>

                <span class="c1">// we haven't received data for more than allowed threshold</span>
                <span class="c1">// reconnecting to the service again</span>
                <span class="n">stream</span> <span class="p">=</span> <span class="n">_subscriber</span><span class="p">.</span><span class="nf">GetStream</span><span class="p">();</span>

                <span class="c1">// here we are recreating cancellation token</span>
                <span class="c1">// and need to take into consideration that parameter `timespan`</span>
                <span class="c1">// is wait duration for the next execution.</span>

                <span class="c1">// meaning that we have to set cancellation token expiration</span>
                <span class="c1">// to `waitDuration + timeout`</span>
                <span class="c1">// otherwise token will be already cancelled when retry policy will execute</span>

                <span class="n">cts</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">CancellationTokenSource</span><span class="p">(</span><span class="n">timespan</span> <span class="p">+</span> <span class="n">_options</span><span class="p">.</span><span class="n">GrpcStreamTimeout</span><span class="p">);</span>
            <span class="p">});</span>

    <span class="k">await</span> <span class="n">policy</span><span class="p">.</span><span class="nf">ExecuteAsync</span><span class="p">(</span><span class="k">async</span> <span class="p">()</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="k">await</span> <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">message</span> <span class="k">in</span> <span class="n">stream</span><span class="p">.</span><span class="nf">ReadAllAsync</span><span class="p">(</span><span class="n">cts</span><span class="p">.</span><span class="n">Token</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="n">_dataBuffer</span><span class="p">.</span><span class="nf">SetNewOptimizedStreamState</span><span class="p">(</span><span class="n">message</span><span class="p">);</span>
            <span class="n">cts</span><span class="p">.</span><span class="nf">CancelAfter</span><span class="p">(</span><span class="n">_options</span><span class="p">.</span><span class="n">GrpcStreamTimeout</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">});</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Hope this helps!
Happy reconnecting!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="gRPC" /><category term="Azure" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="grpc" /><category term="azure" /><summary type="html"><![CDATA[In this blog post we are going to implement feature to reconnect to gRPC stream if specific timeout has elapsed and no new data has been received from the server.]]></summary></entry><entry><title type="html">Azure WebJobs - Eliminate Gap between Runs</title><link href="https://tech-fellow.eu/2021/03/23/azure-webjobs-trick-to-eliminate-gap-between-invokes/" rel="alternate" type="text/html" title="Azure WebJobs - Eliminate Gap between Runs" /><published>2021-03-23T07:10:00+02:00</published><updated>2021-03-23T07:10:00+02:00</updated><id>https://tech-fellow.eu/2021/03/23/azure-webjobs-trick-to-eliminate-gap-between-invokes</id><content type="html" xml:base="https://tech-fellow.eu/2021/03/23/azure-webjobs-trick-to-eliminate-gap-between-invokes/"><![CDATA[<p>Our real-time public transportation tracking systems consists of few Azure WebJobs (yes, web jobs - even in modern “execute your code on some random server you have never seen before and then dispose it” world).</p>

<p>Component which is based on Azure WebJobs is doing heavy calculations and we would like to max-out parallelization as much as possible without paying penalty for leaving the process boundaries (like potentially in for example Azure Functions fan-out/fan-in scenarios).</p>

<p>It’s possible to define timer trigger step by specifying it in attribute usage.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">DoTheWork</span><span class="p">(</span>
    <span class="p">[</span><span class="nf">TimerTrigger</span><span class="p">(</span><span class="s">"*/1 * * * * *"</span><span class="p">)]</span>
    <span class="n">TimerInfo</span> <span class="n">timerInfo</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// heavy work ahead</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As you can see using CRON expressions it’s not possible to specify to run job under 1 second. The lowest step you can get is single second (1s) - <code class="language-plaintext highlighter-rouge">*/1 * * * * *</code>.</p>

<p>It’s fine for the most use cases probably. But our requirement was to execute as frequent as possible. Every millisecond counts for us - so we were looking for a way how to reduce “pauses” between cycles.</p>

<p>It turned out that <code class="language-plaintext highlighter-rouge">TimerTrigger</code> also supports <code class="language-plaintext highlighter-rouge">TimeSpan</code> argument (which is represented as <code class="language-plaintext highlighter-rouge">string</code>). For example:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">DoTheWork</span><span class="p">(</span>
    <span class="p">[</span><span class="nf">TimerTrigger</span><span class="p">(</span><span class="s">"00:00:01"</span><span class="p">)]</span>
    <span class="n">TimerInfo</span> <span class="n">timerInfo</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// heavy work ahead</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is equivalent to run job every second.</p>

<p>As <code class="language-plaintext highlighter-rouge">string</code> is passed down to <code class="language-plaintext highlighter-rouge">TimeSpan</code> for parsing, you can also specify whichever expression you need:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">DoTheWork</span><span class="p">(</span>
    <span class="p">[</span><span class="nf">TimerTrigger</span><span class="p">(</span><span class="s">"00:00:00.0001"</span><span class="p">)]</span>
    <span class="n">TimerInfo</span> <span class="n">timerInfo</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// heavy work ahead</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This will tell WebJobs runtime host that job needs to be executed every <strong>1 millisecond</strong> resulting in job being executed almost all the time.</p>

<p>Also by inheriting from <code class="language-plaintext highlighter-rouge">TimerSchedule</code> class and specifying step yourself.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">EverySecondTrigger</span> <span class="p">:</span> <span class="n">TimerSchedule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">override</span> <span class="kt">bool</span> <span class="n">AdjustForDST</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="k">false</span><span class="p">;</span>

    <span class="k">public</span> <span class="k">override</span> <span class="n">DateTime</span> <span class="nf">GetNextOccurrence</span><span class="p">(</span><span class="n">DateTime</span> <span class="n">now</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">now</span><span class="p">.</span><span class="nf">AddMilliseconds</span><span class="p">(</span><span class="m">1</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">DoTheWork</span><span class="p">(</span>
    <span class="p">[</span><span class="nf">TimerTrigger</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">EverySecondTrigger</span><span class="p">))]</span>
    <span class="n">TimerInfo</span> <span class="n">timerInfo</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// heavy work ahead</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Your own custom trigger might be handy in cases when you need to control whether your job should be executed or not (changing configuration file for example) without recompiling the solution.</p>

<p>For example reading setting from <code class="language-plaintext highlighter-rouge">appsettings.json</code> file).</p>

<p>Program.cs:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
</pre></td><td class="rouge-code"><pre><span class="k">internal</span> <span class="k">class</span> <span class="nc">Program</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="n">IServiceProvider</span> <span class="n">Services</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

    <span class="k">private</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">Main</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">args</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">HostBuilder</span><span class="p">();</span>
        <span class="n">builder</span><span class="p">.</span><span class="nf">ConfigureWebJobs</span><span class="p">(</span><span class="n">b</span> <span class="p">=&gt;</span>
            <span class="p">{</span>
                <span class="n">b</span><span class="p">.</span><span class="nf">AddAzureStorageCoreServices</span><span class="p">();</span>
                <span class="n">b</span><span class="p">.</span><span class="nf">AddAzureStorage</span><span class="p">();</span>
                <span class="n">b</span><span class="p">.</span><span class="nf">AddTimers</span><span class="p">();</span>
            <span class="p">})</span>
            <span class="p">.</span><span class="nf">ConfigureServices</span><span class="p">((</span><span class="n">context</span><span class="p">,</span> <span class="n">services</span><span class="p">)</span> <span class="p">=&gt;</span>
            <span class="p">{</span>
                <span class="n">services</span><span class="p">.</span><span class="n">Configure</span><span class="p">&lt;</span><span class="n">JobSettings</span><span class="p">&gt;(</span><span class="n">context</span><span class="p">.</span><span class="n">Configuration</span><span class="p">.</span><span class="nf">GetSection</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">JobSettings</span><span class="p">)));</span>
            <span class="p">})</span>
            <span class="p">.</span><span class="nf">UseConsoleLifetime</span><span class="p">();</span>

        <span class="kt">var</span> <span class="n">host</span> <span class="p">=</span> <span class="n">builder</span><span class="p">.</span><span class="nf">Build</span><span class="p">();</span>
        <span class="n">Services</span> <span class="p">=</span> <span class="n">host</span><span class="p">.</span><span class="n">Services</span><span class="p">;</span>

        <span class="k">using</span> <span class="p">(</span><span class="n">host</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">await</span> <span class="n">host</span><span class="p">.</span><span class="nf">RunAsync</span><span class="p">();</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>EverySecondTrigger.cs:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">EverySecondTrigger</span> <span class="p">:</span> <span class="n">TimerSchedule</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="kt">bool</span> <span class="n">_enabled</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">EverySecondTrigger</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">_enabled</span> <span class="p">=</span> <span class="n">Program</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="n">GetService</span><span class="p">&lt;</span><span class="n">IOptions</span><span class="p">&lt;</span><span class="n">JobSettings</span><span class="p">&gt;&gt;().</span><span class="n">Value</span><span class="p">.</span><span class="n">TriggerEnabled</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">override</span> <span class="kt">bool</span> <span class="n">AdjustForDST</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="k">false</span><span class="p">;</span>

    <span class="k">public</span> <span class="k">override</span> <span class="n">DateTime</span> <span class="nf">GetNextOccurrence</span><span class="p">(</span><span class="n">DateTime</span> <span class="n">now</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">_enabled</span> <span class="p">?</span> <span class="n">now</span><span class="p">.</span><span class="nf">AddMilliseconds</span><span class="p">(</span><span class="m">1</span><span class="p">)</span> <span class="p">:</span> <span class="n">DateTime</span><span class="p">.</span><span class="n">MaxValue</span><span class="p">.</span><span class="nf">AddMilliseconds</span><span class="p">(-</span><span class="m">1</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Happy scheduling!
[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Azure" /><category term="WebJobs" /><category term=".net" /><category term="c#" /><category term="azure" /><category term="webjobs" /><summary type="html"><![CDATA[Our real-time public transportation tracking systems consists of few Azure WebJobs (yes, web jobs - even in modern “execute your code on some random server you have never seen before and then dispose it” world).]]></summary></entry><entry><title type="html">Real-time Transport Tracking System on Azure - Part 7.1 - Fixing Docker Image Metrics in Azure</title><link href="https://tech-fellow.eu/2021/01/25/building-linux-docker-images-on-windows-machine/" rel="alternate" type="text/html" title="Real-time Transport Tracking System on Azure - Part 7.1 - Fixing Docker Image Metrics in Azure" /><published>2021-01-25T23:15:00+02:00</published><updated>2021-01-25T23:15:00+02:00</updated><id>https://tech-fellow.eu/2021/01/25/building-linux-docker-images-on-windows-machine</id><content type="html" xml:base="https://tech-fellow.eu/2021/01/25/building-linux-docker-images-on-windows-machine/"><![CDATA[<p>This is next post in series about real-time public transport tracking system development based on Azure infrastructure and services. This article is a part of Applied Cloud Stories initiative - <a href="aka.ms/applied-cloud-stories">aka.ms/applied-cloud-stories</a>.</p>

<p>Blog posts in this series:</p>

<ul>
  <li><a href="https://tech-fellow.eu/2019/12/08/building-real-time-public-transport-tracking-system-on-azure-part1/">Part 1 - Scene Background &amp; Solution Architecture</a></li>
  <li><a href="https://tech-fellow.eu/2020/01/21/building-real-time-public-transport-tracking-system-on-azure-part-2-data-collectors-composer/">Part 2 - Data Collectors &amp; Composer</a></li>
  <li><a href="https://tech-fellow.eu/2020/04/08/building-real-time-public-transport-tracking-system-on-azure-part-3/">Part 3 - Event-Based Data Delivery</a></li>
  <li><a href="https://tech-fellow.eu/2020/08/30/building-real-time-public-transport-tracking-system-on-azure-part-4/">Part 4 - Data Processing Pipelines</a></li>
  <li><a href="https://tech-fellow.eu/2020/11/01/building-real-time-public-transport-tracking-system-on-azure-part-5/">Part 5 - Data Broadcast using gRPC</a></li>
  <li><a href="https://tech-fellow.eu/2020/12/14/building-real-time-public-transport-tracking-system-on-azure-part-6-building-frontend/">Part 6 - Building Frontend</a></li>
  <li><a href="https://tech-fellow.eu/2021/01/21/building-real-time-public-transport-tracking-system-on-azure-part-6-packing-everything-up/">Part 7 - Packing Everything Up</a></li>
  <li><strong>Part 7.1 - Fixing Docker Image Metrics in Azure</strong></li>
</ul>

<h2 id="background">Background</h2>

<p>We finished previous blog post with disadvantage of running Windows based image in ACI by stating that guest OS metrics are not exposed in Azure Portal.</p>

<p><img src="/assets/img/2021/01/grpc-aci-no-metrics-2.png" alt="grpc-aci-no-metrics-2" /></p>

<p>This is even mentioned in <a href="https://docs.microsoft.com/en-us/azure/container-instances/container-instances-monitor#preview-limitations">official docs</a>. Metrics currently are only supported for Linux based images.</p>

<p>So let’s fix this by trying to build Linux image on Windows development machine. For this to happen - we gonna need some tools upfront.</p>

<h2 id="preparing-build-environment">Preparing Build Environment</h2>

<h3 id="install-wsl2">Install WSL2</h3>

<p>First, we would need something called “Windows Subsystem for Linux (v2)”. It’s easy installable via <code class="language-plaintext highlighter-rouge">wsl</code> command if you have joined <a href="https://insider.windows.com/en-us/getting-started">“Windows Insiders Program”</a> or you can just follow manual installation steps <a href="https://docs.microsoft.com/en-us/windows/wsl/install-win10#manual-installation-steps">here</a>.</p>

<p>Being able to see this screen is thrilling :)</p>

<p><img src="/assets/img/2021/01/ubuntu.png" alt="ubuntu" /></p>

<h3 id="installing-remote-wsl-vscode-extension">Installing “Remote WSL” VSCode Extension</h3>

<p>After we have installed Linux distro of your choice, we need to install VSCode extension (assuming that you do development in VSCode and know how to install that).</p>

<p>Search for “remote wsl” in extension list.</p>

<p><img src="/assets/img/2021/01/remote-wsl.png" alt="remote-wsl" /></p>

<p>Install it.</p>

<h3 id="preparing-docker-engine-to-talk-to-wsl2">Preparing Docker Engine to Talk to WSL2</h3>

<p>You also will need to prepare Docker for Desktop engine to talk to WSL2.
Do following steps:</p>

<ul>
  <li>Head over to Docker Settings and enable WSL2 integration in “General” tab.</li>
</ul>

<p><img src="/assets/img/2021/01/docker-wsl2.png" alt="docker-wsl2" /></p>

<ul>
  <li>Then under “Resources &gt; WSL Integration” make sure that you see your distro and it’s enabled.</li>
</ul>

<p><img src="/assets/img/2021/01/docker-wsl2-ubuntu.png" alt="docker-wsl2-ubuntu" /></p>

<h2 id="building-image">Building Image</h2>

<h3 id="launching-vscode-in-wsl-mode">Launching VSCode in WSL Mode</h3>

<p>Now to get started:</p>

<ul>
  <li>Open VS Code</li>
  <li>Open terminal</li>
  <li>Type <code class="language-plaintext highlighter-rouge">wsl</code></li>
</ul>

<p><img src="/assets/img/2021/01/wsl-in-vscode.png" alt="wsl-in-vscode" /></p>

<ul>
  <li>Then type <code class="language-plaintext highlighter-rouge">code .</code></li>
</ul>

<p><img src="/assets/img/2021/01/code-opened-in-wsl.png" alt="code-opened-in-wsl" /></p>

<p>This basically means that new instance of VSCode is opened in WSL context (pretending that you are actually at Linux <code class="language-plaintext highlighter-rouge">bash</code>). A bit of mind-blowing, but I can chew that.</p>

<h3 id="changing-image-stages">Changing Image Stages</h3>

<p>Now we need to change image for the <code class="language-plaintext highlighter-rouge">build</code> and <code class="language-plaintext highlighter-rouge">final</code> stages - we need to switch from “Windows” to “Linux”.</p>

<p>Which distro you choose that’s entirely up to you, but I chose the very basic and straight forward edition - “Focal”.</p>

<p>We have to change from</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre>FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
...
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-nanoserver-1809 AS final
...
</pre></td></tr></tbody></table></code></pre></div></div>

<p>to</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre>FROM mcr.microsoft.com/dotnet/sdk:3.1-focal AS build
...
FROM mcr.microsoft.com/dotnet/aspnet:3.1-focal AS final
...
</pre></td></tr></tbody></table></code></pre></div></div>

<p>List of available SDK images you can get <a href="https://hub.docker.com/_/microsoft-dotnet-sdk">here</a> and runtimes <a href="https://hub.docker.com/_/microsoft-dotnet-aspnet/">here</a>.</p>

<h3 id="build-the-image">Build the Image</h3>

<p>Building the image inside WSL2 is exactly the same as we saw it already when we were building Docker image inside Windows OS.</p>

<p>Remote WSL makes it super easy. All <code class="language-plaintext highlighter-rouge">docker</code> commands are working and it feels almost like <em>magic</em>.</p>

<p><img src="/assets/img/2021/01/vscode-wsl-docker.png" alt="vscode-wsl-docker" /></p>

<h2 id="deploying-image-to-azure">Deploying Image to Azure</h2>

<p>Again, the deployment process to Azure is exactly the same as with Windows based images. Just if you would like to override OS type for the ACI - you will have to delete ACI resource before proceeding (as you just can’t change OS type on-fly).</p>

<p>After successful deployment and uptime for some period, we now do have nice metrics for the app.</p>

<p><img src="/assets/img/2021/01/grpc-metrics-in-portal.png" alt="grpc-metrics-in-portal" /></p>

<p>Hope this helps!
Happy containerizing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="gRPC" /><category term="Azure" /><category term=".net" /><category term="c#" /><category term="grpc" /><category term="azure" /><summary type="html"><![CDATA[This is next post in series about real-time public transport tracking system development based on Azure infrastructure and services. This article is a part of Applied Cloud Stories initiative - aka.ms/applied-cloud-stories.]]></summary></entry><entry><title type="html">Building Real-time Public Transport Tracking System on Azure - Part 7 - Packing Everything Up</title><link href="https://tech-fellow.eu/2021/01/21/building-real-time-public-transport-tracking-system-on-azure-part-6-packing-everything-up/" rel="alternate" type="text/html" title="Building Real-time Public Transport Tracking System on Azure - Part 7 - Packing Everything Up" /><published>2021-01-21T13:30:00+02:00</published><updated>2021-01-21T13:30:00+02:00</updated><id>https://tech-fellow.eu/2021/01/21/building-real-time-public-transport-tracking-system-on-azure-part-6-packing-everything-up</id><content type="html" xml:base="https://tech-fellow.eu/2021/01/21/building-real-time-public-transport-tracking-system-on-azure-part-6-packing-everything-up/"><![CDATA[<p>This is next post in series about real-time public transport tracking system development based on Azure infrastructure and services. This article is a part of Applied Cloud Stories initiative - <a href="aka.ms/applied-cloud-stories">aka.ms/applied-cloud-stories</a>.</p>

<p>Blog posts in this series:</p>

<ul>
  <li><a href="https://tech-fellow.eu/2019/12/08/building-real-time-public-transport-tracking-system-on-azure-part1/">Part 1 - Scene Background &amp; Solution Architecture</a></li>
  <li><a href="https://tech-fellow.eu/2020/01/21/building-real-time-public-transport-tracking-system-on-azure-part-2-data-collectors-composer/">Part 2 - Data Collectors &amp; Composer</a></li>
  <li><a href="https://tech-fellow.eu/2020/04/08/building-real-time-public-transport-tracking-system-on-azure-part-3/">Part 3 - Event-Based Data Delivery</a></li>
  <li><a href="https://tech-fellow.eu/2020/08/30/building-real-time-public-transport-tracking-system-on-azure-part-4/">Part 4 - Data Processing Pipelines</a></li>
  <li><a href="https://tech-fellow.eu/2020/11/01/building-real-time-public-transport-tracking-system-on-azure-part-5/">Part 5 - Data Broadcast using gRPC</a></li>
  <li><a href="https://tech-fellow.eu/2020/12/14/building-real-time-public-transport-tracking-system-on-azure-part-6-building-frontend/">Part 6 - Building Frontend</a></li>
  <li><strong>Part 7 - Packing Everything Up</strong></li>
  <li><a href="https://tech-fellow.eu/2021/01/25/building-linux-docker-images-on-windows-machine/">Part 7.1 - Fixing Docker Image Metrics in Azure</a></li>
</ul>

<h2 id="background">Background</h2>

<p>This is blog post in series about building real-time public transport tracking system on Microsoft Azure cloud services. Now it’s time to pack up and deploy services to cloud for smooth production run.</p>

<p>In ideal case - you would be looking for a way to deploy gRPC service to Azure App Service but this is not possible. And here we are - original issue was raised on <a href="https://github.com/dotnet/AspNetCore/issues/9020">Apr 3, 2019</a>. As proper support for gRPC services to be hosted on IIS - this involves changes in IIS and also Windows kernel. Latter for sure means that this process gonna take a while before it lands in Azure (requires Windows update).</p>

<p><img src="/assets/img/2021/01/grpc-on-app-service.png" alt="grpc-on-app-service" /></p>

<p>It’s even stated in<a href="https://docs.microsoft.com/en-us/aspnet/core/tutorials/grpc/grpc-start?view=aspnetcore-3.0&amp;tabs=visual-studio"> official docs</a>.</p>

<p>However, we can’t wait till issue is fixed and we can deploy. We have to find some workaround for this.</p>

<h2 id="create-container-image-for-grpc-service">Create Container Image for gRPC Service</h2>

<p>One thing is for sure - hosting gRPC service anywhere, we will need to build docker image for it. Whether it will Azure Container Instances (ACI), Azure Kubernetes Services (AKS) or any other service - we gonna need an image for it.</p>

<h3 id="add-docker-support">Add Docker Support</h3>

<p>I’m not going to write an introduction about containers here and what they are, there are plenty of really good content already out there. So if you need to load knowledge about “container-fu” - search of it online and you will find good ones.</p>

<p>Let’s get started with containers. In order to start messing with container, we add support for it right in Visual Studio.</p>

<p><img src="/assets/img/2021/01/grpc-add-docker.png" alt="grpc-add-docker" /></p>

<p>You will be asked to choose container OS type.</p>

<p><img src="/assets/img/2021/01/grpc-container-type.png" alt="grpc-container-type" /></p>

<p>I chose “Windows” as I’m working on that OS everyday.</p>

<p>At the end of the process Visual Studio Tools for Docker will add “Dockerfile” file and couple of attributes inside <code class="language-plaintext highlighter-rouge">.csproj</code> file to support building Docker images for your project.</p>

<p>Most of the work is done (more or less). Or at least we got skeleton to start working on.</p>

<p>Visual Studio Tools for Docker generates quite good “Dockerfile” that we just slightly need to modify.</p>

<p>Here is modified file (some of fragments are removed for brevity):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
</pre></td><td class="rouge-code"><pre>FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build

WORKDIR /src
# copy main project
COPY ["src/GrpcService/GrpcService.csproj", "src/GrpcService/"]

# copies also other dependencies
COPY ["src/Abstractions/Abstractions.csproj", "src/Abstractions/"]
# COPY ["src/...csproj", "src/.."]

RUN dotnet restore "src/GrpcService/GrpcService.csproj"
COPY . .
WORKDIR "/src/GrpcService"
RUN dotnet build "GrpcService.csproj" --no-restore -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "GrpcService.csproj" -c Release -o /app/publish

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-nanoserver-1809 AS final
USER ContainerAdministrator
WORKDIR /app
COPY --from=publish /app/publish .

ENTRYPOINT ["dotnet", "GrpcService.dll"]
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Let’s break down whole “Dockerfile” line by line.</p>

<ul>
  <li>Establishing base line for the image on top of which next steps will be executed. We are using public image of the .NET Core 3.1 SDK.</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>Creating working directory and copying all projects to it (it’s like build agent’s checkout directory).</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>WORKDIR /src
COPY ["src/GrpcService/GrpcService.csproj", "src/GrpcService/"]
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>Execute <code class="language-plaintext highlighter-rouge">restore</code> command to fetch all the dependencies and packages.</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>RUN dotnet restore "src/GrpcService/GrpcService.csproj"
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>Build main gRPC service project to get binaries out</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>RUN dotnet build "GrpcService.csproj" --no-restore -c Release -o /app/build
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>Then we are defining new baseline for the image (sort of “creating new stage” for it), assign name “publish” to it and run publish command to get packed output for gRPC service.</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>FROM build AS publish
RUN dotnet publish "GrpcService.csproj" -c Release -o /app/publish
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>Defining last “layer” for the image where actual content of the gRPC service will be located. Here we take “nano-server” public image with ASP.NET Core 3.1 installed. You can think of it as “small windows with all dependencies installed to run ASP.NET Core 3.1 applications”.</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-nanoserver-1809 AS final
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>Create target directory and copy all required output content from publishing “layer”. Don’t worry about “<code class="language-plaintext highlighter-rouge">ContainerAdministrator</code>” for now..</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>USER ContainerAdministrator
WORKDIR /app
COPY --from=publish /app/publish .
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>Define our <code class="language-plaintext highlighter-rouge">public static void Main(string[] args)</code> method as <code class="language-plaintext highlighter-rouge">ENTRYPOINT</code>. This is basically command that will be executed every time you start an image.</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>ENTRYPOINT ["dotnet", "GrpcService.dll"]
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You will need to have <a href="https://www.docker.com/products/docker-desktop">Docker Desktop</a> application in order to run it locally but I guess Visual Studio Tools for Docker already checked this on your system so you should be good to go.</p>

<h3 id="building-an-image">Building an Image</h3>

<p>Once we have definition file for the Docker - it’s only a definition (like source code). We need to compile (actually “build”) it. This is done with <code class="language-plaintext highlighter-rouge">docker ...</code> command. Locate yourself at the directory where “Dockerfile” was generated and run:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>PS C:\grpc-demo&gt; docker build . -t "grpc-server-demo"
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Building process might take a while (but it’s worth it). Parameter <code class="language-plaintext highlighter-rouge">-t</code> is for tagging an image. Essentially you are assigning name to the image which you will be able to refer to later when needed.</p>

<p>You might see something similar in output:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="rouge-code"><pre>...
Step 24/29 : FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-nanoserver-1809 AS final
 ---&gt; ea8c92c37b3f
Step 25/29 : USER ContainerAdministrator
 ---&gt; Using cache
 ---&gt; 9aef174f73a3
Step 26/29 : WORKDIR /app
 ---&gt; Using cache
 ---&gt; 037503659bf2
Step 27/29 : COPY --from=publish /app/publish .
 ---&gt; e7a837c53662
Step 28/29 : COPY GrpcService.pfx .
 ---&gt; 0b745a9a18b9
Step 29/29 : ENTRYPOINT ["dotnet", "GrpcService.dll"]
 ---&gt; Running in af7bf6234ba6
Removing intermediate container af7bf6234ba6
 ---&gt; 70fba1826ae6
Successfully built 70fba1826ae6
Successfully tagged grpc-server-demo:latest
PS C:\grpc-demo&gt;
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="nuget-restore-failure">NuGet Restore Failure</h3>

<p>Sometimes you might see that <code class="language-plaintext highlighter-rouge">dotnet restore</code> is not working properly while build process executes.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre>Step 7/23 : RUN dotnet restore
—&gt; Running in ce2d8740cf2e
Restore completed in 389.74 ms for C:\src\GrpcService\GrpcService.csproj.
C:\Program Files\dotnet\sdk\3.1.300\NuGet.targets(123,5): error : Unable to load the service index for source https://api.nuget.org/v3/index.json. [C:\src\GrpcService\GrpcService.csproj]
C:\Program Files\dotnet\sdk\3.1.300\NuGet.targets(123,5): error : No such host is known [C:\src\GrpcService\GrpcService.csproj]
The command ‘powershell -Command $ErrorActionPreference = ‘Stop’; $ProgressPreference = ‘SilentlyContinue’; dotnet restore’ returned a non-zero code: 1
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This means that Docker image can’t do any DNS resolutions - resulting in build process abort and exit.</p>

<p>One of the ways how to fix this issue is to mess around with network interface metrics.</p>

<p>First you need to get list of network metrics</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>❯ Get-NetIPInterface -AddressFamily IPv4 | Sort-Object -Property InterfaceMetric -Descending
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/2021/01/grpc-network-metrics.png" alt="grpc-network-metrics" /></p>

<p>Docker is using interface from the host to do its network magic. So metrics for the interfaces are used to understand priority of the network interface to use. Lower the metric means higher interface priority. So once you identified which interface is causing your Docker image build problems, you can change metrics for that one.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>❯ Set-NetIPInterface -InterfaceAlias 'Local Area Connection* 1' -InterfaceMetric 59
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="setting-up-kestrel-for-secure-connection">Setting Up Kestrel for Secure Connection</h3>

<p>In order to run successfully gRPC service on top of the Kestrel, you will need to setup SSL certificate for that (gRPC requires secure connection to be present).</p>

<p>One of the options is to issue self-signed certificate.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>&gt; openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365
&gt; openssl pkcs12 -export -out grpc.pfx -inkey key.pem -in cert.pem
</pre></td></tr></tbody></table></code></pre></div></div>

<p>When you are creating certificate - you will be prompted to enter password and other stuff. Write those down somewhere as you will need them later in the process.</p>

<p>Adding certificate to the Docker image is done via environment variables (ASP.NET Core looks for some well-known keys there and if found - uses those). Setting environment variables in Docker is accomplished with a help of <code class="language-plaintext highlighter-rouge">env</code> command (we set variables after establishing <code class="language-plaintext highlighter-rouge">final</code> layer where we copy over published output of the app).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre>FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-nanoserver-1809 AS final

ENV ASPNETCORE_URLS="https://+"
ENV ASPNETCORE_Kestrel__Certificates__Default__Path="./grpc.pfx"
...
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Also we need to copy certificate physically into the image. This is done again with simple <code class="language-plaintext highlighter-rouge">COPY</code>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre>...

COPY --from=publish /app/publish .
COPY grpc.pfx .
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="running-an-image-as-container-locally">Running an Image as Container Locally</h3>

<p>Once you get your image successfully built, it’s time to run it. This is achievable with <code class="language-plaintext highlighter-rouge">docker run</code></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre>PS C:\grpc-demo&gt; docker run --rm -it -p 5051:443 -e ASPNETCORE_HTTPS_PORT=5051 -e ASPNETCORE_Kestrel__Certificates__Default__Password="{-your-password-}"
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://[::]:5051
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Production
info: Microsoft.Hosting.Lifetime[0]
      Content root path: C:\app
...
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Your chosen password for the certificate needs to be passed in as parameter when starting docker image. You can also of course bake it into the image itself but I would not recommend it.</p>

<p>Also we are forwarding Kestrel’s <code class="language-plaintext highlighter-rouge">5051</code> port from the container to be exposed as <code class="language-plaintext highlighter-rouge">443</code> on the host machine.</p>

<p>This is ordinary console output that you would see when starting .NET Core application.
You can freely Ctrl+C there as this <strong>will not</strong> kill the app (will just exit console log stream for that app).</p>

<p>You can list all running containers with <code class="language-plaintext highlighter-rouge">docker ps</code></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>PS C:\grpc-demo&gt; docker ps
CONTAINER ID   IMAGE              COMMAND                  CREATED          STATUS          PORTS     NAMES
82c209c7ced3   grpc-server-demo   "dotnet GrpcService.…"   12 seconds ago   Up 10 seconds             focused_tereshkova
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="running-container-in-azure">Running Container in Azure</h2>

<p>When we have verified that image is runnable locally, we can start preparation work to move this to the cloud and run it in Azure.
Azure provides couple services for this type of workload - Kubernetes Services (AKS) &amp; Container Instances (ACI).</p>

<p>I chose the latter - but you have to justify costs and analyze potential invoice amount before proceeding.</p>

<h3 id="registering-image-in-azure-container-registry-acr">Registering Image in Azure Container Registry (ACR)</h3>

<p>Path to the cloud starts with registering image in Azure Container Registry. It’s like NuGet.org for .NET packages or “npm.org” for frontend stuff. Container host will be using this registry to pull images and run them.</p>

<p>In order to continue we have to create Azure Container Registry. Just search for one in the portal and follow wizard steps there.</p>

<p><img src="/assets/img/2021/01/grpc-acr.png" alt="grpc-acr" /></p>

<p>Name of the registry should be chosen wisely as this is global registry and names might collide.</p>

<p>Then we need to login into Azure from CLI (login process will open browser and will ask you to login into Azure).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; az login
</pre></td></tr></tbody></table></code></pre></div></div>

<p>After successfully establishing link in CLI with Azure, we can login now in our newly created Azure Container Registry.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; az acr login --name myownshinyacr
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As third step - we have to tag somehow just recently created docker image (keep in mind also url of the image with version number at the end - we gonna need this later on).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; docker tag grpc-service-demo myownshinyacr.azurecr.io/grpc-service:v1
</pre></td></tr></tbody></table></code></pre></div></div>

<p>When we have assigned tag to the image - we have to push it out to the registry.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; docker push myownshinyacr.azurecr.io/grpc-service:v1
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre>PS C:\grpc-demo&gt; docker push myownshinyacr.azurecr.io/grpc-service:v1
The push refers to repository [myownshinyacr.azurecr.io/grpc-service]
6a14c3071eb7: Pushed
171573b3ea7e: Pushed
1c7bd158a73c: Pushed
a4d54e85335d: Pushed
904eeede01a3: Pushed
3feb255a247e: Pushed
e66bc7aeeb29: Pushing [=============================================&gt;     ]  62.67MB/69.2MB
2019d72f0a51: Pushed
06e112d86344: Pushed
94035e61bd19: Pushed
a6ef2c7fdcd2: Pushed
8d36ad9cbc77: Skipped foreign layer
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You can inspect container image in registry later just to verify that it’s uploaded correctly.</p>

<p><img src="/assets/img/2021/01/grpc-acr-pushed.png" alt="grpc-acr-pushed" /></p>

<h3 id="creating-azure-container-instance-aci">Creating Azure Container Instance (ACI)</h3>

<p>Now we are ready to run uploaded image in ACI. For this to happen we will need to use <code class="language-plaintext highlighter-rouge">az container</code> command.</p>

<h4 id="create-aci-using-portal">Create ACI Using Portal</h4>

<p>One of the way to create ACI is by using portal wizard.
Again just search for “aci” keyword.</p>

<p><img src="/assets/img/2021/01/grpc-aci.png" alt="grpc-aci" /></p>

<p>And follow instructions and answer asked questions and you are ready to go.</p>

<p>In order to pull down image from the registry, admin user must be enabled there. Head over to the registry and open up “Access Keys” blade and enable “Admin user” option.</p>

<p><img src="/assets/img/2021/01/grpc-acr-admin.png" alt="grpc-acr-admin" /></p>

<h4 id="create-aci-using-command-line-interface">Create ACI Using Command Line Interface</h4>

<p>Another option is to use CLI for this.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre>&gt; az container create \
    --resource-group grpc-demo-rg \
    --name grpc-container \
    --image myownshinyacr.azurecr.io/grpc-service:v1 \
    --registry-login-server myownshinyacr.azurecr.io \
    --registry-username myownshinyacr \
    --registry-password {-your-acr-admin-user-password-} \
    --os-type Windows \
    --ip-address Public \
    --dns-name-label testing-grpc
</pre></td></tr></tbody></table></code></pre></div></div>

<p>But again this looks terribly verbose and I would be dead after trying to type it again tomorrow when we would release newer version of the service.</p>

<h4 id="better-way-to-create-aci">Better Way to Create ACI</h4>

<p>Third option is to just define description file for the ACI using <code class="language-plaintext highlighter-rouge">yaml</code> format ;) Here we can describe all the details we need to specify for our container instance. We do it once and then reuse this definition every time we need to deploy newer version of the gRPC service.</p>

<p>Your <code class="language-plaintext highlighter-rouge">yaml</code> definition file:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
</pre></td><td class="rouge-code"><pre><span class="na">api-version</span><span class="pi">:</span> <span class="s">2018-10-01</span>
<span class="na">location</span><span class="pi">:</span> <span class="s">westeurope</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">grpc-container</span>
<span class="na">properties</span><span class="pi">:</span>
  <span class="na">containers</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">test-grpc-app</span>
    <span class="na">properties</span><span class="pi">:</span>
      <span class="na">image</span><span class="pi">:</span> <span class="s">myownshinyacr.azurecr.io/grpc-service:v1</span>
      <span class="na">ports</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">port</span><span class="pi">:</span> <span class="m">443</span>
        <span class="na">protocol</span><span class="pi">:</span> <span class="s">TCP</span>
      <span class="na">resources</span><span class="pi">:</span>
        <span class="na">requests</span><span class="pi">:</span>
          <span class="na">cpu</span><span class="pi">:</span> <span class="m">4.0</span>
          <span class="na">memoryInGB</span><span class="pi">:</span> <span class="m">4.0</span>
      <span class="na">environmentVariables</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">ASPNETCORE_URLS</span>
        <span class="na">value</span><span class="pi">:</span> <span class="s">https://+</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">ASPNETCORE_HTTPS_PORT</span>
        <span class="na">value</span><span class="pi">:</span> <span class="m">443</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">ASPNETCORE_Kestrel__Certificates__Default__Password</span>
        <span class="na">value</span><span class="pi">:</span> <span class="pi">{</span><span class="nv">-your-certificate-password-</span><span class="pi">}</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">ASPNETCORE_Kestrel__Certificates__Default__Path</span>
        <span class="na">value</span><span class="pi">:</span> <span class="s">grpc.pfx</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">ASPNETCORE_ENVIRONMENT</span>
        <span class="na">value</span><span class="pi">:</span> <span class="s">Production</span>
  <span class="na">restartPolicy</span><span class="pi">:</span> <span class="s">OnFailure</span>
  <span class="na">imageRegistryCredentials</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">server</span><span class="pi">:</span> <span class="s">myownshinyacr.azurecr.io</span>
    <span class="na">username</span><span class="pi">:</span> <span class="s">myownshinyacr</span>
    <span class="na">password</span><span class="pi">:</span> <span class="pi">{</span><span class="nv">-your-acr-admin-user-password-</span><span class="pi">}</span>
  <span class="na">ipAddress</span><span class="pi">:</span>
    <span class="na">ports</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">port</span><span class="pi">:</span> <span class="m">443</span>
      <span class="na">protocol</span><span class="pi">:</span> <span class="s">TCP</span>
    <span class="na">type</span><span class="pi">:</span> <span class="s">Public</span>
    <span class="na">dnsNameLabel</span><span class="pi">:</span> <span class="s">testing-grpc</span>
  <span class="na">osType</span><span class="pi">:</span> <span class="s">Windows</span>
<span class="na">tags</span><span class="pi">:</span> <span class="kc">null</span>
<span class="na">type</span><span class="pi">:</span> <span class="s">Microsoft.ContainerInstance/containerGroups</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>By having this file at hand - we simply execute <code class="language-plaintext highlighter-rouge">az container</code> command by pointing to container service definition file.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; az container create --resource-group Kolumbus-Test --file deploy-grpc.yaml
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="downside-of-aci">Downside of ACI</h2>

<p>Actually there are couple.
Price is the first one. Compared to AKS -&gt; ACI turns out to be beefy (assume this is because of Windows license costs on all hardware that is involved to run your cluster).</p>

<p>Second is around metrics. After running image for a while, I was looking for some metrics (memory, cpu, etc). And turned out that if you are running Windows image on ACI - metrics are juts simply not supported - those are not exposed to collector agents and therefore are not forwarded to Azure monitoring infrastructure to be shown in the portal.</p>

<p>So you end up with following picture:</p>

<p><img src="/assets/img/2021/01/grpc-aci-no-metrics-3.png" alt="grpc-aci-no-metrics-3" /></p>

<p>Which is not super helpful after all. Therefore seems like we gonna have another post - how to do this whole hosting ceremony running on Linux and maybe event switch to AKS.</p>

<h2 id="extras">Extras</h2>

<h3 id="embedding-protobuf-files-within-image">Embedding Protobuf Files within Image</h3>

<p>Also worth mentioning that it has been super helpful for the consumers of the gRPC service to be able to get <code class="language-plaintext highlighter-rouge">.proto</code> files for the services. It’s like browsing <code class="language-plaintext highlighter-rouge">.disco</code> / <code class="language-plaintext highlighter-rouge">wsdl</code> files back in WCF era.</p>

<p>If would be awesome if any consumer who needs to generate client proxy classes for the service - could just point to the proto file and continue. Also we as service authors would not need to think about where to locate <code class="language-plaintext highlighter-rouge">.proto</code> files, how to keep it in sync with deployed code and how to maintain version of it.</p>

<p>Luckily <a href="https://twitter.com/anthonygiretti">Anthony</a> has made this possible - by providing a nice way to embed protobuf file along with your service. More details in his <a href="https://anthonygiretti.com/2020/07/06/exposing-proto-files-in-a-grpc-service-over-a-frameworkless-and-lightweight-api/">blog post</a>.</p>

<p>Thanks <a href="https://twitter.com/brianweet">Brian</a> for proof-reading!</p>

<p>Hope this helps!
Happy packing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="gRPC" /><category term="Azure" /><category term=".net" /><category term="c#" /><category term="grpc" /><category term="azure" /><summary type="html"><![CDATA[This is next post in series about real-time public transport tracking system development based on Azure infrastructure and services. This article is a part of Applied Cloud Stories initiative - aka.ms/applied-cloud-stories.]]></summary></entry><entry><title type="html">Building Real-time Public Transport Tracking System on Azure - Part 6 - Building Frontend</title><link href="https://tech-fellow.eu/2020/12/14/building-real-time-public-transport-tracking-system-on-azure-part-6-building-frontend/" rel="alternate" type="text/html" title="Building Real-time Public Transport Tracking System on Azure - Part 6 - Building Frontend" /><published>2020-12-14T13:30:00+02:00</published><updated>2020-12-14T13:30:00+02:00</updated><id>https://tech-fellow.eu/2020/12/14/building-real-time-public-transport-tracking-system-on-azure-part-6-building-frontend</id><content type="html" xml:base="https://tech-fellow.eu/2020/12/14/building-real-time-public-transport-tracking-system-on-azure-part-6-building-frontend/"><![CDATA[<p>This is next post in series about real-time public transport tracking system development based on Azure infrastructure and services. This article is a part of Applied Cloud Stories initiative - <a href="aka.ms/applied-cloud-stories">aka.ms/applied-cloud-stories</a>.</p>

<p>Blog posts in this series:</p>

<ul>
  <li><a href="https://tech-fellow.eu/2019/12/08/building-real-time-public-transport-tracking-system-on-azure-part1/">Part 1 - Scene Background &amp; Solution Architecture</a></li>
  <li><a href="https://tech-fellow.eu/2020/01/21/building-real-time-public-transport-tracking-system-on-azure-part-2-data-collectors-composer/">Part 2 - Data Collectors &amp; Composer</a></li>
  <li><a href="https://tech-fellow.eu/2020/04/08/building-real-time-public-transport-tracking-system-on-azure-part-3/">Part 3 - Event-Based Data Delivery</a></li>
  <li><a href="https://tech-fellow.eu/2020/08/30/building-real-time-public-transport-tracking-system-on-azure-part-4/">Part 4 - Data Processing Pipelines</a></li>
  <li><a href="https://tech-fellow.eu/2020/11/01/building-real-time-public-transport-tracking-system-on-azure-part-5/">Part 5 - Data Broadcast using gRPC</a></li>
  <li><strong>Part 6 - Building Frontend</strong></li>
  <li><a href="https://tech-fellow.eu/2021/01/21/building-real-time-public-transport-tracking-system-on-azure-part-6-packing-everything-up/">Part 7 - Packing Everything Up</a></li>
  <li><a href="https://tech-fellow.eu/2021/01/25/building-linux-docker-images-on-windows-machine/">Part 7.1 - Fixing Docker Image Metrics in Azure</a></li>
</ul>

<h2 id="background">Background</h2>

<p>Now that we have received the data, ran through all required processing pipelines, prepared various profiles and have written data out to active (connected clients) gRPC channels, it’s time to render snapshot on the screen.</p>

<h2 id="solution">Solution</h2>

<p>For this part we gonna ask for help from my colleague and good friend - <strong>Dzulqarnain Nasir</strong>. So let’s head over to his blog series <a href="https://dnasir.com/2020/11/11/realtime-web-apps-with-grpc-part-1/">here</a>.</p>

<p>He is going to fill up space to write about how to build front-end application that uses gRPC channels to talk to the server, offload heavy processing to web workers (to free up CPU for rendering) and other quite cool things. Bookmark and keep an eye on this blog posts!</p>

<p>Happy frontending!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="gRPC" /><category term="Azure" /><category term=".net" /><category term="c#" /><category term="grpc" /><category term="azure" /><summary type="html"><![CDATA[This is next post in series about real-time public transport tracking system development based on Azure infrastructure and services. This article is a part of Applied Cloud Stories initiative - aka.ms/applied-cloud-stories.]]></summary></entry><entry><title type="html">Episerver Scheduled Jobs - Under the Hood</title><link href="https://tech-fellow.eu/2020/12/07/episerver-scheduled-jobs-under-the-hood/" rel="alternate" type="text/html" title="Episerver Scheduled Jobs - Under the Hood" /><published>2020-12-07T21:00:00+02:00</published><updated>2020-12-07T21:00:00+02:00</updated><id>https://tech-fellow.eu/2020/12/07/episerver-scheduled-jobs-under-the-hood</id><content type="html" xml:base="https://tech-fellow.eu/2020/12/07/episerver-scheduled-jobs-under-the-hood/"><![CDATA[<h2 id="introduction">Introduction</h2>

<p>Have you ever wondered what really happens when you run your scheduled job in Episerver? What happens when Episerver misses to fire off your job, what is scheduler and how job status notifications are implemented? In order to better understand underlying platform - in my opinion, it’s crucial to understand what’s going on under the hood. That should help next time when the thing hits the fan and you have a glass of your favorite whisky with you at Friday evening and you are staring at the screenshot in support ticket.</p>

<p>As I see that nowadays scheduled jobs are quite <a href="https://www.gulla.net/en/blog/episerver-scheduled-jobs-make-it-fail/">popular topic</a> :)</p>

<p>In this blog post we are going to try to peel off some of the details what actually is happening when Episerver needs to run your scheduled jobs.</p>

<p><strong>NB!</strong> Most of the APIs I’m going to talk about are <strong>internal</strong>. Internal for us developers means - that we should not take dependency on those, should avoid using them in our code and overall stay away. I can’t expose Episerver source code directly, therefore I’ll describe behavior with sample code as close as I can.</p>

<p>This post is mostly for educational purpose. Some parts don’t repeat at production! :)</p>

<h2 id="scheduled-job-definition">Scheduled Job Definition</h2>

<h3 id="recommended-implementation">Recommended Implementation</h3>

<p>Let’s start with very simple job definition.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ScheduledPlugIn</span><span class="p">(</span><span class="n">DisplayName</span> <span class="p">=</span> <span class="s">"ScheduledJob1"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ScheduledJob1</span> <span class="p">:</span> <span class="n">ScheduledJobBase</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="kt">bool</span> <span class="n">_stopSignaled</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">ScheduledJob1</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">IsStoppable</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">/// &lt;summary&gt;</span>
    <span class="c1">/// Called when a user clicks on Stop for a manually started job, or when ASP.NET shuts down.</span>
    <span class="c1">/// &lt;/summary&gt;</span>
    <span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Stop</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">_stopSignaled</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">/// &lt;summary&gt;</span>
    <span class="c1">/// Called when a scheduled job executes</span>
    <span class="c1">/// &lt;/summary&gt;</span>
    <span class="c1">/// &lt;returns&gt;A status message to be stored in the database log and visible from admin mode&lt;/returns&gt;</span>
    <span class="k">public</span> <span class="k">override</span> <span class="kt">string</span> <span class="nf">Execute</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="c1">//Call OnStatusChanged to periodically notify progress of job for manually started jobs</span>
        <span class="nf">OnStatusChanged</span><span class="p">(</span><span class="n">String</span><span class="p">.</span><span class="nf">Format</span><span class="p">(</span><span class="s">"Starting execution of {0}"</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nf">GetType</span><span class="p">()));</span>

        <span class="c1">//Add implementation</span>

        <span class="c1">//For long running jobs periodically check if stop is signaled and if so stop execution</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">_stopSignaled</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">return</span> <span class="s">"Stop of job was called"</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="k">return</span> <span class="s">"Change to message that describes outcome of execution"</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is default job definition created by Episerver Visual Studio template. Few things to note here:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">[ScheduledPlugIn(DisplayName = "...")]</code> - you have to annotate your class with attribute in order to get Episerver attention during scanning and registration phase.</li>
  <li><code class="language-plaintext highlighter-rouge">public class ScheduledJob1 : ScheduledJobBase</code> - you are inheriting from the base class. Also this plays some role in the whole infrastructure of scheduled jobs.</li>
  <li><code class="language-plaintext highlighter-rouge">IsStoppable = true;</code> - this is telling Episerver that you do support graceful shutdown of your job. Whether you have to be good or bad at that time - we will experiment later around this.</li>
  <li><code class="language-plaintext highlighter-rouge">OnStatusChanged(...)</code> - this is a way to tell UI users that job did something and here is the thing it did.</li>
</ul>

<h3 id="alternative">Alternative</h3>

<p>You like your parents but sometimes you just want to live alone of with somebody else - when you would like to inherit from different base class for example (or maybe do not want to inherit from anyone and be independent individualist). Then you can just implement <code class="language-plaintext highlighter-rouge">IScheduledJob</code> interface and you should be good to go.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ScheduledPlugIn</span><span class="p">(</span><span class="n">DisplayName</span> <span class="p">=</span> <span class="s">"ScheduledJob1"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ScheduledJob1</span> <span class="p">:</span> <span class="n">IScheduledJob</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">ScheduledJob1</span><span class="p">()</span> <span class="p">{</span> <span class="n">ID</span> <span class="p">=</span> <span class="n">Guid</span><span class="p">.</span><span class="nf">NewGuid</span><span class="p">();</span> <span class="p">}</span>

    <span class="k">public</span> <span class="kt">string</span> <span class="nf">Execute</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="s">"Great success!"</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">Guid</span> <span class="n">ID</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="dont-try-this-at-home-kids">Don’t Try this at Home Kids</h3>

<p>This is recommended approach at all, but if you are willing to fly super alone - then the only thing you need to have is <code class="language-plaintext highlighter-rouge">static Execute</code> method. No other obligations required here.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ScheduledPlugIn</span><span class="p">(</span><span class="n">DisplayName</span> <span class="p">=</span> <span class="s">"ScheduledJob1"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ScheduledJob1</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">Execute</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="c1">// do magic here</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>NB!</strong> This is design is kept in Episerver <em>only</em> for backward compatibility. Please do not use it, you gonna loose a lot of built-in functionality that is available if you inherit from <code class="language-plaintext highlighter-rouge">ScheduledJobBase</code> type.</p>

<h2 id="important-types">Important Types</h2>

<p>Here is a list of some important types and interfaces that will play role in scheduled jobs infrastructure:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">ISchedulerService</code> - implementation responsible for following the given schedule and assign jobs for execution;</li>
  <li><code class="language-plaintext highlighter-rouge">IScheduledJobExecutor</code> - the one who actually invokes jobs;</li>
  <li><code class="language-plaintext highlighter-rouge">IScheduledJobLogRepository</code> - bookkeeper of the stuff happened;</li>
  <li><code class="language-plaintext highlighter-rouge">ScheduledJobBase</code> (together with <code class="language-plaintext highlighter-rouge">IScheduledJob</code>) - base class or implementation which is recommended to use if you are implementing scheduled jobs;</li>
  <li><code class="language-plaintext highlighter-rouge">SchedulerOptions</code> - some of the options you can customize to adjust behavior of the scheduling infrastructure;</li>
</ul>

<p>Some internal key key role players:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">IScheduledJobFactory</code> - this guy can create new instances of the jobs;</li>
  <li><code class="language-plaintext highlighter-rouge">IScheduledJobLocator</code> - this guy can locate jobs in your type collection;</li>
  <li><code class="language-plaintext highlighter-rouge">IScheduledJobScanner</code> - this guy can scan and find job definitions in your assemblies;</li>
</ul>

<h2 id="big-picture">Big Picture</h2>

<p>You have find big picture of some of the most important parts of the scheduled jobs infrastructure.</p>

<p><img src="/assets/img/2020/12/scheduled-jobs.png" alt="scheduled-jobs" /></p>

<p>We are going to walkthrough each of them in sections below.</p>

<h2 id="scanning--registration">Scanning &amp; Registration</h2>

<p>Now when we have defined our job and compile the solution, next time when we will run it “scanning and registration” phase will kick in which is responsible for making sure that all scheduled jobs are discovered and registered.</p>

<p>Everything starts from ordinary initializable module (<code class="language-plaintext highlighter-rouge">EPiServer.Scheduler.Internal.SchedulerInitialization</code>). Process starts with just a few service registrations in DI container. Then during initialization phase init module locates implementation of <code class="language-plaintext highlighter-rouge">IScheduledJobScanner</code> and kicks it off to thread pool (<code class="language-plaintext highlighter-rouge">Task.Run</code>) to get scanning process out of the way. This is interesting approach. It basically queues scanning of the jobs to the thread pool thread and then just continues.</p>

<p>Approach looks something like along these lines:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">InitializableModule</span><span class="p">(</span><span class="n">UninitializeOnShutdown</span> <span class="p">=</span> <span class="k">true</span><span class="p">)]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span> <span class="p">(</span><span class="n">CmsRuntimeInitialization</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">SchedulerInitialization</span> <span class="p">:</span> <span class="n">IConfigurableModule</span><span class="p">,</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_scanner</span> <span class="p">=</span> <span class="n">Task</span><span class="p">.</span><span class="n">Run</span><span class="p">&lt;</span><span class="n">IScheduledJobScanner</span><span class="p">&gt;(()</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
          <span class="kt">var</span> <span class="n">instance</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">Locate</span><span class="p">.</span><span class="n">Advanced</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">IScheduledJobScanner</span><span class="p">&gt;();</span>
          <span class="n">instance</span><span class="p">.</span><span class="nf">Scan</span><span class="p">();</span>

          <span class="k">return</span> <span class="n">instance</span><span class="p">;</span>
        <span class="p">});</span>

        <span class="n">context</span><span class="p">.</span><span class="n">InitComplete</span> <span class="p">+=</span> <span class="k">new</span> <span class="nf">EventHandler</span><span class="p">(</span><span class="n">OnInitComplete</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="k">void</span> <span class="nf">OnInitComplete</span><span class="p">(</span><span class="kt">object</span> <span class="n">sender</span><span class="p">,</span> <span class="n">EventArgs</span> <span class="n">e</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">scanner</span> <span class="p">=</span> <span class="n">_scanner</span><span class="p">.</span><span class="n">Result</span><span class="p">;</span>

        <span class="p">...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">IScheduledJobScanner</code> is asking <code class="language-plaintext highlighter-rouge">IScheduledJobLocator</code> to find all  types with <code class="language-plaintext highlighter-rouge">ScheduledPlugInAttribute</code> attribute. Remember this attribute is present in sample job at introduction section? Attribute is playing important role here - it identifies types and helps Episerver find all jobs defined in code.</p>

<p>Following properties can be set for the job via this attribute (most of the properties are inherited from <code class="language-plaintext highlighter-rouge">PlugInAttribute</code> but these are specifically for scheduled jobs):</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">GUID</code> - unique identifier for your job. It’s not mandatory to have a GUID set for your job, but it is <strong>recommended</strong>. This will help Episerver to understand what to do when you are renaming your job types or just moving to the different namespace.</li>
  <li><code class="language-plaintext highlighter-rouge">IntervalType</code> - you can specify type of internal at which  job should be executed (e.g. “minutes”).</li>
  <li><code class="language-plaintext highlighter-rouge">IntervalLength</code> - specify “step” of the interval (e.g. “5”).</li>
  <li><code class="language-plaintext highlighter-rouge">InitialTime</code> - when job should be started for the 1st time.</li>
  <li><code class="language-plaintext highlighter-rouge">Restartable</code> - is job restartable? This will affect what you can do and how job will behave when restart happens.</li>
  <li><code class="language-plaintext highlighter-rouge">HelpFile</code> - if someone is interested in some manual or documentation, you can use this property to specify link for help page.</li>
</ul>

<p>When list of discovered jobs is returned it also tries to detect any duplicates by the same GUID. If so, an exception will be thrown.</p>

<p>When scanning is done, job definitions are sync with database.
And now the scheduler service can kick in and launch scheduling process.</p>

<h3 id="scheduler-configuration">Scheduler Configuration</h3>

<p>Before scheduler takes over there is a check of whether scheduled jobs should be run on this machine. Yes, sometimes (especially in farm cluster scenario) you would like to disable scheduler on some designated machines. Ok, usually it’s exactly vice versa - you would like to enable scheduler only on specific machine.</p>

<p>To control this, head over to <code class="language-plaintext highlighter-rouge">web.config</code> and look for <code class="language-plaintext highlighter-rouge">&lt;episerver&gt;</code> section.</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;episerver&gt;</span>
    <span class="nt">&lt;applicationSettings</span> <span class="err">"enableScheduler"="true"</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;/episerver&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You can also configure some additional properties (container class <code class="language-plaintext highlighter-rouge">SchedulerOptions</code>) for the scheduler configuration (we will get back to these later):</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">PingTime</code> - ping period for the scheduler (default 30 secs).</li>
  <li><code class="language-plaintext highlighter-rouge">MaximumExecutionAttempts</code> - how many attempts Episerver should try to execute the job if it’s been interrupted. (default 10).</li>
  <li><code class="language-plaintext highlighter-rouge">ContentCacheSlidingExpiration</code> - for how long content loaded in scheduled job context is going to live in the cache (default 60 seconds).</li>
</ul>

<p>The best way how to configure these options is to use <code class="language-plaintext highlighter-rouge">services.Configure&lt;T&gt;()</code>:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ConfigureSchedulerInitialization</span> <span class="p">:</span> <span class="n">IConfigurableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureContainer</span><span class="p">(</span><span class="n">ServiceConfigurationContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">context</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="n">Configure</span><span class="p">&lt;</span><span class="n">SchedulerOptions</span><span class="p">&gt;(</span><span class="n">o</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="c1">// provided here just as example</span>
            <span class="c1">// adjust values to your needs</span>
            <span class="n">o</span><span class="p">.</span><span class="n">PingTime</span> <span class="p">=</span> <span class="n">TimeSpan</span><span class="p">.</span><span class="nf">FromSeconds</span><span class="p">(</span><span class="m">5</span><span class="p">);</span>
        <span class="p">});</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If everything is tip-top, Episerver kicks of The Job Scheduler (<code class="language-plaintext highlighter-rouge">EPiServer.Scheduler.Internal.SchedulerService</code>).</p>

<h2 id="job-execution-pipeline">Job Execution Pipeline</h2>

<p>This job scheduler class is interesting by itself. The problem that it has to solve is basically - stay alive, look for the job which should be executed next and execute it (actually pass control over to another type that we will look at shortly).</p>

<p>What happens when scheduler service is run?</p>

<h3 id="job-scheduler-service">Job Scheduler Service</h3>

<p>It basically creates two wait handles - one for quitting the application (shutdown) and another on the moment of execution of the next job, and awaits in <code class="language-plaintext highlighter-rouge">while</code> loop to whichever hits first. How it knows when next job should be executed? Well, it reads and calculates it before awaiting.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">virtual</span> <span class="k">void</span> <span class="nf">Run</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">waitHandles</span> <span class="p">=</span> <span class="k">new</span> <span class="p">[]</span> <span class="p">{</span> <span class="n">_quit</span><span class="p">,</span> <span class="n">_exec</span> <span class="p">};</span>
    <span class="k">while</span> <span class="p">(!</span><span class="n">cancellationToken</span><span class="p">.</span><span class="n">IsCancellationRequested</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="nf">ReadNextScheduledItem</span><span class="p">();</span>
        <span class="k">switch</span> <span class="p">(</span><span class="n">WaitHandle</span><span class="p">.</span><span class="nf">WaitAny</span><span class="p">(</span><span class="n">waitHandles</span><span class="p">,</span> <span class="n">refreshInterval</span><span class="p">,</span> <span class="k">true</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="k">case</span> <span class="m">0</span><span class="p">:</span>
                <span class="c1">// quit wait handle hit first - exiting the loop</span>
                <span class="k">return</span><span class="p">;</span>
            <span class="k">case</span> <span class="m">1</span><span class="p">:</span>
                <span class="c1">// execution wait handle hit first - executing the job</span>
                <span class="nf">Execute</span><span class="p">();</span>
                <span class="k">continue</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The actual execution wait handle is custom implementation that you can find at <code class="language-plaintext highlighter-rouge">EPiServer.Scheduler.Internal.WaitableTimer</code> and is quite interesting class by itself. It is using <code class="language-plaintext highlighter-rouge">System.Threading.Timer</code> and <code class="language-plaintext highlighter-rouge">System.Threading.AutoResetEvent</code> primitives to simulate wait handle set on the timer (you can wait for event to be raised after some period).</p>

<p>Nowadays cool kidz most probably would just write <code class="language-plaintext highlighter-rouge">await Task.Delay(...)</code> but.. if you are interested in how we did it in old days - this is class to check it out.</p>

<p>So basically job scheduler is responsible to be in tight loop, look for next job to execute at perfect timing and hand over control to <code class="language-plaintext highlighter-rouge">IScheduledJobExecutor</code> to invoke the job.</p>

<p>But before we jump to job executor, let’s see what happens inside <code class="language-plaintext highlighter-rouge">ReadNextScheduledItem()</code> method.</p>

<h3 id="detecting-next-job-to-run">Detecting Next Job to Run</h3>

<p>Now we come to the point where we need to decide which is the next scheduled job we need to execute. It’s done in <code class="language-plaintext highlighter-rouge">ReadNextScheduledItem</code> method.</p>

<p>Following steps are done in this method:</p>

<ul>
  <li>looping through all registered scheduled jobs (list is retrieved from <code class="language-plaintext highlighter-rouge">IScheduledJobRepository</code>)</li>
  <li>if job is enabled &amp; is not registered as failed (we will get back to this in “Job Execution” section)</li>
  <li>if job is required to be executed immediately - it’s selected as next scheduled job</li>
  <li>otherwise - job list is sorted ascending by <code class="language-plaintext highlighter-rouge">NextExecutionUTC</code> property value and first which is not running or missing pings is selected as next scheduled job to be executed.</li>
</ul>

<p>What does it mean that job needs to be executed immediately? Well, there are few checks performed to determine if job needs to be executed immediately:</p>

<ul>
  <li>if job is restartable (<code class="language-plaintext highlighter-rouge">[ScheduledPlugIn(Restartable = true, ...)]</code>)</li>
  <li>AND execution attempts are not exceeding threshold (default 10)</li>
  <li>OR job is missing pings (more in “Pinging Jobs” section)</li>
  <li>AND</li>
  <li>job status is <code class="language-plaintext highlighter-rouge">Running</code></li>
  <li>OR <code class="language-plaintext highlighter-rouge">LastExecutionStatus</code> was set to <code class="language-plaintext highlighter-rouge">Aborted</code> (this is happening when hosting system is gracefully shutting down and notifying about this running jobs at that moment). More about this in “Stopping the Scheduler” section.</li>
</ul>

<p>If job is not required to be executed immediately - then job closest by scheduled execution time is picked (winning job).</p>

<p>Winning job next scheduled execution date and time is set to our old friend <code class="language-plaintext highlighter-rouge">WaitableTimer _exec</code> and we basically return back to the <code class="language-plaintext highlighter-rouge">while</code> loop:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">virtual</span> <span class="k">void</span> <span class="nf">Run</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">waitHandles</span> <span class="p">=</span> <span class="k">new</span> <span class="p">[]</span> <span class="p">{</span> <span class="n">_quit</span><span class="p">,</span> <span class="n">_exec</span> <span class="p">};</span>
    <span class="k">while</span> <span class="p">(!</span><span class="n">cancellationToken</span><span class="p">.</span><span class="n">IsCancellationRequested</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="nf">ReadNextScheduledItem</span><span class="p">();</span>
        <span class="k">switch</span> <span class="p">(</span><span class="n">WaitHandle</span><span class="p">.</span><span class="nf">WaitAny</span><span class="p">(</span><span class="n">waitHandles</span><span class="p">,</span> <span class="n">refreshInterval</span><span class="p">,</span> <span class="k">true</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="p">...</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This means that if date and time is set for <code class="language-plaintext highlighter-rouge">_exec</code> awaitable - <code class="language-plaintext highlighter-rouge">switch</code> statement will be “resumed” once any of those 2 will reset event (remember <code class="language-plaintext highlighter-rouge">AutoResetEvent</code> class used there?).</p>

<p>If <code class="language-plaintext highlighter-rouge">_exec</code> wait handle won - job is carried out for the execution. Here we then switch over to <code class="language-plaintext highlighter-rouge">IScheduledJobExecutor</code> interface and specifically to  <code class="language-plaintext highlighter-rouge">DefaultScheduledJobExecutor</code> implementation.</p>

<p><strong>NB!</strong> But before we switch to the execution - there is one note worth knowing. There could be situations when job scheduler misses scheduled time for the job - and therefore is missing also to pass it over to the executor. This situation is also handled in <code class="language-plaintext highlighter-rouge">ReadNextScheduledItem</code> method. However, if scheduler missed job execution, it will pick it up only after 1 minute. Because of this code in <code class="language-plaintext highlighter-rouge">ReadNextScheduledItem</code> method:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">if</span> <span class="p">(</span><span class="n">CurrentScheduledItem</span><span class="p">.</span><span class="n">NextExec</span><span class="p">.</span><span class="nf">AddMinutes</span><span class="p">(</span><span class="m">1.0</span><span class="p">)</span> <span class="p">&lt;</span> <span class="n">DateTime</span><span class="p">.</span><span class="n">UtcNow</span><span class="p">)</span>
<span class="p">{</span>
    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="starting-job-execution">Starting Job Execution</h3>

<p>When scheduler has picked up the job for the execution - control is passed over to implementation if <code class="language-plaintext highlighter-rouge">IScheduledJobExecutor</code> and specifically by default to <code class="language-plaintext highlighter-rouge">EPiServer.Scheduler.Internal.DefaultScheduledJobExecutor</code> to the <code class="language-plaintext highlighter-rouge">StartAsync</code> method.</p>

<p><code class="language-plaintext highlighter-rouge">SchedulerService</code> creates new instance of <code class="language-plaintext highlighter-rouge">JobExecutionOptions</code> class, sets couple of properties and passes it as parameter to <code class="language-plaintext highlighter-rouge">StartAsync</code> method. <code class="language-plaintext highlighter-rouge">JobExecutionOptions</code> class contains one important property - <code class="language-plaintext highlighter-rouge">RunSynchronously</code> which is not set by the scheduler - and thus resulting with value <code class="language-plaintext highlighter-rouge">false</code>. This will be important to remember when we will look at how jobs are executed manually.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="n">_executor</span><span class="p">.</span><span class="nf">StartAsync</span><span class="p">(</span>
    <span class="n">job</span><span class="p">,</span>
    <span class="k">new</span> <span class="nf">JobExecutionOptions</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">Trigger</span> <span class="p">=</span> <span class="n">CurrentScheduledItem</span><span class="p">.</span><span class="n">Trigger</span><span class="p">,</span>
        <span class="p">...</span>
    <span class="p">});</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Before <em>actual</em> execution of the job executor does few checks:</p>

<ul>
  <li>checks what is the type of the trigger for the execution</li>
  <li>if it’s <code class="language-plaintext highlighter-rouge">Scheduler</code> OR <code class="language-plaintext highlighter-rouge">Restart</code> - then it’s ordinary controlled scheduled execution of the job. in this case - if job status update in database succeeds - then job is executed. if not - job gets new status <code class="language-plaintext highlighter-rouge">UnableToStart</code>.</li>
  <li>otherwise - it checks for passed-in (from <code class="language-plaintext highlighter-rouge">SchedulerService</code>) execution date time and if it’s not <code class="language-plaintext highlighter-rouge">DateTime.MinValue</code> but is in the past - job status is updated in the database and job is immediately executed.</li>
</ul>

<p>Now we got to the point where all the prerequisites are satisfied, everything is  tip-top and we are now at <code class="language-plaintext highlighter-rouge">InternalStartAsync</code> method.</p>

<p>Executor keeps track of currently running jobs in <code class="language-plaintext highlighter-rouge">ConcurrentDictionary</code>. So this is a mechanism behind to avoid double executions for the same job.</p>

<p>Following is the code inside final execution method:</p>

<ul>
  <li>check if currently scheduled job is not already executing - by checking the content of the <code class="language-plaintext highlighter-rouge">ConcurrentDictionary</code> of running jobs. If job is running - abort.</li>
  <li>create class instance of the job type. Here Episerver is using <code class="language-plaintext highlighter-rouge">IScheduledJobFactory</code> implementation.</li>
</ul>

<h3 id="job-factory">Job Factory</h3>

<p>Scheduled jobs during scanning and registration phase are written down to database by capturing some of the type information. Like:</p>

<ul>
  <li>Assembly name</li>
  <li>Type fully qualified name (FQN)</li>
  <li>Target method to invoke</li>
</ul>

<p>Factory <code class="language-plaintext highlighter-rouge">IScheduledJobFactory</code> default implementation <code class="language-plaintext highlighter-rouge">DefaultScheduledJobFactory</code> will try to create new instance of your job type firstly via DI container. If that will fail - then will look for parameterless constructor.</p>

<p>Few things can go wrong here while creating new job instance:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">FileNotFoundException</code> - specified file does not exist anymore</li>
  <li><code class="language-plaintext highlighter-rouge">TypeLoadException</code> - specified job type could be not be found</li>
  <li>StructureMap specific exceptions on why class creation failed</li>
</ul>

<p>By default Episerver wants you to inherit from <code class="language-plaintext highlighter-rouge">ScheduledJobBase</code> class (which is fine, because you get some things out of the box - like status updates).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ScheduledPlugIn</span><span class="p">(</span><span class="n">DisplayName</span> <span class="p">=</span> <span class="s">"ScheduledJob2"</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ScheduledJob2</span> <span class="p">:</span> <span class="n">ScheduledJobBase</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">override</span> <span class="kt">string</span> <span class="nf">Execute</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="p">...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>But at the same time, Episerver also respects your design and allows to have static method.
Interesting is approach with static method. Of course, even if you ignore all goodies provided by Episerver infrastructure and not using <code class="language-plaintext highlighter-rouge">ScheduledJobBase</code> class as your master parent, Episerver needs to “represent” your <code class="language-plaintext highlighter-rouge">static</code> method somehow. This is done via <code class="language-plaintext highlighter-rouge">MethodProxyJob</code> class.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">jobInstance</span> <span class="p">=</span> <span class="n">serviceLocator</span><span class="p">.</span><span class="nf">GetInstance</span><span class="p">(</span><span class="n">typeOfJob</span><span class="p">);</span>

<span class="k">if</span> <span class="p">(</span><span class="n">jobInstance</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="k">new</span> <span class="nf">MethodProxyJob</span><span class="p">(</span><span class="n">job</span><span class="p">.</span><span class="n">ID</span><span class="p">,</span> <span class="n">type</span><span class="p">,</span> <span class="n">method</span><span class="p">,</span> <span class="n">job</span><span class="p">.</span><span class="n">InstanceData</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Instance data of the scheduled job class is binary serialized - in order to deserialize it later when <code class="language-plaintext highlighter-rouge">MethodProxyJob</code> will need instance to execute method on.</p>

<p>If factory will not find any of these definitions - it will just blow up then.
When factory is blowing up due to failure of the creation of the job type - it will mark job as failed via <code class="language-plaintext highlighter-rouge">FailedScheduledJobRegistry</code>. Marking jobs as failed is only in-memory storage. Meaning that on the next restart of the site - Episerver will start over and will try hard to get your job executed again.</p>

<h3 id="executing-job">Executing Job</h3>

<p>Once we have figured out which job to run, have created instance of it, now we are at the point of invoking actual <code class="language-plaintext highlighter-rouge">Execute</code> method finally.</p>

<p>Bu default this is scheduled on thread pool thread:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">DefaultScheduledJobExecutor</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">InternalStartAsync</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="p">...</span>
        <span class="n">Task</span><span class="p">.</span><span class="nf">Run</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="nf">Execute</span><span class="p">(...));</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>First things first, when job starts running - it’s important to shout this out loud to everyone:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="n">_dataAccess</span><span class="p">.</span><span class="nf">UpdateRunningState</span><span class="p">(</span><span class="n">job</span><span class="p">.</span><span class="n">ID</span><span class="p">,</span> <span class="k">true</span><span class="p">,</span> <span class="k">false</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then we open stopwatch and basically let it run:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">sw</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">Stopwatch</span><span class="p">();</span>
<span class="n">sw</span><span class="p">.</span><span class="nf">Start</span><span class="p">();</span>

<span class="n">job</span><span class="p">.</span><span class="nf">Execute</span><span class="p">();</span>

<span class="n">sw</span><span class="p">.</span><span class="nf">Stop</span><span class="p">();</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>After job is executed - then as last thing is to report status of this execution.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">await</span> <span class="nf">LogExecutionAsync</span><span class="p">(</span><span class="n">job</span><span class="p">.</span><span class="n">ID</span><span class="p">,</span> <span class="p">...,</span> <span class="n">status</span><span class="p">,</span> <span class="p">...).</span><span class="nf">ConfigureASwait</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="pinging-job">Pinging Job</h3>

<p>It’s important to control also what’s going on with running scheduled job instance. This is done via additional Timer:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="n">isAliveTimer</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">Timer</span><span class="p">(</span><span class="n">PingDatabaseWithRunningStateCallback</span><span class="p">,</span>
                         <span class="n">job</span><span class="p">.</span><span class="n">ID</span><span class="p">,</span>
                         <span class="n">_schedulerOptions</span><span class="p">.</span><span class="nf">GetPingTime</span><span class="p">(</span><span class="n">job</span><span class="p">),</span>
                         <span class="n">_schedulerOptions</span><span class="p">.</span><span class="nf">GetPingTime</span><span class="p">(</span><span class="n">job</span><span class="p">));</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Pinging basically means that time to time (<code class="language-plaintext highlighter-rouge">_schedulerOptions.GetPingTime</code>) executor updates running state of the job. By default this happens every 30 seconds. And seems like it’s not able to change it right now.</p>

<p>Why it’s important to ping running jobs? Last ping time will be used to determine whether job should be executed immediately after system restart.</p>

<p>It’s assumed that job has crashed after pings are missed for 4 times. So if last ping is 2 minutes or older - Episerver assumes that job has crashed. Missing pings is just one of the parameters to determine if job should be executed immediately.</p>

<h3 id="job-status-updates">Job Status Updates</h3>

<p>Job status update is designed to inform about progress of the job, how far (or deep) it got - basically what’s going on. So that interested personnel is informed about progress and can make appropriate decisions.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">DefaultScheduledJobExecutor</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">void</span> <span class="nf">Execute</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">jobBase</span> <span class="p">=</span> <span class="n">instance</span> <span class="k">as</span> <span class="n">ScheduledJobBase</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">jobBase</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">jobBase</span><span class="p">.</span><span class="n">StatusChanged</span> <span class="p">+=</span> <span class="n">JobInstance_StatusChanged</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="n">instance</span><span class="p">.</span><span class="nf">Execute</span><span class="p">();</span>

        <span class="k">if</span> <span class="p">(</span><span class="n">jobBase</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">jobBase</span><span class="p">.</span><span class="n">StatusChanged</span> <span class="p">-=</span> <span class="n">JobInstance_StatusChanged</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Implementation of the status update is done again via <code class="language-plaintext highlighter-rouge">ScheduledDB</code> (<code class="language-plaintext highlighter-rouge">_dataAccess</code>).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>this._dataAccess.UpdateCurrentStatusMessage(scheduledJobBase.ScheduledJobId, e.Message);
</pre></td></tr></tbody></table></code></pre></div></div>

<p>which at the end - updates <code class="language-plaintext highlighter-rouge">tblScheduledItem</code> table <code class="language-plaintext highlighter-rouge">CurrentStatusMessage</code> column for a given job record.</p>

<p><img src="/assets/img/2020/12/scheduled-jobs-status-update.png" alt="scheduled-jobs-status-update" /></p>

<p>Current status message is displayed in administration user interface for appropriate scheduled job.</p>

<h3 id="manual-execution">Manual Execution</h3>

<p>Sometimes you need to execute scheduled job out of any schedule - just right now, right here.</p>

<p>For this purpose you are able to use manual execution feature. You can either kick-off job programmatically or from the user interface.</p>

<p><img src="/assets/img/2020/12/scheduled-jobs-manual-exec.png" alt="scheduled-jobs-manual-exec" /></p>

<p>Under the hood you will have to use our old friend - <code class="language-plaintext highlighter-rouge">IScheduledJobExecutor</code>. This is code that’s being executed from Episerver CMS user interface:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="n">Executor</span><span class="p">.</span><span class="n">Service</span><span class="p">.</span><span class="nf">StartAsync</span><span class="p">(</span><span class="n">_job</span><span class="p">,</span> <span class="k">new</span> <span class="n">JobExecutionOptions</span>
<span class="p">{</span>
    <span class="n">Trigger</span> <span class="p">=</span> <span class="n">ScheduledJobTrigger</span><span class="p">.</span><span class="n">User</span>
<span class="p">});</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>There is also another “legacy” way to execute scheduled job:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">MyStuff</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="n">IScheduledJobRepository</span> <span class="n">_repo</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">MyStuff</span><span class="p">(</span><span class="n">IScheduledJobRepository</span> <span class="n">repo</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_repo</span> <span class="p">=</span> <span class="n">repo</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">DoMagic</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">job</span> <span class="p">=</span> <span class="n">_repo</span><span class="p">.</span><span class="nf">Get</span><span class="p">(...);</span>
        <span class="n">job</span><span class="p">.</span><span class="nf">ExecuteManually</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This approach is not recommended - it just doesn’t feel right to call <code class="language-plaintext highlighter-rouge">Execute</code> method right on job type :) It’s even decorated with <code class="language-plaintext highlighter-rouge">[Obsolete]</code> attribute to stress this.</p>

<p>Anyways, let’s look inside <code class="language-plaintext highlighter-rouge">ExecuteManually</code> method:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">ExecuteManually</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">Executor</span><span class="p">.</span><span class="nf">StartAsync</span><span class="p">(</span>
        <span class="k">this</span><span class="p">,</span>
        <span class="k">new</span> <span class="n">JobExecutionOptions</span>
        <span class="p">{</span>
            <span class="n">Trigger</span> <span class="p">=</span> <span class="n">ScheduledJobTrigger</span><span class="p">.</span><span class="n">User</span><span class="p">,</span>
            <span class="n">RunSynchronously</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
            <span class="n">PreserveAsyncCompatibility</span> <span class="p">=</span> <span class="k">true</span>
        <span class="p">}</span>
    <span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Look closer at <code class="language-plaintext highlighter-rouge">RunSynchronously</code> and <code class="language-plaintext highlighter-rouge">PreserveAsyncCompatibility</code> values. Even if Episerver sets <code class="language-plaintext highlighter-rouge">RunSynchronously</code> which should mean to execute job synchronously, it also enables async compatibility.</p>

<p>What does this all mean?</p>

<p>To answer - we have to return back to scheduled job executor.
Before deciding how to run the job, we have this code fragment:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">if</span> <span class="p">(</span><span class="nf">ShouldRunAsynchronously</span><span class="p">(</span><span class="n">instance</span><span class="p">,</span> <span class="n">options</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">task</span> <span class="p">=</span> <span class="n">Task</span><span class="p">.</span><span class="nf">Run</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="nf">Execute</span><span class="p">(....));</span>
    <span class="k">return</span> <span class="n">task</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">else</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">task</span> <span class="p">=</span> <span class="nf">Execute</span><span class="p">(...);</span>
    <span class="k">return</span> <span class="n">Task</span><span class="p">.</span><span class="nf">FromResult</span><span class="p">(</span><span class="n">task</span><span class="p">.</span><span class="nf">GetAwaiter</span><span class="p">().</span><span class="nf">GetResult</span><span class="p">());</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>NOTE!</strong> The only reason (at least for now) why <code class="language-plaintext highlighter-rouge">Execute</code> is async - just to be able to await on log entries to be saved in database (<code class="language-plaintext highlighter-rouge">await LogExecutionAsync(...)</code>).</p>

<p>Now we have to tear apart <code class="language-plaintext highlighter-rouge">ShouldRunAsynchronously</code> method:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">static</span> <span class="kt">bool</span> <span class="nf">ShouldRunAsynchronously</span><span class="p">(</span><span class="n">IScheduledJob</span> <span class="n">instance</span><span class="p">,</span> <span class="n">JobExecutionOptions</span> <span class="n">options</span><span class="p">)</span>
<span class="p">{</span>
  <span class="k">if</span> <span class="p">(!</span><span class="n">options</span><span class="p">.</span><span class="n">RunSynchronously</span><span class="p">)</span> <span class="k">return</span> <span class="k">true</span><span class="p">;</span>

  <span class="k">return</span> <span class="n">options</span><span class="p">.</span><span class="n">PreserveAsyncCompatibility</span> <span class="p">&amp;&amp;</span> <span class="n">instance</span> <span class="k">is</span> <span class="n">ScheduledJobBase</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Here few things happen:</p>

<ul>
  <li>If anyone set <code class="language-plaintext highlighter-rouge">RunSynchronously</code> to <code class="language-plaintext highlighter-rouge">false</code> -&gt; job is executed asynchronously.</li>
  <li>If anyone set <code class="language-plaintext highlighter-rouge">PreserveAsyncCompatibility</code> to <code class="language-plaintext highlighter-rouge">true</code> AND job is a subtype of <code class="language-plaintext highlighter-rouge">ScheduledJobBase</code> -&gt; job is executed asynchronously.</li>
</ul>

<p>Here you can see - “normal” scheduled job is executed manually - and still gets queued on thread pool thread:</p>

<p><img src="/assets/img/2020/12/scheduled-jobs-manual-exec-2.png" alt="scheduled-jobs-manual-exec-2" /></p>

<p>On the other hand - we can experiment a bit.
If we manually execute “static” job which does not inherit from <code class="language-plaintext highlighter-rouge">ScheduledJobBase</code> parent - we will get the same thread from which manual execution was triggered.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ScheduledPlugIn</span><span class="p">(</span>
    <span class="n">DisplayName</span> <span class="p">=</span> <span class="s">"ScheduledJob3"</span><span class="p">,</span>
    <span class="n">GUID</span> <span class="p">=</span> <span class="s">"016DB745-F2F1-41C0-A078-778D08F1B3CA"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ScheduledJob3</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">Execute</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="p">...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Here you can see that the same thread (I called it from ASP.NET MVC controller action) is used to execute our scheduled job:</p>

<p><img src="/assets/img/2020/12/scheduled-jobs-manual-exec-3.png" alt="scheduled-jobs-manual-exec-3" /></p>

<p><strong>NB!</strong> So you have to be careful how your jobs are defined and how they are executed - it will depend what features you will get access to (<code class="language-plaintext highlighter-rouge">HttpContext</code> is one of the first type to step on).</p>

<h2 id="stopping-and-restarting-error-handling">Stopping and Restarting, Error Handling</h2>

<h3 id="stopping-the-job">Stopping the Job</h3>

<p>It just feels much better to stop the job and not to <code class="language-plaintext highlighter-rouge">kill</code> it. There are situations when you are sick and tired of waiting and just want to move on. Then you will have to look for an opportunity to stop the job.</p>

<p>Again you can do it from Episerver CMS user interface or programmatically:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">this</span><span class="p">.</span><span class="n">Executor</span><span class="p">.</span><span class="n">Service</span><span class="p">.</span><span class="nf">Cancel</span><span class="p">(</span><span class="n">_job</span><span class="p">.</span><span class="n">ID</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Before actually stopping the job, cancel event is raised via <code class="language-plaintext highlighter-rouge">IEventRegistry</code> (<code class="language-plaintext highlighter-rouge">ID:184468e9-9f0d-4460-aecd-3c08f652c73c</code>). This allows to “capture” stopping of the job on other Episerver instances if interested.</p>

<p>If job by given ID is still running AND again is child class of <code class="language-plaintext highlighter-rouge">ScheduledJobBase</code> AND is <code class="language-plaintext highlighter-rouge">IsStoppable = true</code> then <code class="language-plaintext highlighter-rouge">Stop()</code> method is called on the instance of the job.</p>

<p>What happens when you are “bad citizen”? For example if you tell Episerver that job is stoppable but actually do not respect this?</p>

<p>Here via <code class="language-plaintext highlighter-rouge">Stop</code> method class level field is set to <code class="language-plaintext highlighter-rouge">true</code> -&gt; so this means that you should respect it and check regularly (if your job is quite heavy and intensive).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ScheduledPlugIn</span><span class="p">(</span><span class="n">GUID</span> <span class="p">=</span> <span class="s">"..."</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ScheduledJob1</span> <span class="p">:</span> <span class="n">ScheduledJobBase</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="kt">bool</span> <span class="n">_stopSignaled</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">ScheduledJob1</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">IsStoppable</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Stop</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">_stopSignaled</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">override</span> <span class="kt">string</span> <span class="nf">Execute</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">_stopSignaled</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">return</span> <span class="s">"Stop of the job was called"</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="k">return</span> <span class="s">"Great success!"</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If you don’t respect stop signal and keep running - probably no one will call you again. Basically there are no rules around this - how job should be killed forcibly.</p>

<h3 id="stopping-the-scheduler">Stopping the Scheduler</h3>

<p>What happens when the whole system does shutdown? Remember that whole scheduled job infrastructure is initialized in <code class="language-plaintext highlighter-rouge">IInitializableModule</code>. This means that Episerver is also calling <code class="language-plaintext highlighter-rouge">Uninitialize</code> method for graceful shutdowns (not guaranteed but happens sometimes).</p>

<p>So scheduler service is able to stop all currently running jobs also.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">ServiceLocator</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">ISchedulerService</span><span class="p">&gt;().</span><span class="nf">Stop</span><span class="p">();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Inside <code class="language-plaintext highlighter-rouge">SchedulerService</code> when service is stopping <code class="language-plaintext highlighter-rouge">_quit</code> event is set <code class="language-plaintext highlighter-rouge">AutoResetEvent</code> - meaning that circuit breaker is set for scheduling loop.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre>var waitHandles = new { _quit, _exec.Event };
while (...)
{
    switch (WaitHandle.WaitAny(waitHandles, refreshInterval, true))
    {
        ...
    }
}
</pre></td></tr></tbody></table></code></pre></div></div>

<p>After scheduler loop is broken, Episerver gives <strong>20 seconds</strong> for everyone to pack their parachutes and jump!</p>

<p>If there were any currently running jobs -&gt; those got killed and status is set to <code class="language-plaintext highlighter-rouge">ScheduledJobExecutionStatus.Aborted</code>. Status is saved in database.</p>

<h3 id="restart">Restart</h3>

<p>When system has been interrupted and at that moment running jobs got aborted, this is taken into account next time scheduler service starts.</p>

<p>When reading which job to execute there is a check should job be executed immediately. More info about what other checks are performed there in “Detecting Next Job to Run” section.</p>

<h2 id="what-to-improve-suggestions-for-episerver">What to Improve? Suggestions for Episerver</h2>

<h3 id="provide-access-to-trigger-type">Provide Access to Trigger Type</h3>

<p>When my scheduled jobs runs I would like to access in what manner job has been executed.</p>

<p>Either through base class:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ScheduledPlugIn</span><span class="p">(</span><span class="n">GUID</span> <span class="p">=</span> <span class="s">"..."</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ScheduledJob1</span> <span class="p">:</span> <span class="n">ScheduledJobBase</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">override</span> <span class="kt">string</span> <span class="nf">Execute</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">Trigger</span> <span class="p">==</span> <span class="n">ScheduledJobTrigger</span><span class="p">.</span><span class="n">User</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="c1">// does some manual execution specific magic</span>
            <span class="p">...</span>
        <span class="p">}</span>

         <span class="k">return</span> <span class="s">"Great success!"</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Or maybe even via <code class="language-plaintext highlighter-rouge">Execute()</code> method:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ScheduledPlugIn</span><span class="p">(</span><span class="n">GUID</span> <span class="p">=</span> <span class="s">"..."</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ScheduledJob1</span> <span class="p">:</span> <span class="n">ScheduledJobBase</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">override</span> <span class="kt">string</span> <span class="nf">Execute</span><span class="p">(</span><span class="n">ScheduledJobTrigger</span> <span class="n">trigger</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">trigger</span> <span class="p">==</span> <span class="n">ScheduledJobTrigger</span><span class="p">.</span><span class="n">User</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="c1">// does some manual execution specific magic</span>
            <span class="p">...</span>
        <span class="p">}</span>

         <span class="k">return</span> <span class="s">"Great success!"</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="allow-custom-schedule-calculator">Allow Custom Schedule Calculator</h3>

<p>Despite that <code class="language-plaintext highlighter-rouge">SchedulerService</code> is registered by default in DI container as singleton, it has some <code class="language-plaintext highlighter-rouge">virtual</code> methods meaning that I would be able to override something if I would need to.</p>

<p>But browsing through scheduler service and job executor - it was clear that there is no concrete separation of scheduler, executor and schedule calculator - which would allow me to plug in my own <code class="language-plaintext highlighter-rouge">IScheduledJobExecutionTimeCalculator</code> (does not exist) implementation - allowing me to come up with my own calendar when job needs to be executed.</p>

<p>Some of the parts are done in <code class="language-plaintext highlighter-rouge">SchedulerService</code> (like deciding which is next job and when it needs to execute) and some parts are done in <code class="language-plaintext highlighter-rouge">IScheduledJobExecutor</code> which is responsible for deciding when is next time job should be running after execute.</p>

<h3 id="access-to-last-successful-execution">Access to Last Successful Execution</h3>

<p>There are cases when you need to understand when job has executed successfully last time (for example if you have some differential sync jobs - deltas are sync from specific checkpoints). Of course nowadays we do have our own implementations of checkpoint saves (just like F5 in video games) but it would be nice if this would be available for the job instance.</p>

<p>For example:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ScheduledPlugIn</span><span class="p">(</span><span class="n">GUID</span> <span class="p">=</span> <span class="s">"..."</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ScheduledJob1</span> <span class="p">:</span> <span class="n">ScheduledJobBase</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">override</span> <span class="kt">string</span> <span class="nf">Execute</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">LastSuccessfulTimeUtc</span> <span class="p">&lt;</span> <span class="n">_timeProvider</span><span class="p">.</span><span class="n">UtcNow</span><span class="p">.</span><span class="nf">AddDays</span><span class="p">(-</span><span class="m">5</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="c1">// does some magic if job hasn't been ran for more than 5 days</span>
            <span class="p">...</span>
        <span class="p">}</span>

         <span class="k">return</span> <span class="s">"Great success!"</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="allow-async-execution">Allow Async Execution</h3>

<p>This is big question for jobs especially for those that do synchronizations, remote RPC calls (aka Web API) or any other async operations.</p>

<p>I would like to see this possible:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ScheduledPlugIn</span><span class="p">(</span><span class="n">GUID</span> <span class="p">=</span> <span class="s">"..."</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ScheduledJob1</span> <span class="p">:</span> <span class="n">ScheduledJobBase</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">override</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;</span> <span class="nf">ExecuteAsync</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="k">await</span> <span class="n">_apiClient</span><span class="p">.</span><span class="nf">CallAsync</span><span class="p">();</span>

        <span class="k">return</span> <span class="s">"Great success!"</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="parametrized-execution">Parametrized Execution</h3>

<p>Scheduled job reminds me just a controlled method execution. Sometimes it’s some references to checkpoints, sometimes it points you to the correct configuration, sometimes it gives you precise target object to work on.</p>

<p>Would be awesome if you could pass some arguments to that method.</p>

<p>Like along these lines:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">ParameterClass</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="n">DateTime</span> <span class="n">LastSyncCheckpoint</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>

<span class="p">[</span><span class="nf">ScheduledPlugIn</span><span class="p">(</span><span class="n">GUID</span> <span class="p">=</span> <span class="s">"..."</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ScheduledJob1</span> <span class="p">:</span> <span class="n">ScheduledJobBase</span><span class="p">&lt;</span><span class="n">ParameterClass</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">override</span> <span class="kt">string</span> <span class="nf">Execute</span><span class="p">(</span><span class="n">ParameterClass</span> <span class="n">parameters</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">parameters</span><span class="p">.</span><span class="n">LastSyncCheckpoint</span> <span class="p">&lt;</span> <span class="n">TimeProvider</span><span class="p">.</span><span class="n">UtcNow</span><span class="p">.</span><span class="nf">AddDays</span><span class="p">(-</span><span class="m">5</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="c1">// do some magic</span>
        <span class="p">}</span>

        <span class="k">return</span> <span class="s">"Great success!"</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Would be great if job could mutate these arguments and would get back updated values on next execution cycle.</p>

<p>Some of the attempts to make this possible was done here at <a href="https://github.com/Geta/Geta.ScheduledParameterJob">Geta.ScheduledParameterJob</a> module.</p>

<h3 id="provide-interactive-overview">Provide Interactive Overview</h3>

<p>As site admin - I would like to see all scheduled jobs in single place, single table, with automatic updates of currently executing jobs and failed jobs, enable, disable, execute and stop all at the same table.</p>

<p>Someone also tried to fix this challenge <a href="https://github.com/valdisiljuconoks/TechFellow.ScheduledJobOverview">here</a>.</p>

<p>Things might change in next major version wave (aka Episerver on .NET Core).</p>

<h2 id="summary">Summary</h2>

<p>Scheduled job is not a beast in your site, it is designed to run in background and silently make sure that your jobs are following schedule, are executing and properly shutdown if needed.
You can let Episerver to handle everything, you can also change settings, execute and kill jobs yourself.
You can also override some of the system implementations if you are brave enough :)</p>

<p>Hope this gives you some more insights of what’s going on when Episerver is asked to execute your job on given schedule.</p>

<p>Super big thanks to <a href="https://twitter.com/henriknystrom">Henrik Nyström</a> for fixing all my bugs here :)</p>

<p>Happy scheduling!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="Scheduled Jobs" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><category term="under the hood" /><summary type="html"><![CDATA[Introduction]]></summary></entry><entry><title type="html">Building Real-time Public Transport Tracking System on Azure - Part 5 - Data Broadcast</title><link href="https://tech-fellow.eu/2020/11/01/building-real-time-public-transport-tracking-system-on-azure-part-5/" rel="alternate" type="text/html" title="Building Real-time Public Transport Tracking System on Azure - Part 5 - Data Broadcast" /><published>2020-11-01T13:30:00+02:00</published><updated>2020-11-01T13:30:00+02:00</updated><id>https://tech-fellow.eu/2020/11/01/building-real-time-public-transport-tracking-system-on-azure-part-5</id><content type="html" xml:base="https://tech-fellow.eu/2020/11/01/building-real-time-public-transport-tracking-system-on-azure-part-5/"><![CDATA[<p>This is next post in series about real-time public transport tracking system development based on Azure infrastructure and services. This article is a part of Applied Cloud Stories initiative - <a href="aka.ms/applied-cloud-stories">aka.ms/applied-cloud-stories</a>.</p>

<p>Blog posts in this series:</p>

<ul>
  <li><a href="https://tech-fellow.eu/2019/12/08/building-real-time-public-transport-tracking-system-on-azure-part1/">Part 1 - Scene Background &amp; Solution Architecture</a></li>
  <li><a href="https://tech-fellow.eu/2020/01/21/building-real-time-public-transport-tracking-system-on-azure-part-2-data-collectors-composer/">Part 2 - Data Collectors &amp; Composer</a></li>
  <li><a href="https://tech-fellow.eu/2020/04/08/building-real-time-public-transport-tracking-system-on-azure-part-3/">Part 3 - Event-Based Data Delivery</a></li>
  <li><a href="https://tech-fellow.eu/2020/08/30/building-real-time-public-transport-tracking-system-on-azure-part-4/">Part 4 - Data Processing Pipelines</a></li>
  <li><strong>Part 5 - Data Broadcast using gRPC</strong></li>
  <li><a href="https://tech-fellow.eu/2020/12/14/building-real-time-public-transport-tracking-system-on-azure-part-6-building-frontend/">Part 6 - Building Frontend</a></li>
  <li><a href="https://tech-fellow.eu/2021/01/21/building-real-time-public-transport-tracking-system-on-azure-part-6-packing-everything-up/">Part 7 - Packing Everything Up</a></li>
  <li><a href="https://tech-fellow.eu/2021/01/25/building-linux-docker-images-on-windows-machine/">Part 7.1 - Fixing Docker Image Metrics in Azure</a></li>
</ul>

<h2 id="distribute-data-to-connected-clients">Distribute Data to Connected Clients</h2>

<p>We finished previous post with data processing pipelines and projecting data into profiles in order to reduce unnecessary data processing for every connected client to the application.</p>

<p><img src="/assets/img/2020/11/brtts-p4-4.png" alt="brtts-p4-4" /></p>

<p>Now when we have data profiles in place, let’s talk now on how do get those clients connected. Our application is web based real-time map. In transportation business “real-time” is really important aspect. It affects passengers and their potential decisions made on the data operator provides. Whether it’s delay information for the bus or real-time location updates, all data that helps to make a decision for the passenger or just to stay informed - is valuable.</p>

<p>In order to distribute data to connected clients and provide data stream in near real-time, we have chosen <a href="https://grpc.io/">gRPC</a> technology to accomplish this.</p>

<h2 id="getting-started-with-grpc">Getting Started with gRPC</h2>

<p>I’m not gonna tell you what is gRPC and why it was developed, there are plenty of articles out there that will explain concept in much better way than I could possibly do.</p>

<p>So let’s skip intro and get started with gRPC.
Before we jump onto actual data contract definition by using <code class="language-plaintext highlighter-rouge">.proto</code> files, we need to install supporting tools to do so.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>PM&gt; dotnet add package Grpc.AspNetCore
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This package adds bunch of other packages including important package for the build time - <code class="language-plaintext highlighter-rouge">Grpc.Tools</code>.</p>

<h3 id="creating-the-file">Creating the File</h3>

<p>First thing we need to do is to define the shape of our services. In gRPC world this is done by defining Protobuf file.
Head to <strong>Project &gt; Add New Item…</strong> and search for “proto”.</p>

<p><img src="/assets/img/2020/11/brtts-p5-proto.png" alt="brtts-p5-proto" /></p>

<p>It creates new <code class="language-plaintext highlighter-rouge">.proto</code> file in the solution.
Note that if you inspect file properties, <code class="language-plaintext highlighter-rouge">BuildAction</code> it’s set to <code class="language-plaintext highlighter-rouge">"None"</code>.</p>

<p><img src="/assets/img/2020/11/brtts-p5-proto-actions.png" alt="brtts-p5-proto-actions" /></p>

<p>We have to change it to <code class="language-plaintext highlighter-rouge">"Protobuf compiler"</code>.</p>

<p><img src="/assets/img/2020/11/brtts-p5-proto-actions-2.png" alt="brtts-p5-proto-actions-2" /></p>

<p>Notice that when we changed to <code class="language-plaintext highlighter-rouge">"Protobuf compiler"</code> there are few additional properties shown. Specifically interesting is “gRPC Stub Classes”</p>

<p><img src="/assets/img/2020/11/brtts-p5-proto-actions-3.png" alt="brtts-p5-proto-actions-3" /></p>

<p>Stub classes:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">"Client and Server"</code> - this is telling build system - please generate both server side and client side classes.</li>
  <li><code class="language-plaintext highlighter-rouge">"Client only"</code> - generate only client side classes.</li>
  <li><code class="language-plaintext highlighter-rouge">"Server only"</code> - I’m implementing only server here.</li>
  <li><code class="language-plaintext highlighter-rouge">"Do not generate"</code> - I don’t care about neither server nor client.</li>
</ul>

<p>Which one to use pick? It depends on where you <code class="language-plaintext highlighter-rouge">.proto</code> file is located.</p>

<h3 id="linking-the-proto-file">Linking the Proto File</h3>

<p>We tend to follow file organization where <code class="language-plaintext highlighter-rouge">.proto</code> file itself physically is located in <code class="language-plaintext highlighter-rouge">.Abstractions</code> / <code class="language-plaintext highlighter-rouge">.Models</code> or any other isolated project which can be shared later on.</p>

<p>When creating <code class="language-plaintext highlighter-rouge">.proto</code> file in separate project you need to install <code class="language-plaintext highlighter-rouge">Grpc.Tools</code> package. Then we usually set following properties for the <code class="language-plaintext highlighter-rouge">.proto</code> file:</p>

<p><img src="/assets/img/2020/11/brtts-p5-proto-actions-4.png" alt="brtts-p5-proto-actions-4" /></p>

<p>Now when you have chosen location of your <code class="language-plaintext highlighter-rouge">.proto</code> file, you need to link that to gRPC server project.
One option is to use <a href="https://docs.microsoft.com/en-us/aspnet/core/grpc/dotnet-grpc?view=aspnetcore-3.1">“gRPC .NET Global Tool”</a>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; dotnet-grpc add-file ..\Grpc.Models\protofile.proto
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Another (maybe even easier) is to link file manually.
Head to the gRPC server-side project and add following line in your <code class="language-plaintext highlighter-rouge">.csproj</code> file:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;ItemGroup&gt;</span>
    <span class="nt">&lt;Protobuf</span> <span class="na">Include=</span><span class="s">"..\Grpc.Models\protofile.proto"</span> <span class="na">GrpcServices=</span><span class="s">"Server"</span> <span class="na">Link=</span><span class="s">"protos\v1\protofile.proto"</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;/ItemGroup&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now we have made following structure in our solution:</p>

<p><img src="/assets/img/2020/11/brtts-p5-proto-link.png" alt="brtts-p5-proto-link" /></p>

<p><strong>Note!</strong> that it’s good to start versioning your gRPC services from the very beginning of their lifespan. More info about versioning of the gRPC services could be found <a href="https://docs.microsoft.com/en-us/aspnet/core/grpc/versioning?view=aspnetcore-3.1">here</a>.</p>

<h3 id="defining-grpc-service-shape">Defining gRPC Service Shape</h3>

<p>Now when we have done with file organization, we can finally jump to defining shape of our service.</p>

<p>Let’s start with prerequisite header:</p>

<div class="language-proto highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="na">syntax</span> <span class="o">=</span> <span class="s">"proto3"</span><span class="p">;</span>
<span class="kn">package</span> <span class="nn">vehicle_hub</span><span class="o">.</span><span class="n">v1</span><span class="p">;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is the header for the <code class="language-plaintext highlighter-rouge">.proto</code> file instructing that we are running on v3 of the protocol and also dictating name of the package.</p>

<p>Next thing we need to do - define actual service which will feed the data.</p>

<div class="language-proto highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
</pre></td><td class="rouge-code"><pre><span class="na">syntax</span> <span class="o">=</span> <span class="s">"proto3"</span><span class="p">;</span>
<span class="kn">package</span> <span class="nn">vehicle_hub</span><span class="o">.</span><span class="n">v1</span><span class="p">;</span>

<span class="kd">service</span> <span class="n">DataFeed</span> <span class="p">{</span>
    <span class="k">rpc</span> <span class="n">SubscribeToVehicles</span> <span class="p">(</span><span class="n">Vehicles.GetAllRequest</span><span class="p">)</span> <span class="k">returns</span> <span class="p">(</span><span class="n">stream</span> <span class="n">Vehicles.GetAllResponse</span><span class="p">);</span>
<span class="p">}</span>

<span class="kd">message</span> <span class="nc">Vehicles</span> <span class="p">{</span>
    <span class="kd">message</span> <span class="nc">GetAllRequest</span> <span class="p">{</span>
        <span class="n">RequestOptions</span> <span class="na">options</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="kd">message</span> <span class="nc">GetAllResponse</span> <span class="p">{</span>
        <span class="k">repeated</span> <span class="n">Vehicle</span> <span class="na">data</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
        <span class="kt">int64</span> <span class="na">timestamp</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="kd">message</span> <span class="nc">RequestOptions</span> <span class="p">{</span>
        <span class="k">repeated</span> <span class="n">TransportMode.Values</span> <span class="na">transport_modes</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="kd">message</span> <span class="nc">Vehicle</span> <span class="p">{</span>
        <span class="kt">string</span> <span class="na">id</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
        <span class="kt">double</span> <span class="na">latitude</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
        <span class="kt">double</span> <span class="na">longitude</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kd">message</span> <span class="nc">TransportMode</span> <span class="p">{</span>
    <span class="kd">enum</span> <span class="n">Values</span> <span class="p">{</span>
        <span class="na">None</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="na">Bus</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
        <span class="na">Ferry</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>What is cool about this service - is return type of the method (<code class="language-plaintext highlighter-rouge">stream</code>):</p>

<div class="language-proto highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">rpc</span> <span class="n">SubscribeToVehicles</span> <span class="p">(</span><span class="n">Vehicles.GetAllRequest</span><span class="p">)</span> <span class="k">returns</span> <span class="p">(</span><span class="n">stream</span> <span class="n">Vehicles.GetAllResponse</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We will get back this when implementing server-side service.</p>

<p>Also you can notice that we are using “nested” classes for organizing messages and their types. This is a nice way to group related types together.</p>

<h2 id="implementing-grpc-server-side-service">Implementing gRPC Server-Side (Service)</h2>

<h3 id="creating-grpc-service-project">Creating gRPC Service Project</h3>

<p>The easiest way to create new project is by using Visual Studio templates for this job.</p>

<p>Look for “grpc” in new project wizard window.</p>

<p><img src="/assets/img/2020/11/brtts-p5-new-project.png" alt="brtts-p5-new-project" /></p>

<p>Template is adding all necessary plumbing to get gRPC service up and running and hooked into ASP.NET Core pipeline.</p>

<h3 id="service-implementation-placeholder">Service Implementation Placeholder</h3>

<p>Now when shape of the service is defined with the help of the <code class="language-plaintext highlighter-rouge">.proto</code> file, it’s time to implement the service.</p>

<p>First - we need to create new class and inherit from base type been generated for the gRPC server side:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="rouge-code"><pre><span class="k">using</span> <span class="nn">System.Threading.Tasks</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">Grpc.Core</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">Grpc.Models</span><span class="p">;</span>

<span class="k">namespace</span> <span class="nn">Grpc.Server.Services</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">DataFeedService</span> <span class="p">:</span> <span class="n">DataFeed</span><span class="p">.</span><span class="n">DataFeedBase</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="k">override</span> <span class="n">Task</span> <span class="nf">SubscribeToVehicles</span><span class="p">(</span>
            <span class="n">Vehicles</span><span class="p">.</span><span class="n">Types</span><span class="p">.</span><span class="n">GetAllRequest</span> <span class="n">request</span><span class="p">,</span>
            <span class="n">IServerStreamWriter</span><span class="p">&lt;</span><span class="n">Vehicles</span><span class="p">.</span><span class="n">Types</span><span class="p">.</span><span class="n">GetAllResponse</span><span class="p">&gt;</span> <span class="n">responseStream</span><span class="p">,</span>
            <span class="n">ServerCallContext</span> <span class="n">context</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="c1">// do magic here</span>

            <span class="c1">// 1. register incoming request in profile storage</span>
            <span class="kt">var</span> <span class="n">options</span> <span class="p">=</span> <span class="n">request</span><span class="p">.</span><span class="n">Options</span><span class="p">;</span>
            <span class="n">_profileStore</span><span class="p">.</span><span class="nf">TryRegister</span><span class="p">(</span><span class="n">options</span><span class="p">);</span>

            <span class="m">2</span><span class="p">.</span> <span class="n">TODO</span><span class="p">:</span> <span class="n">subscribe</span> <span class="n">to</span> <span class="n">stream</span> <span class="k">from</span> <span class="n">EventGrid</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The most interesting parameter to this method is <code class="language-plaintext highlighter-rouge">responseStream</code>.
More or less it has only one method - <code class="language-plaintext highlighter-rouge">WriteAsync</code>.</p>

<p><img src="/assets/img/2020/11/brtts-p5-response-stream.png" alt="brtts-p5-response-stream" /></p>

<p>We registered incoming request to the data profile store (which was introduced in <a href="https://tech-fellow.ghost.io/2020/08/30/building-real-time-public-transport-tracking-system-on-azure-part-4/">part 4</a>) and then we need to start writing to the response stream.
Our goal basically is to keep it “alive” and write to it as data comes from the Azure EventGrid prepared through data processing pipeline and profiles straight to this response stream.</p>

<p>gRPC services by default are transient - meaning that each connected client will get its own gRPC service instance. This is nice from the service isolation perspective.</p>

<p>Noticed also that we have been provided by server call <code class="language-plaintext highlighter-rouge">context</code> parameter? This is important parameter also - as it supplies us with <code class="language-plaintext highlighter-rouge">CancellationToken</code> property. This token gives information to the server about client being disconnected, network issues, etc. - meaning that the server can abort and finish-up the stream because it’s not needed anymore. On the other hand - <code class="language-plaintext highlighter-rouge">CancellationToken</code> also provides a way for the server to tell connected client that stream is being cancelled and they can do all necessary disposal and maybe reconnect if that’s needed.</p>

<p>But before we continue - we need to convert this token into cancellable task completition source.</p>

<h3 id="create-task-completition-source">Create Task Completition Source</h3>

<p>So in order to play nicely with async world and keep gRPC service “alive” while we are streaming - we are going to convert passed in <code class="language-plaintext highlighter-rouge">CancellationToken</code> into cancellable task completition source that we can <code class="language-plaintext highlighter-rouge">await</code> later.</p>

<p>For that - we gonna need a small auxiliary (extension) method:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">CancellationTokenExtensions</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="n">TaskCompletionSource</span><span class="p">&lt;</span><span class="kt">object</span><span class="p">&gt;</span> <span class="nf">CreateCancellable</span><span class="p">(</span><span class="k">this</span> <span class="n">CancellationToken</span> <span class="n">cancellationToken</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">taskCompletionSource</span> <span class="p">=</span> <span class="k">new</span> <span class="n">TaskCompletionSource</span><span class="p">&lt;</span><span class="kt">object</span><span class="p">&gt;(</span><span class="n">TaskCreationOptions</span><span class="p">.</span><span class="n">RunContinuationsAsynchronously</span><span class="p">);</span>
        <span class="n">cancellationToken</span><span class="p">.</span><span class="nf">Register</span><span class="p">(</span><span class="n">state</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="p">((</span><span class="n">TaskCompletionSource</span><span class="p">&lt;</span><span class="kt">object</span><span class="p">&gt;)</span><span class="n">state</span><span class="p">).</span><span class="nf">TrySetResult</span><span class="p">(</span><span class="k">null</span><span class="p">);</span> <span class="p">},</span>
                                   <span class="n">taskCompletionSource</span><span class="p">,</span>
                                   <span class="k">false</span><span class="p">);</span>

        <span class="k">return</span> <span class="n">taskCompletionSource</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This small extension method will give us possibility to create new task completition source allowing us to await on task which will be completed when token is cancelled.</p>

<p>So now we are able to continue with gRPC streaming method implementation.</p>

<h3 id="publishing-data-to-grpc-service-after-processing">Publishing Data to gRPC Service After Processing</h3>

<p>In part 4 we implemented background dispatcher service till the phase where we had to implement data broadcast further to gRPC service after it has been processed (<code class="language-plaintext highlighter-rouge">TODO</code> comment).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="nf">SnapshotDispatcherBackgroundService</span><span class="p">(</span>
    <span class="n">SnapshotReceiverBuffer</span> <span class="n">buffer</span><span class="p">,</span>
    <span class="n">MapDataProfileStore</span> <span class="n">profileStore</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">_buffer</span> <span class="p">=</span> <span class="n">buffer</span><span class="p">;</span>
    <span class="n">_profileStore</span> <span class="p">=</span> <span class="n">profileStore</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">protected</span> <span class="k">override</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">ExecuteAsync</span><span class="p">(</span><span class="n">CancellationToken</span> <span class="n">stoppingToken</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">try</span>
    <span class="p">{</span>
        <span class="k">while</span> <span class="p">(</span><span class="k">await</span> <span class="n">_buffer</span><span class="p">.</span><span class="nf">WaitToReadAsync</span><span class="p">(</span><span class="n">stoppingToken</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="k">try</span>
            <span class="p">{</span>
                <span class="c1">// we have received data</span>
                <span class="n">_buffer</span><span class="p">.</span><span class="nf">MarkAllAsRead</span><span class="p">();</span>

                <span class="c1">// fetch data from storage</span>
                <span class="kt">var</span> <span class="n">latestData</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">FetchLatestSnapshot</span><span class="p">();</span>

                <span class="c1">// prepare data for profiles</span>
                <span class="n">_profileStore</span><span class="p">.</span><span class="nf">PrepareData</span><span class="p">(</span><span class="n">latestData</span><span class="p">);</span>

                <span class="c1">// we are ready now to broadcast the data</span>
                <span class="c1">// TODO</span>
            <span class="p">}</span>
            <span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">e</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="c1">// log</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">ex</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// log</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As each gRPC service is transient and new instance is created for each connected client - we need to find a way to implement multi-broadcast pub/sub here. Meaning if two clients are connected - we would need to subscribe to data twice and each gRPC service should receive its own “copy” of the processed data to broadcast further down to the connected clients.</p>

<p>It would be quite interesting and probably challenging to implement this ourselves, but for sake of saving time and do something interesting, let’s rely on simple yet powerful library that is designed just for this reason - <a href="https://www.nuget.org/packages/Easy.MessageHub/">“Easy.MessageHub”</a> (<a href="https://github.com/NimaAra/Easy.MessageHub">GitHub repo</a>).</p>

<p>So after installation of the package we can now finalize our <code class="language-plaintext highlighter-rouge">ExecuteAsync</code> method and implement publishing step of the processed data.</p>

<p>But first, we need to do a registration in DI container (Startup.cs):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="n">IServiceCollection</span> <span class="nf">AddMessageBus</span><span class="p">(</span><span class="k">this</span> <span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">bus</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">MessageHub</span><span class="p">();</span>
    <span class="n">services</span><span class="p">.</span><span class="n">AddSingleton</span><span class="p">&lt;</span><span class="n">IMessageHub</span><span class="p">&gt;(</span><span class="n">bus</span><span class="p">);</span>

    <span class="k">return</span> <span class="n">services</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
    <span class="p">...</span>
    <span class="n">services</span><span class="p">.</span><span class="nf">AddMessageBus</span><span class="p">();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now we can request <code class="language-plaintext highlighter-rouge">IMessageHub</code> type from container and invoke <code class="language-plaintext highlighter-rouge">Publish</code> later on when we need it.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">readonly</span> <span class="n">SnapshotReceiverBuffer</span> <span class="n">_buffer</span><span class="p">;</span>
<span class="k">private</span> <span class="k">readonly</span> <span class="n">MapDataProfileStore</span> <span class="n">_profileStore</span><span class="p">;</span>
<span class="k">private</span> <span class="k">readonly</span> <span class="n">IMessageHub</span> <span class="n">_hub</span><span class="p">;</span>

<span class="k">public</span> <span class="nf">SnapshotDispatcherBackgroundService</span><span class="p">(</span>
    <span class="n">SnapshotReceiverBuffer</span> <span class="n">buffer</span><span class="p">,</span>
    <span class="n">MapDataProfileStore</span> <span class="n">profileStore</span><span class="p">,</span>
    <span class="n">IMessageHub</span> <span class="n">hub</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">_buffer</span> <span class="p">=</span> <span class="n">buffer</span><span class="p">;</span>
    <span class="n">_profileStore</span> <span class="p">=</span> <span class="n">profileStore</span><span class="p">;</span>
    <span class="n">_hub</span> <span class="p">=</span> <span class="n">hub</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">protected</span> <span class="k">override</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">ExecuteAsync</span><span class="p">(</span><span class="n">CancellationToken</span> <span class="n">stoppingToken</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">try</span>
    <span class="p">{</span>
        <span class="k">while</span> <span class="p">(</span><span class="k">await</span> <span class="n">_buffer</span><span class="p">.</span><span class="nf">WaitToReadAsync</span><span class="p">(</span><span class="n">stoppingToken</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="k">try</span>
            <span class="p">{</span>
                <span class="c1">// we have received data</span>
                <span class="n">_buffer</span><span class="p">.</span><span class="nf">MarkAllAsRead</span><span class="p">();</span>

                <span class="c1">// fetch data from storage</span>
                <span class="kt">var</span> <span class="n">latestData</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">FetchLatestSnapshot</span><span class="p">();</span>

                <span class="c1">// prepare data for profiles</span>
                <span class="n">_profileStore</span><span class="p">.</span><span class="nf">PrepareData</span><span class="p">(</span><span class="n">latestData</span><span class="p">);</span>

                <span class="c1">// we are ready now to broadcast the data</span>
                <span class="n">_hub</span><span class="p">.</span><span class="nf">Publish</span><span class="p">(</span><span class="n">latestData</span><span class="p">);</span>
            <span class="p">}</span>
            <span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">e</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="c1">// log</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">ex</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// log</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We are able now to subscribe to publish data and finally start broadcasting to connected clients via gRPC runtime provided <code class="language-plaintext highlighter-rouge">IServerStreamWriter</code> type.</p>

<h3 id="awaiting-on-published-eventgrid-data">Awaiting on Published EventGrid Data</h3>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">DataFeedService</span> <span class="p">:</span> <span class="n">DataFeed</span><span class="p">.</span><span class="n">DataFeedBase</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">override</span> <span class="n">Task</span> <span class="nf">SubscribeToVehicles</span><span class="p">(</span>
        <span class="n">Vehicles</span><span class="p">.</span><span class="n">Types</span><span class="p">.</span><span class="n">GetAllRequest</span> <span class="n">request</span><span class="p">,</span>
        <span class="n">IServerStreamWriter</span><span class="p">&lt;</span><span class="n">Vehicles</span><span class="p">.</span><span class="n">Types</span><span class="p">.</span><span class="n">GetAllResponse</span><span class="p">&gt;</span> <span class="n">responseStream</span><span class="p">,</span>
        <span class="n">ServerCallContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// 1. register incoming request in profile storage</span>
        <span class="kt">var</span> <span class="n">options</span> <span class="p">=</span> <span class="n">request</span><span class="p">.</span><span class="n">Options</span><span class="p">;</span>
        <span class="n">_profileStore</span><span class="p">.</span><span class="nf">TryRegister</span><span class="p">(</span><span class="n">options</span><span class="p">);</span>

        <span class="m">2</span><span class="p">.</span> <span class="n">subscribe</span> <span class="n">to</span> <span class="n">stream</span> <span class="k">from</span> <span class="n">EventGrid</span>
        <span class="kt">var</span> <span class="n">taskCompletionSource</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">CancellationToken</span><span class="p">.</span><span class="nf">CreateCancellable</span><span class="p">();</span>

        <span class="kt">var</span> <span class="n">subscriptionToken</span> <span class="p">=</span> <span class="n">_hub</span><span class="p">.</span><span class="n">Subscribe</span><span class="p">&lt;</span><span class="n">SnapshotBroadcastWorkItem</span><span class="p">.</span><span class="n">Data</span><span class="p">&gt;(...);</span>

        <span class="k">try</span>
        <span class="p">{</span>
            <span class="k">await</span> <span class="n">taskCompletionSource</span><span class="p">.</span><span class="n">Task</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">catch</span><span class="p">(</span><span class="n">TaskCanceledException</span> <span class="n">e</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="c1">// when hub subscription is cancelled due to some kind of exception</span>
            <span class="c1">// TODO: implement error hanlding</span>
        <span class="p">}</span>
        <span class="k">finally</span>
        <span class="p">{</span>
            <span class="n">_hub</span><span class="p">.</span><span class="nf">Unsubscribe</span><span class="p">(</span><span class="n">subscriptionToken</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Here few things are happening  worth describing.</p>

<ol>
  <li>After we created cancellable task completition source, we are subscribing to hub published messages (<code class="language-plaintext highlighter-rouge">_hub.Subscribe&lt;T&gt;()</code>). We are capturing messaging hub subscription token.</li>
  <li>After subscription is made - we need to “keep service alive”. This is done by just awaiting on our earlier made completition source wrapped task. This is ensuring that service scope is not ended until task is finished.</li>
</ol>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">await</span> <span class="n">taskCompletionSource</span><span class="p">.</span><span class="n">Task</span><span class="p">.</span><span class="nf">ConfigureAwait</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ol>
  <li>After service has resumed execution (cancellation token has been cancelled) we are unsubscribing from the “Easy.MessageHub”:</li>
</ol>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="p">...</span>
<span class="k">finally</span>
<span class="p">{</span>
    <span class="n">_hub</span><span class="p">.</span><span class="nf">Unsubscribe</span><span class="p">(</span><span class="n">subscriptionToken</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now question is - what we are going to do inside subscribe method?</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">subscriptionToken</span> <span class="p">=</span> <span class="n">_hub</span><span class="p">.</span><span class="n">Subscribe</span><span class="p">&lt;</span><span class="n">SnapshotBroadcastWorkItem</span><span class="p">.</span><span class="n">Data</span><span class="p">&gt;(...);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>To continue - we need to define yet another extension method (a small helper that will await on <code class="language-plaintext highlighter-rouge">async</code> method and in case of exception will invoke provided callback):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">FireAndRunOnExceptionAsync</span><span class="p">(</span><span class="k">this</span> <span class="n">Task</span> <span class="n">task</span><span class="p">,</span> <span class="n">Action</span><span class="p">&lt;</span><span class="n">Exception</span><span class="p">&gt;</span> <span class="n">callback</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">try</span>
    <span class="p">{</span>
        <span class="k">await</span> <span class="n">task</span><span class="p">.</span><span class="nf">ConfigureAwait</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">e</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">callback</span><span class="p">.</span><span class="nf">Invoke</span><span class="p">(</span><span class="n">e</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Let’s finally implement gRPC streaming method completely:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">DataFeedService</span> <span class="p">:</span> <span class="n">DataFeed</span><span class="p">.</span><span class="n">DataFeedBase</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">override</span> <span class="n">Task</span> <span class="nf">SubscribeToVehicles</span><span class="p">(</span>
        <span class="n">Vehicles</span><span class="p">.</span><span class="n">Types</span><span class="p">.</span><span class="n">GetAllRequest</span> <span class="n">request</span><span class="p">,</span>
        <span class="n">IServerStreamWriter</span><span class="p">&lt;</span><span class="n">Vehicles</span><span class="p">.</span><span class="n">Types</span><span class="p">.</span><span class="n">GetAllResponse</span><span class="p">&gt;</span> <span class="n">responseStream</span><span class="p">,</span>
        <span class="n">ServerCallContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// 1. register incoming request in profile storage</span>
        <span class="kt">var</span> <span class="n">options</span> <span class="p">=</span> <span class="n">request</span><span class="p">.</span><span class="n">Options</span><span class="p">;</span>
        <span class="n">_profileStore</span><span class="p">.</span><span class="nf">TryRegister</span><span class="p">(</span><span class="n">options</span><span class="p">);</span>

        <span class="m">2</span><span class="p">.</span> <span class="n">subscribe</span> <span class="n">to</span> <span class="n">stream</span> <span class="k">from</span> <span class="n">EventGrid</span>
        <span class="kt">var</span> <span class="n">taskCompletionSource</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">CancellationToken</span><span class="p">.</span><span class="nf">CreateCancellable</span><span class="p">();</span>

        <span class="kt">var</span> <span class="n">subscriptionToken</span> <span class="p">=</span> <span class="n">_hub</span><span class="p">.</span><span class="n">Subscribe</span><span class="p">&lt;</span><span class="n">SnapshotBroadcastWorkItem</span><span class="p">.</span><span class="n">Data</span><span class="p">&gt;(</span>
            <span class="n">latestData</span> <span class="p">=&gt;</span> <span class="n">AsyncHelper</span><span class="p">.</span><span class="nf">RunSync</span><span class="p">(</span>
                <span class="k">async</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="k">await</span> <span class="nf">OnNewVehiclesData</span><span class="p">(</span><span class="n">options</span><span class="p">,</span> <span class="n">responseStream</span><span class="p">,</span> <span class="n">context</span><span class="p">)</span>
                    <span class="p">.</span><span class="nf">FireAndRunOnExceptionAsync</span><span class="p">(</span><span class="n">e</span> <span class="p">=&gt;</span>
                    <span class="p">{</span>
                        <span class="n">lastException</span> <span class="p">=</span> <span class="n">e</span><span class="p">;</span>
                        <span class="k">if</span> <span class="p">(!</span><span class="n">taskCompletionSource</span><span class="p">.</span><span class="n">Task</span><span class="p">.</span><span class="n">IsCompleted</span><span class="p">)</span>
                        <span class="p">{</span>
                            <span class="n">taskCompletionSource</span><span class="p">.</span><span class="nf">SetCanceled</span><span class="p">();</span>
                        <span class="p">}</span>
                    <span class="p">})));</span>

        <span class="k">try</span>
        <span class="p">{</span>
            <span class="k">await</span> <span class="n">taskCompletionSource</span><span class="p">.</span><span class="n">Task</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">catch</span><span class="p">(</span><span class="n">TaskCanceledException</span> <span class="n">e</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="c1">// when hub subscription is cancelled due to some kind of exception</span>
            <span class="kt">var</span> <span class="n">message</span> <span class="p">=</span> <span class="n">e</span><span class="p">.</span><span class="n">Message</span><span class="p">;</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">lastException</span> <span class="p">!=</span> <span class="k">default</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="n">message</span> <span class="p">=</span> <span class="n">lastException</span><span class="p">.</span><span class="n">Message</span><span class="p">;</span>
            <span class="p">}</span>

            <span class="k">throw</span> <span class="k">new</span> <span class="nf">RpcException</span><span class="p">(</span><span class="k">new</span> <span class="nf">Status</span><span class="p">(</span><span class="n">StatusCode</span><span class="p">.</span><span class="n">Internal</span><span class="p">,</span> <span class="n">message</span><span class="p">));</span>
        <span class="p">}</span>
        <span class="k">finally</span>
        <span class="p">{</span>
            <span class="n">_hub</span><span class="p">.</span><span class="nf">Unsubscribe</span><span class="p">(</span><span class="n">subscriptionToken</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We also extracted actual callback on new data into separate method - <code class="language-plaintext highlighter-rouge">OnNewVehiclesData</code>. Method just moves code from <code class="language-plaintext highlighter-rouge">Subscribe</code> method to its own just for brevity.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">OnNewVehicles</span><span class="p">(</span>
    <span class="n">ProcessorOptions</span> <span class="n">options</span><span class="p">,</span>
    <span class="n">IServerStreamWriter</span><span class="p">&lt;</span><span class="n">Vehicles</span><span class="p">.</span><span class="n">Types</span><span class="p">.</span><span class="n">GetAllResponse</span><span class="p">&gt;</span> <span class="n">responseStream</span><span class="p">,</span>
    <span class="n">ServerCallContext</span> <span class="n">context</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// get transport model from the profile store</span>
    <span class="kt">var</span> <span class="n">snapshot</span> <span class="p">=</span> <span class="n">_profileStore</span><span class="p">.</span><span class="nf">GetData</span><span class="p">(</span><span class="n">options</span><span class="p">);</span>

    <span class="c1">// prepare result</span>
    <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Vehicles</span><span class="p">.</span><span class="n">Types</span><span class="p">.</span><span class="n">GetAllResponse</span>
    <span class="p">{</span>
        <span class="n">Timestamp</span> <span class="p">=</span> <span class="n">snapshot</span><span class="p">.</span><span class="n">GeneratedAt</span><span class="p">.</span><span class="nf">ToTimestamp</span><span class="p">()</span>
    <span class="p">};</span>

    <span class="c1">// we can't use object initializer as gRPC requires you to add items separately</span>
    <span class="c1">// it generates getter only</span>
    <span class="n">result</span><span class="p">.</span><span class="n">Data</span><span class="p">.</span><span class="nf">AddRange</span><span class="p">(</span><span class="n">snapshot</span><span class="p">.</span><span class="n">Vehicles</span><span class="p">.</span><span class="nf">ToGrpcModel</span><span class="p">());</span>

    <span class="k">await</span> <span class="n">responseStream</span><span class="p">.</span><span class="nf">WriteAsync</span><span class="p">(</span><span class="n">result</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Note that we are executing special callback that we configure in <code class="language-plaintext highlighter-rouge">FireAndRunOnExceptionAsync()</code> in case of exception during <code class="language-plaintext highlighter-rouge">OnNewVehiclesData</code> method - we are capturing exception and cancelling completition source. This will ensure that <code class="language-plaintext highlighter-rouge">await taskCompletionSource.Task;</code> is resumed.</p>

<h2 id="wrapping-up">Wrapping Up</h2>

<p>We implemented our system till the phase where sent data from Azure EventGrid is passed through data processing pipeline and various profiles have been created, and later data is published via messaging hub to the gRPC service for further broadcast to connected clients to the app.</p>

<p>Our architecture now looks like this:</p>

<p><img src="/assets/img/2020/11/brtts-p5-arch.png" alt="brtts-p5-arch" /></p>

<p>We implemented gRPC server side streaming which is quite cool if you think about various possibilities how to talk to connected clients to your app in real-time.
Also liked that gRPC is “protocol-first” approach - meaning that you define the shape of your service and client stubs could be generated ion many different languages - C# and .NET are not the only options.</p>

<p>Next part we will need to implement frontend for the gRPC service. We gonna do a web based interface (where vehicles could be draw on the map canvas) and another frontend will be c# based client for the monitoring of the health of the service.</p>

<p>Stay tuned!</p>

<p>Happy streaming!
[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="gRPC" /><category term="Azure" /><category term=".net" /><category term="c#" /><category term="grpc" /><category term="azure" /><summary type="html"><![CDATA[This is next post in series about real-time public transport tracking system development based on Azure infrastructure and services. This article is a part of Applied Cloud Stories initiative - aka.ms/applied-cloud-stories.]]></summary></entry><entry><title type="html">Bootstrap Content Area Renderer Update for Episerver</title><link href="https://tech-fellow.eu/2020/09/06/bootstrap-content-area-update-for-episerver/" rel="alternate" type="text/html" title="Bootstrap Content Area Renderer Update for Episerver" /><published>2020-09-06T10:15:00+03:00</published><updated>2020-09-06T10:15:00+03:00</updated><id>https://tech-fellow.eu/2020/09/06/bootstrap-content-area-update-for-episerver</id><content type="html" xml:base="https://tech-fellow.eu/2020/09/06/bootstrap-content-area-update-for-episerver/"><![CDATA[<p>Twitter Bootstrap Content Area package hasn’t been updated for a while which might mean either no one is using it or it’s mature enough that does not require new features :)</p>

<p>Not sure if anyone still use it or should I upgrade to any other CSS framework out there..?! Package is going strong with more than 18k downloads for the last version.</p>

<p>Anyhow, I finally got time to sit down and scan through some of the tickets reported for the package that has been hanging around for a while.</p>

<h2 id="registering-renderer-in-ioc">Registering Renderer in IoC</h2>

<p>Interestingly, bug reports were quite odd cases (assuming that Bootstrap renderer is installed and configured properly). Like <code class="language-plaintext highlighter-rouge">BlockIndex</code> returns always <code class="language-plaintext highlighter-rouge">-1</code> (report <a href="https://github.com/valdisiljuconoks/EPiBootstrapArea/issues/59">here</a>).
Also modification of the start element (comes quite handy when you need to anchor content area items with some bookmark and later link to it) of the content area item was not working.</p>

<p>As it turned out, Bootstrap Content Area renderer was not properly registered in IoC container and therefore did not have a chance to plug in and add its own behavior to the rendering pipeline.</p>

<p>Registration of renderer happened like this:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">ServiceContainerInitialization</span><span class="p">))]</span>
<span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">SetupBootstrapRenderer</span> <span class="p">:</span> <span class="n">IConfigurableModule</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="n">ServiceConfigurationContext</span> <span class="n">_context</span><span class="p">;</span>

    <span class="k">void</span> <span class="n">IConfigurableModule</span><span class="p">.</span><span class="nf">ConfigureContainer</span><span class="p">(</span><span class="n">ServiceConfigurationContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_context</span> <span class="p">=</span> <span class="n">context</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">context</span><span class="p">.</span><span class="n">InitComplete</span> <span class="p">+=</span> <span class="n">ContextOnInitComplete</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">context</span><span class="p">.</span><span class="n">InitComplete</span> <span class="p">-=</span> <span class="n">ContextOnInitComplete</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="k">void</span> <span class="nf">ContextOnInitComplete</span><span class="p">(</span><span class="kt">object</span> <span class="n">sender</span><span class="p">,</span> <span class="n">EventArgs</span> <span class="n">eventArgs</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">displayOptions</span> <span class="p">=</span> <span class="nf">GetAllDisplayOptions</span><span class="p">();</span>

        <span class="p">...</span>
        <span class="n">_context</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="n">AddTransient</span><span class="p">&lt;</span><span class="n">ContentAreaRenderer</span><span class="p">&gt;(</span>
            <span class="n">_</span> <span class="p">=&gt;</span> <span class="k">new</span> <span class="nf">BootstrapAwareContentAreaRenderer</span><span class="p">(</span><span class="n">displayOptions</span><span class="p">));</span>
        <span class="p">...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is not going to replace <code class="language-plaintext highlighter-rouge">ContentAreaRenderer</code> in the container. Nor does this code (I’m not sure why tho):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="n">_context</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="n">RemoveAll</span><span class="p">&lt;</span><span class="n">ContentAreaRenderer</span><span class="p">&gt;();</span>
<span class="n">_context</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="n">AddTransient</span><span class="p">&lt;</span><span class="n">ContentAreaRenderer</span><span class="p">&gt;(...);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The only way (at least for now) I found -&gt; is to intercept renderer, “silence” it by ignoring given instance and just carry out custom Bootstrap content area renderer logic:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">void</span> <span class="nf">ContextOnInitComplete</span><span class="p">(</span><span class="kt">object</span> <span class="n">sender</span><span class="p">,</span> <span class="n">EventArgs</span> <span class="n">eventArgs</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">displayOptions</span> <span class="p">=</span> <span class="nf">GetAllDisplayOptions</span><span class="p">();</span>

    <span class="n">_context</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="n">Intercept</span><span class="p">&lt;</span><span class="n">ContentAreaRenderer</span><span class="p">&gt;((</span><span class="n">_</span><span class="p">,</span> <span class="n">__</span><span class="p">)</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="k">new</span> <span class="nf">BootstrapAwareContentAreaRenderer</span><span class="p">(</span><span class="n">displayOptions</span><span class="p">);</span>
    <span class="p">});</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="modify-block-element-fix">Modify Block Element Fix</h2>

<p>Another interesting <a href="https://github.com/valdisiljuconoks/EPiBootstrapArea/issues/60">issue</a> was that provided way to modify block start element was working <a href="https://github.com/valdisiljuconoks/EPiBootstrapArea/blob/master/README.md#modify-block-start-element">as documented</a>. I would not expect much from the library if one is developed and tested during night shifts :)</p>

<p>Idea for the feature is that you are able to override renderer (by inheriting from built-in) and add your own custom logic how block start element is processed. This was nice feature back in days when we had to generate site menu out of content area blocks - meaning that each block start element should have anchor attribute so that menu items could properly link to page bookmarks. Feature was not working in latest version.</p>

<p>At the end it turned out that again improper IoC registration was done. While registering <code class="language-plaintext highlighter-rouge">ContentAreaRenderer</code> in container we have to make sure that we check who is sitting there and respect if renderer is somebody from <code class="language-plaintext highlighter-rouge">BootstrapAwareContentAreaRenderer</code> object family :)</p>

<p>So this is final code for the renderer registration:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">void</span> <span class="nf">ContextOnInitComplete</span><span class="p">(</span><span class="kt">object</span> <span class="n">sender</span><span class="p">,</span> <span class="n">EventArgs</span> <span class="n">eventArgs</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">displayOptions</span> <span class="p">=</span> <span class="nf">GetAllDisplayOptions</span><span class="p">();</span>

    <span class="c1">// setup proper renderer with all registered fallback (+custom ones as well)</span>
    <span class="n">_context</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="n">Intercept</span><span class="p">&lt;</span><span class="n">ContentAreaRenderer</span><span class="p">&gt;((</span><span class="n">_</span><span class="p">,</span> <span class="n">render</span><span class="p">)</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="c1">// existing renderer is not familiar to us - so we can just "swap it out"</span>
        <span class="c1">// this is not the actual swap - as just registering new instance of the renderer does not do the trick</span>
        <span class="c1">// we are here "silencing" original - by intercepting it and forgetting about it :)</span>
        <span class="k">if</span> <span class="p">(!(</span><span class="n">render</span> <span class="k">is</span> <span class="n">BootstrapAwareContentAreaRenderer</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="k">return</span> <span class="k">new</span> <span class="nf">BootstrapAwareContentAreaRenderer</span><span class="p">(</span><span class="n">displayOptions</span><span class="p">);</span>
        <span class="p">}</span>

        <span class="c1">// registered renderer is somebody from our family</span>
        <span class="c1">// this usually happens when somebody wants to do some extension of the Bootstrap aware renderer</span>
        <span class="c1">// therefore inheriting from default one and extending via some virtual methods</span>
        <span class="c1">// do after we have collected all display options here - we have to set that to the original renderer</span>
        <span class="p">((</span><span class="n">BootstrapAwareContentAreaRenderer</span><span class="p">)</span><span class="n">render</span><span class="p">).</span><span class="nf">SetDisplayOptions</span><span class="p">(</span><span class="n">displayOptions</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">render</span><span class="p">;</span>
    <span class="p">});</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="none-display-option">None Display Option</h2>

<p>Sometimes you would like to set display option that does nothing - none of the CSS classes would be added that could mess up your site design. This was actually requested by somebody who has <a href="https://github.com/valdisiljuconoks/EPiBootstrapArea/issues/57">JasonRodman</a> identity at GitHub.</p>

<p>For this reason there is a new built-in display option - <code class="language-plaintext highlighter-rouge">None</code>.</p>

<p>You can add it to the supported <code class="language-plaintext highlighter-rouge">DisplayOptions</code>:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">CustomizedRenderingInitialization</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">ConfigurationContext</span><span class="p">.</span><span class="nf">Setup</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="n">ctx</span><span class="p">.</span><span class="n">CustomDisplayOptions</span>
               <span class="p">.</span><span class="n">Add</span><span class="p">&lt;</span><span class="n">DisplayModeFallback</span><span class="p">.</span><span class="n">None</span><span class="p">&gt;();</span>

            <span class="p">...</span>
        <span class="p">});</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If you set this display option on the block (in this example <code class="language-plaintext highlighter-rouge">"Teaser Block"</code> in Alloy sample site) only following classes will be added to the block container element:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"block teaserblock displaymode-none"</span><span class="nt">&gt;</span>
    <span class="c">&lt;!-- block content --&gt;</span>
<span class="nt">&lt;/div&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Bootstrap aware Episerver content area renderer package v5.3 includes other smaller fixes also.</p>

<p>Happy bootstrapping!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="DeveloperTools" /><category term="Bootstrap" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="bootstrap" /><summary type="html"><![CDATA[Twitter Bootstrap Content Area package hasn’t been updated for a while which might mean either no one is using it or it’s mature enough that does not require new features :)]]></summary></entry><entry><title type="html">Building Real-time Public Transport Tracking System on Azure - Part 4</title><link href="https://tech-fellow.eu/2020/08/30/building-real-time-public-transport-tracking-system-on-azure-part-4/" rel="alternate" type="text/html" title="Building Real-time Public Transport Tracking System on Azure - Part 4" /><published>2020-08-30T11:00:00+03:00</published><updated>2020-08-30T11:00:00+03:00</updated><id>https://tech-fellow.eu/2020/08/30/building-real-time-public-transport-tracking-system-on-azure-part-4</id><content type="html" xml:base="https://tech-fellow.eu/2020/08/30/building-real-time-public-transport-tracking-system-on-azure-part-4/"><![CDATA[<p>This is next post in series about real-time public transport tracking system development based on Azure infrastructure and services. This article is a part of Applied Cloud Stories initiative - <a href="aka.ms/applied-cloud-stories">aka.ms/applied-cloud-stories</a>.</p>

<p>Blog posts in this series:</p>

<ul>
  <li><a href="https://tech-fellow.eu/2019/12/08/building-real-time-public-transport-tracking-system-on-azure-part1/">Part 1 - Scene Background &amp; Solution Architecture</a></li>
  <li><a href="https://tech-fellow.eu/2020/01/21/building-real-time-public-transport-tracking-system-on-azure-part-2-data-collectors-composer/">Part 2 - Data Collectors &amp; Composer</a></li>
  <li><a href="https://tech-fellow.eu/2020/04/08/building-real-time-public-transport-tracking-system-on-azure-part-3/">Part 3 - Event-Based Data Delivery</a></li>
  <li><strong>Part 4 - Data Processing Pipelines</strong></li>
  <li><a href="https://tech-fellow.eu/2020/11/01/building-real-time-public-transport-tracking-system-on-azure-part-5/">Part 5 - Data Broadcast using gRPC and SignalR</a></li>
  <li><a href="https://tech-fellow.eu/2020/12/14/building-real-time-public-transport-tracking-system-on-azure-part-6-building-frontend/">Part 6 - Building Frontend</a></li>
  <li><a href="https://tech-fellow.eu/2021/01/21/building-real-time-public-transport-tracking-system-on-azure-part-6-packing-everything-up/">Part 7 - Packing Everything Up</a></li>
  <li><a href="https://tech-fellow.eu/2021/01/25/building-linux-docker-images-on-windows-machine/">Part 7.1 - Fixing Docker Image Metrics in Azure</a></li>
</ul>

<h2 id="broadcast-phase">Broadcast Phase</h2>

<p>We ended <a href="https://tech-fellow.ghost.io/2020/04/08/building-real-time-public-transport-tracking-system-on-azure-part-3/">last part of this blog post series</a> with a open question what to do next once we have received EventGrid event.</p>

<p>We are now in the phase when data needs to be prepared and broadcasted to connected clients (either mobile apps, browsers, specific data feeds or any other consumer application).</p>

<p>Following architecture is set for  broadcast phase of our real-time public transport tracking system:</p>

<p><img src="/assets/img/2020/08/brtts-p4-1.png" alt="brtts-p4-1" /></p>

<h2 id="receiving-eventgrid-events">Receiving EventGrid Events</h2>

<p>Now we need to distribute if further to connected clients (whoever it might be).</p>

<p>Code fragment that we now need to implement is between these lines:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">if</span> <span class="p">(</span><span class="n">eventGridEvent</span><span class="p">.</span><span class="n">Data</span> <span class="k">is</span> <span class="n">StorageBlobCreatedEventData</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// TODO: magic happens here</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If we inspect received EventGrid data - we see that there is only a reference to blob that has been generated and saved in Azure Storage <strong>and not</strong> the actual content.</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="w">
  </span><span class="p">{</span><span class="w">
    </span><span class="nl">"topic"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/subscriptions/{subscription-id}/resourceGroups/Storage/providers/Microsoft.Storage/storageAccounts/xstoretestaccount"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"subject"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/blobServices/default/containers/oc2d2817345i200097container/blobs/oc2d2817345i20002296blob"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"eventType"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Microsoft.Storage.BlobCreated"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"eventTime"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2017-06-26T18:41:00.9584103Z"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"831e1650-001e-001b-66ab-eeb76e069631"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"data"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="err">...</span><span class="w"> </span><span class="p">},</span><span class="w">
    </span><span class="nl">"dataVersion"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="p">,</span><span class="w">
    </span><span class="nl">"metadataVersion"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1"</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">]</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>This is by design how EventGrid is working - it’s event messaging infrastructure and not data transport. It suppose to trigger an event processing pipeline on the receiver side.</p>

<p>So to get content - we need to fetch it via Storage SDK. It’s quite simple and straight forward.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">storageAccount</span> <span class="p">=</span> <span class="n">CloudStorageAccount</span><span class="p">.</span><span class="nf">Parse</span><span class="p">(</span><span class="n">connectionString</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">client</span> <span class="p">=</span> <span class="n">storageAccount</span><span class="p">.</span><span class="nf">CreateCloudBlobClient</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">container</span> <span class="p">=</span> <span class="n">client</span><span class="p">.</span><span class="nf">GetContainerReference</span><span class="p">(</span><span class="n">containerName</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">blob</span> <span class="p">=</span> <span class="n">container</span><span class="p">.</span><span class="nf">GetBlockBlobReference</span><span class="p">(</span><span class="n">blobName</span><span class="p">);</span>

<span class="k">using</span> <span class="nn">var</span> <span class="n">memoryStream</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">MemoryStream</span><span class="p">(</span><span class="n">initialCapacity</span><span class="p">);</span>
<span class="k">await</span> <span class="n">blob</span><span class="p">.</span><span class="nf">DownloadToStreamAsync</span><span class="p">(</span><span class="n">memoryStream</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">content</span> <span class="p">=</span> <span class="n">memoryStream</span><span class="p">.</span><span class="nf">ToArray</span><span class="p">();</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>To reply back to EventGrid runtime that we have received (“acknowledged”) the message - we have to act quickly. This usually means that we can’t really download the data from the storage, start data processing pipeline, data slicing and preparing for the broadcast and actually do the broadcast - as it all takes time and “blocks” request receiver to send back 200OK message to Azure EventGrid infrastructure.</p>

<p>We have to somehow “buffer” the incoming messages and reply quickly as possible back to EventGrid.</p>

<p>For this purpose we can utilize interesting data structure - <code class="language-plaintext highlighter-rouge">Channel&lt;T&gt;</code> (super cool intro <a href="https://devblogs.microsoft.com/dotnet/an-introduction-to-system-threading-channels/">here</a>).</p>

<p>This allows us to split apart receiver side (writer on the channel) and processor side (reader on the channel).</p>

<p>Definition of the channel is pretty simple:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">readonly</span> <span class="n">Channel</span><span class="p">&lt;</span><span class="n">SnapshotBroadcastWorkItem</span><span class="p">.</span><span class="n">Trigger</span><span class="p">&gt;</span> <span class="n">_buffer</span> <span class="p">=</span>
    <span class="n">Channel</span><span class="p">.</span><span class="n">CreateUnbounded</span><span class="p">&lt;</span><span class="n">SnapshotBroadcastWorkItem</span><span class="p">.</span><span class="n">Trigger</span><span class="p">&gt;(</span><span class="k">new</span> <span class="n">UnboundedChannelOptions</span>
    <span class="p">{</span>
        <span class="n">AllowSynchronousContinuations</span> <span class="p">=</span> <span class="k">false</span><span class="p">,</span>
        <span class="n">SingleReader</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
        <span class="n">SingleWriter</span> <span class="p">=</span> <span class="k">false</span>
    <span class="p">});</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This definition will create data structure that will be used to create buffer between producer of the data (trigger items on the channel) and subscriber of the data. Each of these parties can act on their own frequencies - meaning that you can write to the channel without knowing whether there is anybody on the other side or not (and you actually should not care as long as channel is not empty or you run out of memory).</p>

<p>What I usually like to do - is to hide some implementation details behind abstractions to avoid leaky dependencies outside - no one really cares that underlying transport is <code class="language-plaintext highlighter-rouge">Channel&lt;T&gt;</code>.</p>

<p>Let’s define abstraction around the <code class="language-plaintext highlighter-rouge">Channel&lt;T&gt;</code> data structure:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">SnapshotReceiverBuffer</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">Channel</span><span class="p">&lt;</span><span class="n">SnapshotBroadcastWorkItem</span><span class="p">.</span><span class="n">Trigger</span><span class="p">&gt;</span> <span class="n">_buffer</span> <span class="p">=</span>
        <span class="n">Channel</span><span class="p">.</span><span class="n">CreateUnbounded</span><span class="p">&lt;</span><span class="n">SnapshotBroadcastWorkItem</span><span class="p">.</span><span class="n">Trigger</span><span class="p">&gt;(</span><span class="k">new</span> <span class="n">UnboundedChannelOptions</span>
        <span class="p">{</span>
            <span class="n">AllowSynchronousContinuations</span> <span class="p">=</span> <span class="k">false</span><span class="p">,</span>
            <span class="n">SingleReader</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
            <span class="n">SingleWriter</span> <span class="p">=</span> <span class="k">false</span>
        <span class="p">});</span>

    <span class="k">public</span> <span class="kt">bool</span> <span class="nf">TryAdd</span><span class="p">()</span> <span class="p">=&gt;</span> <span class="n">_buffer</span><span class="p">.</span><span class="n">Writer</span><span class="p">.</span><span class="nf">TryWrite</span><span class="p">(</span><span class="k">new</span> <span class="n">SnapshotBroadcastWorkItem</span><span class="p">.</span><span class="nf">Trigger</span><span class="p">());</span>

    <span class="k">public</span> <span class="n">ValueTask</span><span class="p">&lt;</span><span class="kt">bool</span><span class="p">&gt;</span> <span class="nf">WaitToReadAsync</span><span class="p">(</span><span class="n">CancellationToken</span> <span class="n">stoppingToken</span><span class="p">)</span> <span class="p">=&gt;</span>
        <span class="n">_buffer</span><span class="p">.</span><span class="n">Reader</span><span class="p">.</span><span class="nf">WaitToReadAsync</span><span class="p">(</span><span class="n">stoppingToken</span><span class="p">);</span>

    <span class="k">public</span> <span class="kt">bool</span> <span class="nf">TryRead</span><span class="p">(</span><span class="k">out</span> <span class="n">SnapshotBroadcastWorkItem</span><span class="p">.</span><span class="n">Trigger</span> <span class="n">message</span><span class="p">)</span> <span class="p">=&gt;</span>
        <span class="n">_buffer</span><span class="p">.</span><span class="n">Reader</span><span class="p">.</span><span class="nf">TryRead</span><span class="p">(</span><span class="k">out</span> <span class="n">message</span><span class="p">);</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">MarkAllAsRead</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="k">while</span> <span class="p">(</span><span class="n">_buffer</span><span class="p">.</span><span class="n">Reader</span><span class="p">.</span><span class="nf">TryRead</span><span class="p">(</span><span class="k">out</span> <span class="n">_</span><span class="p">))</span> <span class="p">{</span> <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So you can configure your favorite DI container to keep this as singleton and inject all the time the same instance into services.</p>

<p>So now with an abstraction in place we can go back to our EventGrid receiver code and implement buffer there:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">ApiController</span><span class="p">]</span>
<span class="p">[</span><span class="nf">Route</span><span class="p">(</span><span class="s">"api"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">EventGridReceiverController</span> <span class="p">:</span> <span class="n">ControllerBase</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">SnapshotReceiverBuffer</span> <span class="n">_buffer</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">EventGridReceiverController</span><span class="p">(</span><span class="n">SnapshotReceiverBuffer</span> <span class="n">buffer</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_buffer</span> <span class="p">=</span> <span class="n">buffer</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="p">[</span><span class="nf">Route</span><span class="p">(</span><span class="s">"eventgridreceiver"</span><span class="p">)]</span>
    <span class="p">[</span><span class="n">HttpPost</span><span class="p">]</span>
    <span class="k">public</span> <span class="n">ActionResult</span> <span class="nf">ReceiveEventGridPost</span><span class="p">([</span><span class="n">FromBody</span><span class="p">]</span> <span class="kt">object</span> <span class="n">content</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="nf">HandleEvent</span><span class="p">(</span><span class="n">content</span><span class="p">.</span><span class="nf">ToString</span><span class="p">());</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">ActionResult</span> <span class="nf">HandleEvent</span><span class="p">(</span><span class="kt">string</span> <span class="n">content</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">eventGridSubscriber</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">EventGridSubscriber</span><span class="p">();</span>
        <span class="kt">var</span> <span class="n">eventGridEvents</span> <span class="p">=</span> <span class="n">eventGridSubscriber</span><span class="p">.</span><span class="nf">DeserializeEventGridEvents</span><span class="p">(</span><span class="n">content</span><span class="p">);</span>

        <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">eventGridEvent</span> <span class="k">in</span> <span class="n">eventGridEvents</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="c1">// EventGrid will send verification request and we need to reply with given code</span>
            <span class="c1">// otherwise event subscription creation will fail in Azure and no data will be sent to this endpoint</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">eventGridEvent</span><span class="p">.</span><span class="n">Data</span> <span class="k">is</span> <span class="n">SubscriptionValidationEventData</span> <span class="n">eventData</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="k">return</span> <span class="nf">Ok</span><span class="p">(</span><span class="k">new</span> <span class="n">SubscriptionValidationResponse</span> <span class="p">{</span> <span class="n">ValidationResponse</span> <span class="p">=</span> <span class="n">eventData</span><span class="p">.</span><span class="n">ValidationCode</span> <span class="p">});</span>
            <span class="p">}</span>

            <span class="k">if</span> <span class="p">(</span><span class="n">eventGridEvent</span><span class="p">.</span><span class="n">Data</span> <span class="k">is</span> <span class="n">StorageBlobCreatedEventData</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="n">_buffer</span><span class="p">.</span><span class="nf">TryAdd</span><span class="p">();</span>
            <span class="p">}</span>
        <span class="p">}</span>

        <span class="k">return</span> <span class="nf">Ok</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>With this buffer in place responses are sent almost immediately after request is received in this EventGrid receiver controller.</p>

<p>Visually our architecture is now looking something like this:</p>

<p><img src="/assets/img/2020/08/brtts-p4-2.png" alt="brtts-p4-2" /></p>

<p>We are missing some of the parts that we are going to fill in soon.</p>

<h2 id="data-processing-pipeline">Data Processing Pipeline</h2>

<p>Now as we have data inside channel - we can build reader part to execute some piece of code every time EventGrid receiver controller will write new data to the channel.</p>

<p>Reader side on the channel is long-running process that needs to sit in the background and process items only when there is something on the channel.</p>

<p>This really sounds a perfect use case for new .NET Core feature - <a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-3.1&amp;tabs=visual-studio">BackgroundService</a>.</p>

<p>Let’s start with empty template for the service:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">SnapshotDispatcherBackgroundService</span> <span class="p">:</span> <span class="n">BackgroundService</span>
<span class="p">{</span>
    <span class="k">protected</span> <span class="k">override</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">ExecuteAsync</span><span class="p">(</span><span class="n">CancellationToken</span> <span class="n">stoppingToken</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Second, in order for us to the this service up &amp; running, we need to register it in the service collection (usually this is done in <code class="language-plaintext highlighter-rouge">Startup.cs</code> file):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">services</span><span class="p">.</span><span class="n">AddHostedService</span><span class="p">&lt;</span><span class="n">SnapshotDispatcherBackgroundService</span><span class="p">&gt;();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Having abstractions around <code class="language-plaintext highlighter-rouge">Channel&lt;T&gt;</code> data structure we can provide with some nice methods for the reader part. Essentially what we need to get - is a message pump that is invoked every time there is a new item in the channel and preferably not to block the thread.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="nf">SnapshotDispatcherBackgroundService</span><span class="p">(</span><span class="n">SnapshotReceiverBuffer</span> <span class="n">buffer</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">_buffer</span> <span class="p">=</span> <span class="n">buffer</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">protected</span> <span class="k">override</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">ExecuteAsync</span><span class="p">(</span><span class="n">CancellationToken</span> <span class="n">stoppingToken</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">try</span>
    <span class="p">{</span>
        <span class="k">while</span> <span class="p">(</span><span class="k">await</span> <span class="n">_buffer</span><span class="p">.</span><span class="nf">WaitToReadAsync</span><span class="p">(</span><span class="n">stoppingToken</span><span class="p">).</span><span class="nf">ConfigureAwait</span><span class="p">(</span><span class="k">false</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="k">try</span>
            <span class="p">{</span>
                <span class="c1">// we have received data</span>
                <span class="n">_buffer</span><span class="p">.</span><span class="nf">MarkAllAsRead</span><span class="p">();</span>

                <span class="c1">// fetch data from storage</span>
                <span class="kt">var</span> <span class="n">latestData</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">FetchLatestSnapshot</span><span class="p">().</span><span class="nf">ConfigureAwait</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>

                <span class="c1">// prepare data for profiles</span>
                <span class="c1">// TODO</span>

                <span class="c1">// we are ready now to broadcast the data</span>
                <span class="c1">// TODO</span>
            <span class="p">}</span>
            <span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">e</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="c1">// log</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">ex</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// log</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Here we are using cool feature - async <code class="language-plaintext highlighter-rouge">while</code> loop. We can run <code class="language-plaintext highlighter-rouge">while</code> loop and await asynchronously till the moment then <code class="language-plaintext highlighter-rouge">Channel&lt;T&gt;</code> reader gives us signal that it’s now time to start reading message from the channel - because somebody wrote one or more messages there. Thanks to <code class="language-plaintext highlighter-rouge">await</code> - we are not blocking here.</p>

<p>Now we have something more in our architecture:</p>

<p><img src="/assets/img/2020/08/brtts-p4-3-1.png" alt="brtts-p4-3-1" /></p>

<p>But before we get started with data broadcast, we have to cover data processing step here before broadcast - data profiles.</p>

<h3 id="data-profiles">Data Profiles</h3>

<p>When data is received from EventGrid we are going to broadcast it to the connected clients (either mobile app, browser or any other system).
Before data is sent to clients - some processing has to be done. For example - we should do simple filtering - for example remove all vehicles with invalid coordinates(<code class="language-plaintext highlighter-rouge">Lat = 0, Lng = 0</code>). These vehicles otherwise would be located on “Null Island”. This is step that could be shared across all connected clients and we can execute <code class="language-plaintext highlighter-rouge">InvalidCoordinatesFilter</code> on the server.</p>

<p>Another filtering type - <code class="language-plaintext highlighter-rouge">VehicleStatusFilter</code>. Every vehicle in the snapshot has different status - some of them are on service journey (status = on duty), some of them are parked at depots (status = parked), etc. Depending on visitor “access level” you might see only vehicles with status “on duty”, or you might see all vehicles. Depending who you are - you have specific “data profile” assigned on first visit on the map page.</p>

<p>This is what we call - “Data Profiles”. It’s the shape of the data that is going to be sent to the clients.</p>

<p>Profiles are composed out of individual processing options. Processing options are part of the request to the broadcast service. Either filter is enabled or disabled. In order to avoid duplicate processing and waste of resources - we are going to analyze and compare combination of supplied processing options and construct new data profile only in those cases when there is no one else with the same combination. This would allow us to construct unique data profile and do filtering and processing only once.</p>

<p>We will get to the actual implementation of gRPC service and client proxy code generation, but for now let’s assume that client application is able to pass in processing options somehow.</p>

<p>This is gRPC method that’s being invoked from the client code:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">override</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">Subscribe</span><span class="p">(</span>
    <span class="n">SubscribeRequest</span> <span class="n">request</span><span class="p">,</span>
    <span class="n">IServerStreamWriter</span><span class="p">&lt;</span><span class="n">SubscribeResponse</span><span class="p">&gt;</span> <span class="n">responseStream</span><span class="p">,</span>
    <span class="n">ServerCallContext</span> <span class="n">context</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">_processingOptions</span> <span class="p">=</span> <span class="n">request</span><span class="p">.</span><span class="n">DataProcessingOptions</span><span class="p">;</span>
    <span class="n">_profileStore</span><span class="p">.</span><span class="nf">TryRegister</span><span class="p">(</span><span class="n">_processingOptions</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Here essentially we have implemented a method that is invoked every time new client is connected to the gRPC service and subscribing to vehicle data stream. Don’t worry about all the unknowns there - we will cover those in more details soon.</p>

<p>Client has supplied processing options when connecting to the gRPC service, and from these options we are constructing specific data profile.</p>

<p>This is pretty naive implementation of profile store. It does not support yet data profile teardown - or process when last client with specific profile disconnects from the server - we should also remove this profile from the profile store, as there are no reasons to “prepare” data for that profile anymore.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">MapDataProfileStore</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">ConcurrentDictionary</span><span class="p">&lt;</span><span class="n">DataProcessingOptions</span><span class="p">,</span> <span class="n">ProfileData</span><span class="p">&gt;</span> <span class="n">_profiles</span> <span class="p">=</span>
        <span class="k">new</span> <span class="n">ConcurrentDictionary</span><span class="p">&lt;</span><span class="n">DataProcessingOptions</span><span class="p">,</span> <span class="n">ProfileData</span><span class="p">&gt;();</span>

    <span class="k">public</span> <span class="kt">int</span> <span class="n">Count</span> <span class="p">=&gt;</span> <span class="n">_profiles</span><span class="p">.</span><span class="n">Count</span><span class="p">;</span>

    <span class="k">public</span> <span class="kt">bool</span> <span class="nf">TryRegister</span><span class="p">(</span><span class="n">DataProcessingOptions</span> <span class="n">processingOptions</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">processingOptions</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span> <span class="k">return</span> <span class="k">false</span><span class="p">;</span>

        <span class="kt">bool</span> <span class="n">result</span><span class="p">;</span>

        <span class="k">if</span> <span class="p">(!</span><span class="n">_profiles</span><span class="p">.</span><span class="nf">ContainsKey</span><span class="p">(</span><span class="n">processingOptions</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="kt">var</span> <span class="n">profile</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ProfileData</span><span class="p">();</span>
            <span class="n">result</span> <span class="p">=</span> <span class="n">_profiles</span><span class="p">.</span><span class="nf">TryAdd</span><span class="p">(</span><span class="n">processingOptions</span><span class="p">,</span> <span class="n">profile</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="k">else</span>
        <span class="p">{</span>
            <span class="n">result</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now our system architecture has following look:</p>

<p><img src="/assets/img/2020/08/brtts-p4-4.png" alt="brtts-p4-4" /></p>

<p>This profile store allows us to do bookkeeping of data profiles across all connected clients.</p>

<h3 id="shaping-data-for-profiles">Shaping Data for Profiles</h3>

<p>Now when we have defined what data profiles are - we can slice and shape received data from EventGrid to appropriate profilers.</p>

<p>For that - we will ask profile store to do the work. Our receiver code now is following:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="nf">SnapshotDispatcherBackgroundService</span><span class="p">(</span>
    <span class="n">SnapshotReceiverBuffer</span> <span class="n">buffer</span><span class="p">,</span>
    <span class="n">MapDataProfileStore</span> <span class="n">profileStore</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">_buffer</span> <span class="p">=</span> <span class="n">buffer</span><span class="p">;</span>
    <span class="n">_profileStore</span> <span class="p">=</span> <span class="n">profileStore</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">protected</span> <span class="k">override</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">ExecuteAsync</span><span class="p">(</span><span class="n">CancellationToken</span> <span class="n">stoppingToken</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">try</span>
    <span class="p">{</span>
        <span class="k">while</span> <span class="p">(</span><span class="k">await</span> <span class="n">_buffer</span><span class="p">.</span><span class="nf">WaitToReadAsync</span><span class="p">(</span><span class="n">stoppingToken</span><span class="p">).</span><span class="nf">ConfigureAwait</span><span class="p">(</span><span class="k">false</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="k">try</span>
            <span class="p">{</span>
                <span class="c1">// we have received data</span>
                <span class="n">_buffer</span><span class="p">.</span><span class="nf">MarkAllAsRead</span><span class="p">();</span>

                <span class="c1">// fetch data from storage</span>
                <span class="kt">var</span> <span class="n">latestData</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">FetchLatestSnapshot</span><span class="p">().</span><span class="nf">ConfigureAwait</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>

                <span class="c1">// prepare data for profiles</span>
                <span class="n">_profileStore</span><span class="p">.</span><span class="nf">PrepareData</span><span class="p">(</span><span class="n">latestData</span><span class="p">);</span>

                <span class="c1">// we are ready now to broadcast the data</span>
                <span class="c1">// TODO</span>
            <span class="p">}</span>
            <span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">e</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="c1">// log</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">ex</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// log</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Profile store actually has no idea how to process data, but this job is delegated further to data processing pipeline:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">MapDataProfileStore</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">DataProcessingPipeline</span> <span class="n">_processorPipeline</span><span class="p">;</span>

    <span class="k">private</span> <span class="k">readonly</span> <span class="n">ConcurrentDictionary</span><span class="p">&lt;</span><span class="n">MapDataOptions</span><span class="p">,</span> <span class="n">ProfileData</span><span class="p">&gt;</span> <span class="n">_profiles</span> <span class="p">=</span>
        <span class="k">new</span> <span class="n">ConcurrentDictionary</span><span class="p">&lt;</span><span class="n">MapDataOptions</span><span class="p">,</span> <span class="n">ProfileData</span><span class="p">&gt;();</span>

    <span class="k">public</span> <span class="nf">MapDataProfileStore</span><span class="p">(</span><span class="n">DataProcessingPipeline</span> <span class="n">processorPipeline</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_processorPipeline</span> <span class="p">=</span> <span class="n">processorPipeline</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">PrepareData</span><span class="p">(</span><span class="n">SnapshotBroadcastWorkItem</span><span class="p">.</span><span class="n">Data</span> <span class="n">latestSnapshot</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">Parallel</span><span class="p">.</span><span class="nf">ForEach</span><span class="p">(</span>
            <span class="n">_profiles</span><span class="p">,</span>
            <span class="n">pair</span> <span class="p">=&gt;</span>
            <span class="p">{</span>
                <span class="c1">// create working copy of the data</span>
                <span class="kt">var</span> <span class="n">copy</span> <span class="p">=</span> <span class="n">latestSnapshot</span><span class="p">.</span><span class="nf">Clone</span><span class="p">();</span>
                <span class="kt">var</span> <span class="p">(</span><span class="n">options</span><span class="p">,</span> <span class="k">value</span><span class="p">)</span> <span class="p">=</span> <span class="n">pair</span><span class="p">;</span>

                <span class="c1">// do the actual data processing</span>
                <span class="k">value</span><span class="p">.</span><span class="n">Snapshot</span> <span class="p">=</span> <span class="n">_processorPipeline</span><span class="p">.</span><span class="nf">Process</span><span class="p">(</span><span class="n">copy</span><span class="p">.</span><span class="n">TransportDataModel</span><span class="p">,</span> <span class="n">options</span><span class="p">);</span>
            <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As data processing is more or less CPU intensive usually - we made it a bit faster by running as much parallel processing as we could by using <code class="language-plaintext highlighter-rouge">Parallel.ForEach()</code> feature originally coming form TPL (Task Parallel Library).</p>

<p>And data processor pipeline is more or less straight process to run through various registered processors and filters:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">DataProcessingPipeline</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">IVehicleDataProcessor</span><span class="p">&gt;</span> <span class="n">_processors</span><span class="p">;</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">IVehicleDataFilter</span><span class="p">&gt;</span> <span class="n">_filters</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">DataProcessingPipeline</span><span class="p">(</span>
        <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">IVehicleDataProcessor</span><span class="p">&gt;</span> <span class="n">processors</span><span class="p">,</span>
        <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">IVehicleDataFilter</span><span class="p">&gt;</span> <span class="n">filters</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_processors</span> <span class="p">=</span> <span class="n">processors</span> <span class="p">??</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">IVehicleDataProcessor</span><span class="p">&gt;();</span>
        <span class="n">_filters</span> <span class="p">=</span> <span class="n">filters</span> <span class="p">??</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">IVehicleDataFilter</span><span class="p">&gt;();</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">TransportDataModel</span> <span class="nf">Process</span><span class="p">(</span><span class="n">TransportDataModel</span> <span class="n">model</span><span class="p">,</span> <span class="n">MapDataOptions</span> <span class="n">options</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="n">model</span><span class="p">;</span>

        <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">processor</span> <span class="k">in</span> <span class="n">_processors</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">result</span> <span class="p">=</span> <span class="n">processor</span><span class="p">.</span><span class="nf">Process</span><span class="p">(</span><span class="k">ref</span> <span class="n">result</span><span class="p">,</span> <span class="n">options</span><span class="p">);</span>
        <span class="p">}</span>

        <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">processor</span> <span class="k">in</span> <span class="n">_filters</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">result</span> <span class="p">=</span> <span class="n">processor</span><span class="p">.</span><span class="nf">Filter</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">options</span><span class="p">);</span>
        <span class="p">}</span>

        <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>List of processors and filters are configured as multiple implementations of specific interfaces:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="c1">// vehicle data processing pipeline</span>
<span class="n">services</span><span class="p">.</span><span class="n">AddSingleton</span><span class="p">&lt;</span><span class="n">DataProcessingPipeline</span><span class="p">&gt;();</span>
<span class="n">services</span><span class="p">.</span><span class="n">AddSingleton</span><span class="p">&lt;</span><span class="n">IVehicleDataProcessor</span><span class="p">,</span> <span class="n">DelayStatusProcessor</span><span class="p">&gt;();</span>
<span class="n">services</span><span class="p">.</span><span class="n">AddSingleton</span><span class="p">&lt;</span><span class="n">IVehicleDataFilter</span><span class="p">,</span> <span class="n">InvalidCoordinatesFilter</span><span class="p">&gt;();</span>
<span class="n">services</span><span class="p">.</span><span class="n">AddSingleton</span><span class="p">&lt;</span><span class="n">IVehicleDataFilter</span><span class="p">,</span> <span class="n">UnknownStatusesFilter</span><span class="p">&gt;();</span>
<span class="n">services</span><span class="p">.</span><span class="n">AddSingleton</span><span class="p">&lt;</span><span class="n">IVehicleDataFilter</span><span class="p">,</span> <span class="n">ParkedBusFilter</span><span class="p">&gt;();</span>
<span class="n">services</span><span class="p">.</span><span class="n">AddSingleton</span><span class="p">&lt;</span><span class="n">IVehicleDataFilter</span><span class="p">,</span> <span class="n">VehicleTypesFilter</span><span class="p">&gt;();</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If we zoom in following are internals of the single profile data creation:</p>

<p><img src="/assets/img/2020/08/brtts-p4-5-1.png" alt="brtts-p4-5-1" /></p>

<p>Now when have got through data processing pipeline and prepared data for various profiles we are finally ready for data broadcast to connected clients.</p>

<p>This is story for another gRPC and SignalR focused post.</p>

<p>Happy coding!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="gRPC" /><category term="Azure" /><category term=".net" /><category term="c#" /><category term="grpc" /><category term="azure" /><summary type="html"><![CDATA[This is next post in series about real-time public transport tracking system development based on Azure infrastructure and services. This article is a part of Applied Cloud Stories initiative - aka.ms/applied-cloud-stories.]]></summary></entry><entry><title type="html">Localization Provider Update</title><link href="https://tech-fellow.eu/2020/07/09/localization-provider-update/" rel="alternate" type="text/html" title="Localization Provider Update" /><published>2020-07-09T19:10:00+03:00</published><updated>2020-07-09T19:10:00+03:00</updated><id>https://tech-fellow.eu/2020/07/09/localization-provider-update</id><content type="html" xml:base="https://tech-fellow.eu/2020/07/09/localization-provider-update/"><![CDATA[<p>Hi all,</p>

<p>Not a huge pile of news and features (those I’ve saved for v7.0).</p>

<p>It’s been a while since v1.0 of LocalizationProvider. Originally it has its inception during <a href="https://getadigital.com">my company’s</a> hackathon - we were trying to solve some of the outstanding issues that we came across while working with localized resources based on XML files in <a href="https://world.episerver.com">Episerver CMS</a> platform. It was few years ago.</p>

<p>At first, package back then was humble enough only to target Episerver as supported runtime. But over the time - I saw opportunity (and actually requirement in one of our projects) to support also classical ASP.NET applications (MVC). And of course - <a href="https://docs.microsoft.com/en-us/aspnet/core/">ASP.NET Core</a> came as logical continuation of the journey.</p>

<p>Since then I was working mostly alone on the project. But somehow during v6 development - I started to receive some really great contributions from the community.</p>

<p>For example, in v6 I extracted underlying SQL Server dependency (and also threw out EF dependency - which actually unfortunately led to startup performance improvements). Unfortunately - because IMHO EF has its potential but there are definitely <a href="https://twitter.com/isaac_abraham/status/1279817037255229440">space for improvement</a>. By extracting dependency into its own package - I introduced provider-based infrastructure (still some things needs to be cleaned-up and moved to base library). And this extraction led to new package - storage implementation based on <a href="https://www.nuget.org/packages/LocalizationProvider.Storage.PostgreSql/">PostgreSQL database engine</a>. For which I just had to do some minor code reformatting and merging into master.</p>

<p>Probably I should blog about provider model and CQRS approach which resulted in quite nice extensible / overwritable feature.</p>

<p>Just wanted to shout out big thanks to everyone who has contributed to the project!!</p>

<p>In latest v6.2 there are some other smaller features and bug fixes (also - mostly contributed by community). You can follow list of issues <a href="https://github.com/valdisiljuconoks/LocalizationProvider/milestone/20">here</a>, <a href="https://github.com/valdisiljuconoks/localization-provider-core/milestone/6">here</a> and <a href="https://github.com/valdisiljuconoks/localization-provider-opti/milestone/12">here</a>. So if you have stumbled upon one of them - please take time and update packages.</p>

<p>Some sneak peek for v7:</p>

<ul>
  <li>usability features for Episerver and .NET Core AdminUI</li>
  <li>end of support for classical ASP.NET MVC runtime (relevant code base will be merged into base package)</li>
  <li>import/preview for .NET Core AdminUI</li>
  <li>support for adding notes / comments for resources</li>
  <li>proper support for multi-instance startup in Azure</li>
  <li>storage implementation for <a href="https://docs.microsoft.com/en-us/azure/cosmos-db/table-storage-overview">Azure Table Storage</a></li>
  <li>merge of GitHub repositories back to single one (over the time its proven that submodules are not necessary in this project)</li>
</ul>

<p>If you have any additional feature request / bug report - please file it in <a href="https://github.com/valdisiljuconoks/localizationprovider/issues">GitHub</a>.</p>

<p>Happy localizing and hold-on for the v7 :)</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="Localization Provider" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization provider" /><category term="localization" /><summary type="html"><![CDATA[Hi all,]]></summary></entry><entry><title type="html">Building Real-time Public Transport Tracking System on Azure - Part 3</title><link href="https://tech-fellow.eu/2020/04/09/building-real-time-public-transport-tracking-system-on-azure-part-3/" rel="alternate" type="text/html" title="Building Real-time Public Transport Tracking System on Azure - Part 3" /><published>2020-04-09T11:00:00+03:00</published><updated>2020-04-09T11:00:00+03:00</updated><id>https://tech-fellow.eu/2020/04/09/building-real-time-public-transport-tracking-system-on-azure-part-3</id><content type="html" xml:base="https://tech-fellow.eu/2020/04/09/building-real-time-public-transport-tracking-system-on-azure-part-3/"><![CDATA[<p>This is next post in series about real-time public transport tracking system development based on Azure infrastructure and services. This article is a part of Applied Cloud Stories initiative - <a href="https://aka.ms/applied-cloud-stories">aka.ms/applied-cloud-stories</a>.</p>

<p>Blog posts in this series:</p>

<ul>
  <li><a href="https://tech-fellow.eu/2019/12/08/building-real-time-public-transport-tracking-system-on-azure-part1/">Part 1 - Scene Background &amp; Solution Architecture</a></li>
  <li><a href="https://tech-fellow.eu/2020/01/21/building-real-time-public-transport-tracking-system-on-azure-part-2-data-collectors-composer/">Part 2 - Data Collectors &amp; Composer</a></li>
  <li><strong>Part 3 - Event-Based Data Delivery</strong></li>
  <li><a href="https://tech-fellow.eu/2020/08/30/building-real-time-public-transport-tracking-system-on-azure-part-4/">Part 4 - Data Processing Pipelines</a></li>
  <li><a href="https://tech-fellow.eu/2020/11/01/building-real-time-public-transport-tracking-system-on-azure-part-5/">Part 5 - Data Broadcast using gRPC and SignalR</a></li>
  <li><a href="https://tech-fellow.eu/2020/12/14/building-real-time-public-transport-tracking-system-on-azure-part-6-building-frontend/">Part 6 - Building Frontend</a></li>
  <li><a href="https://tech-fellow.eu/2021/01/21/building-real-time-public-transport-tracking-system-on-azure-part-6-packing-everything-up/">Part 7 - Packing Everything Up</a></li>
  <li><a href="https://tech-fellow.eu/2021/01/25/building-linux-docker-images-on-windows-machine/">Part 7.1 - Fixing Docker Image Metrics in Azure</a></li>
</ul>

<h2 id="background">Background</h2>

<p>In <a href="/2020/01/21/building-real-time-public-transport-tracking-system-on-azure-part-2-data-collectors-composer/">previous blog post</a>, we ended story with state when data is written to the Azure Storage table and blob combination. Collector functions together with Composer WebJob is running smoothly on more or less constant frequency and producing data steadily.</p>

<p>Now we have a task in front of us to deliver this information further to our beloved subscribers. Subscriber here means any other system that is interested in receiving this information and process it further - for example, push data down to the connected clients via browsers.</p>

<p>Of course subscribers could just periodically check for the new data by asking server every X seconds, for example. But then in this case I would not call them subscribers, but spammers. Azure infrastructure should be responsible for delivering this information to subscribers that new snapshot has been generated. This is reactive event-based system architecture.</p>

<p>Scanning <a href="https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-event-overview">feature set documentation</a> for Azure Storage service you might find <strong>EventGrid</strong> keyword.</p>

<p>Essentially we will be implementing now everything that’s needed from blue icon on the right side:</p>

<p><img src="/assets/img/2020/04/5.2.png" alt="5.2" /></p>

<h2 id="reactive-event-publishing">Reactive Event Publishing</h2>

<p>For creating reactive event-based systems in Azure infrastructure EventGrid is ideal recipe for this.</p>

<p>But before we can proceed with EventGrid setup in Azure, we need to establish listener on the receiving side. This is required before setting up EventGrid because during EventGrid setup in Azure data is sent to the endpoint - so there has to be somebody listening on that address.</p>

<p>Otherwise you will end up with situation that endpoint verification just fails.</p>

<p><img src="/assets/img/2020/04/eventgrid-endpoint-validation.png" alt="eventgrid-endpoint-validation" /></p>

<h3 id="create-eventgrid-receiver">Create EventGrid Receiver</h3>

<p>Before you can proceed with EventGrid subscription setup in Azure, you need to establish receiving endpoint otherwise endpoint validation will fail. There has to be somebody answering on that endpoint.</p>

<p>For this we will need a simple web application. Let’s create WebAPI placeholder endpoint for this:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
</pre></td><td class="rouge-code"><pre><span class="k">using</span> <span class="nn">System.Threading.Tasks</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">Microsoft.AspNetCore.Mvc</span><span class="p">;</span>

<span class="k">namespace</span> <span class="nn">MySampleProject.EventGridReceiver</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">ApiController</span><span class="p">]</span>
    <span class="p">[</span><span class="nf">Route</span><span class="p">(</span><span class="s">"api/eg"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">EventGridReceiverController</span> <span class="p">:</span> <span class="n">ControllerBase</span>
    <span class="p">{</span>
        <span class="p">[</span><span class="nf">Route</span><span class="p">(</span><span class="s">"receiver"</span><span class="p">)]</span>
        <span class="p">[</span><span class="n">HttpPost</span><span class="p">]</span>
        <span class="k">public</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">ActionResult</span><span class="p">&gt;</span> <span class="nf">ReceiveEventGridPost</span><span class="p">([</span><span class="n">FromBody</span><span class="p">]</span> <span class="kt">object</span> <span class="n">content</span> <span class="cm">/* not sure why but we need object for ModelBinder to work */</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">await</span> <span class="nf">HandleEventAsync</span><span class="p">(</span><span class="n">content</span><span class="p">.</span><span class="nf">ToString</span><span class="p">());</span>

            <span class="k">return</span> <span class="nf">Ok</span><span class="p">();</span>
        <span class="p">}</span>

        <span class="k">public</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">ActionResult</span><span class="p">&gt;</span> <span class="nf">HandleEventAsync</span><span class="p">(</span><span class="kt">string</span> <span class="n">content</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="c1">// do the magic with received event</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So far so good. Looks like endpoint is setup and it’s ready to receive requests from EventGrid.</p>

<h3 id="setup-eventgrid-in-azure">Setup EventGrid in Azure</h3>

<p>One of the way to create new EventGrid subscription is doing that in Azure Portal:
<img src="/assets/img/2020/04/Picture1.png" alt="Picture1" />
Another way (when you feel hack-ish) is via Azure CLI.</p>

<p>If you haven’t used EventGrid services before in your subscription, you might need to register this provider.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>az login
az provider register --namespace Microsoft.EventGrid
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then we need to fetch FQN of the storage account which we would be using as source for the events (in our case it’s “buffer” storage):</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nv">$storageid</span><span class="o">=</span><span class="err">$</span><span class="p">(</span><span class="n">az</span><span class="w"> </span><span class="nx">storage</span><span class="w"> </span><span class="nx">account</span><span class="w"> </span><span class="nx">show</span><span class="w"> </span><span class="nt">--name</span><span class="w"> </span><span class="nx">buffer</span><span class="w"> </span><span class="nt">--resource-group</span><span class="w"> </span><span class="err">&lt;</span><span class="nx">resource-group</span><span class="err">&gt;</span><span class="w"> </span><span class="nt">--query</span><span class="w"> </span><span class="nx">id</span><span class="w"> </span><span class="nt">--output</span><span class="w"> </span><span class="nx">tsv</span><span class="p">)</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>You can define your endpoint as variable (<code class="language-plaintext highlighter-rouge">$endpoint</code>) or just pass inline.</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="n">az</span><span class="w"> </span><span class="nx">eventgrid</span><span class="w"> </span><span class="nx">event-subscription</span><span class="w"> </span><span class="nx">create</span><span class="w"> </span><span class="nx">\</span><span class="w">
    </span><span class="nt">--source-resource-id</span><span class="w"> </span><span class="nv">$storageid</span><span class="w"> </span><span class="n">\</span><span class="w">
    </span><span class="nt">--subject-begins-with</span><span class="w"> </span><span class="s1">'transportData'</span><span class="w"> </span><span class="nx">\</span><span class="w">
    </span><span class="nt">--name</span><span class="w"> </span><span class="n">to-rt-map-endpoint</span><span class="w"> </span><span class="nx">\</span><span class="w">
    </span><span class="nt">--endpoint</span><span class="w"> </span><span class="nv">$endpoint</span><span class="w">
    </span><span class="nt">--endpoint-type</span><span class="w"> </span><span class="n">webhook</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>However, after setup of this EventGrid subscription and waiting for a bit (you know, just in case) nothing really happens..
<img src="/assets/img/2020/04/Picture2-1.png" alt="Picture2-1" />
I see no heartbeats (being sure that blobs are updated regularly in storage), nothing. It’s single dead line.</p>

<h3 id="eventgrid-endpoint-verification">EventGrid Endpoint Verification</h3>

<p>If I wouldn’t be so lazy and would read what’s been thrown at me, then I would be aware that in order to setup EventGrid event submission to custom webhook endpoint, you have to pass endpoint verification procedure.</p>

<p>Meaning that we need to reply with received verification token prior we are able to receive any events from EventGrid.</p>

<p>So we need to change our endpoint a bit:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">ApiController</span><span class="p">]</span>
<span class="p">[</span><span class="nf">Route</span><span class="p">(</span><span class="s">"api/eg"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">EventGridReceiverController</span> <span class="p">:</span> <span class="n">ControllerBase</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">Route</span><span class="p">(</span><span class="s">"receiver"</span><span class="p">)]</span>
    <span class="p">[</span><span class="n">HttpPost</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">ActionResult</span><span class="p">&gt;</span> <span class="nf">ReceiveEventGridPost</span><span class="p">([</span><span class="n">FromBody</span><span class="p">]</span> <span class="kt">object</span> <span class="n">content</span> <span class="cm">/* not sure why but we need object for ModelBinder to work */</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="k">await</span> <span class="nf">HandleEventAsync</span><span class="p">(</span><span class="n">content</span><span class="p">.</span><span class="nf">ToString</span><span class="p">());</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">ActionResult</span><span class="p">&gt;</span> <span class="nf">HandleEventAsync</span><span class="p">(</span><span class="kt">string</span> <span class="n">content</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">eventGridSubscriber</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">EventGridSubscriber</span><span class="p">();</span>
        <span class="kt">var</span> <span class="n">eventGridEvents</span> <span class="p">=</span> <span class="n">eventGridSubscriber</span><span class="p">.</span><span class="nf">DeserializeEventGridEvents</span><span class="p">(</span><span class="n">content</span><span class="p">);</span>

        <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">eventGridEvent</span> <span class="k">in</span> <span class="n">eventGridEvents</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="c1">// EventGrid will send verification request and we need to reply with given code</span>
            <span class="c1">// otherwise event subscription creation will fail in Azure and no data will be sent to this endpoint</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">eventGridEvent</span><span class="p">.</span><span class="n">Data</span> <span class="k">is</span> <span class="n">SubscriptionValidationEventData</span> <span class="n">eventData</span><span class="p">)</span>
                <span class="k">return</span> <span class="nf">Ok</span><span class="p">(</span><span class="k">new</span> <span class="n">SubscriptionValidationResponse</span>
                <span class="p">{</span>
                    <span class="n">ValidationResponse</span> <span class="p">=</span> <span class="n">eventData</span><span class="p">.</span><span class="n">ValidationCode</span>
                <span class="p">});</span>

            <span class="k">if</span> <span class="p">(</span><span class="n">eventGridEvent</span><span class="p">.</span><span class="n">Data</span> <span class="k">is</span> <span class="n">StorageBlobCreatedEventData</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="c1">// do the magic with event</span>
            <span class="p">}</span>
        <span class="p">}</span>

        <span class="k">return</span> <span class="nf">Ok</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now it seems alive.</p>

<p><img src="/assets/img/2020/04/Picture4-2.png" alt="Picture4-2" /></p>

<h2 id="max-delivery-attempts">Max Delivery Attempts</h2>

<p><strong>NB!</strong> Be aware of default settings when creating EG subscriber endpoints.
<a href="https://docs.microsoft.com/en-us/cli/azure/eventgrid/event-subscription?view=azure-cli-latest#optional-parameters">By default</a> EG is created with re-delivery mechanism in mind.</p>

<p>EventGrid will be instructed to keep an eye on failed messages. If infrastructure discovers that message could not be delivered (endpoint returns not 200 OK response) - message is scheduled for redelivery. By default redelivery count will be set to <code class="language-plaintext highlighter-rouge">30</code>.</p>

<p>At some point when your test environment was down, or even shut off and you become back online.. That moment when you are banging your head against table trying to find out the reason why your server suddenly is dying in the middle of the night, where there is almost no visitors.. :)</p>

<p><img src="/assets/img/2020/04/Picture3.png" alt="Picture3" /></p>

<p>As we are dealing with real-time data and lost events in our case for delivery sites does not matter. I mean if we lost event few minutes or even hours ago - no one really cares because visitors are interested in the most recent data. So we can easily ignore lost packages and not bother EG for scheduling redelivery attempt. You can configure redelivery attempt count while creating subscription:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>az eventgrid event-subscription create \
    ...
    --max-delivery-attempts 1
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="next-steps">Next Steps</h2>

<p>Now when we have received event from EG, we able to start implementing handler method. Basically we will need to fill in between the lines here:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">if</span> <span class="p">(</span><span class="n">eventGridEvent</span><span class="p">.</span><span class="n">Data</span> <span class="k">is</span> <span class="n">StorageBlobCreatedEventData</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// magic happens here</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Happy eventing and stay safe!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="gRPC" /><category term="Azure" /><category term=".net" /><category term="c#" /><category term="grpc" /><category term="azure" /><summary type="html"><![CDATA[This is next post in series about real-time public transport tracking system development based on Azure infrastructure and services. This article is a part of Applied Cloud Stories initiative - aka.ms/applied-cloud-stories.]]></summary></entry><entry><title type="html">LocalizationProvider Under the Tests</title><link href="https://tech-fellow.eu/2020/03/31/localizationprovider-under-the-tests/" rel="alternate" type="text/html" title="LocalizationProvider Under the Tests" /><published>2020-03-31T19:00:00+03:00</published><updated>2020-03-31T19:00:00+03:00</updated><id>https://tech-fellow.eu/2020/03/31/localizationprovider-under-the-tests</id><content type="html" xml:base="https://tech-fellow.eu/2020/03/31/localizationprovider-under-the-tests/"><![CDATA[<p>Recently I got a question from a <a href="https://twitter.com/LucGosso">very good friend</a> of mine about how to properly unit test localization provider.</p>

<p>Tests and even unit ones have been one of the areas where we probably all have committed sins. And I’m no exception. Only recently I’ve <a href="https://github.com/valdisiljuconoks/LocalizationProvider/issues/165">added an interface</a> in front of <code class="language-plaintext highlighter-rouge">LocalizationProvider</code> class to make it easier to work in unit tests.</p>

<p>Adding an interface is just part of the solution (and the easiest one). Writing unit test for the localization provider turned out not to be so easy.</p>

<h2 id="unit-test-with-fakeiteasy">Unit Test with FakeItEasy</h2>

<p>Challenge to write proper unit tests for the localization provider is due to fact that library heavily relies on <a href="https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/expressions">expressions</a> (aka lambdas).</p>

<h3 id="first-attempt">First Attempt</h3>

<p>I would write this naive unit tests in hope that it will run green:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">ResourceClass</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">SomeProperty</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="s">"Some value of the property"</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">SomeServiceWithLocalization</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">ILocalizationProvider</span> <span class="n">_provider</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">SomeServiceWithLocalization</span><span class="p">(</span><span class="n">ILocalizationProvider</span> <span class="n">provider</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_provider</span> <span class="p">=</span> <span class="n">provider</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="kt">string</span> <span class="nf">GetTranslation</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">_provider</span><span class="p">.</span><span class="nf">GetString</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="n">ResourceClass</span><span class="p">.</span><span class="n">SomeProperty</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="p">[</span><span class="n">Fact</span><span class="p">]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">TestInterfaceMock</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">fake</span> <span class="p">=</span> <span class="n">A</span><span class="p">.</span><span class="n">Fake</span><span class="p">&lt;</span><span class="n">ILocalizationProvider</span><span class="p">&gt;();</span>

    <span class="n">A</span><span class="p">.</span><span class="nf">CallTo</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="n">fake</span><span class="p">.</span><span class="nf">GetString</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="n">ResourceClass</span><span class="p">.</span><span class="n">SomeProperty</span><span class="p">)).</span><span class="nf">Returns</span><span class="p">(</span><span class="s">"Fake"</span><span class="p">);</span>

    <span class="kt">var</span> <span class="n">sut</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SomeServiceWithLocalization</span><span class="p">(</span><span class="n">fake</span><span class="p">);</span>

    <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="n">sut</span><span class="p">.</span><span class="nf">GetTranslation</span><span class="p">();</span>

    <span class="n">Assert</span><span class="p">.</span><span class="nf">Equal</span><span class="p">(</span><span class="s">"Fake"</span><span class="p">,</span> <span class="n">result</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>But if you run this - it will be <span style="color: red; font-weight: bold;">red</span>.</p>

<p>This is because FakeItEasy (and other mocking frameworks) uses argument comparer to understand whether specified arguments are the same that has been used to configure mock - and if so, specified behavior (in this case return value) should be executed.</p>

<p>Turns out <code class="language-plaintext highlighter-rouge">Expression</code> is not something that is easy to compare out of the box.
And expression you specified while setting up mock is not the same as one used in <code class="language-plaintext highlighter-rouge">SomeServiceWithLocalization</code>.</p>

<p>You can even compare them directly in unit test:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">Fact</span><span class="p">]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">CompareExpressions</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">Expression</span><span class="p">&lt;</span><span class="n">Func</span><span class="p">&lt;</span><span class="kt">object</span><span class="p">&gt;&gt;</span> <span class="n">exp</span> <span class="p">=</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="n">ResourceClass</span><span class="p">.</span><span class="n">SomeProperty</span><span class="p">;</span>
    <span class="n">Expression</span><span class="p">&lt;</span><span class="n">Func</span><span class="p">&lt;</span><span class="kt">object</span><span class="p">&gt;&gt;</span> <span class="n">exp2</span> <span class="p">=</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="n">ResourceClass</span><span class="p">.</span><span class="n">SomeProperty</span><span class="p">;</span>

    <span class="n">Assert</span><span class="p">.</span><span class="nf">Equal</span><span class="p">(</span><span class="n">exp</span><span class="p">,</span> <span class="n">exp2</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/2020/03/failed-unittest.png" alt="failed-unittest" /></p>

<p>This still fails.</p>

<h2 id="add-expression-comparer">Add Expression Comparer</h2>

<p>What you need to do instead is to teach FakeItEasy how to do an expression comparison.
For this task you can use some ready made packages (like <a href="https://www.nuget.org/packages/Neleus.LambdaCompare/">Neleus.LambdaCompare</a>).</p>

<p>Or you can search around internets and find maybe something suitable for you. I found quite comprehensive expression comparer from <a href="https://gist.github.com/jnm2/83b36ad497b4cb1cbcac">Joseph</a>. This does its job quite well.</p>

<p>Make sure that you copy this somewhere in your unit test project (or shared project that you can use across all your unit tests).</p>

<h2 id="second-attempt">Second Attempt</h2>

<p>With having this comparer in our toolkit we can write second attempt to test localization provider interface.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">Fact</span><span class="p">]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">TestInterfaceMock</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">fake</span> <span class="p">=</span> <span class="n">A</span><span class="p">.</span><span class="n">Fake</span><span class="p">&lt;</span><span class="n">ILocalizationProvider</span><span class="p">&gt;();</span>
    <span class="n">Expression</span><span class="p">&lt;</span><span class="n">Func</span><span class="p">&lt;</span><span class="kt">object</span><span class="p">&gt;&gt;</span> <span class="n">expression</span> <span class="p">=</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="n">ResourceClass</span><span class="p">.</span><span class="n">SomeProperty</span><span class="p">;</span>
    <span class="kt">var</span> <span class="n">comparer</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ExpressionComparer</span><span class="p">();</span>

    <span class="n">A</span>
        <span class="p">.</span><span class="nf">CallTo</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="n">fake</span><span class="p">.</span><span class="nf">GetString</span><span class="p">(</span><span class="n">A</span><span class="p">&lt;</span><span class="n">Expression</span><span class="p">&lt;</span><span class="n">Func</span><span class="p">&lt;</span><span class="kt">object</span><span class="p">&gt;&gt;&gt;.</span><span class="n">That</span><span class="p">.</span><span class="nf">Matches</span><span class="p">(</span><span class="n">e</span> <span class="p">=&gt;</span> <span class="n">comparer</span><span class="p">.</span><span class="nf">Equals</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">e</span><span class="p">))))</span>
        <span class="p">.</span><span class="nf">Returns</span><span class="p">(</span><span class="s">"[SomeProperty] Value from fake"</span><span class="p">);</span>

    <span class="kt">var</span> <span class="n">sut</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SomeServiceWithLocalization</span><span class="p">(</span><span class="n">fake</span><span class="p">);</span>

    <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="n">sut</span><span class="p">.</span><span class="nf">GetTranslation</span><span class="p">();</span>

    <span class="n">Assert</span><span class="p">.</span><span class="nf">Equal</span><span class="p">(</span><span class="s">"[SomeProperty] Value from fake"</span><span class="p">,</span> <span class="n">result</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now this test is <span style="color: green; text-weight: bold;">green</span>.</p>

<p>We can even verify with second expression just to be sure that mock is working as expected.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">ResourceClass</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">SomeProperty</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="s">"Some value of the property"</span><span class="p">;</span>
    <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">SomeProperty2</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="s">"Another translation"</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">SomeServiceWithLocalization</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">ILocalizationProvider</span> <span class="n">_provider</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">SomeServiceWithLocalization</span><span class="p">(</span><span class="n">ILocalizationProvider</span> <span class="n">provider</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_provider</span> <span class="p">=</span> <span class="n">provider</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="kt">string</span> <span class="nf">GetTranslation</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">_provider</span><span class="p">.</span><span class="nf">GetString</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="n">ResourceClass</span><span class="p">.</span><span class="n">SomeProperty</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="kt">string</span> <span class="nf">GetTranslation2</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">_provider</span><span class="p">.</span><span class="nf">GetString</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="n">ResourceClass</span><span class="p">.</span><span class="n">SomeProperty2</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="p">[</span><span class="n">Fact</span><span class="p">]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">TestInterfaceMock</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">fake</span> <span class="p">=</span> <span class="n">A</span><span class="p">.</span><span class="n">Fake</span><span class="p">&lt;</span><span class="n">ILocalizationProvider</span><span class="p">&gt;();</span>
    <span class="n">Expression</span><span class="p">&lt;</span><span class="n">Func</span><span class="p">&lt;</span><span class="kt">object</span><span class="p">&gt;&gt;</span> <span class="n">expression</span> <span class="p">=</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="n">ResourceClass</span><span class="p">.</span><span class="n">SomeProperty</span><span class="p">;</span>
    <span class="n">Expression</span><span class="p">&lt;</span><span class="n">Func</span><span class="p">&lt;</span><span class="kt">object</span><span class="p">&gt;&gt;</span> <span class="n">expression2</span> <span class="p">=</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="n">ResourceClass</span><span class="p">.</span><span class="n">SomeProperty2</span><span class="p">;</span>
    <span class="kt">var</span> <span class="n">comparer</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ExpressionComparer</span><span class="p">();</span>

    <span class="n">A</span>
        <span class="p">.</span><span class="nf">CallTo</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="n">fake</span><span class="p">.</span><span class="nf">GetString</span><span class="p">(</span><span class="n">A</span><span class="p">&lt;</span><span class="n">Expression</span><span class="p">&lt;</span><span class="n">Func</span><span class="p">&lt;</span><span class="kt">object</span><span class="p">&gt;&gt;&gt;.</span><span class="n">That</span><span class="p">.</span><span class="nf">Matches</span><span class="p">(</span><span class="n">e</span> <span class="p">=&gt;</span> <span class="n">comparer</span><span class="p">.</span><span class="nf">Equals</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">e</span><span class="p">))))</span>
        <span class="p">.</span><span class="nf">Returns</span><span class="p">(</span><span class="s">"[SomeProperty] Value from fake"</span><span class="p">);</span>

    <span class="n">A</span>
        <span class="p">.</span><span class="nf">CallTo</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="n">fake</span><span class="p">.</span><span class="nf">GetString</span><span class="p">(</span><span class="n">A</span><span class="p">&lt;</span><span class="n">Expression</span><span class="p">&lt;</span><span class="n">Func</span><span class="p">&lt;</span><span class="kt">object</span><span class="p">&gt;&gt;&gt;.</span><span class="n">That</span><span class="p">.</span><span class="nf">Matches</span><span class="p">(</span><span class="n">e</span> <span class="p">=&gt;</span> <span class="n">comparer</span><span class="p">.</span><span class="nf">Equals</span><span class="p">(</span><span class="n">expression2</span><span class="p">,</span> <span class="n">e</span><span class="p">))))</span>
        <span class="p">.</span><span class="nf">Returns</span><span class="p">(</span><span class="s">"[SomeProperty] Value from fake 2"</span><span class="p">);</span>

    <span class="kt">var</span> <span class="n">sut</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SomeServiceWithLocalization</span><span class="p">(</span><span class="n">fake</span><span class="p">);</span>

    <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="n">sut</span><span class="p">.</span><span class="nf">GetTranslation</span><span class="p">();</span>
    <span class="kt">var</span> <span class="n">result2</span> <span class="p">=</span> <span class="n">sut</span><span class="p">.</span><span class="nf">GetTranslation2</span><span class="p">();</span>

    <span class="n">Assert</span><span class="p">.</span><span class="nf">Equal</span><span class="p">(</span><span class="s">"[SomeProperty] Value from fake"</span><span class="p">,</span> <span class="n">result</span><span class="p">);</span>
    <span class="n">Assert</span><span class="p">.</span><span class="nf">Equal</span><span class="p">(</span><span class="s">"[SomeProperty] Value from fake 2"</span><span class="p">,</span> <span class="n">result2</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Happy unit testing your translations!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="Localization Provider" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization provider" /><category term="localization" /><summary type="html"><![CDATA[Recently I got a question from a very good friend of mine about how to properly unit test localization provider.]]></summary></entry><entry><title type="html">Episerver Localization Provider - Major v6 Released!</title><link href="https://tech-fellow.eu/2020/03/17/episerver-localization-provider-major-v6-released/" rel="alternate" type="text/html" title="Episerver Localization Provider - Major v6 Released!" /><published>2020-03-17T18:00:00+02:00</published><updated>2020-03-17T18:00:00+02:00</updated><id>https://tech-fellow.eu/2020/03/17/episerver-localization-provider-major-v6-released</id><content type="html" xml:base="https://tech-fellow.eu/2020/03/17/episerver-localization-provider-major-v6-released/"><![CDATA[<h2 id="introduction">Introduction</h2>

<p>I’m pleased to announce that v6 of DbLocalizationProvider is finally out to the wild. This stressful and lots of unknowns period was great timing for me to sit down and finish started journey. It’s been a bit bumpy road and longer trip than expected, but here we are..</p>

<p>This post will guide you through some of the most noteworthy changes since last major version.</p>

<p><img src="/assets/img/2020/03/v6-2.png" alt="v6-2" /></p>

<h2 id="major-changes-in-v6">Major Changes in v6</h2>

<ul>
  <li>Library is now licenses under Apache 2.0 license</li>
  <li>Increased lower runtime version up to <code class="language-plaintext highlighter-rouge">net472</code></li>
  <li>Jumped to <a href="https://www.nuget.org/packages/Newtonsoft.Json/12.0.1">JSON.NET v11.0.2</a></li>
  <li>Jumped to <a href="https://nuget.episerver.com/package/?id=EPiServer.CMS&amp;v=11.13.1">Episerver CMS 11.13.1</a> as lower version</li>
  <li>MSSQL as separate package (this opens up extensibility to plugin additional providers). No EF / EFCore dependency anymore.</li>
  <li>Language fallback configuration</li>
  <li>Added interface <code class="language-plaintext highlighter-rouge">ILocalizationProvider</code> for easier unit testing</li>
  <li>Read-only apps</li>
  <li>Logging added to unify functionality across platforms and runtimes</li>
  <li>Smaller bug fixes here and there, as result some of the obsolete query and command handlers were deleted in favor of unified logic across all runtimes (Episerver, ASP.NET &amp; ASP.NET Core)</li>
</ul>

<p>Let’s cover each of the features in more details.</p>

<h2 id="new-features">New Features</h2>

<h3 id="ms-sql-storage-as-separate-package">MS SQL Storage as Separate Package</h3>

<table>
  <tbody>
    <tr>
      <td>One of the biggest change in v6 is that DbLocalizationProvider by default does not have any dependency on EntityFramework</td>
      <td>EFCore anymore and therefore by default if you already have project running on v5.x -&gt; just by upgrading packages to v6 will not solve all your problems.</td>
    </tr>
  </tbody>
</table>

<p>You will need to install additional package with MSSQL Server storage implementation.</p>

<pre><code class="language-cmd">PM&gt; Install-Package LocalizationProvider.Storage.SqlServer
</code></pre>

<p>Once this is done, you need to configure connectionString for the SQL Server package (usually in your <code class="language-plaintext highlighter-rouge">Startup.cs</code> file):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">ServiceContainerInitialization</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">DbLocalizationProviderConnectionSetupModule</span> <span class="p">:</span> <span class="n">IConfigurableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureContainer</span><span class="p">(</span><span class="n">ServiceConfigurationContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="n">ConfigurationManager</span><span class="p">.</span><span class="n">ConnectionStrings</span><span class="p">[</span><span class="s">"EPiServerDB"</span><span class="p">].</span><span class="n">ConnectionString</span><span class="p">;</span>
        <span class="n">ConfigurationContext</span><span class="p">.</span><span class="nf">Setup</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="p">...</span>
            <span class="n">_</span><span class="p">.</span><span class="nf">UseSqlServer</span><span class="p">(</span><span class="n">conection</span><span class="p">);</span>
        <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>NB!</strong> In this example you can see that connection name (<code class="language-plaintext highlighter-rouge">EPiServerDB</code>) has been hard-coded. It’s common name of the connection strings in Episerver. But if you happen (for any reason) to have different connection name of would not like to hard-code it here, then you have retrieve name of the connection from Episerver configuration:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">name</span> <span class="p">=</span> <span class="n">EPiServerDataStoreSection</span><span class="p">.</span><span class="n">Instance</span><span class="p">.</span><span class="n">DataSettings</span><span class="p">.</span><span class="n">ConnectionStringName</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="n">ConfigurationManager</span><span class="p">.</span><span class="n">ConnectionStrings</span><span class="p">[</span><span class="n">name</span><span class="p">].</span><span class="n">ConnectionString</span><span class="p">;</span>

<span class="n">_</span><span class="p">.</span><span class="nf">UseSqlServer</span><span class="p">(</span><span class="n">connection</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>By executing this <code class="language-plaintext highlighter-rouge">UseSqlServer</code> method library will make sure that all necessary query and command handlers are registered to talk to specified database.</p>

<p>At this moment there is no option to customize schema used there (like mapping from your own custom schema to provider’s one). But that might come as I see feature requests on <a href="https://github.com/valdisiljuconoks/localization-provider-core/issues/32">GitHub</a> for this. Vote if you see necessity for your project as well.</p>

<h3 id="fallback-languages">Fallback Languages</h3>

<p>Until v6 fallback languages where somewhat broken and not fully (read “properly”) implemented. I tried to rely on Episerver’s <code class="language-plaintext highlighter-rouge">LocalizationService</code> behavior and rely on fallback mechanism there. But it turned out to be more tricker that initially might sound. Therefore fallback is implemented straight into the library. Which also allows me to provide this feature for other runtimes as well.</p>

<p>By default Episerver initialization module will read fallaback culture value from <code class="language-plaintext highlighter-rouge">web.config</code> file (or which ever other file containing <code class="language-plaintext highlighter-rouge">&lt;episerver.framework&gt;</code> element).</p>

<p>For example (if we take this fragment from config file):</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;episerver.framework&gt;</span>
  ..
  <span class="nt">&lt;localization</span> <span class="na">fallbackBehavior=</span><span class="s">"FallbackCulture, Echo"</span> <span class="na">fallbackCulture=</span><span class="s">"en"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;providers&gt;</span>
      <span class="nt">&lt;add</span> <span class="na">name=</span><span class="s">"db"</span> <span class="na">type=</span><span class="s">"DbLocalizationProvider.EPiServer.DatabaseLocalizationProvider, DbLocalizationProvider.EPiServer"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;/providers&gt;</span>
  <span class="nt">&lt;/localization&gt;</span>
<span class="nt">&lt;/episerver.framework&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Provider initialization module will read this section and make appropriate settings in configuration context:</p>

<ul>
  <li>Fallback behavior is checked. If it does not contain <code class="language-plaintext highlighter-rouge">FallbackCulture</code> no further configuration is done. If behavior contains fallback, then initialization module continues configuring provider.</li>
  <li><code class="language-plaintext highlighter-rouge">English</code> (<code class="language-plaintext highlighter-rouge">"en"</code>) will be used as fallback language.</li>
</ul>

<p>Also you are able to set invariant culture fallback (this means that <code class="language-plaintext highlighter-rouge">CultureInfo.InvariantCulture</code> will be used as last chance for the retrieval of the translation). Invariant culture fallback can be set by:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">ServiceContainerInitialization</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">DbLocalizationProviderConnectionSetupModule</span> <span class="p">:</span> <span class="n">IConfigurableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureContainer</span><span class="p">(</span><span class="n">ServiceConfigurationContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">ConfigurationContext</span><span class="p">.</span><span class="nf">Setup</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="p">...</span>
            <span class="n">_</span><span class="p">.</span><span class="n">EnableInvariantCultureFallback</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
        <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>LocalizationProvider gives you option to configure fallback languages for the library from the code also. If translation in requested language does not exist, list of fallback languages is used to decide which language to try next until either succeeds or fails with no translation found.</p>

<p>To configure fallback languages from code use snippet below:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">ServiceContainerInitialization</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">DbLocalizationProviderConnectionSetupModule</span> <span class="p">:</span> <span class="n">IConfigurableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureContainer</span><span class="p">(</span><span class="n">ServiceConfigurationContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">ConfigurationContext</span><span class="p">.</span><span class="nf">Setup</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="p">...</span>
            <span class="n">_</span><span class="p">.</span><span class="n">FallbackCultures</span>
                <span class="p">.</span><span class="nf">Try</span><span class="p">(</span><span class="k">new</span> <span class="nf">CultureInfo</span><span class="p">(</span><span class="s">"sv"</span><span class="p">))</span>
                <span class="p">.</span><span class="nf">Then</span><span class="p">(</span><span class="k">new</span> <span class="nf">CultureInfo</span><span class="p">(</span><span class="s">"no"</span><span class="p">))</span>
                <span class="p">.</span><span class="nf">Then</span><span class="p">(</span><span class="k">new</span> <span class="nf">CultureInfo</span><span class="p">(</span><span class="s">"en"</span><span class="p">));</span>

        <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Following logic will be used during translation lookup:</p>

<p>1) Developer requests translation in French culture (<code class="language-plaintext highlighter-rouge">"fr"</code>) using <code class="language-plaintext highlighter-rouge">ILocalizationProvider.GetString(() =&gt; ...)</code> method.
2) If translation does not exist -&gt; provider is looking for translation in Swedish  language (<code class="language-plaintext highlighter-rouge">"sv"</code> - first language in the fallback list).
3) If translation does not exist -&gt; provider is looking for translation in Norwegian language (<code class="language-plaintext highlighter-rouge">"no"</code> - second language in the fallback list).
4) If translation is found - one is returned; if not - provider continues process and is looking for translation in English (<code class="language-plaintext highlighter-rouge">"en"</code>).
5) If there is no translation in English -&gt; depending on <code class="language-plaintext highlighter-rouge">ConfigurationContext.EnableInvariantCultureFallback</code> setting -&gt; translation in InvariantCulture may be returned.</p>

<p><strong>NB!</strong> Also worth mentioning that if you would be requesting translation in Norwegian (<code class="language-plaintext highlighter-rouge">"no"</code>) then localization provider is smart enough to understand that requested language is one of the fallback languages and will proceed only with the “rest” of the fallback languages - it this case only <code class="language-plaintext highlighter-rouge">"en"</code> language would be searched and invariant language (if configured so).</p>

<h3 id="localization-provider-hides-behind-interface">Localization Provider Hides Behind Interface</h3>

<p>With request from the community - you can now access provider also via interface <code class="language-plaintext highlighter-rouge">ILocalizationProvider</code>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">SamplePageController</span> <span class="p">:</span> <span class="n">PageController</span><span class="p">&lt;</span><span class="n">SamplePage</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="n">ILocalizationProvider</span> <span class="n">_provider</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">SamplePageController</span><span class="p">(</span><span class="n">ILocalizationProvider</span> <span class="n">provider</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_provider</span> <span class="p">=</span> <span class="n">provider</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">ActionResult</span> <span class="nf">Index</span><span class="p">(</span><span class="n">StartPage</span> <span class="n">currentPage</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">someTranslation</span> <span class="p">=</span> <span class="n">_provider</span><span class="p">.</span><span class="nf">GetString</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="n">SomeResource</span><span class="p">.</span><span class="n">SomeProperty</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Interface mapping and instance is automatically added to Episerver container. Extra registration is not required.</p>

<p>Testing your components should be now much easier.</p>

<h3 id="logging-added-to-all-runtimes">Logging Added to All Runtimes</h3>

<p>I made small effort to unify all runtimes and provider universal API to my own code to do the logging across multiple runtimes. Image SQL Server storage library. That one could be used in Episerver context, pure AS.NET or ASP.NET Core applications. Methods to do the logging should be the same (at least from the library perspective itself). Like:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">SomeLogicInSqlLibrary</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="n">ILogger</span> <span class="n">_logger</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">SomeLogicInSqlLibrary</span><span class="p">(</span><span class="n">ILogger</span> <span class="n">logger</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_logger</span> <span class="p">=</span> <span class="n">logger</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">SomeMethod</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="c1">// perform some action which requires logging</span>
        <span class="p">...</span>

        <span class="n">_logger</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">"This is DONE now!"</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>To make this happen adapters for various runtime logging infrastructures are required (to forward logged messages from  the library to underlying logging infrastructure).</p>

<p>This is done for Episerver if you are using official <code class="language-plaintext highlighter-rouge">EPiServer.Logging</code> APIs.</p>

<h3 id="read-only-apps">Read-Only Apps</h3>

<p>Next major version of localization provider also allows interesting scenario that was not possible (or hard to achieve) - reader/writer and read-only apps.</p>

<p><img src="/assets/img/2020/03/dbloc-readonly-app.png" alt="dbloc-readonly-app" /></p>

<p>I’ve seen common case when one of the applications only had to use localization provider without any other functionality - for example <a href="https://azure.microsoft.com/en-us/services/functions/">Azure Function</a>  which required to send out email to customers and use localized resources to compose email body. Function itself has no resources not wants to scan and register anything in underlying database - it requires only to read up content of the database and use resources.</p>

<p>For this reason you can just set configuration setting <code class="language-plaintext highlighter-rouge">a</code> to <code class="language-plaintext highlighter-rouge">false</code>:</p>

<p>For example in Azure Function:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">Startup</span> <span class="p">:</span> <span class="n">FunctionsStartup</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Configure</span><span class="p">(</span><span class="n">IFunctionsHostBuilder</span> <span class="n">builder</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="nf">AddDbLocalizationProvider</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="n">_</span><span class="p">.</span><span class="n">DiscoverAndRegisterResources</span> <span class="p">=</span> <span class="k">false</span><span class="p">;</span>
            <span class="p">...</span>
        <span class="p">});</span>

        <span class="n">InitializationExtensions</span><span class="p">.</span><span class="nf">UseDbLocalizationProvider</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Here we have to call directly <code class="language-plaintext highlighter-rouge">UseDbLocalizationProvider()</code> method on <code class="language-plaintext highlighter-rouge">InitializationExtensions</code> as there is no extension method specifically for Azure Functions runtime.</p>

<h2 id="changes-from-v5x">Changes from v5.x</h2>

<h3 id="episerver-idisplayresolution-names">Episerver IDisplayResolution Names</h3>

<p>If you have <code class="language-plaintext highlighter-rouge">IDisplayResolution</code> implementations which are using <code class="language-plaintext highlighter-rouge">LocalizationService</code> to retrieve display names (usually found in AlloyTech sample sites) special treatment is required in order to get text from <code class="language-plaintext highlighter-rouge">DbLocalizationProvider</code>.</p>

<p>Assume that you have following display resolution class:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">AndroidVerticalResolution</span> <span class="p">:</span> <span class="n">DisplayResolutionBase</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">AndroidVerticalResolution</span><span class="p">()</span> <span class="p">:</span> <span class="k">base</span><span class="p">(</span><span class="s">"/resolutions/androidvertical"</span><span class="p">,</span> <span class="m">480</span><span class="p">,</span> <span class="m">800</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As you can see we are inheriting from <code class="language-plaintext highlighter-rouge">DisplayResolutionBase</code> which in turn tries to find display name for child class during constructor (default implementation in AlloyTech provided sample project).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">abstract</span> <span class="k">class</span> <span class="nc">DisplayResolutionBase</span> <span class="p">:</span> <span class="n">IDisplayResolution</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="n">Injected</span><span class="p">&lt;</span><span class="n">LocalizationService</span><span class="p">&gt;</span> <span class="n">LocalizationService</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

    <span class="k">protected</span> <span class="nf">DisplayResolutionBase</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">,</span> <span class="kt">int</span> <span class="n">width</span><span class="p">,</span> <span class="kt">int</span> <span class="n">height</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">Id</span> <span class="p">=</span> <span class="nf">GetType</span><span class="p">().</span><span class="n">FullName</span><span class="p">;</span>
        <span class="n">Name</span> <span class="p">=</span> <span class="nf">Translate</span><span class="p">(</span><span class="n">name</span><span class="p">);</span>
        <span class="n">Width</span> <span class="p">=</span> <span class="n">width</span><span class="p">;</span>
        <span class="n">Height</span> <span class="p">=</span> <span class="n">height</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="p">...</span>

    <span class="k">private</span> <span class="kt">string</span> <span class="nf">Translate</span><span class="p">(</span><span class="kt">string</span> <span class="n">resurceKey</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">string</span> <span class="k">value</span><span class="p">;</span>

        <span class="k">if</span><span class="p">(!</span><span class="n">LocalizationService</span><span class="p">.</span><span class="n">Service</span><span class="p">.</span><span class="nf">TryGetString</span><span class="p">(</span><span class="n">resurceKey</span><span class="p">,</span> <span class="k">out</span> <span class="k">value</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="k">value</span> <span class="p">=</span> <span class="n">resurceKey</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="k">return</span> <span class="k">value</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Episerver initializes display resolutions during <code class="language-plaintext highlighter-rouge">CmsRuntimeInitialization</code> module.
As DbLocalizationProvider allows setup code to be located in “ordinary” initialization module, there is a timing issue between <code class="language-plaintext highlighter-rouge">CmsRuntimeInitialization</code> module and your own custom module invoke moments. There <em>could</em> be situations (and usually are) when custom module that does setup of DbLocalizationProvider library is executed <strong>after</strong> <code class="language-plaintext highlighter-rouge">CmsRuntimeInitialization</code> module.
This results into missing display names for your implementations of <code class="language-plaintext highlighter-rouge">IDisplayResolution</code> interfaces (because when display resolutions are initialized, display name is loaded - DbLocalizationProvider library is <em>not yet</em> setup - hence translations are missing).</p>

<p>Workaround for this case is to do DbLocalizationProvider storage initialization a bit earlier (earlier than <code class="language-plaintext highlighter-rouge">CmsRuntimeInitialization</code> is invoked). The easiest way I found is to implement <code class="language-plaintext highlighter-rouge">IConfigurableModule</code> than has dependency on <code class="language-plaintext highlighter-rouge">ServiceContainerInitialization</code>. This more or less guarantees that your setup module is invoked one of the first in the list immediately after IoC setup:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">ServiceContainerInitialization</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">DbLocalizationProviderConnectionSetupModule</span> <span class="p">:</span> <span class="n">IConfigurableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureContainer</span><span class="p">(</span><span class="n">ServiceConfigurationContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="n">ConfigurationManager</span><span class="p">.</span><span class="n">ConnectionStrings</span><span class="p">[</span><span class="s">"EPiServerDB"</span><span class="p">].</span><span class="n">ConnectionString</span><span class="p">;</span>
        <span class="n">ConfigurationContext</span><span class="p">.</span><span class="nf">Setup</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="n">_</span><span class="p">.</span><span class="n">ModelMetadataProviders</span><span class="p">.</span><span class="n">EnableLegacyMode</span> <span class="p">=</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="k">true</span><span class="p">;</span>
            <span class="n">_</span><span class="p">.</span><span class="n">EnableInvariantCultureFallback</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
            <span class="n">_</span><span class="p">.</span><span class="nf">UseSqlServer</span><span class="p">(</span><span class="n">conection</span><span class="p">);</span>
        <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>NB!</strong> Don’t forget to enable <code class="language-plaintext highlighter-rouge">LegacyMode</code> if your display name resource starts with <code class="language-plaintext highlighter-rouge">/</code> - for example <code class="language-plaintext highlighter-rouge">/resolutions/androidvertical</code> (sample from Alloy).</p>

<h3 id="manual-storage-schema-update">Manual Storage Schema Update</h3>

<p>Sometimes it’s hard to control timing of initialization chain. Are you sure where and when your startup code will be called?
If you need to control timing and call initialization code yourself - you can use <code class="language-plaintext highlighter-rouge">Synchronizer</code> class to trigger at least underlying schema updates (if needed) and perform resource synchronization.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
</pre></td><td class="rouge-code"><pre><span class="k">using</span> <span class="nn">System.Configuration</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">DbLocalizationProvider.Storage.SqlServer</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">DbLocalizationProvider.Sync</span><span class="p">;</span>

<span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">ServiceContainerInitialization</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">DbLocalizationProviderConnectionSetupModule</span> <span class="p">:</span> <span class="n">IConfigurableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureContainer</span><span class="p">(</span><span class="n">ServiceConfigurationContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">ConfigurationContext</span><span class="p">.</span><span class="nf">Setup</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="kt">var</span> <span class="n">connectionName</span> <span class="p">=</span> <span class="n">EPiServerDataStoreSection</span><span class="p">.</span><span class="n">Instance</span><span class="p">.</span><span class="n">DataSettings</span><span class="p">.</span><span class="n">ConnectionStringName</span><span class="p">;</span>
            <span class="kt">var</span> <span class="n">connectionString</span> <span class="p">=</span> <span class="n">ConfigurationManager</span>
                                   <span class="p">.</span><span class="n">ConnectionStrings</span><span class="p">[</span><span class="n">connectionName</span><span class="p">]</span>
                                   <span class="p">.</span><span class="n">ConnectionString</span><span class="p">;</span>

            <span class="n">_</span><span class="p">.</span><span class="nf">UseSqlServer</span><span class="p">(</span><span class="n">connectionString</span><span class="p">);</span>
        <span class="p">});</span>

        <span class="c1">// manually sync storage schema - this is required as schema update happens later in startup pipeline</span>
        <span class="c1">// here - as localization provider is called way TOOOOOO early - we make sure that schema is OK and queries do not fail</span>
        <span class="kt">var</span> <span class="n">sync</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">Synchronizer</span><span class="p">();</span>
        <span class="n">sync</span><span class="p">.</span><span class="nf">UpdateStorageSchema</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>I hope that this will not be necessary for you! But just in case.. :)</p>

<p>Happy localizing!
Stay safe!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="Localization Provider" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization provider" /><category term="localization" /><summary type="html"><![CDATA[Introduction]]></summary></entry><entry><title type="html">Localization Provider - Major 6 Released!</title><link href="https://tech-fellow.eu/2020/02/22/localization-provider-major-6/" rel="alternate" type="text/html" title="Localization Provider - Major 6 Released!" /><published>2020-02-22T18:00:00+02:00</published><updated>2020-02-22T18:00:00+02:00</updated><id>https://tech-fellow.eu/2020/02/22/localization-provider-major-6</id><content type="html" xml:base="https://tech-fellow.eu/2020/02/22/localization-provider-major-6/"><![CDATA[<h2 id="introduction">Introduction</h2>

<p>I’m pleased to announce that v6 of DbLocalizationProvider is finally out to the wild. It’s been a bit bumpy road and longer journey as expected, but here we are..</p>

<p>This post will guide you through some of the most noteworthy changes since last major version.</p>

<p><img src="/assets/img/2020/02/2020-02-22_01-07-43.png" alt="2020-02-22_01-07-43" /></p>

<h2 id="major-changes-in-v6">Major Changes in v6</h2>

<ul>
  <li>Apache 2.0 license</li>
  <li>AdminUI registration changes</li>
  <li>Jumped to <code class="language-plaintext highlighter-rouge">netcore31</code> (.NET Core 3.1) version</li>
  <li>Jumped to JSON.NET v11.0.2</li>
  <li>MSSQL as separate package (this opens up extensibility to plugin additional providers). No EF / EFCore dependency anymore.</li>
  <li>Some smaller fixes for AdminUI (like localizing error messages :)</li>
  <li>Language fallback configuration</li>
  <li>Added interface <code class="language-plaintext highlighter-rouge">ILocalizationProvider</code> for easier unit testing</li>
  <li>Logging added to unify functionality across platforms and runtimes</li>
</ul>

<h2 id="getting-started-with-v6">Getting Started with v6</h2>

<p>There are few changes in how to get started with v6 of DbLocalizationProvider.
Let me guide you through that process.</p>

<h3 id="install-storage-implementation-package">Install Storage Implementation Package</h3>

<table>
  <tbody>
    <tr>
      <td>One of the biggest change in v6 is that DbLocalizationProvider by default does not have dependency on EntityFramework</td>
      <td>EFCore and therefore by default if you already have project running on v5.x -&gt; just by upgrading packages to v6 will not solve all your problems.</td>
    </tr>
  </tbody>
</table>

<p>You will need to install additional package with MSSQL Server storage implementation.</p>

<pre><code class="language-cmd">&gt; dotnet add package LocalizationProvider.Storage.SqlServer
</code></pre>

<p>Once this is done, you need to configure connectionString for the SQL Server package (usually in your <code class="language-plaintext highlighter-rouge">Startup.cs</code> file):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">services</span><span class="p">.</span><span class="nf">AddDbLocalizationProvider</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="p">...</span>
        <span class="n">ctx</span><span class="p">.</span><span class="nf">UseSqlServer</span><span class="p">(</span><span class="n">Configuration</span><span class="p">.</span><span class="nf">GetConnectionString</span><span class="p">(</span><span class="s">"DefaultConnection"</span><span class="p">));</span>
    <span class="p">});</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="configure-fallback-languages">Configure Fallback Languages</h3>

<p>LocalizationProvider gives you option to configure fallback languages for the library.
It means that provider will try to get translation in requested language. And if it does not exist in that language, fallback language list is used to decide which language to try next until either succeeds or fails with no translation found.</p>

<p>To configure fallback languages use code below:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">Startup</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">services</span><span class="p">.</span><span class="nf">AddDbLocalizationProvider</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="p">...</span>
            <span class="n">_</span><span class="p">.</span><span class="n">FallbackCultures</span>
                <span class="p">.</span><span class="nf">Try</span><span class="p">(</span><span class="k">new</span> <span class="nf">CultureInfo</span><span class="p">(</span><span class="s">"sv"</span><span class="p">))</span>
                <span class="p">.</span><span class="nf">Then</span><span class="p">(</span><span class="k">new</span> <span class="nf">CultureInfo</span><span class="p">(</span><span class="s">"no"</span><span class="p">))</span>
                <span class="p">.</span><span class="nf">Then</span><span class="p">(</span><span class="k">new</span> <span class="nf">CultureInfo</span><span class="p">(</span><span class="s">"en"</span><span class="p">));</span>
        <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This means that following logic will be used during translation lookup:</p>

<p>1) Developer requests translation in Swedish culture (<code class="language-plaintext highlighter-rouge">"sv"</code>) using <code class="language-plaintext highlighter-rouge">ILocalizationProvider.GetString(() =&gt; ...)</code> method.
2) If translation does not exist -&gt; provider is looking for translation in Norwegian language (<code class="language-plaintext highlighter-rouge">"no"</code> - second language in the fallback list).
3) If translation is found - one is returned; if not - provider continues process and is looking for translation in English (<code class="language-plaintext highlighter-rouge">"en"</code>).
4) If there is no translation in English -&gt; depending on <code class="language-plaintext highlighter-rouge">ConfigurationContext.EnableInvariantCultureFallback</code> setting -&gt; translation in InvariantCulture may be returned.</p>

<h3 id="mapping-adminui-and-clientside-resource-handler">Mapping AdminUI and Clientside Resource Handler</h3>

<p>ASP.NET MVC back in 2.2 days introduced different routing mechanism - called <a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-3.1">EndpointRouting</a>.</p>

<p>If you create new web application using templates - application will use endpoint routing by default. However if you are upgrading existing projects - opt-in to use endpoint routing is optional.</p>

<p>So depending on what routing system your application is using, you might need to register AdminUI and Clientside resource handler differently.</p>

<p>For <strong>old MVC Routing</strong>:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
   <span class="n">services</span>
       <span class="p">.</span><span class="nf">AddControllersWithViews</span><span class="p">(</span><span class="n">opt</span> <span class="p">=&gt;</span> <span class="n">opt</span><span class="p">.</span><span class="n">EnableEndpointRouting</span> <span class="p">=</span> <span class="k">false</span><span class="p">)</span>
       <span class="p">.</span><span class="nf">AddMvcLocalization</span><span class="p">();</span>

   <span class="n">services</span><span class="p">.</span><span class="nf">AddRouting</span><span class="p">();</span>
   <span class="p">...</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">void</span> <span class="nf">Configure</span><span class="p">(</span><span class="n">IApplicationBuilder</span> <span class="n">app</span><span class="p">,</span> <span class="n">IHostingEnvironment</span> <span class="n">env</span><span class="p">)</span>
<span class="p">{</span>
    <span class="p">...</span>
    <span class="n">app</span><span class="p">.</span><span class="nf">UseMvc</span><span class="p">(</span><span class="n">routes</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">routes</span><span class="p">.</span><span class="nf">MapDbLocalizationAdminUI</span><span class="p">();</span>
        <span class="n">routes</span><span class="p">.</span><span class="nf">MapDbLocalizationClientsideProvider</span><span class="p">();</span>

        <span class="n">routes</span><span class="p">.</span><span class="nf">MapRoute</span><span class="p">(</span>
            <span class="n">name</span><span class="p">:</span> <span class="s">"default"</span><span class="p">,</span>
            <span class="n">template</span><span class="p">:</span> <span class="s">"{controller=Home}/{action=Index}/{id?}"</span><span class="p">);</span>
    <span class="p">});</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>For <strong>Endpoint routing</strong>:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
   <span class="n">services</span><span class="p">.</span><span class="nf">AddRouting</span><span class="p">();</span>
   <span class="p">...</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">void</span> <span class="nf">Configure</span><span class="p">(</span><span class="n">IApplicationBuilder</span> <span class="n">app</span><span class="p">,</span> <span class="n">IHostingEnvironment</span> <span class="n">env</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">app</span><span class="p">.</span><span class="nf">UseRouting</span><span class="p">();</span>
    <span class="p">...</span>
    <span class="n">app</span><span class="p">.</span><span class="nf">UseEndpoints</span><span class="p">(</span><span class="n">endpoints</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">endpoints</span><span class="p">.</span><span class="nf">MapControllerRoute</span><span class="p">(</span><span class="s">"default"</span><span class="p">,</span> <span class="s">"{controller=Home}/{action=Index}/{id?}"</span><span class="p">);</span>
        <span class="p">...</span>

        <span class="n">endpoints</span><span class="p">.</span><span class="nf">MapDbLocalizationAdminUI</span><span class="p">();</span>
        <span class="n">endpoints</span><span class="p">.</span><span class="nf">MapDbLocalizationClientsideProvider</span><span class="p">();</span>
    <span class="p">});</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>For more information and sample setup code you can checkout <a href="https://github.com/valdisiljuconoks/localization-provider-core/tree/master/tests/DbLocalizationProvider.Core.AspNetSample">sample Mvc project</a> on github.</p>

<h3 id="securing-adminui">Securing AdminUI</h3>

<p>AdminUI by default is secured via roles which you can configure yourself via <code class="language-plaintext highlighter-rouge">Configure</code> method on startup:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">services</span><span class="p">.</span><span class="nf">AddDbLocalizationProviderAdminUI</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="p">...</span>
        <span class="n">_</span><span class="p">.</span><span class="n">AuthorizedAdminRoles</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="s">"Admins"</span><span class="p">);</span>
        <span class="n">_</span><span class="p">.</span><span class="n">AuthorizedEditorRoles</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="s">"Translators"</span><span class="p">);</span>
    <span class="p">});</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>In order for you to get this working, you need to enable roles based access in your ASP.NET identity setup:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">services</span><span class="p">.</span><span class="n">AddDbContext</span><span class="p">&lt;...&gt;(...);</span>

    <span class="n">services</span>
        <span class="p">.</span><span class="n">AddDefaultIdentity</span><span class="p">&lt;...&gt;(...)</span>
        <span class="p">.</span><span class="n">AddRoles</span><span class="p">&lt;</span><span class="n">IdentityRole</span><span class="p">&gt;();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="bare-minimum-startupcs-to-start-with">Bare Minimum Startup.cs to Start With</h3>

<p>This seems to be bare minimum for the localization provider start functioning OK-ish.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
</pre></td><td class="rouge-code"><pre><span class="k">using</span> <span class="nn">System.Collections.Generic</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System.Globalization</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">DbLocalizationProvider.AdminUI.AspNetCore</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">DbLocalizationProvider.AdminUI.AspNetCore.Routing</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">DbLocalizationProvider.AspNetCore</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">DbLocalizationProvider.AspNetCore.ClientsideProvider.Routing</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">DbLocalizationProvider.Core.AspNetSample.Data</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">DbLocalizationProvider.Core.AspNetSample.Resources</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">DbLocalizationProvider.Storage.SqlServer</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">Microsoft.AspNetCore.Builder</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">Microsoft.AspNetCore.Hosting</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">Microsoft.AspNetCore.Identity</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">Microsoft.AspNetCore.Localization</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">Microsoft.EntityFrameworkCore</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">Microsoft.Extensions.Configuration</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">Microsoft.Extensions.DependencyInjection</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">Microsoft.Extensions.Logging</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">Microsoft.Extensions.Options</span><span class="p">;</span>

<span class="k">namespace</span> <span class="nn">SampleApp</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">Startup</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="nf">Startup</span><span class="p">(</span><span class="n">IConfiguration</span> <span class="n">configuration</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">Configuration</span> <span class="p">=</span> <span class="n">configuration</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="k">public</span> <span class="n">IConfiguration</span> <span class="n">Configuration</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>

        <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">services</span><span class="p">.</span><span class="n">AddDbContext</span><span class="p">&lt;</span><span class="n">ApplicationDbContext</span><span class="p">&gt;(</span>
                <span class="n">options</span> <span class="p">=&gt;</span> <span class="n">options</span><span class="p">.</span><span class="nf">UseSqlServer</span><span class="p">(</span><span class="n">Configuration</span><span class="p">.</span><span class="nf">GetConnectionString</span><span class="p">(</span><span class="s">"DefaultConnection"</span><span class="p">)));</span>

            <span class="n">services</span>
                <span class="p">.</span><span class="n">AddDefaultIdentity</span><span class="p">&lt;</span><span class="n">IdentityUser</span><span class="p">&gt;()</span>
                <span class="p">.</span><span class="n">AddRoles</span><span class="p">&lt;</span><span class="n">IdentityRole</span><span class="p">&gt;()</span>
                <span class="p">.</span><span class="n">AddEntityFrameworkStores</span><span class="p">&lt;</span><span class="n">ApplicationDbContext</span><span class="p">&gt;();</span>

            <span class="n">services</span>
                <span class="p">.</span><span class="nf">AddControllersWithViews</span><span class="p">()</span>
                <span class="p">.</span><span class="nf">AddMvcLocalization</span><span class="p">();</span>

            <span class="n">services</span><span class="p">.</span><span class="nf">AddAuthorization</span><span class="p">();</span>
            <span class="n">services</span><span class="p">.</span><span class="nf">AddRazorPages</span><span class="p">();</span>
            <span class="n">services</span><span class="p">.</span><span class="nf">AddRouting</span><span class="p">();</span>

            <span class="kt">var</span> <span class="n">supportedCultures</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">CultureInfo</span><span class="p">&gt;</span> <span class="p">{</span> <span class="k">new</span> <span class="nf">CultureInfo</span><span class="p">(</span><span class="s">"sv"</span><span class="p">),</span> <span class="k">new</span> <span class="nf">CultureInfo</span><span class="p">(</span><span class="s">"no"</span><span class="p">),</span> <span class="k">new</span> <span class="nf">CultureInfo</span><span class="p">(</span><span class="s">"en"</span><span class="p">)</span> <span class="p">};</span>

            <span class="n">services</span><span class="p">.</span><span class="n">Configure</span><span class="p">&lt;</span><span class="n">RequestLocalizationOptions</span><span class="p">&gt;(</span><span class="n">opts</span> <span class="p">=&gt;</span>
            <span class="p">{</span>
                <span class="n">opts</span><span class="p">.</span><span class="n">DefaultRequestCulture</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">RequestCulture</span><span class="p">(</span><span class="s">"en"</span><span class="p">);</span>
                <span class="n">opts</span><span class="p">.</span><span class="n">SupportedCultures</span> <span class="p">=</span> <span class="n">supportedCultures</span><span class="p">;</span>
                <span class="n">opts</span><span class="p">.</span><span class="n">SupportedUICultures</span> <span class="p">=</span> <span class="n">supportedCultures</span><span class="p">;</span>
            <span class="p">});</span>

            <span class="n">services</span><span class="p">.</span><span class="nf">AddDbLocalizationProvider</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
            <span class="p">{</span>
                <span class="n">_</span><span class="p">.</span><span class="n">EnableInvariantCultureFallback</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
                <span class="n">_</span><span class="p">.</span><span class="n">ScanAllAssemblies</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
                <span class="n">_</span><span class="p">.</span><span class="n">FallbackCultures</span><span class="p">.</span><span class="nf">Try</span><span class="p">(</span><span class="n">supportedCultures</span><span class="p">);</span>
                <span class="n">_</span><span class="p">.</span><span class="nf">UseSqlServer</span><span class="p">(</span><span class="n">Configuration</span><span class="p">.</span><span class="nf">GetConnectionString</span><span class="p">(</span><span class="s">"DefaultConnection"</span><span class="p">));</span>
            <span class="p">});</span>

            <span class="n">services</span><span class="p">.</span><span class="nf">AddDbLocalizationProviderAdminUI</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
            <span class="p">{</span>
                <span class="n">_</span><span class="p">.</span><span class="n">RootUrl</span> <span class="p">=</span> <span class="s">"/localization-admin"</span><span class="p">;</span>
                <span class="n">_</span><span class="p">.</span><span class="n">ShowInvariantCulture</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
                <span class="n">_</span><span class="p">.</span><span class="n">ShowHiddenResources</span> <span class="p">=</span> <span class="k">false</span><span class="p">;</span>
                <span class="n">_</span><span class="p">.</span><span class="n">DefaultView</span> <span class="p">=</span> <span class="n">ResourceListView</span><span class="p">.</span><span class="n">Tree</span><span class="p">;</span>
            <span class="p">});</span>
        <span class="p">}</span>

        <span class="k">public</span> <span class="k">void</span> <span class="nf">Configure</span><span class="p">(</span><span class="n">IApplicationBuilder</span> <span class="n">app</span><span class="p">,</span> <span class="n">IHostingEnvironment</span> <span class="n">env</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">env</span><span class="p">.</span><span class="nf">IsDevelopment</span><span class="p">())</span>
            <span class="p">{</span>
                <span class="n">app</span><span class="p">.</span><span class="nf">UseDeveloperExceptionPage</span><span class="p">();</span>
            <span class="p">}</span>
            <span class="k">else</span>
            <span class="p">{</span>
                <span class="n">app</span><span class="p">.</span><span class="nf">UseExceptionHandler</span><span class="p">(</span><span class="s">"/Home/Error"</span><span class="p">);</span>
                <span class="n">app</span><span class="p">.</span><span class="nf">UseHsts</span><span class="p">();</span>
            <span class="p">}</span>

            <span class="kt">var</span> <span class="n">options</span> <span class="p">=</span> <span class="n">app</span><span class="p">.</span><span class="n">ApplicationServices</span><span class="p">.</span><span class="n">GetService</span><span class="p">&lt;</span><span class="n">IOptions</span><span class="p">&lt;</span><span class="n">RequestLocalizationOptions</span><span class="p">&gt;&gt;();</span>
            <span class="n">app</span><span class="p">.</span><span class="nf">UseRequestLocalization</span><span class="p">(</span><span class="n">options</span><span class="p">.</span><span class="n">Value</span><span class="p">);</span>

            <span class="n">app</span><span class="p">.</span><span class="nf">UseRouting</span><span class="p">();</span>
            <span class="n">app</span><span class="p">.</span><span class="nf">UseHttpsRedirection</span><span class="p">();</span>
            <span class="n">app</span><span class="p">.</span><span class="nf">UseStaticFiles</span><span class="p">();</span>
            <span class="n">app</span><span class="p">.</span><span class="nf">UseAuthentication</span><span class="p">();</span>
            <span class="n">app</span><span class="p">.</span><span class="nf">UseAuthorization</span><span class="p">();</span>

            <span class="n">app</span><span class="p">.</span><span class="nf">UseDbLocalizationProvider</span><span class="p">();</span>
            <span class="n">app</span><span class="p">.</span><span class="nf">UseDbLocalizationProviderAdminUI</span><span class="p">();</span>
            <span class="n">app</span><span class="p">.</span><span class="nf">UseDbLocalizationClientsideProvider</span><span class="p">();</span>

            <span class="n">app</span><span class="p">.</span><span class="nf">UseEndpoints</span><span class="p">(</span><span class="n">endpoints</span> <span class="p">=&gt;</span>
            <span class="p">{</span>
                <span class="n">endpoints</span><span class="p">.</span><span class="nf">MapControllerRoute</span><span class="p">(</span><span class="s">"default"</span><span class="p">,</span> <span class="s">"{controller=Home}/{action=Index}/{id?}"</span><span class="p">);</span>
                <span class="n">endpoints</span><span class="p">.</span><span class="nf">MapRazorPages</span><span class="p">();</span>

                <span class="n">endpoints</span><span class="p">.</span><span class="nf">MapDbLocalizationAdminUI</span><span class="p">();</span>
                <span class="n">endpoints</span><span class="p">.</span><span class="nf">MapDbLocalizationClientsideProvider</span><span class="p">();</span>
            <span class="p">});</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="special-notes">Special Notes</h2>

<h3 id="overwriting-querycommand-handlers">Overwriting Query/Command Handlers</h3>

<p>This applies to use-cases for overwriting command and/or query handlers (by having this code in <code class="language-plaintext highlighter-rouge">Startup.cs</code> or any other global composition root).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="n">app</span><span class="p">.</span><span class="nf">UseDbLocalizationProvider</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">ctx</span><span class="p">.</span><span class="n">TypeFactory</span>
            <span class="p">.</span><span class="n">ForQuery</span><span class="p">&lt;</span><span class="n">AvailableLanguages</span><span class="p">.</span><span class="n">Query</span><span class="p">&gt;()</span>
            <span class="p">.</span><span class="n">SetHandler</span><span class="p">&lt;</span><span class="n">SampleAvailableLanguagesHandler</span><span class="p">&gt;();</span>
    <span class="p">});</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>It’s important to note that if you do overwrite query and/or command handlers to customize localization provider to your needs <strong><em>and</em></strong> at the same time using SQL Server to storage your resources - you have to overwrite handlers <strong>after</strong> you have configured to use SQL Server.</p>

<p>This is due to fact that extension method <code class="language-plaintext highlighter-rouge">UseSqlServer()</code> itself overwrites and sets some of the handlers required to successfully implement storage.</p>

<p>Instead of this:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="n">app</span><span class="p">.</span><span class="nf">UseDbLocalizationProvider</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">ctx</span><span class="p">.</span><span class="n">TypeFactory</span>
            <span class="p">.</span><span class="n">ForQuery</span><span class="p">&lt;</span><span class="n">AvailableLanguages</span><span class="p">.</span><span class="n">Query</span><span class="p">&gt;()</span>
            <span class="p">.</span><span class="n">SetHandler</span><span class="p">&lt;</span><span class="n">SampleAvailableLanguagesHandler</span><span class="p">&gt;();</span>

        <span class="n">ctx</span><span class="p">.</span><span class="nf">UseSqlServer</span><span class="p">(...);</span>
    <span class="p">});</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You have to rewrite to this:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="n">app</span><span class="p">.</span><span class="nf">UseDbLocalizationProvider</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">ctx</span><span class="p">.</span><span class="nf">UseSqlServer</span><span class="p">(...);</span>

        <span class="n">ctx</span><span class="p">.</span><span class="n">TypeFactory</span>
            <span class="p">.</span><span class="n">ForQuery</span><span class="p">&lt;</span><span class="n">AvailableLanguages</span><span class="p">.</span><span class="n">Query</span><span class="p">&gt;()</span>
            <span class="p">.</span><span class="n">SetHandler</span><span class="p">&lt;</span><span class="n">SampleAvailableLanguagesHandler</span><span class="p">&gt;();</span>
    <span class="p">});</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="breaking-changes">Breaking Changes</h2>

<p>Major versions are perfect timing to break something.</p>

<h3 id="configurationcontextconnection-property-is-gone">ConfigurationContext.Connection Property Is Gone</h3>

<p>With v6 there is no storage management inside core libraries. Currently only MSSQL Server implementation is done. Therefore you have to now explicitly register your storage implementation with LocalizationProvider during startup.</p>

<p>Following code will not work anymore:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">services</span><span class="p">.</span><span class="nf">AddDbLocalizationProvider</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">_</span><span class="p">.</span><span class="n">Connection</span> <span class="p">=</span> <span class="s">"...."</span><span class="p">;</span>
    <span class="p">});</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Instead you need to explicitly register MSSQL storage:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">services</span><span class="p">.</span><span class="nf">AddDbLocalizationProvider</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">_</span><span class="p">.</span><span class="nf">UseSqlServer</span><span class="p">(</span><span class="n">Configuration</span><span class="p">.</span><span class="nf">GetConnectionString</span><span class="p">(</span><span class="s">"..."</span><span class="p">));</span>
    <span class="p">});</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="adminui-registration-for-aspnet-applications">AdminUI Registration for ASP.NET Applications</h3>

<p>Old:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="n">app</span><span class="p">.</span><span class="nf">Map</span><span class="p">(</span>
    <span class="s">"/localization-admin"</span><span class="p">,</span>
    <span class="n">b</span> <span class="p">=&gt;</span> <span class="n">b</span><span class="p">.</span><span class="nf">UseDbLocalizationProviderAdminUI</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">_</span><span class="p">.</span><span class="n">ShowInvariantCulture</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
    <span class="p">}));</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>New: depends on your routing system used. Please refer to section above for more detailed description on how to map AdminUI in your app.</p>

<h3 id="reversed-resourcelookupfilter-logic">Reversed ResourceLookupFilter Logic</h3>

<p>In some late v5.x version extra parameter for filter resource lookup was added <code class="language-plaintext highlighter-rouge">ConfigurationContext.ResourceLookupFilter</code>.
First implementation of the filter was created to return <code class="language-plaintext highlighter-rouge">false</code> if resource should not be searched.
However, after inspecting naming of the property - it didn’t match the meaning of the property, therefore in new version v6 logic of this property has been reversed. Now if <code class="language-plaintext highlighter-rouge">true</code> is returned - then resource lookup happens.</p>

<p>If you have used this property and have implemented your logic - please make sure that you revert your logic.</p>

<h3 id="legacymodeenabled-has-moved">LegacyModeEnabled Has Moved</h3>

<p>Property to control if legacy mode is enabled or not has been moved from <code class="language-plaintext highlighter-rouge">ConfigurationContext.ModelMetadataProviders.EnableLegacyMode</code> to <code class="language-plaintext highlighter-rouge">ConfigurationContext.EnableLegacyMode</code>.</p>

<h3 id="createnewresource-command-changes">CreateNewResource Command Changes</h3>

<p>Command <code class="language-plaintext highlighter-rouge">CreateNewResource</code> has been removed and instead now you can create new resources in batch by using <code class="language-plaintext highlighter-rouge">CreateNewResources</code> command. If you still need to create single resource - execute batch command with single resource in collection.</p>

<h2 id="give-it-a-try">Give It a Try!</h2>

<p>I’m happy to get to this milestone. v6 is next major version that includes many tiny changes inside. Things might get lost or broken while you are commuting between versions..</p>

<p>Would be awesome if you share your feedback!</p>

<p>Hope this helps!
Happy localization!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="Localization Provider" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization provider" /><category term="localization" /><summary type="html"><![CDATA[Introduction]]></summary></entry><entry><title type="html">Building Real-time Public Transport Tracking System on Azure - Part 2 - Data Collectors &amp;amp; Composer</title><link href="https://tech-fellow.eu/2020/01/21/building-real-time-public-transport-tracking-system-on-azure-part-2-data-collectors-composer/" rel="alternate" type="text/html" title="Building Real-time Public Transport Tracking System on Azure - Part 2 - Data Collectors &amp;amp; Composer" /><published>2020-01-21T07:00:00+02:00</published><updated>2020-01-21T07:00:00+02:00</updated><id>https://tech-fellow.eu/2020/01/21/building-real-time-public-transport-tracking-system-on-azure-part-2-data-collectors-composer</id><content type="html" xml:base="https://tech-fellow.eu/2020/01/21/building-real-time-public-transport-tracking-system-on-azure-part-2-data-collectors-composer/"><![CDATA[<p>This is next post in series about real-time public transport tracking system development based on Azure infrastructure and services. This article is a part of Applied Cloud Stories initiative - <a href="https://aka.ms/applied-cloud-stories">aka.ms/applied-cloud-stories</a>.</p>

<p>Blog posts in this series:</p>

<ul>
  <li><a href="https://tech-fellow.eu/2019/12/08/building-real-time-public-transport-tracking-system-on-azure-part1/">Part 1 - Scene Background &amp; Solution Architecture</a></li>
  <li><strong>Part 2 - Data Collectors &amp; Composer</strong></li>
  <li><a href="https://tech-fellow.eu/2020/04/08/building-real-time-public-transport-tracking-system-on-azure-part-3/">Part 3 - Event-Based Data Delivery</a></li>
  <li><a href="https://tech-fellow.eu/2020/08/30/building-real-time-public-transport-tracking-system-on-azure-part-4/">Part 4 - Data Processing Pipelines</a></li>
  <li><a href="https://tech-fellow.eu/2020/11/01/building-real-time-public-transport-tracking-system-on-azure-part-5/">Part 5 - Data Broadcast using gRPC and SignalR</a></li>
  <li><a href="https://tech-fellow.eu/2020/12/14/building-real-time-public-transport-tracking-system-on-azure-part-6-building-frontend/">Part 6 - Building Frontend</a></li>
  <li><a href="https://tech-fellow.eu/2021/01/21/building-real-time-public-transport-tracking-system-on-azure-part-6-packing-everything-up/">Part 7 - Packing Everything Up</a></li>
  <li><a href="https://tech-fellow.eu/2021/01/25/building-linux-docker-images-on-windows-machine/">Part 7.1 - Fixing Docker Image Metrics in Azure</a></li>
</ul>

<h2 id="background">Background</h2>

<p>As I wrote in <a href="https://tech-fellow.eu/2019/12/08/building-real-time-public-transport-tracking-system-on-azure-part1/">previous post</a> - buses have devices installed from various vendors on-board (let’s name those <code class="language-plaintext highlighter-rouge">A</code>, <code class="language-plaintext highlighter-rouge">B</code>, <code class="language-plaintext highlighter-rouge">C</code> and <code class="language-plaintext highlighter-rouge">D</code>). Data collection happens with the help of Azure Functions (mostly). We picked serverless deployment schema here because we do have bunch of code fragments that are running on different frequencies. Timer based function execution is the best option you can get in this case. As application developer I don’t need to worry about ensuring that timer goes off at precise moment in time and I don’t need to worry about making sure that timer goes off again after particular period of time. I don’t need to worry about scaling and banging my head against the wall when I would be debugging concurrent code when my custom made infrastructure would decide to fire off another instance of the code to run in parallel. It’s all taken care by Azure Functions runtime and I can focus on my portion of the application.</p>

<p>This is the overall data-flow image of our system:
<img src="/assets/img/2020/01/3-1.png" alt="3-1" /></p>

<p>We are currently talking about these two specific areas:</p>

<p><img src="/assets/img/2020/01/3.1.png" alt="3.1" /></p>

<h2 id="data-collectors">Data Collectors</h2>

<p>Collectors are bunch of Azure Functions that are set to be executed on different frequencies based on timer triggers:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="s">"CollectorFunc1"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">Run</span><span class="p">([</span><span class="nf">TimerTrigger</span><span class="p">(</span><span class="s">"*/1 * * * * *"</span><span class="p">)]</span> <span class="n">TimerInfo</span> <span class="n">myTimer</span><span class="p">,</span> <span class="n">TraceWriter</span> <span class="n">log</span><span class="p">)</span>
<span class="p">{</span>
    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>There is nothing interesting to see here. It’s just a function that is set to run every second (frequency = 1Hz).
The fancy string in <code class="language-plaintext highlighter-rouge">TimerTrigger</code> attribute constructor is CRON expression for scheduling when function needs to run. If you get into trouble to understand or customize that expression - I usually use this <a href="https://codehollow.com/2017/02/azure-functions-time-trigger-cron-cheat-sheet/">cheat sheet</a> to help me get started.</p>

<p>Most of the time function body consists of some service client that connects to vendor’s endpoint and collects data about buses.</p>

<h3 id="receivers-instead-of-collectors-push-data-processing">Receivers instead of Collectors (“Push” Data Processing)</h3>

<p>However, sometimes vendor can only push data to our endpoint. Even more interesting is that some of the vendors can only do that from production environment (e.g. feeding us with only real-life data).
Here we need to be creative and provide “production” &amp; “test” feeds for ourselves.
What we implemented is production data “receiver” in front which is acting as “data broker” and provides data further for our functions. Once data is received from vendor, we use Azure ServiceBus messaging infrastructure to pass data further to our collectors in test and production environments. ServiceBus Topics are ideal for us in this solution.</p>

<p><img src="/assets/img/2020/01/3.2.png" alt="3.2" /></p>

<p>There are few things that needs to be done in order to get this “push architecture” working:</p>

<ol>
  <li>Ensure that ServiceBus topics exists. It’s great when you don’t need to deal with some infrastructure element creation and management - and it’s done straight from the application. During receiver code startup we ensure that required ServiceBus topics are created. We reuse many services and repositories across .NET Core &amp; .NET Framework and there are also few things to keep in mind when reusing the same code across those platforms. For example <code class="language-plaintext highlighter-rouge">connectionStringAccessor</code> is our own abstraction to get access to connectionStrings from <code class="language-plaintext highlighter-rouge">web.config</code> or <code class="language-plaintext highlighter-rouge">settings.json</code> file. More info can be found <a href="/2019/09/15/adding-di-package-to-webjobs-running-on-net-core/">in post about migrating Azure WebJob from .NET framework to .NET Core</a>.</li>
</ol>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">EnsureTopicIsCreatedAsync</span><span class="p">(</span><span class="n">CancellationToken</span> <span class="n">cancellationToken</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">connectionString</span> <span class="p">=</span> <span class="n">_connectionStringAccessor</span><span class="p">.</span><span class="nf">GetConnectionStringMyName</span><span class="p">(</span><span class="s">".."</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">nm</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ManagementClient</span><span class="p">(</span>
        <span class="k">new</span> <span class="nf">ServiceBusConnectionStringBuilder</span><span class="p">(</span><span class="n">connectionString</span><span class="p">).</span><span class="nf">GetNamespaceConnectionString</span><span class="p">());</span>

    <span class="k">if</span><span class="p">(!</span><span class="k">await</span> <span class="n">nm</span><span class="p">.</span><span class="nf">TopicExistsAsync</span><span class="p">(</span><span class="s">"TopicName"</span><span class="p">,</span> <span class="n">cancellationToken</span><span class="p">).</span><span class="nf">ConfigureAwait</span><span class="p">(</span><span class="k">false</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="k">await</span> <span class="n">nm</span><span class="p">.</span><span class="nf">CreateTopicAsync</span><span class="p">(</span>
            <span class="k">new</span> <span class="nf">TopicDescription</span><span class="p">(</span><span class="s">"TopicName"</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="n">EnableBatchedOperations</span> <span class="p">=</span> <span class="k">true</span>
            <span class="p">},</span>
            <span class="n">cancellationToken</span><span class="p">).</span><span class="nf">ConfigureAwait</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ol>
  <li>Write received messages to the topic</li>
</ol>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">SendAsync</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">str</span> <span class="p">=</span> <span class="n">connectionStringAccessor</span><span class="p">.</span><span class="nf">GetConnectionStringMyName</span><span class="p">(</span><span class="s">"..."</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">topicClient</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">TopicClient</span><span class="p">(</span><span class="n">str</span><span class="p">,</span> <span class="s">"TopicName"</span><span class="p">);</span>
    <span class="k">await</span> <span class="n">_topicClient</span><span class="p">.</span><span class="nf">SendAsync</span><span class="p">(</span><span class="k">new</span> <span class="n">Message</span>
    <span class="p">{</span>
        <span class="n">Body</span> <span class="p">=</span> <span class="n">body</span><span class="p">,</span>
        <span class="n">ContentType</span> <span class="p">=</span> <span class="s">"text/plain"</span>
    <span class="p">}).</span><span class="nf">ConfigureAwait</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ol>
  <li>Batch processing messages on “collector” side. Next thing is to aggregate and collect all messages sent to ServiceBus topic.</li>
</ol>

<p>Ensuring that topic subscription is created with correct characteristics:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">InitializeSubscription</span><span class="p">(</span><span class="kt">string</span> <span class="n">connection</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">namespaceManager</span> <span class="p">=</span> <span class="n">NamespaceManager</span><span class="p">.</span><span class="nf">CreateFromConnectionString</span><span class="p">(</span><span class="n">connection</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">namespaceManager</span><span class="p">.</span><span class="nf">SubscriptionExists</span><span class="p">(</span><span class="s">"TopicName"</span><span class="p">,</span> <span class="s">"SubscriptionName"</span><span class="p">))</span> <span class="k">return</span><span class="p">;</span>

    <span class="kt">var</span> <span class="n">sd</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SubscriptionDescription</span><span class="p">(</span><span class="s">"TopicName"</span><span class="p">,</span> <span class="s">"SubscriptionName"</span><span class="p">)</span>
             <span class="p">{</span>
                 <span class="n">EnableBatchedOperations</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
                 <span class="n">Status</span> <span class="p">=</span> <span class="n">EntityStatus</span><span class="p">.</span><span class="n">Active</span>
             <span class="p">};</span>

    <span class="n">namespaceManager</span><span class="p">.</span><span class="nf">CreateSubscription</span><span class="p">(</span><span class="n">sd</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then we can collect messages in batch (by peeking into the subscription looking for new messages):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">Collect</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">factory</span> <span class="p">=</span> <span class="n">MessagingFactory</span><span class="p">.</span><span class="nf">CreateFromConnectionString</span><span class="p">(</span><span class="n">_serviceBusConnection</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">subscriptionClient</span> <span class="p">=</span> <span class="n">factory</span><span class="p">.</span><span class="nf">CreateSubscriptionClient</span><span class="p">(</span><span class="s">"TopicName"</span><span class="p">,</span> <span class="s">"SubscriptionName"</span><span class="p">,</span> <span class="n">ReceiveMode</span><span class="p">.</span><span class="n">ReceiveAndDelete</span><span class="p">);</span>
    <span class="n">subscriptionClient</span><span class="p">.</span><span class="n">PrefetchCount</span> <span class="p">=</span> <span class="m">16</span><span class="p">;</span>

    <span class="k">while</span><span class="p">(</span><span class="n">subscriptionClient</span><span class="p">.</span><span class="nf">PeekBatch</span><span class="p">(</span><span class="m">16</span><span class="p">).</span><span class="nf">Any</span><span class="p">())</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">pendingMessages</span> <span class="p">=</span> <span class="n">subscriptionClient</span><span class="p">.</span><span class="nf">ReceiveBatch</span><span class="p">(</span><span class="m">16</span><span class="p">,</span> <span class="n">TimeSpan</span><span class="p">.</span><span class="nf">FromSeconds</span><span class="p">(</span><span class="m">1</span><span class="p">))?.</span><span class="nf">ToList</span><span class="p">();</span>
        <span class="k">if</span><span class="p">(</span><span class="n">pendingMessages</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">foreach</span><span class="p">(</span><span class="kt">var</span> <span class="n">message</span> <span class="k">in</span> <span class="n">pendingMessages</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="c1">// do processing of the message</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Batch size of 16 is more or less arbitrary choice here. We tested with few selected batch sizes and seems 16 worked out best for us.</p>

<h3 id="saving-the-space-and-time">Saving the Space (and Time)</h3>

<p>Most of the time (when runtime Gods are good to us) collectors and composer are running on 1Hz frequency - meaning that there is a lot of data generated and saved every second. Azure Storage is cheap (really cheap!).
Before our refactoring we were using standard way JSON.NET library to “hibernate” our domain model to some persistence layer and save it to some durable storage.
However, we introduced binary serialization for this data. We reviewed couple of libraries and decided to go with <a href="https://msgpack.org/index.html">MessagePack</a>.</p>

<p>We decided to go with binary format not for the sake of space, but for the time it takes to convert from C# object model to <code class="language-plaintext highlighter-rouge">byte[]</code>.</p>

<p><img src="/assets/img/2020/01/serialziation-time.png" alt="serialziation-time" /></p>

<p>Overall we were able to cut off space requirements from ~ 1.5MB down to ~1.1MB. It’s almost 1/4 of the space.</p>

<p>Code for adding MessagePack to the solution is not complex at all:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">serializedSnapshot</span> <span class="p">=</span> <span class="n">BinaryConverter</span><span class="p">.</span><span class="nf">Serialize</span><span class="p">(</span><span class="n">newSnapshot</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">BinaryConverter</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="kt">byte</span><span class="p">[]</span> <span class="n">Serialize</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">T</span> <span class="n">model</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">model</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">model</span><span class="p">));</span>

        <span class="k">return</span> <span class="n">MessagePackSerializer</span><span class="p">.</span><span class="nf">Serialize</span><span class="p">(</span><span class="n">model</span><span class="p">,</span> <span class="n">ContractlessStandardResolver</span><span class="p">.</span><span class="n">Instance</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">static</span> <span class="n">T</span> <span class="n">Deserialize</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="kt">byte</span><span class="p">[]</span> <span class="n">bytes</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">bytes</span> <span class="p">==</span> <span class="k">null</span> <span class="p">?</span> <span class="k">default</span><span class="p">(</span><span class="n">T</span><span class="p">)</span> <span class="p">:</span> <span class="n">MessagePackSerializer</span><span class="p">.</span><span class="n">Deserialize</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">bytes</span><span class="p">,</span> <span class="n">ContractlessStandardResolver</span><span class="p">.</span><span class="n">Instance</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We use <code class="language-plaintext highlighter-rouge">ContractlessStandardResolver</code> here because not always we are able to control source code of the model that’s being serialized. I guess if we would go with standard resolver (which is relying on field indexes and attributes) would use even less space.</p>

<h2 id="data-composer">Data Composer</h2>

<p>After data has been collected next step is to compose unified transport data model.
Data composer is component between collectors and final data model.</p>

<p><img src="/assets/img/2020/01/5.0.1-1.png" alt="5.0.1-1" /></p>

<p>Composition phase starts with getting latest snapshots from collectors for each vendor’s data.
Interesting aspect here is that data comes grouped by vendors and not by vehicles. Meaning that we receive for example:</p>

<ul>
  <li>coordinates (vendor <code class="language-plaintext highlighter-rouge">A</code>) for bus 1,2,3,4,..</li>
  <li>delay information (vendor <code class="language-plaintext highlighter-rouge">B</code>) for bus 3,7,..</li>
  <li>fuel level (vendor <code class="language-plaintext highlighter-rouge">C</code>) for 10,2,3,..</li>
  <li>speed (vendor <code class="language-plaintext highlighter-rouge">D</code>) for 99,1,3,..</li>
  <li>etc</li>
</ul>

<p>What we need to build after receiving data is aggregated “view” for each of the vehicle:</p>

<ul>
  <li>vehicle #1 - coordinates, speed</li>
  <li>vehicle #2 - coordinates, fuel level</li>
  <li>vehicle #3 - coordinates, delay, fuel level, speed</li>
  <li>etc..</li>
</ul>

<p><img src="/assets/img/2020/01/4.4.png" alt="4.4" /></p>

<p>What we ended up with from data processing architecture perspective is something very similar to <a href="https://docs.microsoft.com/en-us/azure/architecture/patterns/pipes-and-filters">“Pipes &amp; Filters” architecture</a>.</p>

<p>Composition process starts with getting all snapshots from all available data sources (collectors).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="n">Vendor1Response</span> <span class="n">v1Result</span><span class="p">;</span>
<span class="n">Vendor2Response</span> <span class="n">v2Result</span><span class="p">;</span>

<span class="kt">var</span> <span class="n">v1Task</span> <span class="p">=</span> <span class="n">_v1Repository</span><span class="p">.</span><span class="nf">GetLatestAsync</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">v2Task</span> <span class="p">=</span> <span class="n">_v2Repository</span><span class="p">.</span><span class="nf">GetLatestAsync</span><span class="p">();</span>

<span class="n">Task</span><span class="p">.</span><span class="nf">WaitAll</span><span class="p">(</span><span class="n">v1Task</span><span class="p">,</span> <span class="n">v2Task</span><span class="p">);</span>

<span class="n">v1Result</span> <span class="p">=</span> <span class="n">v1Task</span><span class="p">.</span><span class="n">Result</span><span class="p">;</span>
<span class="n">v2Result</span> <span class="p">=</span> <span class="n">v2Task</span><span class="p">.</span><span class="n">Result</span><span class="p">;</span>
<span class="p">...</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="pipes--filters">Pipes &amp; Filters</h3>

<p>Process of sorting data by transport we call “matching data points”. This is next step in data processing pipeline. Logic of the matcher is pretty our customer specific (as it involves various decisions how to “glue” together various data sources and by which values).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">model</span> <span class="p">=</span> <span class="nf">RunMatchers</span><span class="p">(</span><span class="n">v1Result</span><span class="p">,</span> <span class="n">v2Result</span><span class="p">,</span> <span class="p">...);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Next step is to execute some common pre-processors (like detecting transport type, assigning ID for the transport, etc).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>RunCommonPreProcessors(ref model);
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>NB!</strong> We are passing <code class="language-plaintext highlighter-rouge">model</code> here by <code class="language-plaintext highlighter-rouge">ref</code> not because we need access variable by reference (it is already a reference type - <code class="language-plaintext highlighter-rouge">class</code>) but to aware other developers that this method <strong>will</strong> mutate passed in variable. We find it as nice convention.</p>

<p>Then we need to group vehicles by its transport type (filter) and run configured data processors (pipe) for each of the transport type. This is optimization in the process as we don’t need to execute the same processor for bus and boat transport. Common processors have been executed already in common pre-processor pipeline.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">buses</span> <span class="p">=</span> <span class="n">model</span><span class="p">.</span><span class="n">Items</span><span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">t</span> <span class="p">=&gt;</span> <span class="n">t</span><span class="p">.</span><span class="n">TransportType</span> <span class="p">==</span> <span class="n">TransportType</span><span class="p">.</span><span class="n">Bus</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">boats</span> <span class="p">=</span> <span class="n">model</span><span class="p">.</span><span class="n">Items</span><span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">t</span> <span class="p">=&gt;</span> <span class="n">t</span><span class="p">.</span><span class="n">TransportType</span> <span class="p">==</span> <span class="n">TransportType</span><span class="p">.</span><span class="n">Water</span><span class="p">);</span>

<span class="nf">RunBusProcessors</span><span class="p">(</span><span class="k">ref</span> <span class="n">buses</span><span class="p">);</span>
<span class="nf">RunBoatProcessors</span><span class="p">(</span><span class="k">ref</span> <span class="n">boats</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As we are working with reference types here, we can then just to continue with content of <code class="language-plaintext highlighter-rouge">model</code> without copying back result from processors.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nf">RunCommonPostProcessors</span><span class="p">(</span><span class="k">ref</span> <span class="n">model</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/2020/01/5.0.2-2.png" alt="5.0.2-2" /></p>

<p>This is how data processing pipeline looks like.
Building the pipeline for the processors is truly as simple as creating list of processor instances that implement the same interface:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">Composer</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">ICollection</span><span class="p">&lt;</span><span class="n">IPreProcessor</span><span class="p">&gt;</span> <span class="n">_preProcessors</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">Composer</span><span class="p">(</span><span class="n">ICollection</span><span class="p">&lt;</span><span class="n">IPreProcessor</span><span class="p">&gt;</span> <span class="n">preProcessors</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_preProcessors</span> <span class="p">=</span> <span class="n">preProcessors</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">RunCommonPreProcessors</span><span class="p">(</span><span class="k">ref</span> <span class="n">TransportDataModel</span> <span class="n">model</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">foreach</span><span class="p">(</span><span class="kt">var</span> <span class="n">preProcessor</span> <span class="k">in</span> <span class="n">_preProcessors</span><span class="p">)</span>
        <span class="k">foreach</span><span class="p">(</span><span class="kt">var</span> <span class="n">item</span> <span class="k">in</span> <span class="n">model</span><span class="p">.</span><span class="n">Items</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="kt">var</span> <span class="n">transportData</span> <span class="p">=</span> <span class="n">item</span><span class="p">;</span>
            <span class="n">preProcessor</span><span class="p">.</span><span class="nf">Process</span><span class="p">(</span><span class="k">ref</span> <span class="n">transportData</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We need to capture iteration variable <code class="language-plaintext highlighter-rouge">item</code> into separate field <code class="language-plaintext highlighter-rouge">transportData</code> in order to avoid <code class="language-plaintext highlighter-rouge">CS1675</code> (info <a href="https://docs.microsoft.com/en-us/dotnet/csharp/misc/cs1657">here</a>) and escape read-only limitations.</p>

<h3 id="durable-azure-functions-fan-outfan-in">Durable Azure Functions Fan-Out/Fan-In</h3>

<p><strong>NB!</strong> Note here is that Data Composer is running on <em>Azure WebJobs</em> infrastructure. You might be wondering why we are not using some <em>Azure Functions</em> benefits? For example, Durable Azure Functions “Fan-Out/Fan-In” scenario as described <a href="https://docs.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-cloud-backup">here</a>.
We did! We tried this Fan-Out/Fan-In scenario in our test environment. We split whole transport data array into array of individual vehicle and asked Azure Functions runtime to process it in parallel.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
</pre></td><td class="rouge-code"><pre><span class="k">using</span> <span class="nn">Microsoft.Azure.WebJobs.Extensions.DurableTask</span><span class="p">;</span>

<span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="kt">long</span><span class="p">&gt;</span> <span class="nf">Run</span><span class="p">(</span><span class="n">IDurableOrchestrationContext</span> <span class="n">durableContext</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">Vendor1Response</span> <span class="n">v1Result</span><span class="p">;</span>
    <span class="n">Vendor2Response</span> <span class="n">v2Result</span><span class="p">;</span>

    <span class="kt">var</span> <span class="n">v1Task</span> <span class="p">=</span> <span class="n">_v1Repository</span><span class="p">.</span><span class="nf">GetLatestAsync</span><span class="p">();</span>
    <span class="kt">var</span> <span class="n">v2Task</span> <span class="p">=</span> <span class="n">_v2Repository</span><span class="p">.</span><span class="nf">GetLatestAsync</span><span class="p">();</span>

    <span class="n">Task</span><span class="p">.</span><span class="nf">WaitAll</span><span class="p">(</span><span class="n">v1Task</span><span class="p">,</span> <span class="n">v2Task</span><span class="p">);</span>

    <span class="n">v1Result</span> <span class="p">=</span> <span class="n">v1Task</span><span class="p">.</span><span class="n">Result</span><span class="p">;</span>
    <span class="n">v2Result</span> <span class="p">=</span> <span class="n">v2Task</span><span class="p">.</span><span class="n">Result</span><span class="p">;</span>

    <span class="kt">var</span> <span class="n">model</span> <span class="p">=</span> <span class="nf">RunMatchers</span><span class="p">(</span><span class="n">v1Result</span><span class="p">,</span> <span class="n">v2Result</span><span class="p">,</span> <span class="p">...);</span>
    <span class="kt">var</span> <span class="n">tasks</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Task</span><span class="p">[</span><span class="n">model</span><span class="p">.</span><span class="n">Items</span><span class="p">.</span><span class="n">Count</span><span class="p">];</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="p">&lt;</span> <span class="n">model</span><span class="p">.</span><span class="n">Items</span><span class="p">.</span><span class="n">Count</span><span class="p">;</span> <span class="n">i</span><span class="p">++)</span>
    <span class="p">{</span>
        <span class="n">tasks</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="p">=</span> <span class="n">durableContext</span><span class="p">.</span><span class="nf">CallActivityAsync</span><span class="p">(</span><span class="s">"RunPipeline"</span><span class="p">,</span> <span class="n">model</span><span class="p">.</span><span class="n">Items</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
    <span class="p">}</span>

    <span class="k">await</span> <span class="n">Task</span><span class="p">.</span><span class="nf">WhenAll</span><span class="p">(</span><span class="n">tasks</span><span class="p">);</span>

    <span class="c1">// save processed model to storage</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">RunPipeline</span><span class="p">(</span>
    <span class="p">[</span><span class="n">ActivityTrigger</span><span class="p">]</span> <span class="n">TransportDataModelItem</span> <span class="n">item</span><span class="p">,</span>
    <span class="n">ILogger</span> <span class="n">log</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// run all pre-processors on `item`</span>
    <span class="c1">// run all processors</span>
    <span class="c1">// run all post-processors</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Essentially we re-architectured data flow into something like this:</p>

<p><img src="/assets/img/2020/01/5.0.3-1.png" alt="5.0.3-1" /></p>

<p>At the end - every pipeline was represented as sort of microservice that is capable of processing single transport unit.
This seems like pretty descend solution! <strong>However</strong> - after few hundred runs (cold starts, and warm executes) we came to conclusion that Azure Functions Durable runtime (<a href="https://github.com/Azure/durabletask">Durable Task Framework</a> to be precise) <strong><em>spends a lot of time</em></strong> in infrastructure layer. “A lot of time” - for us is a definition of “longer than 1 second”. What I mean by this is that writing to Azure Storage (to persist state), loading that state later in function instance to work on it (“Fan-Out”), then after finish - storing it back, and then at the end - to compose together (“Fan-In”) took for us too long. As we are talking about near real-time processing - we could not afford this delay in our case.</p>

<h3 id="running-in-parallel">Running in Parallel</h3>

<p>So we had to find a solution to process data as fast as possible. At the end we decided to go with Azure WebJobs runtime that is hosted on Azure App Service.
In this case we have more granular control over when and where we would like to introduce parallelization and concurrent data processing. We did many experiments on timing and parallelization degree tuning. After all we implemented parallel processing by transport type:</p>

<p><img src="/assets/img/2020/01/5.0.4.png" alt="5.0.4" /></p>

<p>Running on Azure WebJobs (and having closer access to underlying CPUs) we were able to run processing code quite efficiently.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">buses</span> <span class="p">=</span> <span class="n">model</span><span class="p">.</span><span class="n">Items</span><span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">t</span> <span class="p">=&gt;</span> <span class="n">t</span><span class="p">.</span><span class="n">TransportType</span> <span class="p">==</span> <span class="n">TransportType</span><span class="p">.</span><span class="n">Bus</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">boats</span> <span class="p">=</span> <span class="n">model</span><span class="p">.</span><span class="n">Items</span><span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">t</span> <span class="p">=&gt;</span> <span class="n">t</span><span class="p">.</span><span class="n">TransportType</span> <span class="p">==</span> <span class="n">TransportType</span><span class="p">.</span><span class="n">Water</span><span class="p">);</span>
<span class="p">...</span>

<span class="kt">var</span> <span class="n">tasks</span> <span class="p">=</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">Task</span><span class="p">&gt;();</span>
<span class="kt">var</span> <span class="n">t1</span> <span class="p">=</span> <span class="nf">RunBusProcessors</span><span class="p">(</span><span class="k">ref</span> <span class="n">buses</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">t2</span> <span class="p">=</span> <span class="nf">RunBoatProcessors</span><span class="p">(</span><span class="k">ref</span> <span class="n">boats</span><span class="p">);</span>

<span class="k">await</span> <span class="n">Task</span><span class="p">.</span><span class="nf">WhenAll</span><span class="p">(</span><span class="n">t1</span><span class="p">,</span> <span class="n">t2</span><span class="p">,</span> <span class="p">...);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Running processing pipeline in Azure WebJobs infrastructure allows us to control when and how we do concurrent execution and avoids spending time in infrastructure to support parallel execution using Durable Azure Functions.</p>

<h2 id="building-time-based-index">Building Time-based Index</h2>

<p>What we call “Time-based Index” is actually a combination of table and blob storage for this large amount of data.</p>

<p><img src="/assets/img/2020/01/10-tiny.png" alt="10-tiny" /></p>

<p>“Time-based Index” for generate data is pre-requisite for building feature that we will take a look at in next blog posts in this series. Feature is requiring data lookup by date and time.</p>

<p>As we noticed Azure Blob storage does not support search. <code class="language-plaintext highlighter-rouge">CloudBlobContainer</code> is supporting “direct” access to known blob by its name (for example method <code class="language-plaintext highlighter-rouge">GetBlockBlobReference()</code>). What we will need is - “return me closest blob (composed snapshot of the data) at 2020-01-21 04:55:23 UTC”. We can fire off this query to Blob Storage hoping that SDK will return required data.</p>

<p>What we ended up with is saving records in Azure Table Storage for easy lookup. Each table record has reference to blob for that moment in time.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">StoreSnapshotAsync</span><span class="p">(</span>
    <span class="kt">byte</span><span class="p">[]</span> <span class="n">data</span><span class="p">,</span>
    <span class="kt">string</span> <span class="n">blobReference</span><span class="p">,</span>
    <span class="n">DateTime</span> <span class="n">requestDate</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">container</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">GetTimeMachineBlobContainerAsync</span><span class="p">();</span>
    <span class="kt">var</span> <span class="n">reference</span> <span class="p">=</span> <span class="n">container</span><span class="p">.</span><span class="nf">GetBlockBlobReference</span><span class="p">(</span><span class="n">blobReference</span><span class="p">);</span>

    <span class="k">await</span> <span class="n">reference</span><span class="p">.</span><span class="nf">UploadFromByteArrayAsync</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">data</span><span class="p">.</span><span class="n">Length</span><span class="p">);</span>

    <span class="k">await</span> <span class="nf">SaveBlobReferenceInTableAsync</span><span class="p">(</span><span class="n">blobReference</span><span class="p">,</span> <span class="n">requestDate</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Here <code class="language-plaintext highlighter-rouge">blobReference</code> could be any value. For easier maintenance in the future we are just using human readable format - <code class="language-plaintext highlighter-rouge">$"TransportModel_{generatedAt:dd.MM.yyyy HH:mm:ss}"</code>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">SaveBlobReferenceInTableAsync</span><span class="p">(</span>
    <span class="kt">string</span> <span class="n">blobReference</span><span class="p">,</span>
    <span class="n">DateTime</span> <span class="n">recordDate</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">table</span> <span class="p">=</span> <span class="nf">GetOrCreateTable</span><span class="p">();</span>
    <span class="kt">var</span> <span class="n">newEntity</span> <span class="p">=</span> <span class="k">new</span> <span class="n">BlobMetaDataTableEntity</span>
    <span class="p">{</span>
        <span class="n">PartitionKey</span> <span class="p">=</span> <span class="n">tablePartitionKey</span><span class="p">,</span>
        <span class="n">RowKey</span> <span class="p">=</span> <span class="n">recordDate</span><span class="p">.</span><span class="nf">ToString</span><span class="p">(</span><span class="n">PartitionKeyFormat</span><span class="p">),</span>
        <span class="n">RecordDate</span> <span class="p">=</span> <span class="n">recordDate</span><span class="p">,</span>
        <span class="n">BlobReference</span> <span class="p">=</span> <span class="n">blobReference</span>
    <span class="p">};</span>

    <span class="kt">var</span> <span class="n">insertOperation</span> <span class="p">=</span> <span class="n">TableOperation</span><span class="p">.</span><span class="nf">Insert</span><span class="p">(</span><span class="n">newEntity</span><span class="p">);</span>
    <span class="k">await</span> <span class="n">table</span><span class="p">.</span><span class="nf">ExecuteAsync</span><span class="p">(</span><span class="n">insertOperation</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is how table record looks like (with reference to blob):</p>

<p><img src="/assets/img/2020/01/11.png" alt="11" /></p>

<p>This is blob entity with meta-data:</p>

<p><img src="/assets/img/2020/01/12.png" alt="12" /></p>

<p>By using this table record + reference to blob allows us to do queries like this (to return all composed data snapshots between <code class="language-plaintext highlighter-rouge">08:46:50</code> - <code class="language-plaintext highlighter-rouge">08:47:00</code> on <code class="language-plaintext highlighter-rouge">2020-01-16</code>):</p>

<p><img src="/assets/img/2020/01/13.png" alt="13" /></p>

<p>We will see in future posts how we can make use of this data structure to build some cool features for the solution.</p>

<p>Happy coding!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Azure Functions" /><category term="Azure" /><category term="WebJobs" /><category term=".net" /><category term="c#" /><category term="grpc" /><category term="azure" /><category term="azure functions" /><category term="webjobs" /><summary type="html"><![CDATA[This is next post in series about real-time public transport tracking system development based on Azure infrastructure and services. This article is a part of Applied Cloud Stories initiative - aka.ms/applied-cloud-stories.]]></summary></entry><entry><title type="html">Episerver ContentArea with AllowedTypes Specified by Interface</title><link href="https://tech-fellow.eu/2020/01/12/episerver-contentarea-with-allowedtypes-specified-by-interface/" rel="alternate" type="text/html" title="Episerver ContentArea with AllowedTypes Specified by Interface" /><published>2020-01-12T21:45:00+02:00</published><updated>2020-01-12T21:45:00+02:00</updated><id>https://tech-fellow.eu/2020/01/12/episerver-contentarea-with-allowedtypes-specified-by-interface</id><content type="html" xml:base="https://tech-fellow.eu/2020/01/12/episerver-contentarea-with-allowedtypes-specified-by-interface/"><![CDATA[<h2 id="background">Background</h2>

<p>Once an interesting question was asked on <a href="https://episervercommunity.slack.com/">Episerver Community Slack space</a> how to work with ContentAreas and specifically <code class="language-plaintext highlighter-rouge">[AllowedTypes]</code> and specify restrictions based on interface.</p>

<p><img src="/assets/img/2020/01/2020-01-12_21-23-34.png" alt="2020-01-12_21-23-34" /></p>

<p>My answer wasn’t quite helpful there and also I’m <a href="https://tech-fellow.ghost.io/tag/look-inside/">quite passionate about looking into the foreign code</a> and understanding how platform is built - so I decided to write up a bit expanded version of the answer.</p>

<p>According to aforementioned question you might have for example page type with following <code class="language-plaintext highlighter-rouge">ContentArea</code> definition (based on AlloyTech sample site):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ContentType</span><span class="p">(</span><span class="n">GUID</span> <span class="p">=</span> <span class="s">"19671657-B684-4D95-A61F-8DD4FE60D559"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">SamplePage</span> <span class="p">:</span> <span class="n">SitePageData</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">AllowedTypes</span><span class="p">(</span>
        <span class="n">AllowedTypes</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span> <span class="p">{</span><span class="k">typeof</span><span class="p">(</span><span class="n">ISpecificBlock</span><span class="p">)})]</span>
    <span class="k">public</span> <span class="k">virtual</span> <span class="n">ContentArea</span> <span class="n">MainContentArea</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And some random blocks:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">interface</span> <span class="nc">ISpecificBlock</span>
<span class="p">{</span>
<span class="p">}</span>

<span class="p">[</span><span class="nf">ContentType</span><span class="p">(</span><span class="n">DisplayName</span> <span class="p">=</span> <span class="s">"SpecificBlock"</span><span class="p">,</span> <span class="n">GUID</span> <span class="p">=</span> <span class="s">"..."</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">SpecificBlock</span> <span class="p">:</span> <span class="n">BlockData</span><span class="p">,</span> <span class="n">ISpecificBlock</span>
<span class="p">{</span>
<span class="p">}</span>

<span class="p">[</span><span class="nf">ContentType</span><span class="p">(</span><span class="n">DisplayName</span> <span class="p">=</span> <span class="s">"SpecificBlock 2"</span><span class="p">,</span> <span class="n">GUID</span> <span class="p">=</span> <span class="s">"..."</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">SpecificBlock2</span> <span class="p">:</span> <span class="n">BlockData</span><span class="p">,</span> <span class="n">ISpecificBlock</span>
<span class="p">{</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If you will run this sample code in AlloyTech - you will see that once you created instance of either <code class="language-plaintext highlighter-rouge">SpecificBlock</code> or <code class="language-plaintext highlighter-rouge">SpecificBlock2</code> blocks - you can’t really drag them onto <code class="language-plaintext highlighter-rouge">MainContentArea</code> editor for <code class="language-plaintext highlighter-rouge">StartPage</code>.</p>

<p>Seems like Episerver is not “expanding” interface definition for allowed types for content areas.</p>

<p><strong>NB!</strong> Solutions may contain some workarounds and hacks. Use on your own risk!</p>

<h2 id="getting-it-to-work---registration">Getting It to Work - Registration</h2>

<p>Built-in magic happens in class named <code class="language-plaintext highlighter-rouge">ContentDataAttributeScanningAssigner</code> which implements <code class="language-plaintext highlighter-rouge">IContentTypeModelAssigner</code> interface. Method called <code class="language-plaintext highlighter-rouge">AssignValuesToPropertyDefinition</code>.</p>

<p>In order for us to alter behavior - the easiest way would be to intercept call to original assigner and mix-in our logic along the way.</p>

<p>For this to work we will need to register interceptor. Not sure why Episerver is registering some of the dependencies at <code class="language-plaintext highlighter-rouge">ConfigurationComplete</code> event (might be due to fact that services registered then needs to be “last in the row”). This happens in module called <code class="language-plaintext highlighter-rouge">CmsRuntimeInitialization</code>. So we will need to even more last in the row and intercept assigner after it’s being registered in service collection.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">CmsRuntimeInitialization</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">DependencyResolverInitialization</span> <span class="p">:</span> <span class="n">IConfigurableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureContainer</span><span class="p">(</span><span class="n">ServiceConfigurationContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">context</span><span class="p">.</span><span class="n">ConfigurationComplete</span> <span class="p">+=</span> <span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="n">args</span><span class="p">)</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="n">context</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="n">Intercept</span><span class="p">&lt;</span><span class="n">IContentTypeModelAssigner</span><span class="p">&gt;(</span>
                <span class="p">(</span><span class="n">sl</span><span class="p">,</span> <span class="n">svc</span><span class="p">)</span> <span class="p">=&gt;</span>
                    <span class="k">new</span> <span class="nf">IContentTypeModelAssignerInterceptor</span><span class="p">(</span>
                        <span class="n">svc</span><span class="p">,</span>
                        <span class="n">sl</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">ITypeScannerLookup</span><span class="p">&gt;()));</span>
        <span class="p">};</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="getting-it-to-work---intercepting-assignment">Getting It to Work - Intercepting Assignment</h2>

<p>Next step is to intercept property definition model assignment and “expand” mentioned interface into concrete classes.</p>

<p>For that we will need access to original <code class="language-plaintext highlighter-rouge">IContentTypeModelAssigner</code> and also we will require <code class="language-plaintext highlighter-rouge">ITypeScannerLookup</code> to find concrete classes that implement mentioned interface.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">IContentTypeModelAssignerInterceptor</span> <span class="p">:</span> <span class="n">IContentTypeModelAssigner</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IContentTypeModelAssigner</span> <span class="n">_inner</span><span class="p">;</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">ITypeScannerLookup</span> <span class="n">_typeScannerLookup</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">IContentTypeModelAssignerInterceptor</span><span class="p">(</span>
        <span class="n">IContentTypeModelAssigner</span> <span class="n">inner</span><span class="p">,</span>
        <span class="n">ITypeScannerLookup</span> <span class="n">typeScannerLookup</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_inner</span> <span class="p">=</span> <span class="n">inner</span><span class="p">;</span>
        <span class="n">_typeScannerLookup</span> <span class="p">=</span> <span class="n">typeScannerLookup</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">AssignValues</span><span class="p">(</span><span class="n">ContentTypeModel</span> <span class="n">contentTypeModel</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// we are not changing behavior for this method</span>
        <span class="c1">// so just pass-through</span>

        <span class="n">_inner</span><span class="p">.</span><span class="nf">AssignValues</span><span class="p">(</span><span class="n">contentTypeModel</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">AssignValuesToPropertyDefinition</span><span class="p">(</span>
        <span class="n">PropertyDefinitionModel</span> <span class="n">propertyDefinitionModel</span><span class="p">,</span>
        <span class="n">PropertyInfo</span> <span class="n">property</span><span class="p">,</span>
        <span class="n">ContentTypeModel</span> <span class="n">parentModel</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// execute default behavior</span>
        <span class="n">_inner</span><span class="p">.</span><span class="nf">AssignValuesToPropertyDefinition</span><span class="p">(</span><span class="n">propertyDefinitionModel</span><span class="p">,</span> <span class="n">property</span><span class="p">,</span> <span class="n">parentModel</span><span class="p">);</span>

        <span class="c1">// check if property is of type `ContentArea`</span>
        <span class="c1">// if so - then we are looking for `AllowedTypes` attribute</span>
        <span class="k">if</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">ContentArea</span><span class="p">).</span><span class="nf">IsAssignableFrom</span><span class="p">(</span><span class="n">propertyDefinitionModel</span><span class="p">.</span><span class="n">Type</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="kt">var</span> <span class="n">allowedAttribute</span> <span class="p">=</span> <span class="n">propertyDefinitionModel</span>
                <span class="p">.</span><span class="n">Attributes</span>
                <span class="p">.</span><span class="n">GetSingleAttribute</span><span class="p">&lt;</span><span class="n">AllowedTypesAttribute</span><span class="p">&gt;();</span>

            <span class="k">if</span> <span class="p">(</span><span class="n">allowedAttribute</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">allowedType</span> <span class="k">in</span> <span class="n">allowedAttribute</span><span class="p">.</span><span class="n">AllowedTypes</span><span class="p">)</span>
                <span class="p">{</span>
                    <span class="c1">// let's do magic only when allowed type is interface</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">allowedType</span><span class="p">.</span><span class="n">IsInterface</span><span class="p">)</span>
                    <span class="p">{</span>
                        <span class="kt">var</span> <span class="n">concreteClasses</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">Type</span><span class="p">&gt;();</span>

                        <span class="c1">// we need to find list of classes implementing this interface</span>
                        <span class="kt">var</span> <span class="n">foundChildClasses</span> <span class="p">=</span>
                            <span class="n">_typeScannerLookup</span><span class="p">.</span><span class="n">AllTypes</span><span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">t</span> <span class="p">=&gt;</span> <span class="n">allowedType</span><span class="p">.</span><span class="nf">IsAssignableFrom</span><span class="p">(</span><span class="n">t</span><span class="p">));</span>

                        <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">foundChildClass</span> <span class="k">in</span> <span class="n">foundChildClasses</span><span class="p">)</span>
                        <span class="p">{</span>
                            <span class="n">concreteClasses</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">foundChildClass</span><span class="p">);</span>
                        <span class="p">}</span>

                        <span class="c1">// assign back attribute with added concrete classes</span>
                        <span class="n">allowedAttribute</span><span class="p">.</span><span class="n">AllowedTypes</span> <span class="p">=</span>
                            <span class="n">concreteClasses</span><span class="p">.</span><span class="nf">Concat</span><span class="p">(</span><span class="n">allowedAttribute</span><span class="p">.</span><span class="n">AllowedTypes</span><span class="p">).</span><span class="nf">ToArray</span><span class="p">();</span>
                    <span class="p">}</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>After this code being executed in AlloyTech sample site - you can add block instances which are implementing <code class="language-plaintext highlighter-rouge">ISpecificBlock</code> interface to <code class="language-plaintext highlighter-rouge">SamplePage</code>’s content area named <code class="language-plaintext highlighter-rouge">MainContentArea</code>.</p>

<p>Happy content data modeling!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><category term="open source" /><summary type="html"><![CDATA[Background]]></summary></entry><entry><title type="html">Episerver DeveloperTools - UI Refresh</title><link href="https://tech-fellow.eu/2020/01/03/episerver-developertools-ui-refresh/" rel="alternate" type="text/html" title="Episerver DeveloperTools - UI Refresh" /><published>2020-01-03T21:45:00+02:00</published><updated>2020-01-03T21:45:00+02:00</updated><id>https://tech-fellow.eu/2020/01/03/episerver-developertools-ui-refresh</id><content type="html" xml:base="https://tech-fellow.eu/2020/01/03/episerver-developertools-ui-refresh/"><![CDATA[<p>Been busy with some UI refreshment effort on <a href="https://nuget.episerver.com/package/?id=EPiServer.DeveloperTools">Episerver DeveloperTools</a>.</p>

<p>Latest version (v3.5) released on NuGet feed has following changes:</p>

<ul>
  <li>now UI rewritten in Razor (yes! Episerver developer tools were still written in WebForms).</li>
  <li>With rewrite to Razor view engine and due to some issue in Episerver module delivery mechanism (specifically when module is served from Zip archive) included <code class="language-plaintext highlighter-rouge">web.config</code> file is ignored resulting in runtime errors (more info <a href="https://world.episerver.com/forum/developer-forum/Developer-to-developer/Thread-Container/2019/4/issue-with-razor-views-while-developing-custom-add-on/#204171">here</a>). Because of this change - <code class="language-plaintext highlighter-rouge">Episerver.DeveloperTools</code> is served as “expanded” module - meaning that all view files are copied to target project under appropriate protected module directory. <strong>NB!</strong> Upgrade from previous versions have been tested in sandbox project, but if you face some runtime issues - so just you know of this change!</li>
  <li>also dependency is now set on Episerver UI <code class="language-plaintext highlighter-rouge">[11.21.1, 12)</code>. Which means that UI will be according to new blue-ish theme.</li>
</ul>

<p><img src="/assets/img/2019/11/dev-tools-1.png" alt="dev-tools-1" /></p>

<ul>
  <li>DeveloperTools package have many menu items and might be so that you will have to scroll in order to get to tools outside visible menu area</li>
  <li>Some smaller UI fixes are applied (like adding icons to buttons, etc).</li>
</ul>

<p><strong>NB!</strong> Idea in next iteration is to split all tools apart into separate packages. For example - <code class="language-plaintext highlighter-rouge">EPiServer.DeveloperTools.IoC</code> or <code class="language-plaintext highlighter-rouge">EPiServer.DeveloperTools.LoadedAssemblies</code>. Split would give you an option to install only what you need to use. Still <code class="language-plaintext highlighter-rouge">EPiServer.DeveloperTools</code> package would have reference to all the other packages (very similar as we have seen in <code class="language-plaintext highlighter-rouge">Microsoft.AspNetCore.App</code> package) and would act as “umbrella” package to pull all required packages. Please give me feedback on this idea (pros/cons) in comments below.</p>

<p>If you have any other idea what would be great addition to the tool belt - please reach me out!</p>

<p>To finish this post I’m adding module dependency tool just to remind you how beautiful your Episerver project module dependencies might look :)</p>

<p><img src="/assets/img/2019/11/dev-tools-2.png" alt="dev-tools-2" /></p>

<p>Happy tooling!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><category term="open source" /><summary type="html"><![CDATA[Been busy with some UI refreshment effort on Episerver DeveloperTools.]]></summary></entry><entry><title type="html">Building Real-time Public Transport Tracking System on Azure - Part 1</title><link href="https://tech-fellow.eu/2019/12/08/building-real-time-public-transport-tracking-system-on-azure-part1/" rel="alternate" type="text/html" title="Building Real-time Public Transport Tracking System on Azure - Part 1" /><published>2019-12-08T07:00:00+02:00</published><updated>2019-12-08T07:00:00+02:00</updated><id>https://tech-fellow.eu/2019/12/08/building-real-time-public-transport-tracking-system-on-azure-part1</id><content type="html" xml:base="https://tech-fellow.eu/2019/12/08/building-real-time-public-transport-tracking-system-on-azure-part1/"><![CDATA[<p>This is next post in series about real-time public transport tracking system development based on Azure infrastructure and services. This article is a part of Applied Cloud Stories initiative - <a href="https://aka.ms/applied-cloud-stories">aka.ms/applied-cloud-stories</a>.</p>

<p>This is 1st post in series about real-time public transport tracking system development based on Azure infrastructure and services.</p>

<p>Blog posts in this series:</p>

<ul>
  <li><strong>Part 1 - Scene Background &amp; Solution Architecture</strong></li>
  <li><a href="https://tech-fellow.eu/2020/01/21/building-real-time-public-transport-tracking-system-on-azure-part-2-data-collectors-composer/">Part 2 - Data Collectors &amp; Composer</a></li>
  <li><a href="https://tech-fellow.eu/2020/04/08/building-real-time-public-transport-tracking-system-on-azure-part-3/">Part 3 - Event-Based Data Delivery</a></li>
  <li><a href="https://tech-fellow.eu/2020/08/30/building-real-time-public-transport-tracking-system-on-azure-part-4/">Part 4 - Data Processing Pipelines</a></li>
  <li><a href="https://tech-fellow.eu/2020/11/01/building-real-time-public-transport-tracking-system-on-azure-part-5/">Part 5 - Data Broadcast using gRPC and SignalR</a></li>
  <li><a href="https://tech-fellow.eu/2020/12/14/building-real-time-public-transport-tracking-system-on-azure-part-6-building-frontend/">Part 6 - Building Frontend</a></li>
  <li><a href="https://tech-fellow.eu/2021/01/21/building-real-time-public-transport-tracking-system-on-azure-part-6-packing-everything-up/">Part 7 - Packing Everything Up</a></li>
  <li><a href="https://tech-fellow.eu/2021/01/25/building-linux-docker-images-on-windows-machine/">Part 7.1 - Fixing Docker Image Metrics in Azure</a></li>
</ul>

<p>We are working with transportation company where real-time systems is everyday mindset for each team member. Over few years we have been part of building this system. There were few generations (differences between systems were major refactorings) of the system in this period. Think that we have finally landed on more or less stable implementation. But it’s never frozen - system changes all the time as new services and data become available.</p>

<p>We have been following new technologies (like .NET Core) and data distribution mechanisms (like gRPC). Our customer is keen to try out new features and libraries and these technologies are not exclusion.</p>

<p>Let’s see how this system can be implemented.</p>

<h2 id="architecture">Architecture</h2>

<p>Big picture is quite simple. We have to show data coming from buses to the passengers.</p>

<p><img src="/assets/img/2019/12/1.png" alt="1" /></p>

<p>Picture might look like simple enough, but there are a lot of small moving parts, components and data processing pipelines in the solution. We have to deal with a couple of vendor systems that are used to send data points to centralized aggregator component which is responsible for composing unified transport data snapshot for all running (and also standing still) buses in the region.</p>

<p>Part 2 will focus more on data collection and aggregation process, but from architecture perspective - we built it in the way that new vendors can be plugged-in and obsolete ones can be removed easily. Underlying architecture ideology is based on <a href="https://www.enterpriseintegrationpatterns.com/patterns/messaging/PipesAndFilters.html">pipes and filters architectural style</a>.</p>

<p>We do have many vendors (in picture below showed only vendors named A, B, C, D) to talk to and collect data from. Each of them might be totally different shape and behavior.</p>

<p><img src="/assets/img/2019/12/3.png" alt="3" /></p>

<p>Each vendor supplies data to each processing pipeline where later unified transport data snapshot is produced.
Unified snapshot is then saved in buffer storage. Azure EventGrid subsystem is used to push data further into distribution systems - web application servers to which browsers and other devices are connected to in order to receive real-time updates.</p>

<p><img src="/assets/img/2019/11/5.2.png" alt="5.2" /></p>

<p>Currently we are using <a href="https://dotnet.microsoft.com/apps/aspnet/signalr">SignalR</a> to provide reliable connection to browser to push data through.</p>

<p>Unfortunately due to underlying platform, we are still running on .NET Framework (we have to host SignalR hub on .NET Framework runtime). Exploring new features is part of the deal, therefore we extracted some of the parts of the system into .NET Standard 2.0 projects and started to build new .NET Core powered gRPC Server.</p>

<p>Specifically we want to change this part and try out new protocols and distribution mechanisms.</p>

<p><img src="/assets/img/2019/11/7.png" alt="7" /></p>

<p>So what we trying now is to add additional webhooks to EventGrid registry to forward events also to gRPC server running in <a href="https://docs.microsoft.com/en-us/azure/aks/">AKS</a> for additional distribution scenarios.</p>

<p><img src="/assets/img/2019/12/6.1.png" alt="6.1" /></p>

<p>Stay tuned for more in depth posts about each of the subsystems that take part in the big picture!</p>

<p>Happy coding!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Azure Functions" /><category term="Azure" /><category term="WebJobs" /><category term="gRPC" /><category term="SignalR" /><category term=".net" /><category term="c#" /><category term="grpc" /><category term="azure" /><category term="azure functions" /><category term="webjobs" /><category term="grpc" /><category term="signalr" /><summary type="html"><![CDATA[This is next post in series about real-time public transport tracking system development based on Azure infrastructure and services. This article is a part of Applied Cloud Stories initiative - aka.ms/applied-cloud-stories.]]></summary></entry><entry><title type="html">Converting Azure WebJobs to .NET Core</title><link href="https://tech-fellow.eu/2019/09/15/adding-di-package-to-webjobs-running-on-net-core/" rel="alternate" type="text/html" title="Converting Azure WebJobs to .NET Core" /><published>2019-09-15T08:00:00+03:00</published><updated>2019-09-15T08:00:00+03:00</updated><id>https://tech-fellow.eu/2019/09/15/adding-di-package-to-webjobs-running-on-net-core</id><content type="html" xml:base="https://tech-fellow.eu/2019/09/15/adding-di-package-to-webjobs-running-on-net-core/"><![CDATA[<h2 id="motivation">Motivation</h2>

<p>Migrating something to .NET Core (while stuck with .NET Framework for a while due to surrounding platform dependency constraints) sounds intriguing and challenging at the same time. Our main motivator for the migration has been <a href="https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-core/">performance improvements</a>, <a href="https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-core-2-1/">performance improvements</a> and upcoming <a href="https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-core-3-0/">performance improvements</a> seen throughout .NET Core.</p>

<p>This blog post will walk you through steps we did for migration for one our <a href="https://docs.microsoft.com/en-us/azure/app-service/webjobs-create">web jobs</a> over to .NET Core.</p>

<p>As seen from pull request statistics - it’s actually more removal that adding new code. Throwaway always feels good.</p>

<p><img src="/assets/img/2019/09/2019-07-17_20-53-51.png" alt="2019-07-17_20-53-51" /></p>

<p>Path wasn’t smooth, a bit bumpy - but at the end we reached our destination.</p>

<h2 id="background">Background</h2>

<p>We are building near real-time tracking system for public transportation company. WebJob (still) has one of central role in this system. It does great work by sticking together data from various sources and composing unified data model for later consumption. One of the reason (partially nowadays just historical) we need WebJob in our infrastructure is because running instance needs access to in-memory cache (job running currently requires access to results composed by previous run). Yes - we are storing data in persistent storage. Yes - we know about some “more friendly / managed cache services”. But the fastest way to access results produced by previous run is required. Using in-memory cache showed great results for performance. Hosting options might change of course overtime but for now - WebJob is fair enough for us.</p>

<p>Let’s get started.</p>

<h2 id="planning">Planning</h2>

<p>Before you actually jump to the action and perform real migration tasks, it’s good idea to cross-check project source code and dependencies readiness for migration to .NET Core or .NET Standard. Which target to choose depends on how library is going to be used. As far as I understood:</p>
<ul>
  <li>choose .NET Core is project is going to be “host”. Some executable - either console application or ASP.NET Core web application;</li>
  <li>for the rest - pick .NET Standard (if used APIs are supported there)</li>
</ul>

<p>Great tool for this task is called “Portability Analyzer.” You can grab it from <a href="https://marketplace.visualstudio.com/items?itemName=ConnieYau.NETPortabilityAnalyzer">Visual Studio Marketplace</a>.</p>

<p><img src="/assets/img/2019/09/portability-analyzer.png" alt="portability-analyzer" /></p>

<p>Idea for the tool is to get you prepared before acting. It checks what code is used in project  or solution, also dependencies are checked. Compatibility level for code-base to be migrated to .NET Core or .NET Standard is shown as result report. Tool outputs results in Excel which makes it easy for filtering and reviewing.</p>

<h2 id="transition-to-net-core">Transition to .NET Core</h2>

<h3 id="convert-webjob-project-file">Convert WebJob Project File</h3>

<p>Converting from .NET Framework to .NET Core project file is quite dramatic (in a good way). Zillions of code lines are removed from <code class="language-plaintext highlighter-rouge">.csproj</code> file and only essentials are left.</p>

<p><img src="/assets/img/2019/09/Annotation-2019-08-13-233551.png" alt="Annotation-2019-08-13-233551" /></p>

<p>Before converting, I recommend to migrate from NuGet reference (old-school package references) to “Package Reference” format (even while you are still in .NET Framework). There is a built-in tool inside Visual Studio that can help you with this.</p>

<p><img src="/assets/img/2019/09/migrate-to-pack-ref.png" alt="migrate-to-pack-ref" /></p>

<p>It can be done manually as well of course, but with lots of references - it might get boring at some point.
Tool helps top convert from this:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;ItemGroup&gt;</span>
    <span class="nt">&lt;Reference</span> <span class="na">Include=</span><span class="s">"Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;HintPath&gt;</span>..\..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll<span class="nt">&lt;/HintPath&gt;</span>
    <span class="nt">&lt;/Reference&gt;</span>
<span class="nt">&lt;/ItemGroup&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>to this:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;ItemGroup&gt;</span>
    <span class="nt">&lt;PackageReference</span> <span class="na">Include=</span><span class="s">"Newtonsoft.Json"</span> <span class="na">version=</span><span class="s">"10.0.3"</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;/ItemGroup&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As you can see - we now only need version of the package. You can read more about SDK format type <a href="https://docs.microsoft.com/en-us/dotnet/core/migration/">here</a>.
At the end <code class="language-plaintext highlighter-rouge">.csproj</code> file is much cleaner and have just important parts to get project running.</p>

<p><img src="/assets/img/2019/09/2019-08-13_23-14-11.png" alt="2019-08-13_23-14-11" /></p>

<p>Next step is to upgrade WebJob infrastructure packages to get it running under .NET Core. Following dependencies are required for WebJob to run on .NET Core (at the moment of writing):</p>

<ul>
  <li>Microsoft.Azure.WebJobs (v3.x)</li>
  <li>Microsoft.Azure.WebJobs.Extensions (v3.x)</li>
  <li>Microsoft.Azure.WebJobs.Extensions.Storage (v3.x)</li>
  <li>Microsoft.Extensions.DependencyInjection (v2.2.x)</li>
  <li>Microsoft.Extensions.Options.ConfigurationExtensions (v2.2.x)</li>
</ul>

<p>Optional references:</p>

<ul>
  <li>Microsoft.Extensions.Configuration.CommandLine (v2.2.x)</li>
  <li>Microsoft.Extensions.Logging.Console (v2.2.x)</li>
</ul>

<h3 id="leaving-dependencies-in-net-framework">Leaving Dependencies in .NET Framework</h3>

<p>In cases when you can’t convert dependency to .NET Standard or .NET Core, we extracted sharable pieces into separate project and converted that to .NET Standard and leaving rest of the code in .NET Framework. By doing this we could ensure that code is reused as much as possible (like data structures, model definitions, anything that can be converted to .NET Standard, etc.) and framework specific thingies are left in old project. Results is architecture where part of the system is running on .NET Framework (by referencing .NET Standard targeted shared project) and other part of the system is capable of running on .NET Core (also using the same shared components targeting .NET Standard).</p>

<p>In our case - we had WCF service client reading data from remote API endpoint, processing data and then writing it to the Azure Storage.</p>

<p><img src="/assets/img/2019/09/fx-netstd-core-1-3.png" alt="fx-netstd-core-1-3" /></p>

<p>Later data was read from Azure Storage and processed dureing composition process. However - the same WCF service client library was used to read data from Azure Storage.</p>

<p><img src="/assets/img/2019/09/fx-netstd-core-2.png" alt="fx-netstd-core-2" /></p>

<p>As we realized WCF client API library is not quite movable to .NET Core or .NET Standard target, we have extract some of the shared parts and reuse that in composition process (which will be running on .NET Core).</p>

<p><img src="/assets/img/2019/09/fx-netstd-core-3.png" alt="fx-netstd-core-3" /></p>

<p>Azure Storage reader code fragment was taken out and moved .NET Standard. This extraction also made it possible to read data from other .NET Standard or .NET Core projects in our system.</p>

<h3 id="shared-library-and-transient-dependencies">Shared Library and Transient Dependencies</h3>

<p>In our structure there are some applications still running on .NET Framework. In .NET Framework project it is possible to reference .NET Standard targeted project. You just have to be aware that there are some issues for .NET Framework based project to “collect” transient dependencies coming from .NET Standard project(s) and copy those in output directory.
Meaning that if you have structure <code class="language-plaintext highlighter-rouge">A (netfx) -&gt; B (netstandard) -&gt; C (netstandard)</code> there are high chances that project <code class="language-plaintext highlighter-rouge">C (netstandard)</code> which is transient dependency to project <code class="language-plaintext highlighter-rouge">A (netfx)</code> will not be copied to output directory of <code class="language-plaintext highlighter-rouge">A (netfx)</code>. This will result in runtime errors blaming that required types could not be loaded.
Workaround for this is to just reference project <code class="language-plaintext highlighter-rouge">C (netstandard)</code> directly from project <code class="language-plaintext highlighter-rouge">A (netfx)</code> =&gt; <code class="language-plaintext highlighter-rouge">A (netfx) -&gt; C (netstandard)</code>. Cumbersome, but this works!</p>

<h3 id="converting-programcs">Converting Program.cs</h3>

<p>WebJob is just ordinary console application that is running in Azure WebJobs host.
Looking at old WebJob <code class="language-plaintext highlighter-rouge">Program.cs</code> file you can see that there is not so much configuration (for example - you can’t really see how logging is done):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="k">class</span> <span class="nc">Program</span>
<span class="p">{</span>
    <span class="k">static</span> <span class="k">void</span> <span class="nf">Main</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">container</span> <span class="p">=</span> <span class="nf">ComposeContainer</span><span class="p">();</span>
        <span class="kt">var</span> <span class="n">config</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">JobHostConfiguration</span><span class="p">();</span>

        <span class="k">if</span><span class="p">(</span><span class="n">ScheduledTimeTableConfig</span><span class="p">.</span><span class="n">IsDevelopment</span><span class="p">)</span>
            <span class="n">config</span><span class="p">.</span><span class="nf">UseDevelopmentSettings</span><span class="p">();</span>

        <span class="n">config</span><span class="p">.</span><span class="nf">UseTimers</span><span class="p">();</span>

        <span class="kt">var</span> <span class="n">host</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">JobHost</span><span class="p">(</span><span class="n">config</span><span class="p">);</span>
        <span class="n">host</span><span class="p">.</span><span class="nf">RunAndBlock</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>WebJobs based .NET Framework have lots of configuration located in <code class="language-plaintext highlighter-rouge">App.config</code> file.
New .NET Core WebJobs <code class="language-plaintext highlighter-rouge">Program.cs</code> file is just yet another .NET Core application with all the required configuration in code (which is very nice). It helps to understand what is being used by looking at the code:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
</pre></td><td class="rouge-code"><pre><span class="k">internal</span> <span class="k">class</span> <span class="nc">Program</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">Main</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">args</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">HostBuilder</span><span class="p">();</span>
        <span class="n">builder</span><span class="p">.</span><span class="nf">ConfigureWebJobs</span><span class="p">(</span><span class="n">b</span> <span class="p">=&gt;</span>
                <span class="p">{</span>
                    <span class="n">b</span><span class="p">.</span><span class="nf">AddAzureStorageCoreServices</span><span class="p">();</span>
                    <span class="n">b</span><span class="p">.</span><span class="nf">AddAzureStorage</span><span class="p">();</span>
                    <span class="n">b</span><span class="p">.</span><span class="nf">AddTimers</span><span class="p">();</span>
                <span class="p">})</span>
               <span class="p">.</span><span class="nf">ConfigureAppConfiguration</span><span class="p">(</span><span class="n">b</span> <span class="p">=&gt;</span>
                <span class="p">{</span>
                    <span class="c1">// Adding command line as additional configuration source</span>
                    <span class="n">b</span><span class="p">.</span><span class="nf">AddCommandLine</span><span class="p">(</span><span class="n">args</span><span class="p">);</span>
                <span class="p">})</span>
               <span class="p">.</span><span class="nf">ConfigureLogging</span><span class="p">((</span><span class="n">context</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span> <span class="p">=&gt;</span>
                <span class="p">{</span>
                    <span class="c1">// here we can access context.HostingEnvironment.IsDevelopment() yet</span>
                    <span class="k">if</span><span class="p">(</span><span class="n">context</span><span class="p">.</span><span class="n">Configuration</span><span class="p">[</span><span class="s">"environment"</span><span class="p">]</span> <span class="p">==</span> <span class="n">EnvironmentName</span><span class="p">.</span><span class="n">Development</span><span class="p">)</span>
                    <span class="p">{</span>
                        <span class="n">b</span><span class="p">.</span><span class="nf">SetMinimumLevel</span><span class="p">(</span><span class="n">LogLevel</span><span class="p">.</span><span class="n">Debug</span><span class="p">);</span>
                        <span class="n">b</span><span class="p">.</span><span class="nf">AddConsole</span><span class="p">();</span>
                    <span class="p">}</span>
                    <span class="k">else</span>
                    <span class="p">{</span>
                        <span class="n">b</span><span class="p">.</span><span class="nf">SetMinimumLevel</span><span class="p">(</span><span class="n">LogLevel</span><span class="p">.</span><span class="n">Information</span><span class="p">);</span>
                    <span class="p">}</span>

                    <span class="c1">// configure CommonLogging to use Serilog</span>
                    <span class="kt">var</span> <span class="n">logConfig</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">LogConfiguration</span><span class="p">();</span>
                    <span class="n">context</span><span class="p">.</span><span class="n">Configuration</span><span class="p">.</span><span class="nf">GetSection</span><span class="p">(</span><span class="s">"LogConfiguration"</span><span class="p">).</span><span class="nf">Bind</span><span class="p">(</span><span class="n">logConfig</span><span class="p">);</span>
                    <span class="n">LogManager</span><span class="p">.</span><span class="nf">Configure</span><span class="p">(</span><span class="n">logConfig</span><span class="p">);</span>

                    <span class="kt">var</span> <span class="n">log</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">LoggerConfiguration</span><span class="p">()</span>
                                      <span class="p">.</span><span class="n">WriteTo</span>
                                      <span class="p">.</span><span class="nf">File</span><span class="p">(</span><span class="s">"webjob-log.txt"</span><span class="p">,</span> <span class="n">rollingInterval</span><span class="p">:</span> <span class="n">RollingInterval</span><span class="p">.</span><span class="n">Day</span><span class="p">)</span>
                                      <span class="p">.</span><span class="nf">CreateLogger</span><span class="p">();</span>
                    <span class="n">Log</span><span class="p">.</span><span class="n">Logger</span> <span class="p">=</span> <span class="n">log</span><span class="p">;</span>
                <span class="p">})</span>
               <span class="p">.</span><span class="nf">ConfigureServices</span><span class="p">((</span><span class="n">context</span><span class="p">,</span> <span class="n">services</span><span class="p">)</span> <span class="p">=&gt;</span>
                <span class="p">{</span>
                    <span class="n">services</span><span class="p">.</span><span class="nf">AddSingleton</span><span class="p">(</span><span class="n">context</span><span class="p">.</span><span class="n">Configuration</span><span class="p">);</span>
                    <span class="n">services</span><span class="p">.</span><span class="nf">AddMemoryCache</span><span class="p">();</span>

                    <span class="c1">// other DI configuration here</span>
                <span class="p">})</span>
               <span class="p">.</span><span class="nf">UseConsoleLifetime</span><span class="p">();</span>

        <span class="kt">var</span> <span class="n">host</span> <span class="p">=</span> <span class="n">builder</span><span class="p">.</span><span class="nf">Build</span><span class="p">();</span>
        <span class="n">Services</span> <span class="p">=</span> <span class="n">host</span><span class="p">.</span><span class="n">Services</span><span class="p">;</span>

        <span class="k">using</span><span class="p">(</span><span class="n">host</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">await</span> <span class="n">host</span><span class="p">.</span><span class="nf">RunAsync</span><span class="p">();</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Following happens in this code fragment:</p>

<ul>
  <li>creating new instance of generic host builder (<code class="language-plaintext highlighter-rouge">HostBuilder</code>)</li>
  <li>as you can see we are not explicitly setting configuration (loading <code class="language-plaintext highlighter-rouge">.json</code> file or using environment variables) - this is done by default already by WebJob configuration (<code class="language-plaintext highlighter-rouge">.ConfigureWebJobs()</code>). Source for this is <a href="https://github.com/Azure/azure-webjobs-sdk/blob/137196291b5edd421e34dbd283486b4640a9334b/src/Microsoft.Azure.WebJobs.Host/Hosting/WebJobsHostBuilderExtensions.cs#L36">available here</a>. Only thing we need to configure is to add command-line argument support. This comes handy when you are debugging and need to pass-in various settings on-fly.</li>
  <li>next need to add logging support. Historically our platform is based on <code class="language-plaintext highlighter-rouge">log4net</code> library to provide logging capabilities for our systems. Over the time we have been able to move away to some more generic abstractions like <code class="language-plaintext highlighter-rouge">Common.Logging</code> in order to remove direct dependency on <code class="language-plaintext highlighter-rouge">log4net</code> library. However this time decided that we have opportunity to remove this dependency at all. We researched couple other logging platforms and decided to go with <a href="https://serilog.net/">Serilog</a>.</li>
  <li>next comes DependencyInjection -&gt; here we are adding our services and its lifetime configuration to service collection.</li>
  <li>then we need to tell host we are in console mode (it adds <code class="language-plaintext highlighter-rouge">ConsoleLifetime</code> configuration as <code class="language-plaintext highlighter-rouge">IHostLifetime</code> implementation). This lifetime manager ensures that application is alive and going to die only by receiving <code class="language-plaintext highlighter-rouge">Ctrl+C</code> keystroke or <code class="language-plaintext highlighter-rouge">SIGTERM</code> and only then initiates shutdown.</li>
  <li>then we are building host itself (<code class="language-plaintext highlighter-rouge">builder.Build()</code>)</li>
  <li>capturing the services from host (<code class="language-plaintext highlighter-rouge">IServiceCollection</code>). This will be required later for job timer functionality. More details below.</li>
  <li>then we need to build the host and launch it</li>
</ul>

<h3 id="adding-di-support">Adding DI Support</h3>

<p>We’ve been using StructureMap dependency injection library for ages, and built practices around it. Team used to APIs and behavior of the StructureMap. Therefore we thought it makes sense to continue to use it and give Microsoft.Extensions.DependencyInjection (aka “MSDI”) package another chance in some different project.</p>

<p>To make StructureMap working under .NET Core infrastructure we will need StructureMap adapter for Microsoft dependency injection framework.</p>

<p>This can be added by following package:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&lt;PackageReference Include="StructureMap.Microsoft.DependencyInjection" Version="2.0.0" /&gt;
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We can configure and setup StructureMap container and tell Microsoft DI infrastructure about services that are configured in StructureMap to be used.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
</pre></td><td class="rouge-code"><pre><span class="k">internal</span> <span class="k">class</span> <span class="nc">Program</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">Main</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">args</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">HostBuilder</span><span class="p">();</span>
        <span class="n">builder</span><span class="p">.</span><span class="nf">ConfigureWebJobs</span><span class="p">(...)</span>
               <span class="p">.</span><span class="nf">UseServiceProviderFactory</span><span class="p">(</span>
                   <span class="k">new</span> <span class="nf">StructureMapServiceProviderFactory</span><span class="p">(</span><span class="n">ComposeContainer</span><span class="p">))</span>
               <span class="p">...</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="k">static</span> <span class="n">Container</span> <span class="nf">ComposeContainer</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">container</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">Container</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="c1">// here goes code to configure container..</span>
            <span class="c1">// for example:</span>
            <span class="c1">//</span>
            <span class="c1">// _.For&lt;ISomeInterface&gt;().Use&lt;SomeServiceImpl&gt;().Singleton();</span>
        <span class="p">});</span>

        <span class="k">return</span> <span class="n">container</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>What’s left is to implement builder for <code class="language-plaintext highlighter-rouge">IServiceProvider</code> implementation. For this we will need access to configured StructureMap container.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="rouge-code"><pre><span class="k">internal</span> <span class="k">class</span> <span class="nc">StructureMapServiceProviderFactory</span> <span class="p">:</span> <span class="n">IServiceProviderFactory</span><span class="p">&lt;</span><span class="n">IContainer</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">Func</span><span class="p">&lt;</span> <span class="n">IContainer</span><span class="p">&gt;</span> <span class="n">_containerBuilder</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">StructureMapServiceProviderFactory</span><span class="p">(</span><span class="n">Func</span><span class="p">&lt;</span><span class="n">IContainer</span><span class="p">&gt;</span> <span class="n">containerBuilder</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_containerBuilder</span> <span class="p">=</span> <span class="n">containerBuilder</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">IContainer</span> <span class="nf">CreateBuilder</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">container</span> <span class="p">=</span> <span class="nf">_containerBuilder</span><span class="p">();</span>
        <span class="n">container</span><span class="p">.</span><span class="nf">Populate</span><span class="p">(</span><span class="n">services</span><span class="p">);</span>

        <span class="k">return</span> <span class="n">container</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">IServiceProvider</span> <span class="nf">CreateServiceProvider</span><span class="p">(</span><span class="n">IContainer</span> <span class="n">containerBuilder</span><span class="p">)</span>
        <span class="p">=&gt;</span> <span class="n">containerBuilder</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">IServiceProvider</span><span class="p">&gt;();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Black magic to “glue” MSDI world with StructureMap one is in this line <code class="language-plaintext highlighter-rouge">container.Populate(services);</code>. During this <code class="language-plaintext highlighter-rouge">Populate()</code> method specific service provider and scope factory are added:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">Populate</span><span class="p">(</span><span class="k">this</span> <span class="n">Registry</span> <span class="n">registry</span><span class="p">,</span>
                            <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">ServiceDescriptor</span><span class="p">&gt;</span> <span class="n">descriptors</span><span class="p">,</span>
                            <span class="kt">bool</span> <span class="n">checkDuplicateCalls</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">registry</span><span class="p">.</span><span class="n">For</span><span class="p">&lt;</span><span class="n">IServiceProvider</span><span class="p">&gt;()</span>
            <span class="p">.</span><span class="nf">LifecycleIs</span><span class="p">(</span><span class="n">Lifecycles</span><span class="p">.</span><span class="n">Container</span><span class="p">)</span>
            <span class="p">.</span><span class="n">Use</span><span class="p">&lt;</span><span class="n">StructureMapServiceProvider</span><span class="p">&gt;();</span>

    <span class="n">registry</span><span class="p">.</span><span class="n">For</span><span class="p">&lt;</span><span class="n">IServiceScopeFactory</span><span class="p">&gt;()</span>
            <span class="p">.</span><span class="nf">LifecycleIs</span><span class="p">(</span><span class="n">Lifecycles</span><span class="p">.</span><span class="n">Container</span><span class="p">)</span>
            <span class="p">.</span><span class="n">Use</span><span class="p">&lt;</span><span class="n">StructureMapServiceScopeFactory</span><span class="p">&gt;();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is what happens when you look under the hood for these lines:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="n">builder</span><span class="p">.</span><span class="nf">UseServiceProviderFactory</span><span class="p">();</span>  <span class="c1">// .UseSPF() in diagram</span>
<span class="p">..</span>
<span class="n">builder</span><span class="p">.</span><span class="nf">Build</span><span class="p">();</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/2019/09/fx-netstd-core-4.png" alt="fx-netstd-core-4" /></p>

<p>Now every time WebJob infrastructure will require service provider - it will be built from StructureMap container. This is nice addition to be able to use StructureMap advanced type lookup or scanning features instead of relying on explicit service registration in MSDI case.</p>

<h3 id="iconfiguration-access-in-iserviceprovider-factory">IConfiguration Access in IServiceProvider Factory</h3>

<p>Sometimes you might need access to <code class="language-plaintext highlighter-rouge">IConfiguration</code> interface to fetch settings to conditionally configure container.
I haven’t figure out better approach to do this, so sharing what I’ve got here.
First, we need to change signature of <code class="language-plaintext highlighter-rouge">ComposeContainer()</code> method  to accept now <code class="language-plaintext highlighter-rouge">IConfiguration configuration</code> as parameter:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">static</span> <span class="n">Container</span> <span class="nf">ComposeContainer</span><span class="p">(</span><span class="n">IConfiguration</span> <span class="n">configuration</span><span class="p">)</span>
<span class="p">{</span>
    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then we need to change signature of factory constructor:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="nf">StructureMapServiceProviderFactory</span><span class="p">(</span>
    <span class="n">Func</span><span class="p">&lt;</span><span class="n">IConfiguration</span><span class="p">,</span> <span class="n">IContainer</span><span class="p">&gt;</span> <span class="n">containerBuilder</span><span class="p">)</span>
<span class="p">{</span>
    <span class="p">....</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And now while we create container instance we need to get access to <code class="language-plaintext highlighter-rouge">IConfiguration</code> implementation and pass that into the function invocation.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="n">IContainer</span> <span class="nf">CreateBuilder</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// temporary build service provider</span>
    <span class="c1">// to get access to IConfiguration implementation</span>
    <span class="kt">var</span> <span class="n">sp</span> <span class="p">=</span> <span class="n">services</span><span class="p">.</span><span class="nf">BuildServiceProvider</span><span class="p">();</span>
    <span class="kt">var</span> <span class="n">container</span> <span class="p">=</span> <span class="nf">_containerBuilder</span><span class="p">(</span><span class="n">sp</span><span class="p">.</span><span class="n">GetService</span><span class="p">&lt;</span><span class="n">IConfiguration</span><span class="p">&gt;());</span>
    <span class="n">container</span><span class="p">.</span><span class="nf">Populate</span><span class="p">(</span><span class="n">services</span><span class="p">);</span>

    <span class="k">return</span> <span class="n">container</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>I’m not quite sure that this is the best approach to get instance of <code class="language-plaintext highlighter-rouge">IConfiguration</code> implementation is whether this is good idea in general to call <code class="language-plaintext highlighter-rouge">services.BuildServiceProvider()</code>.</p>

<p>Later by having access to <code class="language-plaintext highlighter-rouge">IConfiguration</code> instance, container setup logic can conditionally add some services to the container or configure instance specific settings from configuration.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">static</span> <span class="n">Container</span> <span class="nf">ComposeContainer</span><span class="p">(</span><span class="n">IConfiguration</span> <span class="n">configuration</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">config</span> <span class="p">=</span> <span class="n">configuration</span><span class="p">.</span><span class="nf">GetSection</span><span class="p">(</span><span class="s">"ConfigSection"</span><span class="p">).</span><span class="n">Get</span><span class="p">&lt;</span><span class="n">SomeConfig</span><span class="p">&gt;();</span>
    <span class="kt">var</span> <span class="n">container</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">Container</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="p">...</span> <span class="p">});</span>

    <span class="k">if</span><span class="p">(</span><span class="n">config</span><span class="p">.</span><span class="n">IsSomethingEnabled</span><span class="p">)</span>
        <span class="n">container</span><span class="p">.</span><span class="nf">Configure</span><span class="p">(...);</span>

    <span class="k">return</span> <span class="n">container</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="structuremap-constructor-selector-policy">StructureMap Constructor Selector Policy</h3>

<p>Once StructureMap is properly configured and ready to roll, you have to keep in mind that StructureMap’s MSDI adapter default constructor selector policy looks for “the most specific constructor”. Source code can be <a href="https://github.com/structuremap/StructureMap.Microsoft.DependencyInjection/blob/master/src/StructureMap.Microsoft.DependencyInjection/ContainerExtensions.cs#L98">found here</a>.</p>

<p>Meaning that there might be some runtime issues once you get your WebJob up &amp; running.</p>

<p>For example, when you add <code class="language-plaintext highlighter-rouge">ConsoleLogger</code> to the configuration, there will be a case when somewhere deep down in rabbit hole someone will require instance of <code class="language-plaintext highlighter-rouge">ConsoleLoggerProvider</code>. Which in turn (hopping over some stacks here) will create new instance of <code class="language-plaintext highlighter-rouge">WebJobsOptionsFactory</code> class.
This class has two constructors:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
</pre></td><td class="rouge-code"><pre><span class="k">internal</span> <span class="k">class</span> <span class="nc">WebJobsOptionsFactory</span><span class="p">&lt;</span><span class="n">TOptions</span><span class="p">&gt;</span> <span class="p">:</span>
    <span class="n">IOptionsFactory</span><span class="p">&lt;</span><span class="n">TOptions</span><span class="p">&gt;</span> <span class="k">where</span> <span class="n">TOptions</span> <span class="p">:</span> <span class="k">class</span><span class="err">,</span> <span class="nc">new</span><span class="p">()</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">OptionsFactory</span><span class="p">&lt;</span><span class="n">TOptions</span><span class="p">&gt;</span> <span class="n">_innerFactory</span><span class="p">;</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IOptionsLoggingSource</span> <span class="n">_logSource</span><span class="p">;</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IOptionsFormatter</span><span class="p">&lt;</span><span class="n">TOptions</span><span class="p">&gt;</span> <span class="n">_optionsFormatter</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">WebJobsOptionsFactory</span><span class="p">(</span>
        <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">IConfigureOptions</span><span class="p">&lt;</span><span class="n">TOptions</span><span class="p">&gt;&gt;</span> <span class="n">setups</span><span class="p">,</span>
        <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">IPostConfigureOptions</span><span class="p">&lt;</span><span class="n">TOptions</span><span class="p">&gt;&gt;</span> <span class="n">postConfigures</span><span class="p">,</span>
        <span class="n">IOptionsLoggingSource</span> <span class="n">logSource</span><span class="p">)</span> <span class="p">:</span> <span class="k">this</span><span class="p">(</span><span class="n">setups</span><span class="p">,</span> <span class="n">postConfigures</span><span class="p">,</span> <span class="n">logSource</span><span class="p">,</span> <span class="k">null</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="p">...</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="nf">WebJobsOptionsFactory</span><span class="p">(</span>
        <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">IConfigureOptions</span><span class="p">&lt;</span><span class="n">TOptions</span><span class="p">&gt;&gt;</span> <span class="n">setups</span><span class="p">,</span>
        <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">IPostConfigureOptions</span><span class="p">&lt;</span><span class="n">TOptions</span><span class="p">&gt;&gt;</span> <span class="n">postConfigures</span><span class="p">,</span>
        <span class="n">IOptionsLoggingSource</span> <span class="n">logSource</span><span class="p">,</span>
        <span class="n">IOptionsFormatter</span><span class="p">&lt;</span><span class="n">TOptions</span><span class="p">&gt;</span> <span class="n">optionsFormatter</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="p">...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As you can see first constructor relies on second one just by providing <code class="language-plaintext highlighter-rouge">null</code> to the <code class="language-plaintext highlighter-rouge">IOptionsFormatter&lt;TOptions&gt;</code> implementation.
However, StructureMap does not support this kind of constructor resolution and will invoke “the most specific” constructor -&gt; constructor with most parameters will be selected - looking for implementation of <code class="language-plaintext highlighter-rouge">IOptionsFormatter&lt;TOptions&gt;</code>.</p>

<p>Which will result in following runtime error:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
</pre></td><td class="rouge-code"><pre>No default Instance is registered and cannot be automatically determined for type 'IOptionsFormatter&lt;ConsoleLoggerOptions&gt;'

There is no configuration specified for IOptionsFormatter&lt;ConsoleLoggerOptions&gt;

1.) new WebJobsOptionsFactory`1(*Default of IEnumerable&lt;IConfigureOptions&lt;ConsoleLoggerOptions&gt;&gt;*, *Default of IEnumerable&lt;IPostConfigureOptions&lt;ConsoleLoggerOptions&gt;&gt;*, *Default of IOptionsLoggingSource*, *Default of IOptionsFormatter&lt;ConsoleLoggerOptions&gt;*)
2.) WebJobsOptionsFactory&lt;ConsoleLoggerOptions&gt; ('dabbde68-0a4c-4636-b291-4fb356b67a14')
3.) Instance of IOptionsFactory&lt;ConsoleLoggerOptions&gt; ('dabbde68-0a4c-4636-b291-4fb356b67a14')
4.) new OptionsMonitor`1(*Default of IOptionsFactory&lt;ConsoleLoggerOptions&gt;*, *Default of IEnumerable&lt;IOptionsChangeTokenSource&lt;ConsoleLoggerOptions&gt;&gt;*, *Default of IOptionsMonitorCache&lt;ConsoleLoggerOptions&gt;*)
5.) OptionsMonitor&lt;ConsoleLoggerOptions&gt; ('c3ab42b9-4c41-4a07-af71-3c9df514ce96')
6.) Instance of IOptionsMonitor&lt;ConsoleLoggerOptions&gt; ('c3ab42b9-4c41-4a07-af71-3c9df514ce96')
7.) new ConsoleLoggerProvider(*Default of IOptionsMonitor&lt;ConsoleLoggerOptions&gt;*)
8.) Microsoft.Extensions.Logging.Console.ConsoleLoggerProvider
9.) Instance of Microsoft.Extensions.Logging.ILoggerProvider (Microsoft.Extensions.Logging.Console.ConsoleLoggerProvider)
10.) All registered children for IEnumerable&lt;ILoggerProvider&gt;
11.) Instance of IEnumerable&lt;ILoggerProvider&gt;
12.) new LoggerFactory(*Default of IEnumerable&lt;ILoggerProvider&gt;*, *Default of IOptionsMonitor&lt;LoggerFilterOptions&gt;*)
13.) Microsoft.Extensions.Logging.LoggerFactory
14.) Instance of Microsoft.Extensions.Logging.ILoggerFactory (Microsoft.Extensions.Logging.LoggerFactory)
15.) new Logger`1(*Default of ILoggerFactory*)
16.) Logger&lt;ApplicationLifetime&gt; ('bf048bf3-567a-459e-9634-8b6d277e6507')
17.) Instance of ILogger&lt;ApplicationLifetime&gt; ('bf048bf3-567a-459e-9634-8b6d277e6507')
18.) new ApplicationLifetime(*Default of ILogger&lt;ApplicationLifetime&gt;*)
19.) Microsoft.Extensions.Hosting.Internal.ApplicationLifetime
20.) Instance of Microsoft.Extensions.Hosting.IApplicationLifetime (Microsoft.Extensions.Hosting.Internal.ApplicationLifetime)
21.) new Host(*Default of IServiceProvider*, *Default of IApplicationLifetime*, *Default of ILogger&lt;Host&gt;*, *Default of IHostLifetime*, *Default of IOptions&lt;HostOptions&gt;*)
22.) Microsoft.Extensions.Hosting.Internal.Host
23.) Instance of Microsoft.Extensions.Hosting.IHost (Microsoft.Extensions.Hosting.Internal.Host)
24.) Container.GetInstance(Microsoft.Extensions.Hosting.IHost)
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The same applies for <code class="language-plaintext highlighter-rouge">IWebHookProvider</code> for example.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>StructureMap.StructureMapConfigurationException: 'No default Instance is registered and cannot be automatically determined for type 'Microsoft.Azure.WebJobs.Host.Config.IWebHookProvider''
</pre></td></tr></tbody></table></code></pre></div></div>

<p>These are two dependencies that I discovered were not registered in container but required to build instance of WebJob host with console logging configured.</p>

<p>Workaround for this is to “silence” or fake implementations for these types. It’s doable by configuring StructureMap’s container:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">static</span> <span class="n">Container</span> <span class="nf">ComposeContainer</span><span class="p">(...)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">container</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">Container</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">_</span><span class="p">.</span><span class="nf">For</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">IOptionsFormatter</span><span class="p">&lt;&gt;)).</span><span class="nf">Use</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span> <span class="k">null</span><span class="p">);</span>
        <span class="n">_</span><span class="p">.</span><span class="nf">For</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">IWebHookProvider</span><span class="p">)).</span><span class="nf">Use</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span> <span class="k">null</span><span class="p">);</span>

        <span class="p">...</span>
    <span class="p">};</span>

    <span class="k">return</span> <span class="n">container</span><span class="p">;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="converting-custom-timers">Converting Custom Timers</h3>

<p>In our WebJob solution we do have separate timer trigger for each of the jobs.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">SomeJob</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">Run</span><span class="p">([</span><span class="nf">TimerTrigger</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">SomeJobTrigger</span><span class="p">))]</span>
                            <span class="n">TimerInfo</span> <span class="n">timerInfo</span><span class="p">,</span>
                            <span class="n">ILogger</span> <span class="n">log</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// job logic goes here...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Trigger itself:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">SomeJobTrigger</span> <span class="p">:</span> <span class="n">TimerSchedule</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">TimeSpan</span> <span class="n">_interval</span> <span class="p">=</span> <span class="n">TimeSpan</span><span class="p">.</span><span class="nf">Parse</span><span class="p">(</span><span class="s">"00:05:00"</span><span class="p">);</span>

    <span class="k">public</span> <span class="k">override</span> <span class="n">DateTime</span> <span class="nf">GetNextOccurrence</span><span class="p">(</span><span class="n">DateTime</span> <span class="n">now</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// here `_config` might be any implementation</span>
        <span class="c1">// which is able to read config from somewhere</span>
        <span class="c1">// we are for now just using ConfigurationManager.AppSettings[""]</span>
        <span class="k">if</span><span class="p">(!</span><span class="n">_config</span><span class="p">.</span><span class="n">SomeJobTriggerEnabled</span><span class="p">)</span>
            <span class="k">return</span> <span class="n">DateTime</span><span class="p">.</span><span class="n">MaxValue</span><span class="p">.</span><span class="nf">AddYears</span><span class="p">(-</span><span class="m">100</span><span class="p">);</span>

        <span class="kt">var</span> <span class="n">timeSpan</span> <span class="p">=</span> <span class="n">_interval</span><span class="p">;</span>
        <span class="k">return</span> <span class="n">now</span> <span class="p">+</span> <span class="n">timeSpan</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>It’s nice feature for Azure Functions to have possibility to enable or disable individual functions via portal.</p>

<p><img src="/assets/img/2019/09/func-on-off.png" alt="func-on-off" /></p>

<p>We wanted something similar for our WebJobs as well. This would allow us to have possibility to enable / disable specific job without redeploying whole solution (which requires decorate job class with <code class="language-plaintext highlighter-rouge">[Disabled]</code> attribute). We can change configuration and restart job host instance without redeployments.</p>

<p>In the new .NET Core world we have to have access to <code class="language-plaintext highlighter-rouge">IServiceCollection</code> in order to get configuration options out of it.</p>

<p>Can add <code class="language-plaintext highlighter-rouge">IOptions&lt;T&gt;</code> instance to the service container:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
</pre></td><td class="rouge-code"><pre><span class="k">internal</span> <span class="k">class</span> <span class="nc">Program</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">Main</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">args</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">HostBuilder</span><span class="p">();</span>
        <span class="n">builder</span><span class="p">.</span><span class="nf">ConfigureWebJobs</span><span class="p">(...)</span>
               <span class="p">.</span><span class="nf">ConfigureServices</span><span class="p">((</span><span class="n">context</span><span class="p">,</span> <span class="n">services</span><span class="p">)</span> <span class="p">=&gt;</span>
                <span class="p">{</span>
                    <span class="n">services</span><span class="p">.</span><span class="nf">AddSingleton</span><span class="p">(</span><span class="n">context</span><span class="p">.</span><span class="n">Configuration</span><span class="p">);</span>
                    <span class="n">services</span><span class="p">.</span><span class="nf">AddMemoryCache</span><span class="p">();</span>

                    <span class="c1">// other DI configuration here</span>
                    <span class="n">services</span><span class="p">.</span><span class="n">Configure</span><span class="p">&lt;</span><span class="n">SomeJobConfig</span><span class="p">&gt;(</span><span class="n">context</span><span class="p">.</span><span class="n">Configuration</span><span class="p">.</span><span class="nf">GetSection</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">SomeJobConfig</span><span class="p">)))</span>
                <span class="p">});</span>

        <span class="c1">// run the host</span>
        <span class="p">...</span>
        <span class="n">Services</span> <span class="p">=</span> <span class="n">host</span><span class="p">.</span><span class="n">Services</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">/// &lt;summary&gt;</span>
    <span class="c1">/// We need access to service provider later in TimedTrigger - to get data from the config file</span>
    <span class="c1">/// &lt;/summary&gt;</span>
    <span class="k">public</span> <span class="k">static</span> <span class="n">IServiceProvider</span> <span class="n">Services</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And settings file itself (<code class="language-plaintext highlighter-rouge">SomeJobConfig.cs</code>):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">SomeJobConfig</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">bool</span> <span class="n">SomeJobTriggerEnabled</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now when we do have options configured for our WebJobs, access to it via service collection:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">SomeJobTrigger</span> <span class="p">:</span> <span class="n">TimerSchedule</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">TimeSpan</span> <span class="n">_interval</span> <span class="p">=</span> <span class="n">TimeSpan</span><span class="p">.</span><span class="nf">Parse</span><span class="p">(</span><span class="s">"00:05:00"</span><span class="p">);</span>

    <span class="k">public</span> <span class="nf">SomeJobTrigger</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">_config</span> <span class="p">=</span> <span class="n">Program</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="n">GetService</span><span class="p">&lt;</span><span class="n">IOptions</span><span class="p">&lt;</span><span class="n">SomeJobConfig</span><span class="p">&gt;&gt;().</span><span class="n">Value</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">override</span> <span class="n">DateTime</span> <span class="nf">GetNextOccurrence</span><span class="p">(</span><span class="n">DateTime</span> <span class="n">now</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// got access to configuration settings via IOptions&lt;T&gt;</span>
        <span class="k">if</span><span class="p">(!</span><span class="n">_config</span><span class="p">.</span><span class="n">SomeJobTriggerEnabled</span><span class="p">)</span>
            <span class="k">return</span> <span class="n">DateTime</span><span class="p">.</span><span class="n">MaxValue</span><span class="p">.</span><span class="nf">AddYears</span><span class="p">(-</span><span class="m">100</span><span class="p">);</span>

        <span class="kt">var</span> <span class="n">timeSpan</span> <span class="p">=</span> <span class="n">_interval</span><span class="p">;</span>
        <span class="k">return</span> <span class="n">now</span> <span class="p">+</span> <span class="n">timeSpan</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="getting-connectionstrings">Getting ConnectionStrings</h3>

<p>As previous version of WebJobs (and including some common shared libraries) were on .NET Framework, we had <code class="language-plaintext highlighter-rouge">ConfigurationManager</code> usage in our code-base wherever we needed access to some configuration data. It’s still possible to use <code class="language-plaintext highlighter-rouge">ConfigurationManager</code> in .NET Standard libraries via <a href="https://devblogs.microsoft.com/dotnet/announcing-the-windows-compatibility-pack-for-net-core/">Platform Compatibility Pack</a>, but in this case we wanted to go full native and access configuration from <code class="language-plaintext highlighter-rouge">IConfiguration</code> interface instance directly.</p>

<p>We had these code fragments all around the code-base:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">SomeDataAccessThingy</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">DoMagic</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="c1">// need to get connection string first</span>
        <span class="kt">var</span> <span class="n">connection</span> <span class="p">=</span> <span class="n">ConfigurationManager</span><span class="p">.</span><span class="n">ConnectionStrings</span><span class="p">[</span><span class="n">name</span><span class="p">].</span><span class="n">ConnectionString</span><span class="p">;</span>

        <span class="c1">// magic continues here..</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As you can see this is not very friendly for the migration.
We extracted access to <code class="language-plaintext highlighter-rouge">ConfigurationManager</code> API into separate class in order to isolate and locate all usages of these APIs.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">interface</span> <span class="nc">IConnectionStringAccessor</span>
<span class="p">{</span>
    <span class="kt">string</span> <span class="nf">GetConnectionStringMyName</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Next we need to provide two implementation of this interface - one for .NET Framework applications (we still have couple of them in our infrastructure) and another one for the .NET Core platform.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="c1">// this one will be used in .NET Framework applications</span>
<span class="c1">// just by injecting proper implementation for IConnectionStringAccessor interface</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">DefaultConnectionStringAccessor</span> <span class="p">:</span> <span class="n">IConnectionStringAccessor</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="nf">GetConnectionStringMyName</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="n">ConfigurationManager</span><span class="p">.</span><span class="n">ConnectionStrings</span><span class="p">[</span><span class="n">name</span><span class="p">].</span><span class="n">ConnectionString</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And for .NET Core:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="c1">// this one will be used in .NET Core applications</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">NetCoreConnectionStringAccessor</span> <span class="p">:</span> <span class="n">IConnectionStringAccessor</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IConfiguration</span> <span class="n">_configuration</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">NetCoreConnectionStringAccessor</span><span class="p">(</span><span class="n">IConfiguration</span> <span class="n">configuration</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_configuration</span> <span class="p">=</span> <span class="n">configuration</span><span class="p">;</span>
    <span class="p">}</span>

     <span class="k">public</span> <span class="kt">string</span> <span class="nf">GetConnectionStringMyName</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="n">_configuration</span><span class="p">.</span><span class="nf">GetConnectionString</span><span class="p">(</span><span class="n">name</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now instead of accessing <code class="language-plaintext highlighter-rouge">ConfigurationManager</code> directly - we use our accessor that abstracts away actual implementation of how to get connection strings from platform APIs - meaning that common shared libraries are now more “cross-platform” ready.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="n">CloudBlobClient</span> <span class="nf">GetBlobClient</span><span class="p">(</span><span class="kt">string</span> <span class="n">connectionName</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">connectionString</span> <span class="p">=</span> <span class="n">_connectionStringAccessor</span>
                               <span class="p">.</span><span class="nf">GetConnectionStringMyName</span><span class="p">(</span><span class="n">connectionName</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">storageAccount</span> <span class="p">=</span> <span class="n">CloudStorageAccount</span><span class="p">.</span><span class="nf">Parse</span><span class="p">(</span><span class="n">connectionString</span><span class="p">);</span>

    <span class="k">return</span> <span class="n">storageAccount</span><span class="p">.</span><span class="nf">CreateCloudBlobClient</span><span class="p">();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="container-vs-pure-di-aka-poor-mans-di-principle">Container vs Pure DI (aka Poor Man’s DI) Principle</h3>

<p>Dependency Injection is a principle when writing your class library code you don’t think about how you are going to get implementation of the interface you need, or some sort of configuration for your service to run successfully. You can just assume that someone will pass it in while constructing instance of your class. This is <a href="https://en.wikipedia.org/wiki/Dependency_injection#Constructor_injection">constructor dependency injection</a>.</p>

<p>With introduction of additional dependency (to retrieve connection strings from different sources depending on target running platform) for various services - there is now a change in constructor signature. This of course should be taken into account and solved by dependency injection framework (aka IoC).</p>

<p>Before:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">SomeServiceImpl</span> <span class="p">:</span> <span class="n">ISomeService</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">SomeServiceImpl</span><span class="p">(</span><span class="n">IDependency</span> <span class="n">dep</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// .. capture passed in deps</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">DoStuff</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="c1">// ...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">SomeServiceImpl</span> <span class="p">:</span> <span class="n">ISomeService</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">SomeServiceImpl</span><span class="p">(</span><span class="n">IDependency</span> <span class="n">dep</span><span class="p">,</span> <span class="n">IConnectionStringAccessor</span> <span class="n">accessor</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// .. capture passed in deps</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">DoStuff</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="c1">// ...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Everything compiles and you can run the app. What you will get is an error telling you that dependency injection framework can’t resolve <code class="language-plaintext highlighter-rouge">IConnectionStringAccessor</code> dependency. Funny part - this is <strong>not</strong> compile time error. Exception is thrown only at runtime. Meaning everything needs to be double checked (hoping that service object graph is build and verified at app startup and not at later stages on demand).</p>

<p>Pure DI (also known as “Poor Man’s DI”) is concept that I read about from Mark Seeman’s blog posts. It didn’t quite catch me at the beginning and left me wondering who would on Earth would like to keep track of all constructor signature changes and adjust it every time.</p>

<p>However, now I do understand <a href="https://blog.ploeh.dk/2012/11/06/WhentouseaDIContainer/">“strongly-typed” part</a> of the Pure DI principle.
If you are relying on conventions to build your service instances and registration is something like this:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">Configureservices</span><span class="p">(</span><span class="n">ServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">services</span><span class="p">.</span><span class="n">Add</span><span class="p">&lt;</span><span class="n">ISomeService</span><span class="p">,</span> <span class="n">SomeServiceImpl</span><span class="p">&gt;();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>There is no compile time check about all required dependencies or whether instance of <code class="language-plaintext highlighter-rouge">SomeServiceImpl</code> is constructable at all.
Compared to following code when object graph is constructed manually:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">Configureservices</span><span class="p">(</span><span class="n">ServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">services</span><span class="p">.</span><span class="n">Add</span><span class="p">&lt;</span><span class="n">ISomeService</span><span class="p">&gt;(</span><span class="n">_</span> <span class="p">=&gt;</span> <span class="p">()</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="k">new</span> <span class="nf">SomeServiceImpl</span><span class="p">(</span><span class="k">new</span> <span class="nf">Dependency</span><span class="p">()</span> <span class="cm">/* missing connection string accessor */</span><span class="p">)</span>
    <span class="p">});</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You will immediately see compilation error and you will not able to construct new instance of <code class="language-plaintext highlighter-rouge">SomeServiceImpl</code> without supplying all required dependencies.
Of course, as Mark mentioned it out, using Pure DI - requires much higher level of self-discipline and maintainability of the code drops dramatically. But it has its strengths.</p>

<h2 id="running-net-core-app-as-webjob-in-azure">Running .NET Core App as WebJob in Azure</h2>

<p>Once you have done converting from .NET Framework to .NET Core / .NET Standard, the easiest way to verify that everything is working - just by launching project locally. That will open up Console window and output all logging directly there.
However - to get it running under Azure WebJobs host - requires a bit of work to be done upfront.
You have to have <code class="language-plaintext highlighter-rouge">run.cmd</code> file (or similar executable that follows <a href="https://github.com/projectkudu/kudu/wiki/WebJobs">naming conventions</a> for Azure Functions host). This executable file will ensure that WebJob is launched properly using <code class="language-plaintext highlighter-rouge">dotnet.exe</code> tool.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>dotnet {name-of-your-entry-project}.dll
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>NB!</strong> Note that you don’t need to include <code class="language-plaintext highlighter-rouge">run</code> (like <code class="language-plaintext highlighter-rouge">dotnet run {name-of-your-entry-project}.dll</code>).</p>

<p>Locate this file in the root of WebJobs folder and deploy together with your application.</p>

<h2 id="some-practical-gotchas">Some Practical Gotchas</h2>

<h3 id="switching-between-targeted-platforms">Switching Between Targeted Platforms</h3>

<p>While you are in transition phase between .NET Framework and .NET Core you might need to switch branches and work on some bug fixes in old project version that is still targeting .NET Framework. It’s sounds like easy task to do, but when you see errors like this:</p>

<p><img src="/assets/img/2019/09/2019-09-02_22-11-45.png" alt="2019-09-02_22-11-45" /></p>

<p>It might take some brain power of yours to figure out what’s going on here.</p>

<p>What we figured out is requirement to delete <code class="language-plaintext highlighter-rouge">obj/</code> folders. If you have many projects just like we do, this small snippet might become handy to remove all.</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="n">Get-ChildItem</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="o">*</span><span class="nx">/obj</span><span class="w"> </span><span class="nt">-Attributes</span><span class="w"> </span><span class="nx">Directory</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Remove-Item</span><span class="w"> </span><span class="nt">-Recurse</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>Not sure what causes this error, but we are glad to solve it.</p>

<h3 id="clean-state">Clean State</h3>

<p>Be sure that you start you journey in “clean state”. Meaning that it’s recommended to “re-clone” repository in different location and have the latest source code straight from origin (source code version control repository). Once you convert your project from .NET Framework project file format to SDK based - there is no explicit file includes anymore (enlisting which files should be included in resulting assembly). All files that are found on the disk in project folder are included in final build by default.
For this mistake it cost me couple hours of effort to fix compilation errors and keeping code up-to-date for API changes caused by some dependency library. At the end it turned out that file was deleted long time ago and my changes to the file are basically waste of time.. Always keep your workbench clean and work on code base that is the latest.</p>

<h2 id="summary">Summary</h2>

<p>Converting to .NET Core technically is not complex task. However, it takes significant amount of time to verify and test converted application to be 200% sure that application is running properly and is ready for production launch. By default project should target .NET Standard if possible.</p>

<p>Looking forward to migrate further to <a href="https://devblogs.microsoft.com/dotnet/announcing-net-core-3-0-preview-9/">.NET Core v3.0</a>.</p>

<p>Happy converting!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Azure" /><category term="WebJobs" /><category term=".net" /><category term="c#" /><category term="grpc" /><category term="azure" /><category term="webjobs" /><summary type="html"><![CDATA[Motivation]]></summary></entry><entry><title type="html">LocalizationProvider v5.7 Is Out</title><link href="https://tech-fellow.eu/2019/07/01/localizationprovider-v5-7-is-out/" rel="alternate" type="text/html" title="LocalizationProvider v5.7 Is Out" /><published>2019-07-01T19:00:00+03:00</published><updated>2019-07-01T19:00:00+03:00</updated><id>https://tech-fellow.eu/2019/07/01/localizationprovider-v5-7-is-out</id><content type="html" xml:base="https://tech-fellow.eu/2019/07/01/localizationprovider-v5-7-is-out/"><![CDATA[<p>It’s been a while since last Episerver <code class="language-plaintext highlighter-rouge">DbLocalizationProvider</code> package update. Fortunately this release includes couple bug fixes delivered by amazing developer community and also few new features.</p>

<p>What’s included in this release:</p>
<ul>
  <li>“Transient” referenced projects are now properly respected and scanned (<a href="https://github.com/valdisiljuconoks/localization-provider-core/issues/23">#github/28</a>)</li>
  <li>Resource import in Episerver was not polite and threw up when importing not active/disabled languages (<a href="https://github.com/valdisiljuconoks/localization-provider-epi/issues/30">#github/30</a>)</li>
  <li>Duplicate keys are ignored and first one is taken during MigrationTool process (<a href="https://github.com/valdisiljuconoks/localization-provider-epi/pull/25">#pull/25</a>)</li>
</ul>

<p>There are also some other smaller bug fixes, but who really reads release notes?! So will not bother you with bureaucracy here.</p>

<p>Most of the effort went to implement long requested feature of tree view in package version for AspNet Core platform. Had some “what da heck?” moments while digging my details through <a href="https://vuejs.org/">Vue.js</a> framework. Hope it works well and supports basic features you might need. It’s still far from perfect, but hey - I have to leave something for the future to improve, otherwise I would be out of business ;)</p>

<p><img src="/assets/img/2019/07/tree-view.png" alt="tree-view" /></p>

<p>There were also thing or two that I unfortunately had to move to next version. Sorry for that. Will work on those within next version. Otherwise v5.7 would stay in “cookings” even longer..</p>

<p>Next major version (v6.0) is already in the oven and I believe features added there will make somebody happy while someone else might go crazy and/or swear at me :) Well.. that’s what major versions are designed for, right?!</p>

<p>As usual, if you do have any feedback please share it on <a href="https://github.com/valdisiljuconoks/LocalizationProvider">GitHub</a>. You can use main package repository and I’ll move issue to appropriate repository if needed.</p>

<p>Open-source package developers / maintainers - keep up good work! Community appreciate it!</p>

<p>Happy localizing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="Localization Provider" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization provider" /><category term="localization" /><summary type="html"><![CDATA[It’s been a while since last Episerver DbLocalizationProvider package update. Fortunately this release includes couple bug fixes delivered by amazing developer community and also few new features.]]></summary></entry><entry><title type="html">Effectively Working with Git Submodules</title><link href="https://tech-fellow.eu/2019/05/09/effectively-work-with-git-submodules/" rel="alternate" type="text/html" title="Effectively Working with Git Submodules" /><published>2019-05-09T08:00:00+03:00</published><updated>2019-05-09T08:00:00+03:00</updated><id>https://tech-fellow.eu/2019/05/09/effectively-work-with-git-submodules</id><content type="html" xml:base="https://tech-fellow.eu/2019/05/09/effectively-work-with-git-submodules/"><![CDATA[<h2 id="background">Background</h2>

<p>During development of <code class="language-plaintext highlighter-rouge">DbLocalizationProvider</code> I had single repository in GitHub containing  more that one package as result of the build. Initially there was just a EPiServer package to add support for database driven localization resources. Later realized that there is actually not so much to do to add support for Asp.Net Mvc (.NET Framework) applications and later also for .NET Core applications.</p>

<p>This results into:</p>

<ul>
  <li>packages for EPiServer applications</li>
  <li>packages for Asp.Net Mvc applications</li>
  <li>packages for Asp.Net Core applications</li>
  <li>abstract/core packages containing only general purpose functionality (like expression tree walker or resource definition attributes)</li>
</ul>

<p><img src="/assets/img/2019/05/submod-0.png" alt="submod-0" /></p>

<p>As you can see there might be some issue with having multiple purpose packages (with different life-cycles and versions) located in single Git repository.
So decided to split whole code-base into git submodules and setup separate repositories for each of the sub-systems. This is a blog post about the stuff I had to do.</p>

<h2 id="draw-module-boundaries">Draw Module Boundaries</h2>

<p>It’s important to understand where each module ends and where next begins as you be referencing each other through sort of NuGet package references. Decision has to be made around type locations - where each type should go and which project will be used where.
Actually for development purposes using ordinary project reference is much more preferred way to work with. This gives nicer debugger experience for developer without any hustle to enable symbols and be able to “step into” the package source code.</p>

<h2 id="create-repositories-with-submodules">Create Repositories with Submodules</h2>

<h3 id="create-main-module-repo">Create Main Module Repo</h3>

<p>Now when you have decided module boundaries it’s time to create repositories for each of the module. You start with top-level module repo which does not have any external dependencies on any other module (core/common functionality).</p>

<p>We start in the following order:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">main</code> package repository (core/common functionality)</li>
  <li><code class="language-plaintext highlighter-rouge">aspnet</code> (repository for Asp.Net Mvc applications, has dependency on <code class="language-plaintext highlighter-rouge">main</code> module)</li>
  <li><code class="language-plaintext highlighter-rouge">epi</code> (repository for EPiServer integration, has dependency on <code class="language-plaintext highlighter-rouge">main</code> and <code class="language-plaintext highlighter-rouge">aspnet</code>)</li>
  <li><code class="language-plaintext highlighter-rouge">netcore</code> (.NET Core repository, has dependency on <code class="language-plaintext highlighter-rouge">main</code>)</li>
</ul>

<p>We create repository for localization provider core/common module.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>$ git init main
</pre></td></tr></tbody></table></code></pre></div></div>

<p>After whole code-base has been moved in, we can push it out to GitHub.</p>

<h3 id="create-repo-with-submodule">Create Repo With Submodule</h3>

<p>After we have <code class="language-plaintext highlighter-rouge">main</code> module repository available, we can create new one for Asp.Net Mvc (<code class="language-plaintext highlighter-rouge">aspnet</code>) packages.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>$ git init aspnet
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now tricky part is that I would like to include source from  <code class="language-plaintext highlighter-rouge">main</code> repository as part of the solution - like normal projects. Then I would be able to debug it through, change and adjust on-demand if needed, etc.
We need to “<em>include</em>” projects from <code class="language-plaintext highlighter-rouge">main</code> repository into <code class="language-plaintext highlighter-rouge">aspnet</code> repository. This is achievable by “linking” <code class="language-plaintext highlighter-rouge">main</code> repository content into <code class="language-plaintext highlighter-rouge">aspnet</code>. Keep in mind that linking is possible by pointing to some directory under which linked repository content will be “cloned”.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>$ git submodule add {main-repo-url} lib/localization-provider
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This will link <code class="language-plaintext highlighter-rouge">main</code> package current HEAD to the <code class="language-plaintext highlighter-rouge">aspnet</code> repository under <code class="language-plaintext highlighter-rouge">lib/localization-provider</code> resulting content of the <code class="language-plaintext highlighter-rouge">main</code> repository becoming as part of (submodule) <code class="language-plaintext highlighter-rouge">aspnet</code> repository.</p>

<p>Later we can repeat the same exercise for EPiServer repository as well.</p>

<p>Information about just added submodule is written in <code class="language-plaintext highlighter-rouge">.gitmodules</code> file (in root folder of parent repository).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>[submodule "lib/localization-provider"]
    path = lib/localization-provider
    url = https://github.com/valdisiljuconoks/LocalizationProvider.git
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="detached-head">Detached HEAD</h3>

<p><strong>NB!</strong> This is very important to remember that submodule linking sets included submodule into <em>detached HEAD</em> state.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre>$ cd lib/localization-provider
$ git status
HEAD detached at 8d6dc87
nothing to commit, working tree clean
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Meaning that when working with submodules - this rare git case becomes norm. As you would like to refer to particular commit and not tracking branch, which is essentially a moving target. You want to “lock down” yourself to specific version of the submodule.</p>

<h3 id="adjust-package-references-for-projects-in-aspnet-repo-netfx">Adjust Package References for Projects in Asp.Net Repo (NetFx)</h3>

<p>This applies only to .NET Framework project types (where SDK project style <code class="language-plaintext highlighter-rouge">&lt;PackageReference&gt;</code> is not supported).</p>

<p>Once you have linked <code class="language-plaintext highlighter-rouge">main</code> under <code class="language-plaintext highlighter-rouge">aspnet</code> - you need to make couple of changes for the IDE to understand new structure.
Adding reference to NuGet package in Asp.Net Mvc repository Visual Studio will create following reference hint path:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre>&lt;Reference&gt;
    &lt;HintPath&gt;
        ..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll.
    &lt;/HintPath&gt;
&lt;/Reference&gt;
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Which looks quite good when working in Asp.Net Mvc repository. However, this will become problem when we will link <code class="language-plaintext highlighter-rouge">aspnet</code> repository one level up - in <code class="language-plaintext highlighter-rouge">epi</code>. Then references will be broken. Also NuGet package restore works in that way - when packages are restored on the level of solution file (under <code class="language-plaintext highlighter-rouge">packages</code> folder).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre>epi/
    |-libs/
        |-aspnet/
            |-packages/      &lt;&lt; Asp.Net projects would be referencing to this folder
            |-libs/
                |-localization-provider
    |-packages/              &lt;&lt; packages are restored here
    LocalizationProvider.EPiServer.sln
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So to fix this issue - you need to change reference path to NuGet folder.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre>&lt;Reference&gt;
    &lt;HintPath&gt;
        $(SolutionDir)\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll.
    &lt;/HintPath&gt;
&lt;/Reference&gt;
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This <code class="language-plaintext highlighter-rouge">$(SolutionDir)</code> variable will ensure that top-level directory is used when looking for referenced NuGet packages.</p>

<h3 id="publish-new-repos">Publish New Repos</h3>

<p>Publishing and pushing changes to upstream is exactly the same way as you would do for ordinary repository. There is no special magic when it comes to submodules and committing changes.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>$ git push
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="cloning-repo-with-submodules">Cloning Repo with Submodules</h2>

<p>When you start from scratch and need to close repository that includes submodules, you have to explicitly tell that:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>$ git clone --recurse-submodules git://github.com/...
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Or sometimes repository is already cloned (but you forgot to include submodules). No worries - this scenario is also covered:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>$ git submodule update --init --recursive
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>NB!</strong> Sometimes you might fail to clone repo with submodules due to some weird access restrictions when submodule is configured to link to SSH instead of HTTPS. There are many resolution attempts <a href="https://www.google.com/search?q=failed+to+clone+git+with+submodules+access+restricted+publickey">on internets</a>.</p>

<p>Trick here was to explicitly set <code class="language-plaintext highlighter-rouge">git</code> protocol for the linkage (and not just <code class="language-plaintext highlighter-rouge">ssh</code>).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>[submodule "lib/localization-provider"]
    path = lib/localization-provider
    url = git@github.com:valdisiljuconoks/LocalizationProvider.git
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="building-packages-with-git-submodules">Building Packages with Git Submodules</h2>

<p>I’ve tried couple of online (Travis, Appvoyer, etc)  build systems to get around git submodules. I could not get it working properly with git submodules (there were some checkout issues for repos with submodules). Looked around and realized that there is absolutely no issues to run build with submodules on VSTS (now Azure DevOps) infrastructure. Everything worked out of the box.</p>

<p><img src="/assets/img/2019/05/submod-2.png" alt="submod-2" /></p>

<p>Resulting in build log entries:</p>

<p><img src="/assets/img/2019/05/submod-1.png" alt="submod-1" /></p>

<h3 id="strongly-naming-submodule-assemblies">Strongly Naming Submodule Assemblies</h3>

<p>It’s <a href="https://channel9.msdn.com/Events/dotnetConf/2018/S107">good practice</a> to have strong name for your OSS projects.
My recommendation here is to have a strong name key in core/common repository and then whoever needs to sign would be referencing to the path where core/common content is linked as submodule.
For example <code class="language-plaintext highlighter-rouge">DbLocalizationProvider.EPiServer.csproj</code> file content for signing:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>&lt;PropertyGroup&gt;
  &lt;AssemblyOriginatorKeyFile&gt;..\..\lib\aspnet\lib\localization-provider\strongname.snk&lt;/AssemblyOriginatorKeyFile&gt;
&lt;/PropertyGroup&gt;
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="update-repo-with-latest-submodule-version">Update Repo with Latest Submodule Version</h2>

<h3 id="checking-for-changes-in-submodule">Checking for Changes in Submodule</h3>

<p>At the end of the day linked submodule is normal git repository with just a special status in linked parent repo. Other than that - you can perform standard git commands against that repo.</p>

<p>For example, when you need to understand whether there are any new changes from the moment when you added submodule - you can use <code class="language-plaintext highlighter-rouge">git fetch</code>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre>$ cd lib/localization-provider
$ git fetch
remote: Enumerating objects: 7, done.
remote: Counting objects: 100% (7/7), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 4 (delta 3), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (4/4), done.
From github.com:valdisiljuconoks/LocalizationProvider
   9ecf9eb..3a6ab2a  master     -&gt; origin/master
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="moving-submodule-to-new-version">Moving Submodule to New Version</h3>

<p>When you have decided to move on with submodule and include newer version in your parent repository you can safely execute this command:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>$ git submodule update --remote
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Or if you want to pull changes from specific branch (and be lazy and do it for all submodules if you have more than one):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>git submodule foreach git pull origin master
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Every time you do changes to submodule reference, it becomes as ordinary “parent” repository change that you must include and commit in order to “publish” new linkage. Kinda annoying sometimes, but that’s part of the deal.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="rouge-code"><pre>$ git submodule update --remote
remote: Enumerating objects: 7, done.
remote: Counting objects: 100% (7/7), done.
remote: Compressing objects: 100% (4/4), done.
Unpacking objects: 100% (4/4), done.
remote: Total 4 (delta 2), reused 0 (delta 0), pack-reused 0
From github.com:valdisiljuconoks/LocalizationProvider
   8d6dc87..3bcc663  develop    -&gt; origin/develop
Submodule path 'localization-provider': checked out '3bcc6630a7d8b76e51c499574dcb10ef85064a2a'

$ git status
On branch develop
Your branch is up to date with 'origin/develop'.

Changes not staged for commit:
  (use "git add &lt;file&gt;..." to update what will be committed)
  (use "git checkout -- &lt;file&gt;..." to discard changes in working directory)

        modified:   localization-provider (new commits)

no changes added to commit (use "git add" and/or "git commit -a")
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="changing-submodule">Changing Submodule</h2>

<p>As submodule is ordinary git repository that’s being linked to some parent, you can do any changes you need to directly from parent repository.
However there is a catch here. Currently it’s lack of proper tooling.
For example, if I change file located in core/common repository, Visual Studio will show just changes in that submodule (without specifying what files were changed).</p>

<p><img src="/assets/img/2019/05/submod-3.png" alt="submod-3" /></p>

<p>Also files will not be marked as changed in Solution Explorer.</p>

<p>But I was quite surprised about capabilities of VSCode. That amazing piece of source code is able to show changes made to more than one git repo:</p>

<p><img src="/assets/img/2019/05/submod-4.png" alt="submod-4" /></p>

<h2 id="branching-with-submodules">Branching With Submodules</h2>

<p>As written above when adding submodule to the repository, current HEAD is used as reference for the submodule (latest commit is linked).</p>

<p>However sometimes it’s required to track only specific branch and not the most recent commit. To do so, you will need to specify branch while adding submodule to the repository. This is achievable with <code class="language-plaintext highlighter-rouge">-b</code> parameter followed by branch name.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>$ git submodule add -b master {main-repo-url} lib/localization-provider
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now after adding submodule with tracking <code class="language-plaintext highlighter-rouge">master</code> branch, HEAD from that branch will be used as linkage for the submodule. Which means that if you do <code class="language-plaintext highlighter-rouge">$ git submodule update --remote</code> and there are new commits in other branches - those will be ignored and only <code class="language-plaintext highlighter-rouge">master</code> branch will be observed for the changes.</p>

<p>Also sometimes it’s convenient to follow conventions and track the same branch in submodule as in “parent repository”. For example, if you are in <code class="language-plaintext highlighter-rouge">develop</code> branch in parent repository and you want to track also <code class="language-plaintext highlighter-rouge">develop</code> branch in submodule, then you have to specify branch name as <code class="language-plaintext highlighter-rouge">.</code> symbol. This feature is available since <a href="https://github.com/git/git/commit/c8386962d6590ec6f71f353bc5b1b573b1e71b16">git v2.10+</a>.</p>

<p>But you have to do a bit of manual steps before because there is no branch named <code class="language-plaintext highlighter-rouge">.</code> and you cannot link to that branch.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>$ git submodule add -b . {main-repo-url} lib/localization-provider
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Line above will give you an error.</p>

<p>Steps you need to do to add “current” parent repository branch to be the same for submodule branch as well:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">git submodule add -b master {main-repo-url} lib/localization-provider</code> - adding <code class="language-plaintext highlighter-rouge">master</code> branch as tracking branch for the submodule</li>
  <li>edit your <code class="language-plaintext highlighter-rouge">.gitmodules</code> file and change branch name from <code class="language-plaintext highlighter-rouge">master</code> to <code class="language-plaintext highlighter-rouge">.</code></li>
  <li><code class="language-plaintext highlighter-rouge">git submodule update --remote</code></li>
</ul>

<p>This is new <code class="language-plaintext highlighter-rouge">.gitmodules</code> file for <code class="language-plaintext highlighter-rouge">aspnet</code> repository:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre>[submodule "lib/localization-provider"]
    path = lib/localization-provider
    url = https://github.com/valdisiljuconoks/LocalizationProvider.git
    branch = .
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="best-practice-to-modify-submodule">Best Practice to Modify Submodule</h2>

<p>After working with repositories containing submodules we realized that it’s better to avoid direct changes to submodule source code from the parent repository. There might be specific check-in policies for the submodule repository, maybe special rules how code is added, how PR are created and reviewed, branching policy, etc.</p>

<p>Therefore we found it better to switch to submodule repository and create branch there, make changes, add unit tests, verify, create PR, review code, merge, etc. Or whatever your git flow might look like.. And then after new changes have been stabilized and merged, then switch back to parent repository and pull new changes in by doing <code class="language-plaintext highlighter-rouge">git submodule update --remote</code>.</p>

<p>Happy submoduling!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Git" /><category term=".net" /><category term="c#" /><category term="git" /><summary type="html"><![CDATA[Background]]></summary></entry><entry><title type="html">LocalizationProvider Client Side Feature now also for Asp.Net Mvc Apps</title><link href="https://tech-fellow.eu/2019/04/21/localizationprovider-joins-asp-net-mvc-family/" rel="alternate" type="text/html" title="LocalizationProvider Client Side Feature now also for Asp.Net Mvc Apps" /><published>2019-04-21T19:00:00+03:00</published><updated>2019-04-21T19:00:00+03:00</updated><id>https://tech-fellow.eu/2019/04/21/localizationprovider-joins-asp-net-mvc-family</id><content type="html" xml:base="https://tech-fellow.eu/2019/04/21/localizationprovider-joins-asp-net-mvc-family/"><![CDATA[<p>There are sometimes moments when you just need to take deep inhale and add backward support for apps that most probably you will hardly see selected in “File &gt; New Project”. We do have some projects still based on “pure” Asp.Net Mvc that need client-side localization. Therefore adding support for this type of apps sounds like feature with “must have” label. At least for now. This applies to v5.5.1 and forward.</p>

<p>However, if you are targeting .NET Core - support is <a href="https://tech-fellow.eu/2019/03/09/client-side-localization-in-asp-net-core-using-dblocalizationprovider/">already there</a> and you are good to go!</p>

<h2 id="getting-started">Getting Started</h2>

<p>In order to start localizing your applications you will need to install Asp.Net Mvc localization provider client-side support package:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="w"> </span><span class="n">Install-Package</span><span class="w"> </span><span class="nx">LocalizationProvider.JsResourceHandler</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>This package will drag down couple of dependencies as well, but believe me - those are required in order to run the library :)</p>

<p>Next is to register client-side resource provider within your app. This is done in <code class="language-plaintext highlighter-rouge">Startup.cs</code> file:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">Startup</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Configuration</span><span class="p">(</span><span class="n">IAppBuilder</span> <span class="n">app</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// setup of the core functionality</span>
        <span class="n">app</span><span class="p">.</span><span class="nf">UseDbLocalizationProvider</span><span class="p">(...);</span>

        <span class="c1">// register client-side support</span>
        <span class="n">app</span><span class="p">.</span><span class="nf">UseDbLocalizationProviderJsHandler</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="adding-resources">Adding Resources</h2>

<p>Once package is installed, you can add localizable resources as you <a href="https://github.com/valdisiljuconoks/LocalizationProvider/blob/master/docs/resource-types.md">would do it normally</a>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">MyProject.Localization</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">HomePageResources</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">Header</span> <span class="p">=&gt;</span> <span class="s">"This is home page header!"</span><span class="p">;</span>
        <span class="p">...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="require-resource-on-client-side">Require Resource on Client-Side</h2>

<p>Sometimes it is required to pull down resources on client-side and work with them from some scripting language. This is possible.</p>

<h3 id="pulling-resources-via-htmlhelpers">Pulling Resources via HtmlHelpers</h3>

<p>If you will pull down resources via <code class="language-plaintext highlighter-rouge">HtmlHelper</code> you are basically letting library to generate special <code class="language-plaintext highlighter-rouge">&lt;script&gt;</code> tag with link to handler endpoint for getting resources.</p>

<pre><code class="language-razor">@Html.GetTranslations(typeof(MyProject.Localization.HomePageResources))
</code></pre>

<p>This will generate <code class="language-plaintext highlighter-rouge">script</code> tag with link to <code class="language-plaintext highlighter-rouge">/jsl10n/MyProject.Localization.HomePageResources</code>. By default client-side resource handler is installed on <code class="language-plaintext highlighter-rouge">/jsl10n</code> path. Currently it’s not configurable and requires some manual labor to add support. If it’s important for you - please create a GitHub issue!</p>

<h3 id="pulling-resources-as-json">Pulling Resources as JSON</h3>

<p>Sometimes you may need to pull down resources in JSON format and work with them totally differently and not necessarily pollute <code class="language-plaintext highlighter-rouge">window</code> global scope. Anyways so essentially - to get resources down on client-side as JSON, you need pull them via some XHR method (pick any library that does this).</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="o">&lt;</span><span class="nx">script</span> <span class="nx">type</span><span class="o">=</span><span class="dl">"</span><span class="s2">text/javascript</span><span class="dl">"</span><span class="o">&gt;</span>
    <span class="nf">$</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
        <span class="nx">$</span><span class="p">.</span><span class="nf">ajax</span><span class="p">({</span>
            <span class="na">url</span><span class="p">:</span> <span class="dl">'</span><span class="s1">/jsl10n/MyProject.Localization.HomePageResources?json=true</span><span class="dl">'</span><span class="p">,</span>
            <span class="na">method</span><span class="p">:</span> <span class="dl">'</span><span class="s1">GET</span><span class="dl">'</span>
        <span class="p">}).</span><span class="nf">done</span><span class="p">(</span><span class="nf">function </span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
            <span class="nb">document</span><span class="p">.</span><span class="nf">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">theJsPlaceholder1</span><span class="dl">'</span><span class="p">).</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="nx">data</span><span class="p">.</span><span class="nx">MyProject</span><span class="p">.</span><span class="nx">Localization</span><span class="p">.</span><span class="nx">HomePageResources</span><span class="p">.</span><span class="nx">Header</span><span class="p">;</span>
        <span class="p">});</span>
    <span class="p">});</span>
<span class="o">&lt;</span><span class="sr">/script</span><span class="err">&gt;
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>Key here is to add <code class="language-plaintext highlighter-rouge">json=true</code> query string parameter. Also HTTP header detection will be supported, but this feature didn’t make it to the first version.</p>

<p>Structure of the JSON returned is exactly the same as you would write resource translation access code on the server-side. It’s basically <a href="https://docs.microsoft.com/en-us/dotnet/framework/reflection-and-codedom/specifying-fully-qualified-type-names">FQN</a> of the property.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="p">...</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="nx">data</span><span class="p">.</span><span class="nx">MyProject</span><span class="p">.</span><span class="nx">Localization</span><span class="p">.</span><span class="nx">HomePageResources</span><span class="p">.</span><span class="nx">Header</span><span class="p">;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="scoping">Scoping</h3>

<p>Scoping for the requested resources also works. For example, you might request only <code class="language-plaintext highlighter-rouge">/jsl10n/MyProject.Localization</code>. That should return all localizable resources in that namespace. Structure of the JSON returned will be the same as when requesting specific resource class.</p>

<h3 id="note-on-4047-error">Note on 404.7 Error</h3>

<p>We have seen that sometimes you might get 404.7 error back from IIS whatever you do. This turns out to be reserved <a href="https://docs.microsoft.com/en-us/iis/configuration/system.webserver/security/requestfiltering/fileextensions/">file extension request filtering</a> in IIS. We noticed this with quite common folder name <code class="language-plaintext highlighter-rouge">Resources/</code>. So when you might be requesting all localized resources under <code class="language-plaintext highlighter-rouge">Resources/</code> folder - you will end up with url <code class="language-plaintext highlighter-rouge">.Resources</code>. This will most probably be blocked under IIS settings. Either you should allow this “file extension” or just request specific resource class.</p>

<h3 id="nested-resource-classes">Nested Resource Classes</h3>

<p>It’s supported to have nested localizable classes which makes it quite nice resource grouping possibilities. By using nested classes resource key will contain <code class="language-plaintext highlighter-rouge">+</code> symbol. This symbol is not nicely supported in url, therefore - you should replace it with <code class="language-plaintext highlighter-rouge">---</code> (triple dash).</p>

<p>Example:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">MyProject.Localization</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">CommonResources</span>
    <span class="p">{</span>
        <span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
        <span class="k">public</span> <span class="k">class</span> <span class="nc">HomePageResources</span>
        <span class="p">{</span>
            <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">Header</span> <span class="p">=&gt;</span> <span class="s">"This is home page header!"</span><span class="p">;</span>
            <span class="p">...</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>To request <code class="language-plaintext highlighter-rouge">HomePageResources</code> class in client-side, you should construct url in following format: <code class="language-plaintext highlighter-rouge">/jsl10n/MyProject.Localization.CommonResources---HomePageResources</code>.</p>

<p>Happy localizing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="ASP.NET" /><category term="C#" /><category term="Open Source" /><category term="Localization Provider" /><category term="add-on" /><category term=".net" /><category term="asp.net" /><category term="c#" /><category term="open source" /><category term="localization provider" /><category term="localization" /><summary type="html"><![CDATA[There are sometimes moments when you just need to take deep inhale and add backward support for apps that most probably you will hardly see selected in “File &gt; New Project”. We do have some projects still based on “pure” Asp.Net Mvc that need client-side localization. Therefore adding support for this type of apps sounds like feature with “must have” label. At least for now. This applies to v5.5.1 and forward.]]></summary></entry><entry><title type="html">Client-side Localization in Asp.Net Core Using LocalizationProvider</title><link href="https://tech-fellow.eu/2019/03/09/client-side-localization-in-asp-net-core-using-dblocalizationprovider/" rel="alternate" type="text/html" title="Client-side Localization in Asp.Net Core Using LocalizationProvider" /><published>2019-03-09T18:00:00+02:00</published><updated>2019-03-09T18:00:00+02:00</updated><id>https://tech-fellow.eu/2019/03/09/client-side-localization-in-asp-net-core-using-dblocalizationprovider</id><content type="html" xml:base="https://tech-fellow.eu/2019/03/09/client-side-localization-in-asp-net-core-using-dblocalizationprovider/"><![CDATA[<p>Starting with v5.4.1 version of the <a href="https://www.nuget.org/packages/LocalizationProvider.AspNetCore/">LocalizationProvider package for .NET Core</a>, it’s now possible to work with translations also on client-side.</p>

<h2 id="getting-started">Getting Started</h2>

<p>Let’s get started.</p>

<p>First of all you need to initialize and add client-side resource handler to your application. As usual in .NET Core apps this done via <code class="language-plaintext highlighter-rouge">Startup.cs</code> file:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">Startup</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">Startup</span><span class="p">(</span><span class="n">IConfiguration</span> <span class="n">configuration</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">Configuration</span> <span class="p">=</span> <span class="n">configuration</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">IConfiguration</span> <span class="n">Configuration</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Configure</span><span class="p">(</span><span class="n">IApplicationBuilder</span> <span class="n">app</span><span class="p">,</span> <span class="n">IHostingEnvironment</span> <span class="n">env</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="p">...</span>
        <span class="n">app</span><span class="p">.</span><span class="nf">UseDbLocalizationProvider</span><span class="p">();</span>
        <span class="n">app</span><span class="p">.</span><span class="nf">UseDbLocalizationClientsideProvider</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then in your markup files you can use following helper method to pull down resources.</p>

<p>Assume that we have following resource class:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">MyProject</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">SampleResources</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">PageHeader</span> <span class="p">=&gt;</span> <span class="s">"This is page header"</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then by adding this code to your Razor page:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="p">&lt;</span><span class="n">body</span><span class="p">&gt;</span>
    <span class="p">...</span>
    <span class="n">@Html</span><span class="p">.</span><span class="nf">GetTranslations</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">SampleResources</span><span class="p">))</span>
<span class="p">&lt;/</span><span class="n">body</span><span class="p">&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You will get <code class="language-plaintext highlighter-rouge">SampleResources</code> class pulled down to client-side formatted as JSON object and assigned to <code class="language-plaintext highlighter-rouge">window.jsl10n</code> object by default. You can work with it in following way:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="p">@</span><span class="nd">Html</span><span class="p">.</span><span class="nc">GetTranslations</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="nx">SampleResources</span><span class="p">))</span>

<span class="o">&lt;</span><span class="nx">script</span><span class="o">&gt;</span>
    <span class="nb">document</span><span class="p">.</span><span class="nf">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">...</span><span class="dl">'</span><span class="p">).</span><span class="nx">innerHTML</span> <span class="o">=</span>
            <span class="nb">window</span><span class="p">.</span><span class="nx">jsl10n</span><span class="p">.</span><span class="nx">MyProject</span><span class="p">.</span><span class="nx">SampleResources</span><span class="p">.</span><span class="nx">PageHeader</span><span class="p">;</span>
<span class="o">&lt;</span><span class="sr">/script</span><span class="err">&gt;
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>Developer experience working with resources on client-side wanted to keep close enough with the same experience when using package on server-side.</p>

<p>You can also fetch <em>only</em> required resource keys (without pulling down whole class):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="err">@</span><span class="p">(</span><span class="n">Html</span><span class="p">.</span><span class="nf">GetTranslations</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="n">SampleResources</span><span class="p">.</span><span class="n">PageHeader</span><span class="p">))</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You can also ask to pull down various resources multiple times. All of the requested resources will be “merged” under this “jsl10n” key on <code class="language-plaintext highlighter-rouge">window</code> object.</p>

<h2 id="aliases">Aliases</h2>

<p>Sometimes you need to assigned different resources to different scopes or somehow group them differently. This is possible by using aliases. What it means is that following code:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="n">@Html</span><span class="p">.</span><span class="nf">GetTranslations</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">SampleResources</span><span class="p">),</span> <span class="s">"no"</span><span class="p">,</span> <span class="s">"norwegianScope"</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>will return resource translations for Norwegian language for <code class="language-plaintext highlighter-rouge">SampleResources</code> resource under <code class="language-plaintext highlighter-rouge">norwegianScope</code> key on <code class="language-plaintext highlighter-rouge">window</code> object level. Sometimes might become handy if needed.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="kd">var</span> <span class="nx">headerInNorwegian</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">norwegianScope</span><span class="p">.</span><span class="nx">MyProject</span><span class="p">.</span><span class="nx">SampleResources</span><span class="p">.</span><span class="nx">PageHeader</span><span class="p">;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="why-window-object">Why <code class="language-plaintext highlighter-rouge">window</code> Object?</h2>

<p>Pulled down translated object needs to be assigned to something in order to work with it. I chose <code class="language-plaintext highlighter-rouge">window</code> object, but it could be anything actually.</p>

<p>But you might ask - what about case when I need to dynamically pull down resources on my own and don’t need to pollute global scope with some weird objects?</p>

<p>In these cases you can issue request directly to localization provider endpoint and get only JSON representation of the resource class translations.</p>

<p>For example, issuing request straight to resource endpoint and providing <code class="language-plaintext highlighter-rouge">json</code> query parameter, you will get back only JSON object.</p>

<p><img src="/assets/img/2019/03/2019-03-09_09-05-30.png" alt="2019-03-09_09-05-30" /></p>

<h2 id="get-involved">Get Involved!</h2>

<p>Database driver localization provider is available for multiple platforms and runtimes. Landing repository is here: <a href="https://github.com/valdisiljuconoks/LocalizationProvider">https://github.com/valdisiljuconoks/LocalizationProvider</a>.</p>

<p>Happy localizing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="ASP.NET" /><category term="C#" /><category term="Open Source" /><category term="Localization Provider" /><category term="add-on" /><category term=".net" /><category term="asp.net" /><category term="c#" /><category term="open source" /><category term="localization provider" /><category term="localization" /><summary type="html"><![CDATA[Starting with v5.4.1 version of the LocalizationProvider package for .NET Core, it’s now possible to work with translations also on client-side.]]></summary></entry><entry><title type="html">Object Cache Viewer Joins EPiServer Developer Tools</title><link href="https://tech-fellow.eu/2019/03/03/cache-manager-joins-episerver-developer-tools/" rel="alternate" type="text/html" title="Object Cache Viewer Joins EPiServer Developer Tools" /><published>2019-03-03T10:05:00+02:00</published><updated>2019-03-03T10:05:00+02:00</updated><id>https://tech-fellow.eu/2019/03/03/cache-manager-joins-episerver-developer-tools</id><content type="html" xml:base="https://tech-fellow.eu/2019/03/03/cache-manager-joins-episerver-developer-tools/"><![CDATA[<p>It’s super cool to work together with the community and unite effort across all areas to strengthen EPiServer ecosystem and toolsets.</p>

<p>After chat with <a href="https://github.com/jaytem">Joe Mayberry</a> we decided that his local object cache viewer would be great addition to <a href="https://nuget.episerver.com/package/?id=EPiServer.DeveloperTools">EPiServer DeveloperTools</a>.</p>

<p>Thanks to Joe’s contributions local object cache viewer is now part of EPiServer DeveloperTools package. During the merge we added small extra to the tool - you can now also see approx. size of the cache entry (might be sometimes useful to know who ate the cake).</p>

<p><img src="/assets/img/2019/03/cache-viewer.png" alt="cache-viewer" /></p>

<p>Code to calculate cache entry size is quite naïve, but seems to give good enough numbers:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">static</span> <span class="kt">long</span> <span class="nf">GetObjectSize</span><span class="p">(</span><span class="kt">object</span> <span class="n">obj</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">if</span><span class="p">(</span><span class="n">obj</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
        <span class="k">return</span> <span class="m">0</span><span class="p">;</span>

    <span class="k">try</span>
    <span class="p">{</span>
        <span class="k">using</span> <span class="p">(</span><span class="n">Stream</span> <span class="n">s</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">MemoryStream</span><span class="p">())</span>
        <span class="p">{</span>
            <span class="kt">var</span> <span class="n">formatter</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">BinaryFormatter</span><span class="p">();</span>
            <span class="n">formatter</span><span class="p">.</span><span class="nf">Serialize</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">obj</span><span class="p">);</span>

            <span class="k">return</span> <span class="n">s</span><span class="p">.</span><span class="n">Length</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="p">-</span><span class="m">1</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>There are also couple of other features that we need to add to cache viewer / manager, but those are coming :)</p>

<p>Cache viewer / manager will be available starting from v3.4</p>

<p>Happy caching!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="Localization Provider" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization provider" /><category term="localization" /><summary type="html"><![CDATA[It’s super cool to work together with the community and unite effort across all areas to strengthen EPiServer ecosystem and toolsets.]]></summary></entry><entry><title type="html">How Risky are EPiServer.DeveloperTools on Production Environment?</title><link href="https://tech-fellow.eu/2019/02/14/how-risky-are-episerver-developertools-on-production-environment/" rel="alternate" type="text/html" title="How Risky are EPiServer.DeveloperTools on Production Environment?" /><published>2019-02-14T10:00:00+02:00</published><updated>2019-02-14T10:00:00+02:00</updated><id>https://tech-fellow.eu/2019/02/14/how-risky-are-episerver-developertools-on-production-environment</id><content type="html" xml:base="https://tech-fellow.eu/2019/02/14/how-risky-are-episerver-developertools-on-production-environment/"><![CDATA[<p>We had a great conversation at the EPiServer Partner Close-Up conference with one and only <a href="https://twitter.com/athraen">Allan Thræn</a> about future plans and such. And one of the topics we chatted about was that in our opinion no one really knows whether <a href="https://nuget.episerver.com/package/?id=EPiServer.DeveloperTools">“EPiServer.DeveloperTools”</a> package is safe to install to production environment or not. Will it do any harm? It’s great for local development and probably staging also. But what about production? What exactly the package does, what it intercepts, mimics or changes in the running code?!
Therefore I thought - it’s good timing to shed some light on the package and look inside - what exactly it is.</p>

<p><img src="/assets/img/2019/02/nuget.png" alt="" /></p>

<h2 id="features-of-developertools-package">Features of DeveloperTools Package</h2>
<p>This is most probably the most descriptive list known about features that package offers:</p>

<ul>
  <li><strong>IoC Viewer</strong> - this feature should help you to answer questions what kind of service or interface registration you do have in your StructureMap’s (or any other supported dependency injection) container. Handy time to time;</li>
  <li><strong>Content Type Analyzer</strong> - don’t you agree, that when weird stuff happening around content types and code -&gt; database synchronization, reviewing content type definition in admin ui one-by-one is not super exciting task. Table view of the content types and sync status is great addition;</li>
  <li><strong>Loaded Assemblies</strong> - have you wondered - what exactly website is loading and which versions of the 3rd party dependencies we have? If so, then loaded assemblies will give you list of almost all files you could potentially find in <code class="language-plaintext highlighter-rouge">bin/</code> directory;</li>
  <li><strong>Local Object Cache Manager</strong> - sometimes it’s cool to see who is using your memory and also be able to throw somebody out of shared space. this feature will give you these powers;</li>
  <li><strong>LogViewer</strong> - watch your logs in almost real-time. This is pretty awesome and <strong>dangerous</strong> at the same time. “DON’T do it at production!” is stated as disclaimer, it <strong>will</strong> slow your site down. But if there is no other option and site is dead anyways - this is useful;</li>
  <li><strong>Memory Dump</strong> - if you like nerd-like hard-core and love <a href="https://www.microsoft.com/en-us/p/windbg-preview/9pgjgd53tn86">WinDbg</a>, this command is just for you!</li>
  <li><strong>Modules Dependency Graph</strong> - configurable and initializable modules are great addition to your EPiServer website, but it’s not clear which module needs what? There is a chance you might find the answer using this tool;</li>
  <li><strong>Remote Event</strong> - statistics about sent and received events. Practical when you are dealing with “remote server out of sync” cases;</li>
  <li><strong>Revert to Default</strong> - this is going to be <a href="https://github.com/episerver/DeveloperTools/issues/16">merged together</a> with “Content Type Analyzer”, at some point :troll:</li>
  <li><strong>Routes</strong> - tool to test your skills in “guess the route handler for incoming request” game;</li>
  <li><strong>Startup Performance</strong> - if you are all heads down into the performance of your site and wonder why my EPiServer startup takes 5 minutes - here is a list of all the modules that’s are invoked during startup and actual timing for each of them;</li>
  <li><strong>Templates</strong> - do you know which template renderer is responsible for rendering your content? If not - come here and check;</li>
  <li><strong>View Engines/Locations</strong> - “Content type could not be rendered. View with name X is not found in these locations: …”? Sounds familiar? Check your view engine registrations and view locations here.</li>
</ul>

<p>All of these features are available under “Developer” menu.</p>

<p><img src="/assets/img/2019/02/2019-02-13_23-28-45.png" alt="2019-02-13_23-28-45" /></p>

<h3 id="ioc-viewer">IoC Viewer</h3>
<p>EPiServer dependency injection techniques initially were based on hard reference to StructureMap library. Can’t recall precise EPiServer version, but at some point StructureMap was made more like an optional dependency allowed other IoC libraries to step in and provide dependency injection feature.
However, sometimes it’s very important to understand and check what kind of registrations (even more important is possibility to check life of the dependency). Using this feature from DeveloperTools - it’s possible to see output from <code class="language-plaintext highlighter-rouge">container.WhatDoIHave()</code> and then use searchable table to find stuff you were looking for.</p>

<p><img src="/assets/img/2019/02/ioc.png" alt="ioc" /></p>

<p>The only hacky trick DeveloperTools package uses - the way how it gets to the StructureMap container (not EPiServer’s <code class="language-plaintext highlighter-rouge">ServiceCollection</code> container, but StructureMap one).
It was found that reference to the StructureMap container holds <code class="language-plaintext highlighter-rouge">StructureMapConfiguration</code> which available as <code class="language-plaintext highlighter-rouge">Services</code> private property of <code class="language-plaintext highlighter-rouge">InitializationEngine</code> which however is stored as private field on <code class="language-plaintext highlighter-rouge">InitializationModule</code> module (it’s <code class="language-plaintext highlighter-rouge">IHttpModule</code>). You can read more about whole chain and EPiServer’s initialization process <a href="/2018/12/01/episerver-init-infrastructure-under-the-hood/">here</a>. Code is dirty, but it works:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">ie</span> <span class="p">=</span> <span class="p">(</span><span class="n">InitializationEngine</span><span class="p">)</span> <span class="k">typeof</span><span class="p">(</span><span class="n">InitializationModule</span><span class="p">).</span><span class="nf">GetField</span><span class="p">(</span><span class="s">"_engine"</span><span class="p">,</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">NonPublic</span> <span class="p">|</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">Static</span><span class="p">)</span>
                                                            <span class="p">.</span><span class="nf">GetValue</span><span class="p">(</span><span class="k">null</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">services</span> <span class="p">=</span> <span class="n">ie</span><span class="p">.</span><span class="nf">GetType</span><span class="p">()</span>
                 <span class="p">.</span><span class="nf">GetProperty</span><span class="p">(</span><span class="s">"Services"</span><span class="p">,</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">NonPublic</span> <span class="p">|</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">Instance</span><span class="p">)</span>
                 <span class="p">.</span><span class="nf">GetValue</span><span class="p">(</span><span class="n">ie</span><span class="p">,</span> <span class="k">null</span><span class="p">)</span> <span class="k">as</span> <span class="n">StructureMapConfiguration</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">container</span> <span class="p">=</span> <span class="n">services</span><span class="p">.</span><span class="n">Container</span><span class="p">;</span>
<span class="p">...</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="content-type-analyzer">Content Type Analyzer</h3>
<p>Have you had an issue when you defined content types are just not synced with EPiServer and you are pulling your hairs out of your head to understand why? What is wrong, which property(-ies) are not synced and why this is happening? If yes, this feature of DeveloperTools might be handy for you.</p>

<p><img src="/assets/img/2019/02/content-type-analyzer.png" alt="content-type-analyzer" /></p>

<p>It’s basically a searchable table of all content types and properties with sync status. Feature just uses data available from <code class="language-plaintext highlighter-rouge">ContentTypeModelRepository</code>, no fancy hacky way to get to the content type info.
If you will have conflict during sync operation - it will be nicely shown there as well.</p>

<p><img src="/assets/img/2019/02/content-type-analyzer--error.png" alt="content-type-analyzer--error" /></p>

<p>Thanks <a href="http://marisks.net/2018/05/14/finding-content-type-conflict-reasons/">Māri for the code</a>.</p>

<h3 id="loaded-assemblies">Loaded Assemblies</h3>
<p>Sometimes things might get messy and weird and it could turn out that some unwanted assemblies are loaded that shouldn’t be there. “Loaded Assemblies” feature enlists everyone that’s found in <code class="language-plaintext highlighter-rouge">AppDomain</code> using <code class="language-plaintext highlighter-rouge">AppDomain.CurrentDomain.GetAssemblies()</code>. Location of the assembly is nice addition as well.</p>

<p><img src="/assets/img/2019/02/loaded-asm.png" alt="loaded-asm" /></p>

<p>Extra bonus - you are also able to read all discovered <code class="language-plaintext highlighter-rouge">EnvironmentVariables</code> and a sneak peak into couple of properties for the current <code class="language-plaintext highlighter-rouge">HttpRequest</code>.</p>

<h3 id="local-object-cache-manager">Local Object Cache Manager</h3>

<p>Thanks to Joe’s contributions local object cache viewer is now part of EPiServer DeveloperTools package. During the contribution we added small extra to the tool - you can now also see approx. size of the cache entry (might be sometimes useful).</p>

<p><img src="/assets/img/2019/03/cache-viewer.png" alt="cache-viewer" /></p>

<p>This feature will get some UX polishing, but other than that - it’s works great and gives you possibility to throw something out even from “remote” cache as well.</p>

<h3 id="logviewer">LogViewer</h3>
<p>Do the action in the site and see EPiServer’s log entries on fly. No need to remote session into server (sometimes it’s not even possible).</p>

<p>Trick here is to add <code class="language-plaintext highlighter-rouge">InMemoryAppender</code> for log4net. Yes, DeveloperTools package use direct reference to log4net at the moment. Why not? :) If you do other logging mechanism - this will not work.</p>

<p><img src="/assets/img/2019/02/logging.png" alt="logging" /></p>

<p>This small code snipper basically ensures that in-memory rolling appender is added to the log4net list so then it will be possible to “intercept” and output those log entries on the page:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">void</span> <span class="nf">CreateDefaultMemoryAppender</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">_memoryAppender</span> <span class="p">=</span> <span class="k">new</span> <span class="n">RollingMemoryAppender</span> <span class="p">{</span> <span class="n">Name</span> <span class="p">=</span> <span class="s">"DeveloperToolsLogViewer"</span> <span class="p">};</span>
    <span class="n">_memoryAppender</span><span class="p">.</span><span class="nf">ActivateOptions</span><span class="p">();</span>
    <span class="kt">var</span> <span class="n">repository</span> <span class="p">=</span> <span class="n">LogManager</span><span class="p">.</span><span class="nf">GetRepository</span><span class="p">()</span> <span class="k">as</span> <span class="n">Hierarchy</span><span class="p">;</span>

    <span class="k">if</span><span class="p">(</span><span class="n">repository</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">repository</span><span class="p">.</span><span class="n">Root</span><span class="p">.</span><span class="nf">AddAppender</span><span class="p">(</span><span class="n">_memoryAppender</span><span class="p">);</span>
        <span class="n">repository</span><span class="p">.</span><span class="n">Root</span><span class="p">.</span><span class="n">Level</span> <span class="p">=</span> <span class="n">Level</span><span class="p">.</span><span class="n">All</span><span class="p">;</span>
        <span class="n">repository</span><span class="p">.</span><span class="n">Configured</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
        <span class="n">repository</span><span class="p">.</span><span class="nf">RaiseConfigurationChanged</span><span class="p">(</span><span class="n">EventArgs</span><span class="p">.</span><span class="n">Empty</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="memory-dump">Memory Dump</h3>
<p>I hope everyone loves <a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/">WinDbg</a> or similar hardcore!</p>

<p>If you encounter an error on production (let’s say memory leak) and the only way to diagnose it is by analyzing memory dump, one of the easy way is to use this tool to get things done.</p>

<p><img src="/assets/img/2019/02/mem-dump.png" alt="mem-dump" /></p>

<p>It uses couple of Win32 imports to get to the some internals, but that’s not a big deal.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">NativeMethods</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">DllImport</span><span class="p">(</span><span class="s">"dbghelp.dll"</span><span class="p">,</span>
         <span class="n">EntryPoint</span> <span class="p">=</span> <span class="s">"MiniDumpWriteDump"</span><span class="p">,</span>
         <span class="n">CallingConvention</span> <span class="p">=</span> <span class="n">CallingConvention</span><span class="p">.</span><span class="n">StdCall</span><span class="p">,</span>
         <span class="n">CharSet</span> <span class="p">=</span> <span class="n">CharSet</span><span class="p">.</span><span class="n">Unicode</span><span class="p">,</span>
         <span class="n">ExactSpelling</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
         <span class="n">SetLastError</span> <span class="p">=</span> <span class="k">true</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">extern</span> <span class="kt">bool</span> <span class="nf">MiniDumpWriteDump</span><span class="p">(</span><span class="n">IntPtr</span> <span class="n">hProcess</span><span class="p">,</span>
                                                <span class="kt">uint</span> <span class="n">processId</span><span class="p">,</span>
                                                <span class="n">IntPtr</span> <span class="n">hFile</span><span class="p">,</span>
                                                <span class="kt">uint</span> <span class="n">dumpType</span><span class="p">,</span>
                                                <span class="k">ref</span> <span class="n">MiniDumpExceptionInformation</span> <span class="n">expParam</span><span class="p">,</span>
                                                <span class="n">IntPtr</span> <span class="n">userStreamParam</span><span class="p">,</span>
                                                <span class="n">IntPtr</span> <span class="n">callbackParam</span><span class="p">);</span>

    <span class="p">[</span><span class="nf">DllImport</span><span class="p">(</span><span class="s">"kernel32.dll"</span><span class="p">,</span> <span class="n">EntryPoint</span> <span class="p">=</span> <span class="s">"GetCurrentThreadId"</span><span class="p">,</span> <span class="n">ExactSpelling</span> <span class="p">=</span> <span class="k">true</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">extern</span> <span class="kt">uint</span> <span class="nf">GetCurrentThreadId</span><span class="p">();</span>

    <span class="p">[</span><span class="nf">DllImport</span><span class="p">(</span><span class="s">"kernel32.dll"</span><span class="p">,</span> <span class="n">EntryPoint</span> <span class="p">=</span> <span class="s">"GetCurrentProcess"</span><span class="p">,</span> <span class="n">ExactSpelling</span> <span class="p">=</span> <span class="k">true</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">extern</span> <span class="n">IntPtr</span> <span class="nf">GetCurrentProcess</span><span class="p">();</span>
<span class="p">}</span>

<span class="p">[</span><span class="nf">StructLayout</span><span class="p">(</span><span class="n">LayoutKind</span><span class="p">.</span><span class="n">Sequential</span><span class="p">,</span> <span class="n">Pack</span> <span class="p">=</span> <span class="m">4</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">struct</span> <span class="nc">MiniDumpExceptionInformation</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">uint</span> <span class="n">ThreadId</span><span class="p">;</span>
    <span class="k">public</span> <span class="n">IntPtr</span> <span class="n">ExceptionPointers</span><span class="p">;</span>
    <span class="p">[</span><span class="nf">MarshalAs</span><span class="p">(</span><span class="n">UnmanagedType</span><span class="p">.</span><span class="n">Bool</span><span class="p">)]</span> <span class="k">public</span> <span class="kt">bool</span> <span class="n">ClientPointers</span><span class="p">;</span>
<span class="p">}</span>

<span class="p">[</span><span class="n">Flags</span><span class="p">]</span>
<span class="k">public</span> <span class="k">enum</span> <span class="n">DumpType</span> <span class="p">:</span> <span class="kt">uint</span>
<span class="p">{</span>
    <span class="n">MiniDumpNormal</span> <span class="p">=</span> <span class="m">0x00000000</span><span class="p">,</span>
    <span class="n">MiniDumpWithDataSegs</span> <span class="p">=</span> <span class="m">0x00000001</span><span class="p">,</span>
    <span class="n">MiniDumpWithFullMemory</span> <span class="p">=</span> <span class="m">0x00000002</span><span class="p">,</span>
    <span class="n">MiniDumpWithHandleData</span> <span class="p">=</span> <span class="m">0x00000004</span><span class="p">,</span>
    <span class="n">MiniDumpFilterMemory</span> <span class="p">=</span> <span class="m">0x00000008</span><span class="p">,</span>
    <span class="n">MiniDumpScanMemory</span> <span class="p">=</span> <span class="m">0x00000010</span><span class="p">,</span>
    <span class="n">MiniDumpWithUnloadedModules</span> <span class="p">=</span> <span class="m">0x00000020</span><span class="p">,</span>
    <span class="n">MiniDumpWithIndirectlyReferencedMemory</span> <span class="p">=</span> <span class="m">0x00000040</span><span class="p">,</span>
    <span class="n">MiniDumpFilterModulePaths</span> <span class="p">=</span> <span class="m">0x00000080</span><span class="p">,</span>
    <span class="n">MiniDumpWithProcessThreadData</span> <span class="p">=</span> <span class="m">0x00000100</span><span class="p">,</span>
    <span class="n">MiniDumpWithPrivateReadWriteMemory</span> <span class="p">=</span> <span class="m">0x00000200</span><span class="p">,</span>
    <span class="n">MiniDumpWithoutOptionalData</span> <span class="p">=</span> <span class="m">0x00000400</span><span class="p">,</span>
    <span class="n">MiniDumpWithFullMemoryInfo</span> <span class="p">=</span> <span class="m">0x00000800</span><span class="p">,</span>
    <span class="n">MiniDumpWithThreadInfo</span> <span class="p">=</span> <span class="m">0x00001000</span><span class="p">,</span>
    <span class="n">MiniDumpWithCodeSegs</span> <span class="p">=</span> <span class="m">0x00002000</span><span class="p">,</span>
    <span class="n">MiniDumpWithoutAuxiliaryState</span> <span class="p">=</span> <span class="m">0x00004000</span><span class="p">,</span>
    <span class="n">MiniDumpWithFullAuxiliaryState</span> <span class="p">=</span> <span class="m">0x00008000</span><span class="p">,</span>
    <span class="n">MiniDumpWithPrivateWriteCopyMemory</span> <span class="p">=</span> <span class="m">0x00010000</span><span class="p">,</span>
    <span class="n">MiniDumpIgnoreInaccessibleMemory</span> <span class="p">=</span> <span class="m">0x00020000</span><span class="p">,</span>
    <span class="n">MiniDumpValidTypeFlags</span> <span class="p">=</span> <span class="m">0x0003ffff</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">MiniDump</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">WriteDump</span><span class="p">(</span><span class="kt">string</span> <span class="n">fileName</span><span class="p">,</span> <span class="n">DumpType</span> <span class="n">typeOfdumpType</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">MiniDumpExceptionInformation</span> <span class="n">info</span><span class="p">;</span>
        <span class="n">info</span><span class="p">.</span><span class="n">ThreadId</span> <span class="p">=</span> <span class="n">NativeMethods</span><span class="p">.</span><span class="nf">GetCurrentThreadId</span><span class="p">();</span>
        <span class="n">info</span><span class="p">.</span><span class="n">ClientPointers</span> <span class="p">=</span> <span class="k">false</span><span class="p">;</span>
        <span class="n">info</span><span class="p">.</span><span class="n">ExceptionPointers</span> <span class="p">=</span> <span class="n">Marshal</span><span class="p">.</span><span class="nf">GetExceptionPointers</span><span class="p">();</span>

        <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">fs</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">FileStream</span><span class="p">(</span><span class="n">fileName</span><span class="p">,</span> <span class="n">FileMode</span><span class="p">.</span><span class="n">Create</span><span class="p">,</span> <span class="n">FileAccess</span><span class="p">.</span><span class="n">Write</span><span class="p">,</span> <span class="n">FileShare</span><span class="p">.</span><span class="n">None</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="kt">var</span> <span class="n">processId</span> <span class="p">=</span> <span class="p">(</span><span class="kt">uint</span><span class="p">)</span> <span class="n">Process</span><span class="p">.</span><span class="nf">GetCurrentProcess</span><span class="p">().</span><span class="n">Id</span><span class="p">;</span>
            <span class="kt">var</span> <span class="n">processHandle</span> <span class="p">=</span> <span class="n">Process</span><span class="p">.</span><span class="nf">GetCurrentProcess</span><span class="p">().</span><span class="n">Handle</span><span class="p">;</span>
            <span class="kt">var</span> <span class="n">dumpType</span> <span class="p">=</span> <span class="p">(</span><span class="kt">uint</span><span class="p">)</span> <span class="n">typeOfdumpType</span><span class="p">;</span>
            <span class="n">NativeMethods</span><span class="p">.</span><span class="nf">MiniDumpWriteDump</span><span class="p">(</span><span class="n">processHandle2</span><span class="p">,</span>
                                            <span class="n">processId</span><span class="p">,</span>
                                            <span class="n">fs</span><span class="p">.</span><span class="n">SafeFileHandle</span><span class="p">.</span><span class="nf">DangerousGetHandle</span><span class="p">(),</span>
                                            <span class="n">dumpType</span><span class="p">,</span>
                                            <span class="k">ref</span> <span class="n">info</span><span class="p">,</span>
                                            <span class="n">IntPtr</span><span class="p">.</span><span class="n">Zero</span><span class="p">,</span>
                                            <span class="n">IntPtr</span><span class="p">.</span><span class="n">Zero</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>But be aware, that while dump is being made, your site is basically “frozen”. All the threads are stopped, nothing happens. If memory usage is huge (as it’s usually the case for the leaks) - site might be unresponsive for longer period of time. But who really cares then when site is just crushing all the time when memory limit is reached?</p>

<p>Yes, and also I do agree that EPiServer DeveloperTools could deliver this file directly back to the browser as downloadable content.. Experience would be very similar to the one you could experience using Kudu console in Azure.</p>

<p><img src="/assets/img/2019/02/kudu.png" alt="kudu" /></p>

<h3 id="modules-dependency-graph">Modules Dependency Graph</h3>
<p>This is more like nice-to-look-at feature. No huge interaction or features there, but sometimes it’s nice to see your configurable or initializable module dependencies and see who is the man in the center.</p>

<p><img src="/assets/img/2019/02/modules-dep.png" alt="modules-dep" /></p>

<p>You can either filter on all modules (including EPiServer’s ones as well) or just look at your own custom defined ones.</p>

<p><img src="/assets/img/2019/02/mod-dep-all.png" alt="mod-dep-all" /></p>

<p>With all the EPiServer’s modules included - things are getting hairy there.</p>

<h3 id="remote-event">Remote Event</h3>
<p>Part of the DeveloperTools is also feature to deal with remote events. It’s very convenient to cross-check health and statistics of particular events when needed. This is important when you are debugging remoting related case.</p>

<p><img src="/assets/img/2019/02/remote-events.png" alt="remote-events" /></p>

<p>You can also invoke (send) particular event - kinda mimic the server behavior.
Feature uses <code class="language-plaintext highlighter-rouge">IEventRegistry</code>, <code class="language-plaintext highlighter-rouge">EventProviderService</code> and <code class="language-plaintext highlighter-rouge">ServerStateService</code> services.</p>

<h3 id="revert-to-default">Revert to Default</h3>
<p>This particular feature is going to be merged together with “Content Type Analyzer” as those two are pretty closely related.</p>

<p>This part of the library invokes following code for selected content type(-s):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">ct</span> <span class="p">=</span> <span class="n">contentTypeRepository</span><span class="p">.</span><span class="nf">Load</span><span class="p">(</span><span class="n">id</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">writableContentType</span> <span class="p">=</span> <span class="n">ct</span><span class="p">.</span><span class="nf">CreateWritableClone</span><span class="p">()</span> <span class="k">as</span> <span class="n">ContentType</span><span class="p">;</span>
<span class="n">writableContentType</span><span class="p">.</span><span class="nf">ResetContentType</span><span class="p">();</span>

<span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">propDef</span> <span class="k">in</span> <span class="n">writableContentType</span><span class="p">.</span><span class="n">PropertyDefinitions</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">propeDef</span><span class="p">.</span><span class="nf">ResetPropertyDefinition</span><span class="p">();</span>
    <span class="n">_propertyDefinitionRepository</span><span class="p">.</span><span class="nf">Save</span><span class="p">(</span><span class="n">propeDef</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><img src="/assets/img/2019/02/revert.png" alt="revert" /></p>

<p>Uses <code class="language-plaintext highlighter-rouge">IContentTypeRepository</code> &amp; <code class="language-plaintext highlighter-rouge">IPropertyDefinitionRepository</code> services.
Becomes handy when you messed around with your content types.</p>

<h3 id="routes">Routes</h3>
<p>Do you know all the routes that are registered in <code class="language-plaintext highlighter-rouge">RouteTable</code> and through which Asp.Net Mvc is trying to lookup handler for your incoming request? Do you know why your controller is not invoked? Or do you know why some of the parameters are recognizable? This feature will be your 1st tool to understand what’s going on in your routes.</p>

<p><img src="/assets/img/2019/02/routes.png" alt="routes" /></p>

<p>Feature also gives you overview of all defaults for the route definition. Nice!</p>

<h3 id="startup-performance">Startup Performance</h3>
<p>Why your startup is slow? Here you might find answers. This feature uses pretty cool type that I was not aware before: <code class="language-plaintext highlighter-rouge">TimeMeters.GetAllRegistered();</code>. It gives you timing registries that were collected during startup (initialization engine setup and invoke of all discovered modules).</p>

<p><img src="/assets/img/2019/02/perf.png" alt="perf" /></p>

<p>You can see who is the winner for this instance of the app.</p>

<h3 id="templates">Templates</h3>
<p>Very helpful information that you can get out of <code class="language-plaintext highlighter-rouge">ITemplateRepository</code> and <code class="language-plaintext highlighter-rouge">ContentTypeModelRepository</code> services. It may answer question about why my content type is rendered as it’s rendered? Why some of the blocks look differently? And how my content will look like when I will use tags?</p>

<p><img src="/assets/img/2019/02/templates.png" alt="templates" /></p>

<p>Sometimes it might get really hot to understand all the mechanics behind the process which is responsible for deciding which of the template will be used for rendering of particular content.</p>

<h3 id="view-engineslocations">View Engines/Locations</h3>
<p>Last but not least, this feature gives you an overview of all registered view locations where <code class="language-plaintext highlighter-rouge">ViewEngine</code>-s might look at. This had been convenient couple times when you are looking why block is not rendered, why view is not picked-up and why Asp.Net Mvc is using totally wrong view to render the content.</p>

<p><img src="/assets/img/2019/02/views.png" alt="views" /></p>

<p>This becomes practical together with “Templates” section.</p>

<h2 id="is-it-risky">Is It Risky?</h2>

<p><strong>“USE AT YOUR OWN RISK!”</strong> This is basically disclaimer of the tools package. EPiServer or any other party do not take any responsibility for damage made to the websites when package is installed. With great power comes great responsibility! EPiServer initially didn’t want to release this as NuGet package on the feed. But I saw opportunity to pack it up and distribute for other fellow developers as well. This makes life a bit easier for packaging, updates and fixing the bugs.</p>

<p>There is no configurable or initializable modules in the package that might alter the running code. Package provides functionality based on existing features or hooks inside EPiServer platform. However, there are couple features that are risky to enable or use. So you should be careful with those.</p>

<p>Worth to note that all of this is availably only for users with “AdminAccess” permissions. In my opinion all the these features are more or less read-only and could not do big harm except “Revert to Default” &amp; “Memory Dump” features. User passwords and any other secrets might just be exposed during memory dump analysis. So be aware.</p>

<p>Hope you will not get into the situation when you will need DeveloperTools on production server.</p>

<p>Happy debugging!
[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="DeveloperTools" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><category term="open source" /><summary type="html"><![CDATA[We had a great conversation at the EPiServer Partner Close-Up conference with one and only Allan Thræn about future plans and such. And one of the topics we chatted about was that in our opinion no one really knows whether “EPiServer.DeveloperTools” package is safe to install to production environment or not. Will it do any harm? It’s great for local development and probably staging also. But what about production? What exactly the package does, what it intercepts, mimics or changes in the running code?! Therefore I thought - it’s good timing to shed some light on the package and look inside - what exactly it is.]]></summary></entry><entry><title type="html">Capture Exception in Azure Functions Poison Queue Trigger</title><link href="https://tech-fellow.eu/2019/02/06/capture-exception-in-azure-functions-poison-queue-trigger/" rel="alternate" type="text/html" title="Capture Exception in Azure Functions Poison Queue Trigger" /><published>2019-02-06T09:45:00+02:00</published><updated>2019-02-06T09:45:00+02:00</updated><id>https://tech-fellow.eu/2019/02/06/capture-exception-in-azure-functions-poison-queue-trigger</id><content type="html" xml:base="https://tech-fellow.eu/2019/02/06/capture-exception-in-azure-functions-poison-queue-trigger/"><![CDATA[<p>I’ll not talk about how cool Azure Functions are (because they are cool), but will focus on pretty tiny but very important aspect when running functions - how to get exception details out of poison message when using <code class="language-plaintext highlighter-rouge">[QueueTrigger]</code> trigger on Azure Storage Queues and “normal” handling of the message just fails and runtime decides to move message to poison queue. Code samples are provided for Azure Functions V2, but guess it applies to previous version as well.</p>

<h2 id="queue-message-handler">Queue Message Handler</h2>

<p>To have a queue message handler in Azure Functions is damn pretty simple.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="s">"HandleMessageFunction"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">RunAsync</span><span class="p">(</span>
    <span class="p">[</span><span class="nf">QueueTrigger</span><span class="p">(</span><span class="s">"incoming-queue"</span><span class="p">)]</span>
    <span class="n">MyQueueMessageObject</span> <span class="n">message</span><span class="p">,</span>
    <span class="n">ILogger</span> <span class="n">log</span><span class="p">,</span>
    <span class="n">ExecutionContext</span> <span class="n">executionContext</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// handling message here</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>What you do with your incoming message - that’s entirely up to you.
If you fail for some reason to handle message properly (read - you throw exceptions during the handling), runtime will decide at some point to move your message to poison queue. You can read more about this mechanism <a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-storage-queue#trigger---poison-messages">here</a>. You can of course do <code class="language-plaintext highlighter-rouge">try\catch</code> option here as well, but then question is what exactly are you going to do inside <code class="language-plaintext highlighter-rouge">catch</code> to make a retry later? Best option is to just let an exception fly up to the runtime and delegate dequeue on next round.</p>

<h2 id="handling-poison-messages">Handling Poison Messages</h2>

<p>When you fail to handle message properly (there is even a threshold how many times runtime will retry to give you your message for processing before moving to the poison queue):</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="p">{</span><span class="w">
    </span><span class="nl">"version"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2.0"</span><span class="p">,</span><span class="w">
    </span><span class="err">...</span><span class="w">
    </span><span class="nl">"extensions"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"queues"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
            </span><span class="nl">"maxDequeueCount"</span><span class="p">:</span><span class="w"> </span><span class="mi">3</span><span class="w">
        </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>To get notifications about bad messages that end up in poison queue (max dequeue threshold reached) you can create another function with trigger on <code class="language-plaintext highlighter-rouge">{your-queue-name}-poison</code>:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="s">"HandleErrorFunction"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">RunAsync</span><span class="p">(</span>
    <span class="p">[</span><span class="nf">QueueTrigger</span><span class="p">(</span><span class="s">"incoming-queue-poison"</span><span class="p">,</span> <span class="n">Connection</span> <span class="p">=</span> <span class="s">"AzureWebJobsStorage"</span><span class="p">)]</span>
    <span class="n">MyQueueMessageObject</span> <span class="n">poisonMessage</span><span class="p">,</span>
    <span class="n">ILogger</span> <span class="n">log</span><span class="p">,</span>
    <span class="n">ExecutionContext</span> <span class="n">executionContext</span><span class="p">)</span>
<span class="p">{</span>
    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Again, here what you do with poison message - is up to you.</p>

<p>But how to get exception details from failed “normal” handling process?</p>

<p>There are <a href="https://stackoverflow.com/questions/46852385/how-to-determine-reason-for-poison-queue-message">couple of hacky solutions provided</a> (including implementing your own interceptor - <code class="language-plaintext highlighter-rouge">FunctionInvocationFilterAttribute</code> or implementing custom <code class="language-plaintext highlighter-rouge">IQueueProcessorFactory</code> which is responsible for the logic how message is moved to the poison queue.</p>

<h2 id="getting-exception-details">Getting Exception Details</h2>

<p>There is another alternative to get an exception details that was thrown while handling incoming message. Still might involve some hacky workarounds, but thought it’s worth sharing.</p>

<p>In <a href="https://stackoverflow.com/questions/46852385/how-to-determine-reason-for-poison-queue-message">hacky solutions in SO</a> there was a need to store exception details somewhere (if you choose <code class="language-plaintext highlighter-rouge">FunctionInvocationFilterAttribute</code> option). I would like to see exception together with incoming poison message - it’s easier to reason about and handle further notification if needed.</p>

<p>For this work, we will have to return to original “normal” message handling function.</p>

<p>Note that we were asking runtime to bind our incoming message to our strongly typed object model:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="s">"HandleMessageFunction"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">RunAsync</span><span class="p">(</span>
    <span class="p">...</span>
    <span class="n">MyQueueMessageObject</span> <span class="n">message</span><span class="p">,</span>
    <span class="p">...)</span>
<span class="p">{</span>
    <span class="c1">// handling message here</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>There are couple of known types to which runtime can bind your incoming queue message. One of the possibility is to bind to very base class - <code class="language-plaintext highlighter-rouge">CloudQueueMessage</code>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="s">"HandleMessageFunction"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">RunAsync</span><span class="p">(</span>
    <span class="p">...</span>
    <span class="n">CloudQueueMessage</span> <span class="n">queueMessage</span><span class="p">,</span>
    <span class="p">...)</span>
<span class="p">{</span>
    <span class="c1">// handling message here</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This type will be needed later.
<strong>NB!</strong> The only disadvantage of the approach is that if we want to work in strongly-typed object model for the queue message - we need to deserialize it back.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="s">"HandleMessageFunction"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">RunAsync</span><span class="p">(</span>
    <span class="p">...</span>
    <span class="n">CloudQueueMessage</span> <span class="n">queueMessage</span><span class="p">,</span>
    <span class="p">...)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">message</span> <span class="p">=</span>
        <span class="n">JsonConvert</span><span class="p">.</span><span class="n">DeserializeObject</span><span class="p">&lt;</span><span class="n">MyQueueMessageObject</span><span class="p">&gt;(</span><span class="n">queueMessage</span><span class="p">.</span><span class="n">AsString</span><span class="p">);</span>

    <span class="c1">// handling message here</span>
    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now in order to capture exception details we need of course back <code class="language-plaintext highlighter-rouge">try/catch</code> statement:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="s">"HandleMessageFunction"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">RunAsync</span><span class="p">(</span>
    <span class="p">...</span>
    <span class="n">CloudQueueMessage</span> <span class="n">queueMessage</span><span class="p">,</span>
    <span class="p">...)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">message</span> <span class="p">=</span>
        <span class="n">JsonConvert</span><span class="p">.</span><span class="n">DeserializeObject</span><span class="p">&lt;</span><span class="n">MyQueueMessageObject</span><span class="p">&gt;(</span><span class="n">queueMessage</span><span class="p">.</span><span class="n">AsString</span><span class="p">);</span>

    <span class="k">try</span>
    <span class="p">{</span>
        <span class="c1">// handling message here</span>
        <span class="p">...</span>
    <span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">ex</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">message</span><span class="p">.</span><span class="n">ExceptionDetails</span> <span class="p">=</span> <span class="n">e</span><span class="p">.</span><span class="nf">ToString</span><span class="p">();</span>
        <span class="n">queueMessage</span><span class="p">.</span><span class="nf">SetMessageContent</span><span class="p">(</span>
            <span class="n">JsonConvert</span><span class="p">.</span><span class="nf">SerializeObject</span><span class="p">(</span><span class="n">composedMessageItem</span><span class="p">));</span>

        <span class="k">throw</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now we need to add <code class="language-plaintext highlighter-rouge">ExceptionDetails</code> property to our object model:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">MyQueueMessageObject</span>
<span class="p">{</span>
    <span class="p">...</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">ExceptionDetails</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>I haven’t tried message object model <code class="language-plaintext highlighter-rouge">Exception</code> type property - might not work. String representation was enough.</p>

<p>Now you are able to get exception details inside your poison queue handler and decide where and how you are going to deliver exception to the responsible personnel.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="s">"HandleErrorFunction"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">RunAsync</span><span class="p">(</span>
    <span class="p">[</span><span class="nf">QueueTrigger</span><span class="p">(</span><span class="s">"incoming-queue-poison"</span><span class="p">,</span> <span class="n">Connection</span> <span class="p">=</span> <span class="s">"AzureWebJobsStorage"</span><span class="p">)]</span>
    <span class="n">MyQueueMessageObject</span> <span class="n">poisonMessage</span><span class="p">,</span>
    <span class="n">ILogger</span> <span class="n">log</span><span class="p">,</span>
    <span class="n">ExecutionContext</span> <span class="n">executionContext</span><span class="p">)</span>
<span class="p">{</span>
    <span class="p">...</span>
    <span class="kt">var</span> <span class="n">notif</span> <span class="p">=</span> <span class="k">new</span> <span class="n">MailMessage</span>
                <span class="p">{</span>
                    <span class="n">Body</span> <span class="p">=</span> <span class="n">poisonMessage</span><span class="p">.</span><span class="n">ExceptionDetails</span>
                <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>NB!</strong> When you will receive <code class="language-plaintext highlighter-rouge">CloudQueueMessage</code> on subsequent retries (after you failed to process it before) <code class="language-plaintext highlighter-rouge">ExceptionDetails</code> property will not be filled in. It gets “filled in” only on last retry before message is moved to the poison queue. I’m just speculating here (and haven’t checked source code of the queue processor) but it looks like that message “as whole object” is updated and stored back in storage only when it’s being moved to the poison queue. During “normal” handling retry cycles runtime just updates <code class="language-plaintext highlighter-rouge">dequeue</code> count of the message but body remains the same.</p>

<p>There are couple of ways to solve this problem, we liked this approach as it involved less code, exception details were always present within poison message and we do not need to inject some custom processors and interceptors in runtime to get this done.</p>

<p>May no poison messages be with you!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Azure" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="azure" /><summary type="html"><![CDATA[I’ll not talk about how cool Azure Functions are (because they are cool), but will focus on pretty tiny but very important aspect when running functions - how to get exception details out of poison message when using [QueueTrigger] trigger on Azure Storage Queues and “normal” handling of the message just fails and runtime decides to move message to poison queue. Code samples are provided for Azure Functions V2, but guess it applies to previous version as well.]]></summary></entry><entry><title type="html">ASP.NET Mvc Areas for EPiServer Forms</title><link href="https://tech-fellow.eu/2019/01/04/asp-net-mvc-areas-for-episerver-forms/" rel="alternate" type="text/html" title="ASP.NET Mvc Areas for EPiServer Forms" /><published>2019-01-04T14:30:00+02:00</published><updated>2019-01-04T14:30:00+02:00</updated><id>https://tech-fellow.eu/2019/01/04/asp-net-mvc-areas-for-episerver-forms</id><content type="html" xml:base="https://tech-fellow.eu/2019/01/04/asp-net-mvc-areas-for-episerver-forms/"><![CDATA[<h2 id="forms--mvc-areas">Forms &amp; Mvc Areas</h2>

<p>According to <a href="https://world.episerver.com/documentation/developer-guides/forms/creating-a-custom-form-block/">Episerver documentation</a> it’s possible to override templates used for form elements by creating appropriate views under <code class="language-plaintext highlighter-rouge">~/Views/Shared/ElementBlocks</code> folder (or any other folder if you have customized location of the form elements views).
Or you can also provide additional folders for Episerver Forms library to look into by registering new <code class="language-plaintext highlighter-rouge">ICustomViewLocation</code> instance(-s). You can even control order of the locations:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ServiceConfiguration</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">ICustomViewLocation</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">MyFormsViewLocation</span> <span class="p">:</span> <span class="n">CustomViewLocationBase</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">override</span> <span class="kt">int</span> <span class="n">Order</span> <span class="p">{</span> <span class="k">get</span> <span class="p">=&gt;</span> <span class="m">1</span><span class="p">;</span> <span class="k">set</span> <span class="p">{</span> <span class="p">}</span> <span class="p">}</span>

    <span class="k">public</span> <span class="k">override</span> <span class="kt">string</span><span class="p">[]</span> <span class="n">Paths</span> <span class="p">=&gt;</span> <span class="k">new</span><span class="p">[]</span>
                                      <span class="p">{</span>
                                          <span class="s">"..."</span>
                                      <span class="p">};</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Apparently there are folks out there that still are using Asp.Net Mvc Areas to organize project structure (despite that there is also an alternative <a href="http://marisks.net/2017/12/17/better-feature-folders/">“feature folders”</a>). Most probably because of possibility to have folders as discriminators for sites or built in support from Visual Studio to work with areas:</p>

<p><img src="/assets/img/2019/01/2019-01-03_11-34-33.png" alt="2019-01-03_11-34-33" /></p>

<p>If you have other reasons why you are using Asp.Net Mvc Areas for your Episerver project - let me know, I would like to hear your story!</p>

<p>However using Mvc Areas and Episerver Forms - this approach does not work out well. For supporting Mvc Areas you will need to drop support using tiny <a href="https://nuget.episerver.com/package/?id=MvcAreasForEPiServer.Forms">NuGet package</a> I just ducttaped together.</p>

<h2 id="forms-elements-customization-test-drive">Forms Elements Customization Test Drive</h2>

<p>I’m playing around with forms element customization options in my sandbox test project. Would like to walk you through to get a picture of customizations available for Episerver forms elements.
Currently site is built with following features:</p>

<ul>
  <li>it’s based on AlloyTech sample project</li>
  <li>project handles 2 separate sites (distinguished by domain) - and each site has its own Mvc area (<code class="language-plaintext highlighter-rouge">Site1</code> and <code class="language-plaintext highlighter-rouge">Site2</code>)</li>
  <li>project also has ordinary page with controller in area with name <code class="language-plaintext highlighter-rouge">Area1</code></li>
  <li>and there are bunch of standard AlloyTech pages as well (those views are in root folder)</li>
</ul>

<p>Sandbox project customizes <code class="language-plaintext highlighter-rouge">TextboxElementBlock</code> element for each of these areas. We have following overrides:</p>

<ul>
  <li>common/root text box element for the forms has <span style="background-color:green">green</span> background</li>
  <li>text box element located in <code class="language-plaintext highlighter-rouge">Area1</code> has <span style="background-color:pink">pink</span> background</li>
  <li>element for <code class="language-plaintext highlighter-rouge">Site1</code> has <span style="background-color:purple">purple</span> background</li>
  <li>element for <code class="language-plaintext highlighter-rouge">Site2</code> has <span style="background-color:yellow">yellow</span> background</li>
</ul>

<p>In project system it looks something like this:</p>

<p><img src="/assets/img/2019/01/2019-01-03_10-50-03.png" alt="2019-01-03_10-50-03" /></p>

<h3 id="common-form-element">Common Form Element</h3>

<p>When you are having a form in ordinary page which is located in root folders, Episerver will pick up template that is located under <code class="language-plaintext highlighter-rouge">Views/</code> folder.</p>

<p><img src="/assets/img/2019/01/2019-01-03_10-56-53.png" alt="2019-01-03_10-56-53" /></p>

<h3 id="form-element-in-page-located-in-area">Form Element in Page located in Area</h3>

<p>When you are using Mvc Areas in your project, it’s possible to configure infrastructure to support Mvc Areas for ordinary Episerver pages (area will be detected by location of the controller for the page). If you have a form on the page that is located in area (this time in <code class="language-plaintext highlighter-rouge">Area1</code>) rendering of the form elements should be based on templates that are found in that area (or fallback on common/root templates).</p>

<p><img src="/assets/img/2019/01/2019-01-03_11-00-35.png" alt="2019-01-03_11-00-35" /></p>

<h3 id="form-element-in-different-sites">Form Element in Different Sites</h3>

<p>And exactly the same support is available with you are hosting multiple sites on your Episerver installation and have decided to split your project into Mvc Areas each for separate site. And having templates for form elements there - Episerver should pick the right ones (those psychedelic colors are just there for me to distinguish between different areas).</p>

<p><img src="/assets/img/2019/01/2019-01-03_11-03-39.png" alt="2019-01-03_11-03-39" /></p>

<h2 id="where-to-get-it">Where to get it?</h2>

<p>Asp.Net Mvc Areas support for Episerver forms is packed and released as <a href="https://nuget.episerver.com/package/?id=MvcAreasForEPiServer.Forms">“MvcAreasForEPiServer.Forms”</a> NuGet package.</p>

<h2 id="known-issues">Known Issues</h2>

<p>Nuget package references <code class="language-plaintext highlighter-rouge">EPiServer.Forms</code> package version 4.12.0 (lowest that targets Episerver v11). If you install newer <code class="language-plaintext highlighter-rouge">EPiServer.Forms</code> package in your project, it does not add assembly version binding redirects. So you might run into an issue that runtime is not able to find appropriate versions of some of the .dll files. If so, then you need to add couple of redirects manually (here assumption is that 4.21.0 version is installed in your project):</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;configuration&gt;</span>
  <span class="nt">&lt;runtime&gt;</span>
    <span class="nt">&lt;assemblyBinding&gt;</span>
      <span class="nt">&lt;dependentAssembly&gt;</span>
        <span class="nt">&lt;assemblyIdentity</span> <span class="na">name=</span><span class="s">"EPiServer.Forms"</span> <span class="na">publicKeyToken=</span><span class="s">"8fe83dea738b45b7"</span> <span class="na">culture=</span><span class="s">"neutral"</span> <span class="nt">/&gt;</span>
        <span class="nt">&lt;bindingRedirect</span> <span class="na">oldVersion=</span><span class="s">"0.0.0.0-4.21.0.0"</span> <span class="na">newVersion=</span><span class="s">"4.21.0.0"</span> <span class="nt">/&gt;</span>
      <span class="nt">&lt;/dependentAssembly&gt;</span>
        <span class="nt">&lt;assemblyIdentity</span> <span class="na">name=</span><span class="s">"EPiServer.Forms.Core"</span> <span class="na">publicKeyToken=</span><span class="s">"8fe83dea738b45b7"</span> <span class="na">culture=</span><span class="s">"neutral"</span> <span class="nt">/&gt;</span>
        <span class="nt">&lt;bindingRedirect</span> <span class="na">oldVersion=</span><span class="s">"0.0.0.0-4.21.0.0"</span> <span class="na">newVersion=</span><span class="s">"4.21.0.0"</span> <span class="nt">/&gt;</span>
      <span class="nt">&lt;/dependentAssembly&gt;</span>
        <span class="nt">&lt;assemblyIdentity</span> <span class="na">name=</span><span class="s">"EPiServer.Forms.UI"</span> <span class="na">publicKeyToken=</span><span class="s">"8fe83dea738b45b7"</span> <span class="na">culture=</span><span class="s">"neutral"</span> <span class="nt">/&gt;</span>
        <span class="nt">&lt;bindingRedirect</span> <span class="na">oldVersion=</span><span class="s">"0.0.0.0-4.21.0.0"</span> <span class="na">newVersion=</span><span class="s">"4.21.0.0"</span> <span class="nt">/&gt;</span>
      <span class="nt">&lt;/dependentAssembly&gt;</span>
    <span class="nt">&lt;/assemblyBinding&gt;</span>
  <span class="nt">&lt;/runtime&gt;</span>
<span class="nt">&lt;/configuration&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="source-code">Source Code</h2>

<p>As usual source code for the package could be found on GitHub (<a href="https://github.com/valdisiljuconoks/MvcAreasForEPiServer">https://github.com/valdisiljuconoks/MvcAreasForEPiServer</a>).</p>

<p>Happy forming into areas! :)
[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Azure" /><category term="Episerver" /><category term="Optimizely" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="azure" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[Forms &amp; Mvc Areas]]></summary></entry><entry><title type="html">Localized Episerver Enum Properties</title><link href="https://tech-fellow.eu/2018/12/29/localized-episerver-enum-properties/" rel="alternate" type="text/html" title="Localized Episerver Enum Properties" /><published>2018-12-29T00:30:00+02:00</published><updated>2018-12-29T00:30:00+02:00</updated><id>https://tech-fellow.eu/2018/12/29/localized-episerver-enum-properties</id><content type="html" xml:base="https://tech-fellow.eu/2018/12/29/localized-episerver-enum-properties/"><![CDATA[<p>Time to time I receive questions on how to properly translate <code class="language-plaintext highlighter-rouge">System.Enum</code> based properties on Episerver using DbLocalizationProvider package.</p>

<p>The support has been around for quite while, but I’ve never really blogged about it properly. So thought this is a good time to finish-up this amazing year and write how to utilize built-in support from the package.</p>

<p>Let’s assume that you do have a page defined as following:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ContentType</span><span class="p">(</span><span class="n">DisplayName</span> <span class="p">=</span> <span class="s">"..."</span><span class="p">,</span> <span class="n">GUID</span> <span class="p">=</span> <span class="s">".."</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">StartPage</span> <span class="p">:</span> <span class="n">PageData</span>
<span class="p">{</span>
    <span class="p">...</span>

    <span class="p">[</span><span class="nf">BackingType</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">PropertyNumber</span><span class="p">))]</span>
    <span class="k">public</span> <span class="k">virtual</span> <span class="n">SomeValuesEnum</span> <span class="n">SomeValue</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">enum</span> <span class="n">SomeValuesEnum</span>
<span class="p">{</span>
    <span class="n">None</span> <span class="p">=</span> <span class="m">0</span><span class="p">,</span>
    <span class="n">FirstValue</span> <span class="p">=</span> <span class="m">1</span><span class="p">,</span>
    <span class="n">SecondValue</span> <span class="p">=</span> <span class="m">2</span><span class="p">,</span>
    <span class="n">ThirdOne</span> <span class="p">=</span> <span class="m">3</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is pretty straight forward approach how to do the enumeration based property definition in Episerver. However, when it comes to how UI is localized and how Episerver is able to get proper display values from the drop-downs - it might get a bit tricky to line up all parts.</p>

<p>DbLocalizationPackage however, is here to rescue you an ease this process with couple of decorations and that’s it.</p>

<p>1) you will need to decorate enumeration type with <code class="language-plaintext highlighter-rouge">[LocalizedResource]</code> attribute for the package to pick it up and register resources and corresponding translations.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
<span class="k">public</span> <span class="k">enum</span> <span class="n">SomeValuesEnum</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"NOONE!"</span><span class="p">)]</span>
    <span class="n">None</span> <span class="p">=</span> <span class="m">0</span><span class="p">,</span>

    <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"1st value"</span><span class="p">)]</span>
    <span class="n">FirstValue</span> <span class="p">=</span> <span class="m">1</span><span class="p">,</span>

    <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"This is second"</span><span class="p">)]</span>
    <span class="n">SecondValue</span> <span class="p">=</span> <span class="m">2</span><span class="p">,</span>

    <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"And here comes last (3rd)"</span><span class="p">)]</span>
    <span class="p">[</span><span class="nf">TranslationForCulture</span><span class="p">(</span><span class="s">"Tredje"</span><span class="p">,</span> <span class="s">"no"</span><span class="p">)]</span>
    <span class="p">[</span><span class="nf">TranslationForCulture</span><span class="p">(</span><span class="s">"Third (EN)"</span><span class="p">,</span> <span class="s">"en"</span><span class="p">)]</span>
    <span class="n">ThirdOne</span> <span class="p">=</span> <span class="m">3</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You can use <a href="https://github.com/valdisiljuconoks/LocalizationProvider/blob/master/docs/translate-enum-net.md?ref=tech-fellow.ghost.io">any of the supported attributes</a> here to customize translations for each enumeration value and even provide alternative translation for specific languages.</p>

<p>2) You will need to decorate property itself on page model class to indicate Episerver, that this is a bit special property and needs some attention before rendering (decorate with <code class="language-plaintext highlighter-rouge">[LocalizedEnum]</code> attribute):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ContentType</span><span class="p">(</span><span class="n">DisplayName</span> <span class="p">=</span> <span class="s">"..."</span><span class="p">,</span> <span class="n">GUID</span> <span class="p">=</span> <span class="s">".."</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">StartPage</span> <span class="p">:</span> <span class="n">PageData</span>
<span class="p">{</span>
    <span class="p">...</span>

    <span class="p">[</span><span class="nf">LocalizedEnum</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">SomeValuesEnum</span><span class="p">))]</span>
    <span class="p">[</span><span class="nf">BackingType</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">PropertyNumber</span><span class="p">))]</span>
    <span class="k">public</span> <span class="k">virtual</span> <span class="n">SomeValuesEnum</span> <span class="n">SomeValue</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>What’s happening behind the scene is that <code class="language-plaintext highlighter-rouge">[LocalizedEnum]</code> attribute is actually metadata provider for the Episerver (inheriting from <code class="language-plaintext highlighter-rouge">[SelectOneAttribute]</code> attribute).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">LocalizedEnumAttribute</span> <span class="p">:</span> <span class="n">SelectOneAttribute</span><span class="p">,</span> <span class="n">IMetadataAware</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">LocalizedEnumAttribute</span><span class="p">(</span><span class="n">Type</span> <span class="n">enumType</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">EnumType</span> <span class="p">=</span> <span class="n">enumType</span> <span class="p">??</span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">enumType</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">Type</span> <span class="n">EnumType</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

    <span class="k">public</span> <span class="k">new</span> <span class="k">void</span> <span class="nf">OnMetadataCreated</span><span class="p">(</span><span class="n">ModelMetadata</span> <span class="n">metadata</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">SelectionFactoryType</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="n">LocalizedEnumSelectionFactory</span><span class="p">&lt;&gt;).</span><span class="nf">MakeGenericType</span><span class="p">(</span><span class="n">EnumType</span><span class="p">);</span>
        <span class="k">base</span><span class="p">.</span><span class="nf">OnMetadataCreated</span><span class="p">(</span><span class="n">metadata</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>It instructs Episerver to use generic <code class="language-plaintext highlighter-rouge">LocalizedEnumSelectionFactory</code> type when rendering values on Episerver UI.</p>

<p><img src="/assets/img/2018/12/2018-12-28_22-47-30.png" alt="" /></p>

<p>And selection factory is even more straight forward by just iterating over given enumeration type and translating each value.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">LocalizedEnumSelectionFactory</span><span class="p">&lt;</span><span class="n">TEnum</span><span class="p">&gt;</span> <span class="p">:</span> <span class="n">ISelectionFactory</span> <span class="k">where</span> <span class="n">TEnum</span> <span class="p">:</span> <span class="k">struct</span>
<span class="err">{</span>
    <span class="nc">public</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">ISelectItem</span><span class="p">&gt;</span> <span class="nf">GetSelections</span><span class="p">(</span><span class="n">ExtendedMetadata</span> <span class="n">metadata</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">values</span> <span class="p">=</span> <span class="n">Enum</span><span class="p">.</span><span class="nf">GetValues</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">TEnum</span><span class="p">))</span>
                         <span class="p">.</span><span class="n">Cast</span><span class="p">&lt;</span><span class="n">Enum</span><span class="p">&gt;();</span>

        <span class="k">foreach</span><span class="p">(</span><span class="kt">var</span> <span class="k">value</span> <span class="k">in</span> <span class="n">values</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">yield</span> <span class="k">return</span> <span class="k">new</span> <span class="n">SelectItem</span>
                         <span class="p">{</span>
                             <span class="n">Text</span> <span class="p">=</span> <span class="k">value</span><span class="p">.</span><span class="nf">Translate</span><span class="p">(),</span>
                             <span class="n">Value</span> <span class="p">=</span> <span class="k">value</span>
                         <span class="p">};</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And while writing this post I just realized that there were no support for multi choice (aka <code class="language-plaintext highlighter-rouge">[SelectMany]</code> attribute). So I just added that to the package. So if you need multiple-selection support as well, please wait couple days while package being approved.</p>

<p>To enable multi-selection, just provide <code class="language-plaintext highlighter-rouge">true</code> as second argument for the attribute:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ContentType</span><span class="p">(</span><span class="n">DisplayName</span> <span class="p">=</span> <span class="s">"..."</span><span class="p">,</span> <span class="n">GUID</span> <span class="p">=</span> <span class="s">".."</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">StartPage</span> <span class="p">:</span> <span class="n">PageData</span>
<span class="p">{</span>
    <span class="p">...</span>

    <span class="p">[</span><span class="nf">LocalizedEnum</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">SomeValuesEnum</span><span class="p">),</span> <span class="k">true</span><span class="p">)]</span>
    <span class="p">[</span><span class="nf">BackingType</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">PropertyNumber</span><span class="p">))]</span>
    <span class="k">public</span> <span class="k">virtual</span> <span class="n">SomeValuesEnum</span> <span class="n">SomeValue</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Happy localizing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term="Localization Provider" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="episerver" /><category term="optimizely" /><category term="localization" /><summary type="html"><![CDATA[Time to time I receive questions on how to properly translate System.Enum based properties on Episerver using DbLocalizationProvider package.]]></summary></entry><entry><title type="html">Episerver Init Infrastructure - Under the Hood</title><link href="https://tech-fellow.eu/2018/12/01/episerver-init-infrastructure-under-the-hood/" rel="alternate" type="text/html" title="Episerver Init Infrastructure - Under the Hood" /><published>2018-12-01T21:00:00+02:00</published><updated>2018-12-01T21:00:00+02:00</updated><id>https://tech-fellow.eu/2018/12/01/episerver-init-infrastructure-under-the-hood</id><content type="html" xml:base="https://tech-fellow.eu/2018/12/01/episerver-init-infrastructure-under-the-hood/"><![CDATA[<p>From the consumer perspective it looks like just a bunch of <code class="language-plaintext highlighter-rouge">IConfigurableModule</code> or maybe some of the <code class="language-plaintext highlighter-rouge">IInitializableModule</code> and the rest of the magic is hidden. Having couple of these in your Episerver solution - and everything works as expected.
But what really happens under the hood and how Episerver initialization system really works? This is a blog post about it.</p>

<h2 id="consumer-perspective">Consumer Perspective</h2>

<p>From the consumer perspective, having a initializable module in Episerver platform is pretty straight forward. You create class, implement interface and decorate it with some metadata to be visible to Episerver scanning process and you are done.
There are 3 types of modules you can have:</p>

<ul>
  <li>configurable module (<code class="language-plaintext highlighter-rouge">IConfigurableModule</code>) - this giving you a chance to configure service collection (aka IoC container);</li>
  <li>initializable module (<code class="language-plaintext highlighter-rouge">IInitializableModule</code>) - classical way of doing to stuff once and at the beginning of the site startup;</li>
  <li>http events aware initializable module (<code class="language-plaintext highlighter-rouge">IInitializableHttpModule</code>) - the same as classical initializable module, but allows also access to <code class="language-plaintext highlighter-rouge">HttpApplication</code> instance. This is useful if you need to subscribe to some web application lifetime events;</li>
</ul>

<p>Module looks like this:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">MyCustomInitModule</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="p">...</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="p">...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>But how that everything sticks together and how Episerver is initializing whole infrastructure? That’s interesting for me.</p>

<h2 id="where-init-phase-starts">Where Init Phase Starts?</h2>

<p>When you sneak peek into your project’s <code class="language-plaintext highlighter-rouge">Global.asax.cs</code> file you will notice that this type inherits from <code class="language-plaintext highlighter-rouge">EPiServer.Global</code> type (part of the <code class="language-plaintext highlighter-rouge">EPiServer.Cms.AspNet.dll</code>). This is done by Visual Studio templates automatically. When you are creating site from really “scratch” (which you probably should not do) - you will need to inherit from that type yourself.
When <code class="language-plaintext highlighter-rouge">EPiServer.Global</code> type is being created (in constructor), what we see there is following line:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="n">InitializationModule</span><span class="p">.</span><span class="nf">FrameworkInitialization</span><span class="p">(</span><span class="n">HostType</span><span class="p">.</span><span class="n">WebApplication</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Body of the <code class="language-plaintext highlighter-rouge">FrameworkInitialization</code> method calls <code class="language-plaintext highlighter-rouge">InitializationEngine</code> setup.</p>

<p><img src="/assets/img/2018/12/Untitled.png" alt="Untitled" /></p>

<p>This engine then is responsible for setting up everything in order to initialize modules and setup couple of other framework stuff before Episerver is ready to serve requests.</p>

<h2 id="initialization-engine-setup">Initialization Engine Setup</h2>

<p>There are couple of notable things that happens while <code class="language-plaintext highlighter-rouge">Global.asax.cs</code> sets up initialization engine.</p>

<h3 id="appdomain-setup">AppDomain Setup</h3>

<p>Think this is pretty interesting as well, but is beyond the scope of this blog post. So I’ll will dedicate additional post for this topic. But basically here in this step Episerver makes sure that assemblies are found and could be resolved in current AppDomain (this is <strong>not</strong> yet assembly scanning process).</p>

<h3 id="legacy-system-presence-check">Legacy System Presence Check</h3>

<p>Check of the presence for the old system assemblies:</p>

<ul>
  <li>An exception will be thrown if there is an old Add-On system libraries (<code class="language-plaintext highlighter-rouge">EPiServer.Packaging.UI.dll</code> 3.0)</li>
  <li>Mirroring System is old (<code class="language-plaintext highlighter-rouge">EPiServer.MirroringService.dll</code> major version is not the same as running Episerver assembly version)</li>
  <li>Shell is old (<code class="language-plaintext highlighter-rouge">EPiServer.Shell.dll</code> major version is lower than <code class="language-plaintext highlighter-rouge">10</code>)</li>
  <li>Legacy assemblies are present (if any one of these are found in output directory then exception is raised <code class="language-plaintext highlighter-rouge">EPiServer.Implementation</code>, <code class="language-plaintext highlighter-rouge">EPiServer.BaseLibrary</code> or <code class="language-plaintext highlighter-rouge">EPiServer.WorkflowFoundation</code>). These are most of the time left-overs from any major Episerver upgrade process.</li>
</ul>

<p>If any of these predicates turns out to be <code class="language-plaintext highlighter-rouge">true</code>, then initialization process is aborted.</p>

<h2 id="engine-initialization-execute-transition">Engine Initialization (Execute Transition)</h2>

<p>Initialization engine needs to scan all assemblies and register found modules and then initialize them (this is done through engine’s state transitions).</p>

<p>Two states which engine needs to transits through:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">PreInitialize</code> - Initializing <code class="language-plaintext highlighter-rouge">IConfigurableModule</code>s (this is uninitialized engine state which means that nothing has been done to the engine and it’s ready to start calling configurable modules for setup)</li>
  <li><code class="language-plaintext highlighter-rouge">Initializing</code> - Initializing <code class="language-plaintext highlighter-rouge">IInitializableModule</code>s (here engine is responsible to setup all initializable modules)</li>
</ul>

<h3 id="scanning-assemblies">Scanning Assemblies</h3>

<p>There are couple of notable things that are done during assembly scanning process (in order to find all modules in current app domain):</p>

<ul>
  <li>assembly type scanner is setup - this step basically sets up scanner to go through all available assemblies in current app domain and create lookup tables for found known types there (I think assembly and type scanner is worth its own blog post..?!);</li>
  <li>capturing all types that has one of the attributes - either <code class="language-plaintext highlighter-rouge">InitializableModuleAttribute</code> or <code class="language-plaintext highlighter-rouge">ModuleDependencyAttribute</code></li>
</ul>

<p><strong>NB!</strong> Also pay attention that after all types with these attributes are found, instance of that type is created via <code class="language-plaintext highlighter-rouge">Activator.CreateInstance(..)</code>. Which prevents and makes it impossible to use construction injection pattern for managing dependencies for the initialization modules. This basically is “<a href="http://blog.ploeh.dk/2011/04/27/Providerisnotapattern/#4c7b89305e744b22b9cadb8fd4f1d74e">constrained construction</a>” anti-pattern and should be avoided.</p>

<p>Instance is created and casted to <code class="language-plaintext highlighter-rouge">IInitializableModule</code> interface. You might be wondering - how Episerver is able to find all configurable modules? Those fall under the same category because:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">interface</span> <span class="nc">IConfigurableModule</span> <span class="p">:</span> <span class="n">IInitializableModule</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="configurable-modules">Configurable Modules</h3>

<p>Before <code class="language-plaintext highlighter-rouge">IConfigurableModule</code> modules can be configured, those should be sorted out by dependencies. Basically Episerver looks at all found modules and figures out which modules need to be called after which - establishing call order. For example:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">EPiServer.Data</span>
<span class="p">{</span>
  <span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
  <span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span> <span class="p">(</span><span class="n">ServiceContainerInitialization</span><span class="p">))]</span>
  <span class="k">public</span> <span class="k">class</span> <span class="nc">DataInitialization</span> <span class="p">:</span> <span class="n">IConfigurableModule</span><span class="p">,</span> <span class="n">IInitializableModule</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This module needs to be called after <code class="language-plaintext highlighter-rouge">ServiceContainerInitialization</code> module has finished its configuration method.
Once modules are sorted by dependencies, there is nothing more special about configuring modules except ServiceLocator setup (described in next section). <code class="language-plaintext highlighter-rouge">ConfigureContainer</code> method is called passing in current configuration context (with access to service collection or IoC container).
Once whole configuration phase is finished, event <code class="language-plaintext highlighter-rouge">ConfigurationComplete</code> is raised - for anyone interested to perform any special action after service collection is setup and configurable modules are initialized.</p>

<h3 id="servicelocator-provider">ServiceLocator Provider</h3>

<p>Essential part around service configuration - is creation and setup of the ServiceLocator. This still is important part of the Episerver which ensures that developers can continue to use this “<a href="http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/">anti-pattern</a>” :) Under the hood - yes, of course service locator most probably is required, but in my opinion, it shouldn’t be exposed to public. But it definitely takes time to refactor this.
Anyway, default service locator provider implementation in Episerver is based on <a href="http://structuremap.github.io/">StructureMap</a> library. So then how Episerver is able to find this provider and use it as a default one?
While Episerver is configuring modules - it needs to understand who is going to fulfill service locator responsibilities. It’s done by scanning assemblies and looking for <code class="language-plaintext highlighter-rouge">[ServiceLocatorFactory]</code> attribute on assembly level.
There is an attribute in <code class="language-plaintext highlighter-rouge">EPiServer.ServiceLocation.StructureMap.dll</code> assembly (which you get when install <code class="language-plaintext highlighter-rouge">EPiServer.ServiceLocation.StructureMap</code> NuGet package):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">assembly</span><span class="p">:</span> <span class="nf">ServiceLocatorFactory</span><span class="p">(</span><span class="k">typeof</span> <span class="p">(</span><span class="n">StructureMapServiceLocatorFactory</span><span class="p">))]</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This factory must implement <code class="language-plaintext highlighter-rouge">IServiceLocatorFactory</code> interface and will be used during service locator infrastructure setup. Interesting is fact that exception with message <code class="language-plaintext highlighter-rouge">"There is no dependency injection framework installed. Resolve this issue by installing NuGet package 'EPiServer.ServiceLocation.StructureMap'."</code> is thrown if Episerver is not able to find any assembly with this attribute. Should message change at the moment when someone will implement other IoC container adapter? :)</p>

<p><img src="/assets/img/2018/12/Untitled2.png" alt="Untitled2" /></p>

<p>After initialization context is constructed and everyone had their chance to configure it, <code class="language-plaintext highlighter-rouge">IServiceLocator</code> implementation is created via this <code class="language-plaintext highlighter-rouge">IServiceLocatorFactory</code> and stored as “famously” known <code class="language-plaintext highlighter-rouge">ServiceLocator.Current</code> instance.</p>

<h3 id="initializable-modules">Initializable Modules</h3>

<p>Later engine transits into next phase - “Initializing”. During this phase - main objective is to initialize all <code class="language-plaintext highlighter-rouge">IInitializableModule</code> instances. Engine itself is passed to each of the modules as argument of main initialization method - ensuring that initializable modules have access to service locator if needed and other types from the engine.
Order of the call is already known and sorted out in previous phase - when sorting was applied for configurable module list before the call.</p>

<p>Interesting part of this step is - transformations. It looks like a way to apply various transformations before module initialization. One of the built-in configuration transformation I found is - <code class="language-plaintext highlighter-rouge">LegacyDatabaseHandlerSetup</code>.</p>

<p><img src="/assets/img/2018/12/Untitled3.png" alt="Untitled3" /></p>

<p>Honestly - I’m not quite sure I understand full purpose of this step and it looks like something obsolete and leftover from previous generations.</p>

<h3 id="engine-states">Engine States</h3>

<p>These are main <code class="language-plaintext highlighter-rouge">InitializationEngine</code> states (there are more, but usage seems to be limited):</p>

<p><img src="/assets/img/2018/12/Untitled4.png" alt="Untitled4" /></p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">PreInitialize</code> - this is default start position for the engine. At this state engine would start to configure all modules;</li>
  <li><code class="language-plaintext highlighter-rouge">Initializing</code> - here engine would be ready to initialize known modules;</li>
  <li><code class="language-plaintext highlighter-rouge">InitializeFailed</code> - if one of the module fails, engine sets this status and basically blows up with an exception;</li>
  <li><code class="language-plaintext highlighter-rouge">InitializeDelayed</code> - this state we will look at a bit later;</li>
  <li><code class="language-plaintext highlighter-rouge">InitializeComplete</code> - engine enters into this state when everything is done with the modules and <code class="language-plaintext highlighter-rouge">InitComplete</code> event handlers are being called;</li>
  <li><code class="language-plaintext highlighter-rouge">Initialized</code> - everything is tip-top and Episerver is ready to proceed with other business before serving requests to visitors;</li>
</ul>

<h3 id="initializing-http-events">Initializing Http Events</h3>

<p>There are other type of initializable modules - <code class="language-plaintext highlighter-rouge">IInitializableHttpModule</code>. You might be asking what’s special about them? Most probably nothing expect that they do have access to <code class="language-plaintext highlighter-rouge">HttpApplication</code> instance - which gives them opportunity to subscribe to any web application lifetime event if needed.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">InitializeHttpEvents</span><span class="p">(</span><span class="n">HttpApplication</span> <span class="n">application</span><span class="p">)</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You might be wondering why this is not responsibility of the <code class="language-plaintext highlighter-rouge">InitializationEngine</code>? I would bet that this is part of <code class="language-plaintext highlighter-rouge">InitializationModule</code> due to fact that module has access to <code class="language-plaintext highlighter-rouge">HttpApplication</code> and Episerver most probably wanted to keep engine “host agnostic” - meaning the fact that Episerver is running in IIS actually is just host “context” and not part of the engine itself. Engine could be called from unit tests, console application or any other host type.</p>

<h2 id="delaying-initialization">Delaying Initialization</h2>

<p>There is a special mechanism built into initialization engine to delay execution of particular module (and all it’s dependent child modules).</p>

<h3 id="delaying-init-module">Delaying Init Module</h3>

<p>In case when you cannot continue for some reasons to initialize your logic further and need to wait until “normal” request is made to the site, you can do that by throwing particular type of the exception. Initialization engine reacts on <code class="language-plaintext highlighter-rouge">TerminateInitializationException</code> and behaves appropriately.</p>

<p>So, for example, you will write following code:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">EPiServer</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">DelayedInitModule</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">resolver</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">Locate</span><span class="p">.</span><span class="n">Advanced</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">IUrlResolver</span><span class="p">&gt;();</span>
        <span class="kt">var</span> <span class="n">url</span> <span class="p">=</span> <span class="n">resolver</span><span class="p">.</span><span class="nf">GetUrl</span><span class="p">(</span><span class="n">ContentReference</span><span class="p">.</span><span class="n">StartPage</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Variable <code class="language-plaintext highlighter-rouge">url</code> will always contain <code class="language-plaintext highlighter-rouge">null</code>. Because <code class="language-plaintext highlighter-rouge">UrlResolver</code> is able to do its business only after routes have been registered. However, routes are registered on 1st “real” request to the site. Thus you cannot get address of the content until routes are registered.
However, there is a way to workaround this behavior and “continue” initialization routine after 1st real request to the site by throwing this exception:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">DelayedInitModule</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">resolver</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">Locate</span><span class="p">.</span><span class="n">Advanced</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">IUrlResolver</span><span class="p">&gt;();</span>
        <span class="kt">var</span> <span class="n">url</span> <span class="p">=</span> <span class="n">resolver</span><span class="p">.</span><span class="nf">GetUrl</span><span class="p">(</span><span class="n">ContentReference</span><span class="p">.</span><span class="n">StartPage</span><span class="p">);</span>

        <span class="k">if</span><span class="p">(</span><span class="n">url</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
            <span class="k">throw</span> <span class="k">new</span> <span class="nf">TerminateInitializationException</span><span class="p">(</span><span class="s">"Astalavista baby! I'll be back.."</span><span class="p">);</span>

        <span class="c1">// do business with `url`</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is the way how you can tell Episerver that you want to continue later. But how framework is able to resume delayed modules?</p>

<h3 id="initialization-iis-module">Initialization IIS Module</h3>

<p>If one of the module throws this <code class="language-plaintext highlighter-rouge">TerminateInitializationException</code> exception (actually you can throw any exception and Episerver will try to resume init process anyways, but think it’s good to throw appropriate exception showing your intention) - whole process is stopped and Episerver “continues” do other business but not initializing modules further.</p>

<p>Resume option comes from <code class="language-plaintext highlighter-rouge">InitializationModule</code> IIS module. You can find one in <code class="language-plaintext highlighter-rouge">web.config</code> file:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre>  <span class="nt">&lt;system.webServer&gt;</span>
    ..
    <span class="nt">&lt;modules</span> <span class="na">runAllManagedModulesForAllRequests=</span><span class="s">"true"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;add</span> <span class="na">name=</span><span class="s">"InitializationModule"</span> <span class="na">type=</span><span class="s">"EPiServer.Framework.Initialization.InitializationModule, EPiServer.Framework.AspNet"</span> <span class="na">preCondition=</span><span class="s">"managedHandler"</span> <span class="nt">/&gt;</span>
      ...
    <span class="nt">&lt;/modules&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Episerver initialization IIS module is responsible for resuming any delayed initialization. Also it’s responsible to initialize any HttpEvent aware modules in the system (implementing <code class="language-plaintext highlighter-rouge">IInitializableHttpModule</code> interface).</p>

<p><strong>NB!</strong> But beware that module which is delaying kinda it’s own initialization is actually acting as “circuit-breaker”. Meaning that - if there are other modules in the list which are “sorted behind” delayed module (even without explicit dependency on delayed module) - those will not be called on “1st” engine initialization cycle.</p>

<h2 id="uninitialize">Uninitialize</h2>

<p>Here in uninitialization phase is not a big deal. You have to be good citizen and close any connections, dispose all garbage you have collected so far, release any resources that you have acquired, etc. Basically exactly what you would do in <code class="language-plaintext highlighter-rouge">IDisposable</code> interface implementation.</p>

<p>Also it’s good idea to unsubscribe from any events you have subscribed to before.</p>

<h2 id="replacing-initializationengine">Replacing InitializationEngine</h2>

<p>Once I <a href="https://world.episerver.com/forum/developer-forum/-Episerver-75-CMS/Thread-Container/2018/9/how-do-i-remove-or-hide-the-customized-search-block-type-from-editors/">had a challenge</a> to make it possible for initializable module to support constructor injection and avoid using ServiceLocator.
Despite initialization engine implements also interface (<code class="language-plaintext highlighter-rouge">IInitializationEngine</code>), it’s not possible to replace engine implementation via any official way (except reflection) to plug your own engine.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">InitializationEngine</span> <span class="p">:</span> <span class="n">IInitializationEngine</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>But inside <code class="language-plaintext highlighter-rouge">InitializationModule</code> class we see following:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">if</span> <span class="p">(</span><span class="n">InitializationModule</span><span class="p">.</span><span class="n">_engine</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
  <span class="n">ApplicationDomainInitializer</span><span class="p">.</span><span class="n">Instance</span><span class="p">.</span><span class="nf">SetupAppDomain</span><span class="p">(</span><span class="n">hostType</span><span class="p">);</span>
  <span class="n">InitializationModule</span><span class="p">.</span><span class="n">_engine</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">InitializationEngine</span><span class="p">(...);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And this:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="c1">/// &lt;summary&gt;Exposed for (shady) unit test reasons&lt;/summary&gt;</span>
<span class="k">internal</span> <span class="k">static</span> <span class="n">InitializationEngine</span> <span class="n">Engine</span>
<span class="p">{</span>
  <span class="k">get</span> <span class="p">=&gt;</span> <span class="n">InitializationModule</span><span class="p">.</span><span class="n">_engine</span><span class="p">;</span>
  <span class="k">set</span> <span class="p">=&gt;</span> <span class="n">InitializationModule</span><span class="p">.</span><span class="n">_engine</span> <span class="p">=</span> <span class="k">value</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And also reference to engine is stored in field:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">static</span> <span class="n">InitializationEngine</span> <span class="n">_engine</span><span class="p">;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Which basically means that it’s impossible to add support to DI “from outside” unless you replace whole initialization engine.</p>

<p>However, looking at this problem from the other perspective, having service locator usage in initializable module - is not SO bad, as it’s part of the composition root for the application, is called once and it could be that “dark” nasty corner of the app which none wants to walk close by.</p>

<p>Happy initializing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="Scheduled Jobs" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><category term="under the hood" /><summary type="html"><![CDATA[From the consumer perspective it looks like just a bunch of IConfigurableModule or maybe some of the IInitializableModule and the rest of the magic is hidden. Having couple of these in your Episerver solution - and everything works as expected. But what really happens under the hood and how Episerver initialization system really works? This is a blog post about it.]]></summary></entry><entry><title type="html">Razor UI Class Library with Dynamic Area Name</title><link href="https://tech-fellow.eu/2018/11/11/razor-ui-class-library-with-dynamic-area-name/" rel="alternate" type="text/html" title="Razor UI Class Library with Dynamic Area Name" /><published>2018-11-11T00:30:00+02:00</published><updated>2018-11-11T00:30:00+02:00</updated><id>https://tech-fellow.eu/2018/11/11/razor-ui-class-library-with-dynamic-area-name</id><content type="html" xml:base="https://tech-fellow.eu/2018/11/11/razor-ui-class-library-with-dynamic-area-name/"><![CDATA[<h2 id="new-packaging-process">New Packaging Process</h2>

<p>In general when working with packages that contains artifacts (like client side resources, scripts and what not) I’m a big fan of single-file packaging. Which means - stuff required by package is “packed” together with primary output. Essentially resulting in simpler installation, upgrade or sometimes even removal process.</p>

<p>Earlier (in Asp.Net MVC times) I was messing around with embedding files together with primary assembly and then later during runtime convincing <a href="https://www.nuget.org/packages/Microsoft.Owin.StaticFiles/">Owin FileServer</a> to serve my files as part of the hosting application. It was doable (take a <a href="https://github.com/valdisiljuconoks/localization-provider-aspnet/blob/master/src/DbLocalizationProvider.AdminUI/AppBuilderExtensions.cs#L18">look at DbLocalizationProvider</a> AdminUI for Asp.Net MVC apps). Despite that it’s achievable, still it felt a little bit of hacking here and there.</p>

<h2 id="razor-class-libraries">Razor Class Libraries</h2>

<p>As I had to move forward with .Net Core implementation for the localization provider, this was a great chance to jump straight to <code class="language-plaintext highlighter-rouge">netcore21</code> and try new feature - <a href="https://docs.microsoft.com/en-us/aspnet/core/razor-pages/ui-class?view=aspnetcore-2.1&amp;tabs=visual-studio">Razor Class Library</a>.</p>

<p>So, everything start with new project:</p>

<p><img src="/assets/img/2018/11/2018-11-09_13-26-20.png" alt="2018-11-09_13-26-20" /></p>

<p>What is changes is who is the main responsible party for the compilation process of the project (replace <code class="language-plaintext highlighter-rouge">Microsoft.NET.Sdk</code> with <code class="language-plaintext highlighter-rouge">Microsoft.NET.Sdk.Razor</code>):</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;Project</span> <span class="na">Sdk=</span><span class="s">"Microsoft.NET.Sdk.Razor"</span><span class="nt">&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Once the project is setup and ready, you can add new Razor Page to it:</p>

<p><img src="/assets/img/2018/11/2018-11-09_13-38-27.png" alt="2018-11-09_13-38-27" /></p>

<p>If you peek under the hood, firstly Razor markup has new directive <code class="language-plaintext highlighter-rouge">@page</code>.
Also it generates new <code class="language-plaintext highlighter-rouge">.cshtml.cs</code> file which contains definition of the page model. This is typical C# class inheriting from <code class="language-plaintext highlighter-rouge">Microsoft.AspNetCore.Mvc.RazorPages.PageModel</code> type. Base class gives you much shortcuts and access to various environmental types - like <code class="language-plaintext highlighter-rouge">Request</code>. You will find much similarities with <code class="language-plaintext highlighter-rouge">Controller</code> from Asp.Net MVC days. It also somehow reminds a bit WebForms code-behind classes (oh, this was retro). There are couple of <a href="https://docs.microsoft.com/en-us/aspnet/core/razor-pages/?view=aspnetcore-2.1&amp;tabs=visual-studio#writing-a-basic-form">auto-wired handler methods</a> that you can implement and those are guaranteed to be called during page life-cycle.</p>

<h2 id="routing-to-razor-page">Routing to Razor Page</h2>

<p>Now, when class library has bunch of of these Razor pages, those got compiled into <code class="language-plaintext highlighter-rouge">*.Views.dll</code> file. This extra separate file contains your Razor page compiled version. It’s much very similar of what <code class="language-plaintext highlighter-rouge">BuildMvcViews</code> did in Asp.Net MVC context.</p>

<p>Sneak peek in <code class="language-plaintext highlighter-rouge">*.Views.dll</code> file:</p>

<p><img src="/assets/img/2018/11/2018-11-09_13-51-34.png" alt="2018-11-09_13-51-34" /></p>

<p>Idea how get access to the Razor page from hosting project is via its “areas” (don’t mix with <a href="https://docs.microsoft.com/en-us/aspnet/mvc/videos/mvc-2/how-do-i/aspnet-mvc-2-areas">Asp.Net MVC areas</a> - those we used to organize code into some sort of feature folders back then).</p>

<p>This said, having file organization and area names like these, we can access Razor page via exactly the same url under which page was stored in class library.</p>

<p><img src="/assets/img/2018/11/2018-11-09_18-10-51.png" alt="2018-11-09_18-10-51" /></p>

<h2 id="problem-with-routing">Problem with Routing</h2>

<p>Issue using Razor pages is that area name is more or less hard-coded (chosen by package owner) and should be used when accessing the pages in hosting project. This is no issue if package owner and hosting project “agree” on path to be used to access pages.
However, for example in localization provider Admin UI package my idea is to allow completely dynamic path to the administrative user interface. Hosting project owner can choose what name will be used in url:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">services</span><span class="p">.</span><span class="nf">AddDbLocalizationProviderAdminUI</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">_</span><span class="p">.</span><span class="n">RootUrl</span> <span class="p">=</span> <span class="s">"/localization-admin"</span><span class="p">;</span>
        <span class="p">...</span>
    <span class="p">});</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Configuration above will make sure that DbLocalizationProvider AdminUI is “mounted” to url “<code class="language-plaintext highlighter-rouge">https://{something-something}/localization-admin</code>”. Of course I could choose path to hard-code this url and always “mount” to that url (which is actually by default if you don’t specify anything), but thought that if <a href="https://www.nuget.org/packages/LocalizationProvider.AdminUI/">Asp.Net MVC package</a> or <a href="https://nuget.episerver.com/package/?id=DbLocalizationProvider.AdminUI.EPiServer">EPiServer counterpart</a> allows this configuration, why .Net Core package would be exclusion?</p>

<p>But, as you can image - we somehow have to replace “static” hard-coded path with configured one during the runtime.</p>

<h2 id="dynamic-area-name-for-razor-pages">Dynamic Area Name for Razor Pages</h2>

<p>After couple hours investigation and research (it’s pretty amazing when underlying framework is open source) found a solution for our issue here.</p>

<p>First, we need to give area name anyways. This could be anything, any junk. I just picked some random generated GUID for the area name.</p>

<p><img src="/assets/img/2018/11/2018-11-09_18-26-15.png" alt="2018-11-09_18-26-15" /></p>

<p>Second, we need to play around a bit with Mvc conventions and reconfigure (or add new options to be precise) our area name to route to other (configured path).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="n">IServiceCollection</span> <span class="nf">AddDbLocalizationProviderAdminUI</span><span class="p">(</span>
    <span class="k">this</span> <span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">,</span>
    <span class="n">Action</span><span class="p">&lt;</span><span class="n">UiConfigurationContext</span><span class="p">&gt;</span> <span class="n">setup</span> <span class="p">=</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// add support for admin ui razor class library pages</span>
    <span class="n">services</span><span class="p">.</span><span class="n">Configure</span><span class="p">&lt;</span><span class="n">RazorPagesOptions</span><span class="p">&gt;(</span><span class="n">_</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">_</span><span class="p">.</span><span class="n">Conventions</span><span class="p">.</span><span class="nf">AddAreaPageRoute</span><span class="p">(</span><span class="s">"4D5A2189D188417485BF6C70546D34A1"</span><span class="p">,</span>
                                        <span class="s">"/AdminUI"</span><span class="p">,</span>
                                        <span class="n">UiConfigurationContext</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">RootUrl</span><span class="p">);</span>
    <span class="p">});</span>

    <span class="k">return</span> <span class="n">services</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is also one of the reasons why path to the AdminUI should be configured in <code class="language-plaintext highlighter-rouge">ConfigureServices</code> stage and not <code class="language-plaintext highlighter-rouge">Configure</code> stage in <code class="language-plaintext highlighter-rouge">Startup.cs</code> file. If we would be adding <code class="language-plaintext highlighter-rouge">RazorPageOptions</code> after services are configured - it will have not effects on Asp.Net Mvc pipeline what so ever.</p>

<p>Code above basically “remaps” all requests that will be sent to <code class="language-plaintext highlighter-rouge">UiConfigurationContext.Current.RootUrl</code> (which by default is <code class="language-plaintext highlighter-rouge">localization-admin</code>) to our randomly generated area.</p>

<p>Now we are able to customize address of the AdminUI to whatever we want.</p>

<p><img src="/assets/img/2018/11/2018-11-09_18-36-23.png" alt="2018-11-09_18-36-23" /></p>

<p>Happy routing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term="Localization Provider" /><category term="ASP.NET" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="episerver" /><category term="optimizely" /><category term="localization" /><category term="asp.net" /><summary type="html"><![CDATA[New Packaging Process]]></summary></entry><entry><title type="html">Hungry Azure WebJob - Journey of Memory Analysis</title><link href="https://tech-fellow.eu/2018/11/04/hungry-azure-webjob-journey-of/" rel="alternate" type="text/html" title="Hungry Azure WebJob - Journey of Memory Analysis" /><published>2018-11-04T10:45:00+02:00</published><updated>2018-11-04T10:45:00+02:00</updated><id>https://tech-fellow.eu/2018/11/04/hungry-azure-webjob-journey-of</id><content type="html" xml:base="https://tech-fellow.eu/2018/11/04/hungry-azure-webjob-journey-of/"><![CDATA[<h2 id="background">Background</h2>

<p>We do have some of the stuff push out to the cloud infrastructure. One of the component is WebJob that runs 24/7 and is set to trigger every 2 seconds. You might be wondering why we are not modern and not running stuff in serverless world (for example Azure Functions)? We do have that stuff also, but here take is that we need access to previous run results (there are some heavy caching requirements) and latency that we would need to pay to get access to persistent storage is too much for us.</p>

<p>So running something 24/7 for every 2 seconds sounds like service which is checking patient heartbeat and reacting on any deviations. It’s almost true, but in our case patients are public transportation passengers.</p>

<p>So at some point, I received complaint from customer that our service is “stopped” and nothing really happens and then after some time it’s back to the normal. For me this sounds like peak of something and it’s reset. As there is no end-users connected to the service, there can’t be any peaks because of high traffic. It should be more or less constant workload.</p>

<p>Then I took a look at Service Plan resource utilization.</p>

<p><img src="/assets/img/2018/11/2018-10-05_11-11-59.jpg" alt="" /></p>

<h2 id="dump-analysis">Dump Analysis</h2>

<p>It is actually very convenient to grab a process dump straight from the Advanced Tools (aka Kudos console):</p>

<p><img src="/assets/img/2018/11/2018-11-04_08-00-27-1.png" alt="" /></p>

<p>And then dump is available under Process Explorer section:</p>

<p><img src="/assets/img/2018/11/2018-11-04_08-05-40.png" alt="" /></p>

<p>Now what should I do with this dump?</p>

<p>Firstly, I tried couple times to utilize Visual Studio for this, to run some memory analysis there, but it ended up with this error all the time (<a href="https://developercommunity.visualstudio.com/content/problem/60975/debug-managed-memory-crashes-due-to-insufficient-m.html?ref=tech-fellow.eu">I’ve read</a> that it’s not related to available memory on your laptop at all, but with the underlying architecture in which VS is running).</p>

<p><img src="/assets/img/2018/11/drunkvs.png" alt="" /></p>

<p>What else?? Of course, your best friend - <a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-download-tools?ref=tech-fellow.eu">WinDbg</a> to the rescue (to be honest - nowadays I much more prefer <a href="https://microsoft.com/store/p/windbg/9pgjgd53tn86?ref=tech-fellow.eu">WinDbg Preview</a>)!</p>

<p>First we need to let WinDbg to analyze the dump - <code class="language-plaintext highlighter-rouge">!analyze</code> command does this.</p>

<p>When win debugger got an idea of what’s going on - we can take a look at managed heap.</p>

<pre><code class="language-dotnetcli">&gt; !eeheap -gc


f1010000  f1011000  f1770350  0x75f350(7730000)
f5010000  f5011000  f5631fb8  0x620fb8(6426552)
Large object heap starts at 0x02b21000
 segment     begin  allocated      size
02b20000  02b21000  03a31948  0xf10948(15796552)
f6010000  f6011000  f67ad3c0  0x79c3c0(7979968)
b4010000  b4011000  b4cd7c08  0xcc6c08(13397000)
Total Size:              Size: 0xdbecfd08 (3689741576) bytes.
------------------------------
GC Heap Size:    Size: 0xdbecfd08 (3689741576) bytes.
</code></pre>

<p>GC heap size of <code class="language-plaintext highlighter-rouge">3689741576</code> (around <code class="language-plaintext highlighter-rouge">3.5GB</code>) seems a bit too much for me. It’s definitely a memory leak somewhere. Which gets cleaned up when GC is under pressure and memory consumption threshold has been reached. That’s why we can see some drops of the memory time to time.</p>

<p>Next what we can do is to dump statistics about the heap (note this operation might take a while as it needs to sum up count and size of all types found on the heap).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre>&gt; !dumpheap -stat


...
718ad824  8872810    106473720 System.Object
06630b10  3976024    132126336 GeoJSON.Net.Geometry.IPosition[]
71911e28  9787140    234891360 System.Collections.Concurrent.ConcurrentDictionary`2+Node[[System.Type, mscorlib],[System.Boolean, mscorlib]]
718ad484  5299303    452138906 System.String
05e9feb8 21103512    844140480 GeoJSON.Net.Geometry.Position
Total 124613918 objects
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Among the others high volume objects there are couple interesting cases:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre>...
01036f40   305849     11010564 StructureMap.Container
0103c794   305895     11012220 StructureMap.Graph.PluginFamily
...
0164b9b4   305895     18353700 System.Collections.Generic.Dictionary`2+Entry[[System.String, mscorlib],[StructureMap.Pipeline.Instance, StructureMap]][]
0402e37c   305849     19574336 StructureMap.Pipeline.ObjectInstance
0103c494   305850     19574400 StructureMap.Graph.PluginGraph
...
06630348   305849     23244460 GeoJSON.Net.Geometry.Polygon[]
01643e28   611698     24467920 System.Collections.Concurrent.ConcurrentDictionary`2[[System.Int32, mscorlib],[StructureMap.Pipeline.LazyLifecycleObject`1[[System.Object, mscorlib]], StructureMap]]
...
04112344  3670178     44042136 StructureMap.Pipeline.LazyLifecycleObject`1+Boxed[[System.Object, mscorlib]]
...
06630494  3976025     63616396 GeoJSON.Net.Geometry.LineString[]
01643dc0  3670178     73403560 StructureMap.Pipeline.LazyLifecycleObject`1[[System.Object, mscorlib]]
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This definitely shows up as weird and needs more investigation. If there is a huge number of StructureMap’s <code class="language-plaintext highlighter-rouge">Container</code> instances, this means that somewhere in the code there is a creation of the container and not proper disposal.</p>

<p>We can dump all the instances of the <code class="language-plaintext highlighter-rouge">Container</code> object:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre>&gt; !dumpheap -type StructureMap.Container
 Address       MT     Size
...
02879a7c 0402dc98       24
02879e48 05279c4c       20
...
16a4d688 01640d60       36
...
</pre></td></tr></tbody></table></code></pre></div></div>

<p>There a lot of instances of this type. So I even did wait for the WinDbg to finish enlisting (just killed it). But it’s a matter of getting details about single instance of the <code class="language-plaintext highlighter-rouge">Container</code> (let’s pick random one).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre>&gt; !DumpObj /d 16a4d688
Name:        StructureMap.Container
MethodTable: 01036f40
EEClass:     012192fc
Size:        36(0x24) bytes
File:        D:\local\Temp\jobs\continuous\WebJob\klbujtvv.m45\StructureMap.dll
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
01640d60  400000f        4 ...r, StructureMap]]  0 instance 16a8cdec _children
0103b73c  4000010        8 ...ap.IPipelineGraph  0 instance 16a8cc6c _pipelineGraph
718ad824  4000011        c        System.Object  0 instance 16a8ce38 _syncLock
718f1f0c  4000012       1c       System.Boolean  1 instance        0 _disposedLatch
01036dd8  4000013       14         System.Int32  1 instance        1 _role
718ad484  4000014       10        System.String  0 instance 16a8ce44 &lt;Name&gt;k__BackingField
01036e8c  4000015       18         System.Int32  1 instance        1 &lt;DisposalLock&gt;k__BackingField
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Next thing to query dump file is to understand who is keeping (at least this instance) alive. This is achieved with <code class="language-plaintext highlighter-rouge">gcroot</code> command.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre>&gt; !gcroot 16a4d688
Thread 29fc:
    00d9ef18 040ecf9a Microsoft.Azure.WebJobs.JobHost.RunAndBlock()
        edi:
            -&gt;  01b7483c Microsoft.Azure.WebJobs.JobHost
            -&gt;  01b748e4 Microsoft.Azure.WebJobs.Host.Executors.JobHostContextFactory
            -&gt;  01b73a84 Microsoft.Azure.WebJobs.Host.Executors.DefaultStorageAccountProvider
            -&gt;  01b737ec Microsoft.Azure.WebJobs.JobHostConfiguration
            -&gt;  01b73954 System.Collections.Concurrent.ConcurrentDictionary`2[[System.Type, mscorlib],[System.Object, mscorlib]]
            -&gt;  01b73a6c System.Collections.Concurrent.ConcurrentDictionary`2+Tables[[System.Type, mscorlib],[System.Object, mscorlib]]
            -&gt;  01b739e4 System.Collections.Concurrent.ConcurrentDictionary`2+Node[[System.Type, mscorlib],[System.Object, mscorlib]][]
            -&gt;  01b74568 System.Collections.Concurrent.ConcurrentDictionary`2+Node[[System.Type, mscorlib],[System.Object, mscorlib]]
            -&gt;  01b74670 MyProject.WebJob.StructureMapActivator
            -&gt;  01b220e4 StructureMap.Container
            -&gt;  01b375e4 System.Collections.Concurrent.ConcurrentBag`1[[StructureMap.Container, StructureMap]]
            ...
</pre></td></tr></tbody></table></code></pre></div></div>

<p>What caught my eyes is this line:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>01b74670 MyProject.WebJob.StructureMapActivator
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Which means that there is a “not runtime” class instance that keeps reference to the container. Let’s take a closer look.</p>

<h2 id="webjob-source">WebJob Source</h2>

<p>Let’s look at WebJob source code. This is basically the essence of the job (all not relevant details are removed).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">Job</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IService</span> <span class="n">_service</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">Job</span><span class="p">(</span><span class="n">IService</span> <span class="n">service</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_service</span> <span class="p">=</span> <span class="n">service</span> <span class="p">??</span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">service</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">RunJob</span><span class="p">([</span><span class="nf">TimerTrigger</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">JobTrigger</span><span class="p">))]</span> <span class="n">TimerInfo</span> <span class="n">timerInfo</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">await</span> <span class="n">_service</span><span class="p">.</span><span class="nf">RunAsync</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Essentially most of the time our idea about webjobs or functions is that those are just a hosting infrastructure part of the system. They are responsible to let the component from the domain to be run in particular environment. Web job or function is just a shell layer infrastructure code in overall architecture (e.g. <a href="/2016/10/17/baking-round-shaped-software/">pizza architecture</a>)<br />
There is not a big deal to understand what webjob does. But how it gets injected <code class="language-plaintext highlighter-rouge">IService</code> instance in construction? This leads us to right direction of our analysis.</p>

<h3 id="dependency-injection-in-webjobs">Dependency Injection In WebJobs</h3>

<p>Once I <a href="/2017/04/12/disposable-dependency-for-azure-webjob/">blogged</a> about how to implement your own dependency injection. I could of course go with <a href="http://blog.ploeh.dk/2014/06/10/pure-di/?ref=tech-fellow.eu">Pure DI</a>. But we decided to utilize StructureMap in our WebJob area as well (because we are using it everywhere else and team is used to that).<br />
I’ll not repeat whole blog post about dependency injection here, but just extract relevant parts.In order to support injections in webjobs, runtime actually already supports this with extension point - called job activator.<br />
This is configured in your <code class="language-plaintext highlighter-rouge">Main()</code> method:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="k">static</span> <span class="k">void</span> <span class="nf">Main</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">container</span> <span class="p">=</span> <span class="nf">ComposeContainer</span><span class="p">();</span>
    <span class="kt">var</span> <span class="n">config</span> <span class="p">=</span> <span class="k">new</span> <span class="n">JobHostConfiguration</span>
                    <span class="p">{</span>
                        <span class="n">JobActivator</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">StructureMapActivator</span><span class="p">(</span><span class="n">container</span><span class="p">)</span>
                    <span class="p">};</span>

    <span class="k">if</span><span class="p">(</span><span class="n">JobConfig</span><span class="p">.</span><span class="n">IsDevelopment</span><span class="p">)</span>
        <span class="n">config</span><span class="p">.</span><span class="nf">UseDevelopmentSettings</span><span class="p">();</span>

    <span class="n">config</span><span class="p">.</span><span class="nf">UseTimers</span><span class="p">();</span>

    <span class="kt">var</span> <span class="n">host</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">JobHost</span><span class="p">(</span><span class="n">config</span><span class="p">);</span>
    <span class="n">host</span><span class="p">.</span><span class="nf">RunAndBlock</span><span class="p">();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>In code fragment above <code class="language-plaintext highlighter-rouge">ComposeContainer()</code> is just a method that configures and returns <code class="language-plaintext highlighter-rouge">Container</code> instance for the job activator to use.
Let’s look at <code class="language-plaintext highlighter-rouge">StructureMapActivator</code> code:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">StructureMapActivator</span> <span class="p">:</span> <span class="n">IJobActivator</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">Container</span> <span class="n">_container</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">StructureMapActivator</span><span class="p">(</span><span class="n">Container</span> <span class="n">container</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_container</span> <span class="p">=</span> <span class="n">container</span> <span class="p">??</span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">container</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">T</span> <span class="n">CreateInstance</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">nestedContainer</span> <span class="p">=</span> <span class="n">_container</span><span class="p">.</span><span class="nf">CreateChildContainer</span><span class="p">();</span>
        <span class="kt">var</span> <span class="n">function</span> <span class="p">=</span> <span class="n">nestedContainer</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;();</span>

        <span class="kt">var</span> <span class="n">disposableFunction</span> <span class="p">=</span> <span class="n">function</span> <span class="k">as</span> <span class="n">BaseFunction</span><span class="p">;</span>
        <span class="n">disposableFunction</span><span class="p">?.</span><span class="nf">SetChildContainer</span><span class="p">(</span><span class="n">nestedContainer</span><span class="p">);</span>

        <span class="k">return</span> <span class="n">function</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Activator main responsibility is to create child container for every job execution.</p>

<p><strong>NB!</strong> Reviewing stacktrace and also long-lived instances of container lead me to the conclusion that job activator had to create nested containers instead (and not child containers). Nested containers would behave very similar to as it would work in web request context - for example in <a href="http://structuremap.github.io/the-container/nested-containers/?ref=tech-fellow.eu#why-nested-containers-over-httpcontext-or-threadlocal-scoping">ASP.NET application</a>. I’m glad that we had this issue - this helped to fix container type usage as well!</p>

<p>Back to track about job activator. Every single dependency resolver (or <a href="http://blog.ploeh.dk/2011/07/28/CompositionRoot/?ref=tech-fellow.eu">composition root</a>) purpose is to resolve dependencies. But most importantly it’s also responsible for <em>releasing</em> resolved dependencies. This is just a good behavior of triple R (<a href="http://blog.ploeh.dk/2010/09/29/TheRegisterResolveReleasepattern/?ref=tech-fellow.eu">RRR pattern</a>).<br />
As you can see <code class="language-plaintext highlighter-rouge">IJobActivator</code> definition has just a single method - <code class="language-plaintext highlighter-rouge">CreateInstance</code>. Disposal pattern is implemented in the runtime. Runtime tries to dispose resolved job instance when it’s done its work (fragment from <code class="language-plaintext highlighter-rouge">Microsoft.Azure.WebJobs.Host.Executors.FunctionInvoker&lt;TReflected&gt;</code>):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">InvokeAsync</span><span class="p">(</span><span class="kt">object</span><span class="p">[]</span> <span class="n">arguments</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">await</span> <span class="n">Task</span><span class="p">.</span><span class="nf">Yield</span><span class="p">();</span>
    <span class="n">TReflected</span> <span class="n">instance</span> <span class="p">=</span> <span class="k">this</span><span class="p">.</span><span class="n">_instanceFactory</span><span class="p">.</span><span class="nf">Create</span><span class="p">();</span>
    <span class="k">using</span> <span class="p">((</span><span class="kt">object</span><span class="p">)</span> <span class="n">instance</span> <span class="k">as</span> <span class="n">IDisposable</span><span class="p">)</span>
        <span class="k">await</span> <span class="k">this</span><span class="p">.</span><span class="n">_methodInvoker</span><span class="p">.</span><span class="nf">InvokeAsync</span><span class="p">(</span><span class="n">instance</span><span class="p">,</span> <span class="n">arguments</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This means that if returned job implements <code class="language-plaintext highlighter-rouge">IDisposable</code> then runtime will dispose it. Otherwise - nothing will happen. Interestingly to note that <code class="language-plaintext highlighter-rouge">null</code> is also supported as valid <code class="language-plaintext highlighter-rouge">using</code> argument.</p>

<p>The only way how <code class="language-plaintext highlighter-rouge">StructureMapActivator</code> could implement disposable pattern is to push this responsibility to the job itself. Because once job instance is resolved activator walks off the stage. It’s not involved in further lifecycle management process of the job.</p>

<p>What happens when job is activated?</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">disposableFunction</span> <span class="p">=</span> <span class="n">function</span> <span class="k">as</span> <span class="n">BaseFunction</span><span class="p">;</span>
<span class="n">disposableFunction</span><span class="p">?.</span><span class="nf">SetChildContainer</span><span class="p">(</span><span class="n">nestedContainer</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Nested container is passed down to job instance. Why? Just because someone needs to dispose it. And unfortunately it’s particular job’s responsibility now.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">BaseFunction</span> <span class="p">:</span> <span class="n">IDisposable</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="n">IContainer</span> <span class="n">_childContainer</span><span class="p">;</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Dispose</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">_childContainer</span><span class="p">?.</span><span class="nf">Dispose</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">SetChildContainer</span><span class="p">(</span><span class="n">IContainer</span> <span class="n">nestedContainer</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_childContainer</span> <span class="p">=</span> <span class="n">nestedContainer</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="root-cause">Root Cause</h2>

<p>Just for a second, let’s glimpse on the definition of our job:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">Job</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">Job</span><span class="p">(</span><span class="n">IService</span> <span class="n">service</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="p">...</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">RunJob</span><span class="p">([</span><span class="nf">TimerTrigger</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">JobTrigger</span><span class="p">))]</span> <span class="n">TimerInfo</span> <span class="n">timerInfo</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="p">...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Yeah!</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">Job</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So where is BaseFunction? You know..!? Just forgot to put it there.. Genius!</p>

<p>This is the simplest resolution I’ve ever have done..</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">Job</span> <span class="p">:</span> <span class="n">BaseFunction</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now, every time job finishes its work - nested container is properly disposed.Memory consumption now looks much nicer:</p>

<p><img src="/assets/img/2018/11/mem.jpg" alt="" /></p>

<p>Happy diagnosing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="WebJobs" /><category term="Azure" /><category term="Debugging" /><category term=".net" /><category term="c#" /><category term="asp.net" /><category term="azure" /><category term="debugging" /><summary type="html"><![CDATA[Background]]></summary></entry><entry><title type="html">Durable Episerverless</title><link href="https://tech-fellow.eu/2018/10/28/durable-episerverless/" rel="alternate" type="text/html" title="Durable Episerverless" /><published>2018-10-28T15:30:00+02:00</published><updated>2018-10-28T15:30:00+02:00</updated><id>https://tech-fellow.eu/2018/10/28/durable-episerverless</id><content type="html" xml:base="https://tech-fellow.eu/2018/10/28/durable-episerverless/"><![CDATA[<p>There been couple of times when we together with friend of mine (<a href="https://twitter.com/HenrikFransas">Henrik Fransas</a>) have presented <a href="/2017/11/21/episerver-azure-functions-episerverless/">Episerver and Azure Functions</a> (aka “episerverless”) and how they play well together. However, looking at overall our sample application architecture - it still seems to be a bit brittle and composed together out of some small moving parts.</p>

<p>This is our initial architecture:</p>

<p><img src="/assets/img/2018/10/2018-10-28_14-36-31.png" alt="" /></p>

<p>As you can see there are lots of small parts, composed together, having queues in between functions (be sure to spell them correctly) and even also Service Bus topic to get out of the parallel processing (by having subscriptions to the topic from the Function2 and Function4).</p>

<p>It’s working, but knowing me - I suppose there must be a better way to accomplish the same task.</p>

<h2 id="durable-functions-to-the-rescue">Durable Functions to the Rescue</h2>

<p><a href="https://docs.microsoft.com/en-us/azure/azure-functions/durable-functions-overview">Azure Durable Functions</a> made it debut earlier this year. Thought it’s good chance to try it and see how architecture might change when introducing this piece of black magic here.</p>

<p>So, let’s get started.</p>

<h3 id="entry-point-function">Entry Point Function</h3>

<p>First of all - connection from Episerver up to Azure Function endpoint (to initiate whole pipeline of image process) does not change much. We still are talking to function via HttpClient instance:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">HttpResponseMessage</span><span class="p">&gt;</span> <span class="nf">CallFunctionAsync</span><span class="p">(</span><span class="kt">string</span> <span class="n">contentReference</span><span class="p">,</span>
    <span class="kt">byte</span><span class="p">[]</span> <span class="n">byteData</span><span class="p">,</span>
    <span class="kt">string</span> <span class="n">imageUrl</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">req</span> <span class="p">=</span> <span class="k">new</span> <span class="n">ProcessingRequest</span>
    <span class="p">{</span>
        <span class="n">FileId</span> <span class="p">=</span> <span class="n">contentReference</span><span class="p">,</span>
        <span class="n">Content</span> <span class="p">=</span> <span class="n">byteData</span><span class="p">,</span>
        <span class="n">Width</span> <span class="p">=</span> <span class="m">150</span><span class="p">,</span>
        <span class="n">ImageUrl</span> <span class="p">=</span> <span class="n">imageUrl</span>
    <span class="p">};</span>

    <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">content</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">StringContent</span><span class="p">(</span><span class="n">JsonConvert</span><span class="p">.</span><span class="nf">SerializeObject</span><span class="p">(</span><span class="n">req</span><span class="p">)))</span>
    <span class="p">{</span>
        <span class="n">content</span><span class="p">.</span><span class="n">Headers</span><span class="p">.</span><span class="n">ContentType</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">MediaTypeHeaderValue</span><span class="p">(</span><span class="s">"application/json"</span><span class="p">);</span>
        <span class="k">return</span> <span class="k">await</span>
            <span class="n">Global</span><span class="p">.</span><span class="n">HttpClient</span><span class="p">.</span><span class="n">Value</span><span class="p">.</span><span class="nf">PostAsync</span><span class="p">(</span>
                <span class="n">_settings</span><span class="p">.</span><span class="n">Settings</span><span class="p">.</span><span class="n">RequestFunctionUri</span><span class="p">,</span>
                <span class="n">content</span><span class="p">).</span><span class="nf">ConfigureAwait</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Difference from the ordinary function (nondurable one) is that entry point function needs to initiate orchestractor, kick off durable process and return “something”. This “something” is nothing else as simple <code class="language-plaintext highlighter-rouge">HttpResponseMessage</code> containg some magic auto-generated url end-points for consumer party to check durable process status. It’s up to the consumer side of course to use thes endpoints of not, but just makes it possible to display some sort of progress report if needed.</p>

<p>This is now Function1 body:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="s">"Function1"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">HttpResponseMessage</span><span class="p">&gt;</span> <span class="nf">Run</span><span class="p">(</span>
    <span class="p">[</span><span class="nf">HttpTrigger</span><span class="p">(</span><span class="n">AuthorizationLevel</span><span class="p">.</span><span class="n">Anonymous</span><span class="p">,</span> <span class="s">"post"</span><span class="p">)]</span> <span class="n">ProcessingRequest</span> <span class="n">request</span><span class="p">,</span>
                                                        <span class="n">HttpRequestMessage</span> <span class="n">req</span><span class="p">,</span>
    <span class="p">[</span><span class="nf">Blob</span><span class="p">(</span><span class="s">"%input-container%/{FileId}"</span><span class="p">)]</span>                <span class="n">CloudBlockBlob</span> <span class="n">outBlob</span><span class="p">,</span>
    <span class="p">[</span><span class="n">OrchestrationClient</span><span class="p">]</span>                               <span class="n">DurableOrchestrationClient</span> <span class="n">starter</span><span class="p">,</span>
                                                        <span class="n">TraceWriter</span> <span class="n">log</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">log</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">"(Fun1) Received image for processing..."</span><span class="p">);</span>

    <span class="k">await</span> <span class="n">outBlob</span><span class="p">.</span><span class="nf">UploadFromByteArrayAsync</span><span class="p">(</span><span class="n">request</span><span class="p">.</span><span class="n">Content</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">request</span><span class="p">.</span><span class="n">Content</span><span class="p">.</span><span class="n">Length</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">analysisRequest</span> <span class="p">=</span> <span class="k">new</span> <span class="n">AnalysisReq</span>
    <span class="p">{</span>
        <span class="n">BlobRef</span> <span class="p">=</span> <span class="n">outBlob</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span>
        <span class="n">Width</span> <span class="p">=</span> <span class="n">request</span><span class="p">.</span><span class="n">Width</span><span class="p">,</span>
        <span class="n">ImageUrl</span> <span class="p">=</span> <span class="n">request</span><span class="p">.</span><span class="n">ImageUrl</span>
    <span class="p">};</span>

    <span class="kt">var</span> <span class="n">instanceId</span> <span class="p">=</span> <span class="k">await</span> <span class="n">starter</span><span class="p">.</span><span class="nf">StartNewAsync</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">ProcessingSequence</span><span class="p">),</span> <span class="n">analysisRequest</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="n">starter</span><span class="p">.</span><span class="nf">CreateCheckStatusResponse</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="n">instanceId</span><span class="p">);</span>

    <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Note, that we demanded from the Azure Functions runtime to give us something call <code class="language-plaintext highlighter-rouge">DurableOrchestrationClient</code>. This type isresponsible for allowing us to kick-off some durable process. Throught the orchestration client, we are able to start our process:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">instanceId</span> <span class="p">=</span> <span class="k">await</span> <span class="n">starter</span><span class="p">.</span><span class="nf">StartNewAsync</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">ProcessingSequence</span><span class="p">),</span> <span class="n">analysisRequest</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>and also return response to the caller about how we are doing:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="n">starter</span><span class="p">.</span><span class="nf">CreateCheckStatusResponse</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="n">instanceId</span><span class="p">);</span>

<span class="k">return</span> <span class="n">result</span><span class="p">;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Once durable process is started, consumer party gets back similar response (instance <code class="language-plaintext highlighter-rouge">id</code> and access <code class="language-plaintext highlighter-rouge">code</code> will be different, also note that url themselves might be different depending on which runtime version you are running function on, this is v1.0):</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="p">{</span><span class="w">
  </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"b4950....2fdaa8"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"statusQueryGetUri"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://localhost:7071/admin/extensions/DurableTaskExtension/instances/b4950....2fdaa8?taskHub=DurableFunctionsHub&amp;connection=Storage&amp;code=gj1VN...nILg=="</span><span class="p">,</span><span class="w">
  </span><span class="nl">"sendEventPostUri"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://localhost:7071/admin/extensions/DurableTaskExtension/instances/b4950....2fdaa8/raiseEvent/{eventName}?taskHub=DurableFunctionsHub&amp;connection=Storage&amp;code=gj1VN...nILg=="</span><span class="p">,</span><span class="w">
  </span><span class="nl">"terminatePostUri"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://localhost:7071/admin/extensions/DurableTaskExtension/instances/b4950....2fdaa8/terminate?reason={text}&amp;taskHub=DurableFunctionsHub&amp;connection=Storage&amp;code=gj1VN...nILg=="</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>Here is couple of notes to make:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">id</code> - this is unique identifier of the orchestration instance (durable process)</li>
  <li><code class="language-plaintext highlighter-rouge">statusQueryGetUri</code> - here we cna get more info about the status of the instance if needed</li>
  <li><code class="language-plaintext highlighter-rouge">sendEventPostUri</code> - here we can send in custom event to the instance if needed</li>
  <li><code class="language-plaintext highlighter-rouge">terminatePostUri</code> - and if none cares about this instance anymore, here we can kill it</li>
</ul>

<p>Returning status check response makes it possible to implement something known as “<a href="https://docs.microsoft.com/en-us/azure/azure-functions/durable-functions-http-api">Async HTTP API</a>” pattern.</p>

<h3 id="orchestrator-function">Orchestrator Function</h3>

<p>Next, wex should look at orchestrator function itself.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">ProcessingSequence</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">ProcessingSequence</span><span class="p">))]</span>
    <span class="p">[</span><span class="nf">StorageAccount</span><span class="p">(</span><span class="s">"my-storage-connection"</span><span class="p">)]</span>
    <span class="p">[</span><span class="k">return</span><span class="p">:</span> <span class="nf">Queue</span><span class="p">(</span><span class="s">"done-images"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">AsciiArtResult</span><span class="p">&gt;</span> <span class="nf">Run</span><span class="p">(</span>
        <span class="p">[</span><span class="n">OrchestrationTrigger</span><span class="p">]</span> <span class="n">DurableOrchestrationContext</span> <span class="n">context</span><span class="p">,</span>
        <span class="n">TraceWriter</span> <span class="n">log</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">input</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">GetInput</span><span class="p">&lt;</span><span class="n">AnalysisReq</span><span class="p">&gt;();</span>

        <span class="p">...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As you can see, core part of the function via which whole durable process can happen is <code class="language-plaintext highlighter-rouge">DurableOrchestrationContext</code> parameter.
We can now start to implement our workflow (and what is nice about whole this setup, is that workflow definition is code-first).</p>

<p>We need first to get out from the context incoming parameters (<code class="language-plaintext highlighter-rouge">analysisRequest</code>) that were sent to the function via <code class="language-plaintext highlighter-rouge">starter</code>:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">Function1</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="s">"Function1"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">HttpResponseMessage</span><span class="p">&gt;</span> <span class="nf">Run</span><span class="p">(</span>
        <span class="p">...</span>
        <span class="p">[</span><span class="n">OrchestrationClient</span><span class="p">]</span>                               <span class="n">DurableOrchestrationClient</span> <span class="n">starter</span>
        <span class="p">...)</span>
    <span class="p">{</span>
        <span class="p">...</span>
        <span class="kt">var</span> <span class="n">instanceId</span> <span class="p">=</span> <span class="k">await</span> <span class="n">starter</span><span class="p">.</span><span class="nf">StartNewAsync</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">ProcessingSequence</span><span class="p">),</span> <span class="n">analysisRequest</span><span class="p">);</span>
        <span class="p">...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is doable fromt the <code class="language-plaintext highlighter-rouge">context</code>:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">input</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">GetInput</span><span class="p">&lt;</span><span class="n">AnalysisReq</span><span class="p">&gt;();</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now we are ready to proceed with <code class="language-plaintext highlighter-rouge">Function2</code>:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">ProcessingSequence</span><span class="p">))]</span>
<span class="p">[</span><span class="nf">StorageAccount</span><span class="p">(</span><span class="s">"my-storage-connection"</span><span class="p">)]</span>
<span class="p">[</span><span class="k">return</span><span class="p">:</span> <span class="nf">Queue</span><span class="p">(</span><span class="s">"done-images"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">AsciiArtResult</span><span class="p">&gt;</span> <span class="nf">Run</span><span class="p">(</span>
    <span class="p">[</span><span class="n">OrchestrationTrigger</span><span class="p">]</span> <span class="n">DurableOrchestrationContext</span> <span class="n">context</span><span class="p">,</span>
    <span class="n">TraceWriter</span> <span class="n">log</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">input</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">GetInput</span><span class="p">&lt;</span><span class="n">AnalysisReq</span><span class="p">&gt;();</span>

    <span class="kt">var</span> <span class="n">visionResult</span> <span class="p">=</span> <span class="k">await</span> <span class="n">context</span><span class="p">.</span><span class="n">CallActivityAsync</span><span class="p">&lt;(</span><span class="kt">string</span> <span class="n">Description</span><span class="p">,</span> <span class="kt">string</span><span class="p">[]</span> <span class="n">Tags</span><span class="p">)&gt;(</span><span class="k">nameof</span><span class="p">(</span><span class="n">Function2</span><span class="p">),</span> <span class="n">input</span><span class="p">);</span>
    <span class="p">...</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Note that functions that take part in orchestration are not called functiosn anymore, but <code class="language-plaintext highlighter-rouge">Activity</code>. So call to the other function or activity is just as simple as <code class="language-plaintext highlighter-rouge">context.CallActivityAsync&lt;TResponse&gt;(...)</code>.</p>

<p>Knowing this we can now implement whole workflow quite easily:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">ProcessingSequence</span><span class="p">))]</span>
<span class="p">[</span><span class="nf">StorageAccount</span><span class="p">(</span><span class="s">"my-storage-connection"</span><span class="p">)]</span>
<span class="p">[</span><span class="k">return</span><span class="p">:</span> <span class="nf">Queue</span><span class="p">(</span><span class="s">"done-images"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">AsciiArtResult</span><span class="p">&gt;</span> <span class="nf">Run</span><span class="p">(</span>
    <span class="p">[</span><span class="n">OrchestrationTrigger</span><span class="p">]</span> <span class="n">DurableOrchestrationContext</span> <span class="n">context</span><span class="p">,</span>
    <span class="n">TraceWriter</span> <span class="n">log</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">input</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">GetInput</span><span class="p">&lt;</span><span class="n">AnalysisReq</span><span class="p">&gt;();</span>

    <span class="kt">var</span> <span class="n">visionResult</span> <span class="p">=</span> <span class="k">await</span> <span class="n">context</span><span class="p">.</span><span class="n">CallActivityAsync</span><span class="p">&lt;(</span><span class="kt">string</span> <span class="n">Description</span><span class="p">,</span> <span class="kt">string</span><span class="p">[]</span> <span class="n">Tags</span><span class="p">)&gt;(</span><span class="k">nameof</span><span class="p">(</span><span class="n">Function2</span><span class="p">),</span> <span class="n">input</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">asciiResult</span> <span class="p">=</span> <span class="k">await</span> <span class="n">context</span><span class="p">.</span><span class="n">CallActivityAsync</span><span class="p">&lt;</span><span class="n">AsciiArtResult</span><span class="p">&gt;(</span><span class="k">nameof</span><span class="p">(</span><span class="n">Function3</span><span class="p">),</span> <span class="n">input</span><span class="p">);</span>

    <span class="kt">var</span> <span class="n">adultContentResult</span> <span class="p">=</span> <span class="k">await</span> <span class="n">context</span><span class="p">.</span><span class="n">CallActivityAsync</span><span class="p">&lt;</span><span class="kt">bool</span><span class="p">&gt;(</span><span class="k">nameof</span><span class="p">(</span><span class="n">Function4</span><span class="p">),</span> <span class="n">input</span><span class="p">);</span>
    <span class="k">if</span><span class="p">(</span><span class="n">adultContentResult</span><span class="p">)</span>
        <span class="k">await</span> <span class="n">context</span><span class="p">.</span><span class="n">CallActivityAsync</span><span class="p">&lt;</span><span class="n">TwilioSmsAttribute</span><span class="p">&gt;(</span><span class="k">nameof</span><span class="p">(</span><span class="n">Function5</span><span class="p">),</span> <span class="n">input</span><span class="p">);</span>

    <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">AsciiArtResult</span><span class="p">(</span><span class="n">asciiResult</span><span class="p">.</span><span class="n">BlobRef</span><span class="p">,</span>
                                    <span class="n">ConfigurationManager</span><span class="p">.</span><span class="n">AppSettings</span><span class="p">[</span><span class="s">"output-container"</span><span class="p">],</span>
                                    <span class="n">visionResult</span><span class="p">.</span><span class="n">Description</span><span class="p">,</span>
                                    <span class="n">visionResult</span><span class="p">.</span><span class="n">Tags</span><span class="p">);</span>

    <span class="n">log</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">$"(</span><span class="p">{</span><span class="k">nameof</span><span class="p">(</span><span class="n">ProcessingSequence</span><span class="p">)}</span><span class="s">) Finished processing the image."</span><span class="p">);</span>

    <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="activity-definition">Activity Definition</h3>

<p>Activity body implementation itself is not changed much from the days when it was ordinary function. The only thing we must change is how we decorate incoming parameters to the activity - now we have to use <code class="language-plaintext highlighter-rouge">[ActivityTrigger]</code> instead of other trigger types supported by Azure Functions.</p>

<p><strong>NB!</strong> Parameters to the activities cannot be complex thingies, those should be serializable (due to orchestrator implementation and durable functions architecture - state of the orchestration instance is saved in Azure Storage along with incoming parameters):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">Function2</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;(</span><span class="kt">string</span> <span class="n">Description</span><span class="p">,</span> <span class="kt">string</span><span class="p">[]</span> <span class="n">Tags</span><span class="p">)&gt;</span> <span class="nf">Run</span><span class="p">(</span>
    <span class="p">[</span><span class="n">ActivityTrigger</span><span class="p">]</span>                                      <span class="n">AnalysisReq</span> <span class="n">request</span><span class="p">,</span>
                                                           <span class="n">TraceWriter</span> <span class="n">log</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">log</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">$"(</span><span class="p">{</span><span class="k">nameof</span><span class="p">(</span><span class="n">Function2</span><span class="p">)}</span><span class="s">) Running image analysis..."</span><span class="p">);</span>
    <span class="p">...</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The rest of the activities should be changed in similar way.</p>

<h3 id="new-architecture-picture">New Architecture Picture</h3>

<p>So, once we have finished transition to durable functions, architecture picture changed dramatically:</p>

<p><img src="/assets/img/2018/10/2018-10-28_14-38-09.png" alt="" /></p>

<p>Happy orchestrating!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="Azure" /><category term="Azure Functions" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><category term="azure" /><category term="azure functions" /><summary type="html"><![CDATA[There been couple of times when we together with friend of mine (Henrik Fransas) have presented Episerver and Azure Functions (aka “episerverless”) and how they play well together. However, looking at overall our sample application architecture - it still seems to be a bit brittle and composed together out of some small moving parts.]]></summary></entry><entry><title type="html">Episerver Images got Responsive Resize</title><link href="https://tech-fellow.eu/2018/10/25/episerver-images-got-responsive-resize/" rel="alternate" type="text/html" title="Episerver Images got Responsive Resize" /><published>2018-10-25T16:30:00+03:00</published><updated>2018-10-25T16:30:00+03:00</updated><id>https://tech-fellow.eu/2018/10/25/episerver-images-got-responsive-resize</id><content type="html" xml:base="https://tech-fellow.eu/2018/10/25/episerver-images-got-responsive-resize/"><![CDATA[<p>Latest <a href="http://imageresizing.net/?ref=tech-fellow.eu">ImageResizer</a> library version now can also generate <code class="language-plaintext highlighter-rouge">&lt;picture&gt;</code> element. Thanks to lately movement by <a href="https://hacksbyme.net/about/?ref=tech-fellow.eu">Erik</a> and <a href="https://world.episerver.com/System/Users-and-profiles/Community-Profile-Card/?userid=be03d326-b35f-e611-9afb-0050568d2da8&amp;ref=tech-fellow.eu">Vincent</a>.</p>

<p>When you need to deal with images and want to adapt to various screen sizes - it’s time to switch to <code class="language-plaintext highlighter-rouge">&lt;picture&gt;</code> element.</p>

<p>Note that new method to generate picture element with all the corresponding sources and source sets is as simple as following:</p>

<pre><code class="language-razor">@Html.ResizePicture(Model.CurrentPage.MainImage, PictureProfiles.SampleImage)
</code></pre>

<p>Current page’s <code class="language-plaintext highlighter-rouge">MainImage</code> property is of type <code class="language-plaintext highlighter-rouge">ContentReference</code>. Basically simple straight forward Episerver property for image definition.</p>

<p>– What are those picture profiles you passed as last element?</p>

<p>Picture profile is an entity that describes how image should be scaled and rendered in various cases. For example in this code sample we have <code class="language-plaintext highlighter-rouge">SampleImage</code> profile:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="n">PictureProfile</span> <span class="n">SampleImage</span> <span class="p">=</span>
    <span class="k">new</span> <span class="n">PictureProfile</span>
    <span class="p">{</span>
        <span class="n">SrcSetWidths</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span> <span class="p">{</span> <span class="m">480</span><span class="p">,</span> <span class="m">768</span><span class="p">,</span> <span class="m">992</span><span class="p">,</span> <span class="m">1200</span> <span class="p">},</span>
        <span class="n">SrcSetSizes</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span>
        <span class="p">{</span>
            <span class="s">"50vw"</span><span class="p">,</span>
        <span class="p">},</span>
       <span class="n">DefaultWidth</span> <span class="p">=</span> <span class="m">992</span>
    <span class="p">};</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Here we can specify couple of properties to customize <code class="language-plaintext highlighter-rouge">&lt;picture&gt;</code> element:</p>

<ul>
  <li>Source set sizes (<strong>SrcSetSizes</strong>) - this regulates image size for various <a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images?ref=tech-fellow.eu">media conditions</a>.</li>
  <li>Source set widths (<strong>SrcSetWidths</strong>) - this regulates various image sizes (resized by width specified here). Used to generate <em>srcset</em> attribute.</li>
  <li>Default width (<strong>DefaultWidth</strong>) - what is default width of the image. This is for old-school browsers those have no clue about <code class="language-plaintext highlighter-rouge">&lt;picture&gt;</code> element existence.</li>
</ul>

<p>Code above generates following markup:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;picture&gt;</span>
    <span class="nt">&lt;source</span> <span class="na">sizes=</span><span class="s">"50vw"</span>
            <span class="na">srcset=</span><span class="s">"/globalassets/batman.jpg?w=480 480w,
                    /globalassets/batman.jpg?w=768 768w,
                    /globalassets/batman.jpg?w=992 992w,
                    /globalassets/batman.jpg?w=1200 1200w"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;img</span> <span class="na">alt=</span><span class="s">""</span> <span class="na">src=</span><span class="s">"/globalassets/batman.jpg?w=992"</span><span class="nt">&gt;</span>
<span class="nt">&lt;/picture&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Simple enough.</p>

<h3 id="customized-image-url">Customized Image Url</h3>

<p>You might be wondering, if helper method takes in <code class="language-plaintext highlighter-rouge">ContentReference</code> property, how am I going to specify various parameters for my images if I need to? For example “quality” is one of the example.</p>

<p>Roger! There is also a <code class="language-plaintext highlighter-rouge">UrlBuilder</code> overload, that is able to work with any arbitrary url. So, for example if I need to specify quality for all my images when generating <code class="language-plaintext highlighter-rouge">&lt;picture&gt;</code> element, I can actually resize “inline” and then render urls based on resulting image path:</p>

<pre><code class="language-razor">@Html.ResizePicture(Model.CurrentPage.MainImage
                                     .ResizeImage()
                                     .Quality(10),
                    PictureProfiles.SampleImage)
</code></pre>

<p>This code will generate following markup:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;picture&gt;</span>
    <span class="nt">&lt;source</span> <span class="na">sizes=</span><span class="s">"50vw"</span>
            <span class="na">srcset=</span><span class="s">"/globalassets/batman.jpg?quality=10&amp;w=480 480w,
                    /globalassets/batman.jpg?quality=10&amp;w=768 768w,
                    /globalassets/batman.jpg?quality=10&amp;w=992 992w,
                    /globalassets/batman.jpg?quality=10&amp;w=1200 1200w"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;img</span> <span class="na">alt=</span><span class="s">""</span> <span class="na">src=</span><span class="s">"/globalassets/batman.jpg?quality=10&amp;w=992"</span><span class="nt">&gt;</span>
<span class="nt">&lt;/picture&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="multiple-picture-sources">Multiple Picture Sources</h3>

<p>Now imagine that for some silly reasons you need to supply multiple picture sources for various viewport widths or under any other conditions. Might sound silly, but I’ve seen websites like this.</p>

<p>Roger! This is also supported by the package. Now this can be implemented like this.</p>

<p>First, we need to define multiple properties to use in various media condition cases (in this case I’m just following <a href="https://getbootstrap.com/docs/4.0/layout/grid/?ref=tech-fellow.eu">Bootstrap grid system</a> setup):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">StartPage</span> <span class="p">:</span> <span class="n">SitePageData</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">UIHint</span><span class="p">(</span><span class="n">UIHint</span><span class="p">.</span><span class="n">Image</span><span class="p">)]</span>
    <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Description</span> <span class="p">=</span> <span class="s">"XS (&lt; 576)"</span><span class="p">,</span> <span class="n">Order</span> <span class="p">=</span> <span class="m">200</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">virtual</span> <span class="n">ContentReference</span> <span class="n">XSImage</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

    <span class="p">[</span><span class="nf">UIHint</span><span class="p">(</span><span class="n">UIHint</span><span class="p">.</span><span class="n">Image</span><span class="p">)]</span>
    <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Description</span> <span class="p">=</span> <span class="s">"Small (&gt;= 576)"</span><span class="p">,</span> <span class="n">Order</span> <span class="p">=</span> <span class="m">201</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">virtual</span> <span class="n">ContentReference</span> <span class="n">SMImage</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

    <span class="p">[</span><span class="nf">UIHint</span><span class="p">(</span><span class="n">UIHint</span><span class="p">.</span><span class="n">Image</span><span class="p">)]</span>
    <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Description</span> <span class="p">=</span> <span class="s">"Medium (&gt;= 768)"</span><span class="p">,</span> <span class="n">Order</span> <span class="p">=</span> <span class="m">202</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">virtual</span> <span class="n">ContentReference</span> <span class="n">MDImage</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

    <span class="p">[</span><span class="nf">UIHint</span><span class="p">(</span><span class="n">UIHint</span><span class="p">.</span><span class="n">Image</span><span class="p">)]</span>
    <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Description</span> <span class="p">=</span> <span class="s">"Medium (&gt;= 992)"</span><span class="p">,</span> <span class="n">Order</span> <span class="p">=</span> <span class="m">203</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">virtual</span> <span class="n">ContentReference</span> <span class="n">LGImage</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

    <span class="p">[</span><span class="nf">UIHint</span><span class="p">(</span><span class="n">UIHint</span><span class="p">.</span><span class="n">Image</span><span class="p">)]</span>
    <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Description</span> <span class="p">=</span> <span class="s">"Extra Large (&gt;= 1200)"</span><span class="p">,</span> <span class="n">Order</span> <span class="p">=</span> <span class="m">204</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">virtual</span> <span class="n">ContentReference</span> <span class="n">XLImage</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Next we would need to define our picture profile:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="n">PictureProfile</span> <span class="n">BootstrapGrid</span> <span class="p">=</span>
    <span class="k">new</span> <span class="n">PictureProfile</span>
    <span class="p">{</span>
        <span class="n">DefaultWidth</span> <span class="p">=</span> <span class="m">576</span><span class="p">,</span>
        <span class="n">SrcMedias</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span>
                    <span class="p">{</span>
                        <span class="s">"(min-width: 1200px)"</span><span class="p">,</span>
                        <span class="s">"(min-width: 992px)"</span><span class="p">,</span>
                        <span class="s">"(min-width: 768px)"</span><span class="p">,</span>
                        <span class="s">"(min-width: 576px)"</span><span class="p">,</span>
                        <span class="s">"(max-width: 575.98px)"</span>
                    <span class="p">},</span>
        <span class="n">SrcSetWidths</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span>
                       <span class="p">{</span>
                           <span class="m">1200</span><span class="p">,</span>
                           <span class="m">1200</span><span class="p">,</span>
                           <span class="m">992</span><span class="p">,</span>
                           <span class="m">768</span><span class="p">,</span>
                           <span class="m">576</span>
                       <span class="p">}</span>
    <span class="p">};</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Note, that we have now possibility to define various medias which are specified for every source element.</p>

<p><strong>NB!</strong> Specified media attribute is generated in the sequence as specified here in picture profile. Note that CSS is cascade and first match top down will win.</p>

<p>And now the last piece in the puzzle - markup generation method (here also the order of the images is important to match source media order):</p>

<pre><code class="language-razor">@Html.ResizePictures(new[]
                     {
                         Model.CurrentPage.XLImage,
                         Model.CurrentPage.LGImage,
                         Model.CurrentPage.MDImage,
                         Model.CurrentPage.SMImage,
                         Model.CurrentPage.XSImage
                     }, PictureProfiles.BootstrapGrid)
</code></pre>

<p>Following markup is generated here:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;picture&gt;</span>
    <span class="nt">&lt;source</span> <span class="na">media=</span><span class="s">"(min-width: 1200px)"</span> <span class="na">srcset=</span><span class="s">"/globalassets/xl.jpg?w=1200"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;source</span> <span class="na">media=</span><span class="s">"(min-width: 992px)"</span> <span class="na">srcset=</span><span class="s">"/globalassets/lg.jpg?w=1200"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;source</span> <span class="na">media=</span><span class="s">"(min-width: 768px)"</span> <span class="na">srcset=</span><span class="s">"/globalassets/md.jpg?w=992"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;source</span> <span class="na">media=</span><span class="s">"(min-width: 576px)"</span> <span class="na">srcset=</span><span class="s">"/globalassets/sm.jpg?w=768"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;source</span> <span class="na">media=</span><span class="s">"(max-width: 575.98px)"</span> <span class="na">srcset=</span><span class="s">"/globalassets/xs.jpg?w=576"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;img</span> <span class="na">alt=</span><span class="s">""</span> <span class="na">src=</span><span class="s">"/globalassets/xl.jpg?w=576"</span><span class="nt">&gt;</span>
<span class="nt">&lt;/picture&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Also arbitrary image urls are supported (in cases when you need to fine tuning each image):</p>

<pre><code class="language-razor">@Html.ResizePictures(new[]
                     {
                         Html.ResizeImage(Model.CurrentPage.XLImage).Quality(10),
                         Html.ResizeImage(Model.CurrentPage.LGImage).Quality(20),
                         Html.ResizeImage(Model.CurrentPage.MDImage).Quality(30),
                         Html.ResizeImage(Model.CurrentPage.SMImage).Quality(40),
                         Html.ResizeImage(Model.CurrentPage.XSImage).Quality(50)
                     }, PictureProfiles.BootstrapGrid)
</code></pre>

<h3 id="fallback-in-case-of-devnull">Fallback in Case of /dev/null/</h3>

<p>It’s not good if you generate empty <code class="language-plaintext highlighter-rouge">&lt;img&gt;</code> tags. I know it’s been patched to avoid sub-sequential web requests in most of the browsers, but still.. Why should I render empty images for my site if I could fallback to some nice looking “no image” placeholder?</p>

<p>This is also supported:</p>

<pre><code class="language-razor">@Html.ResizePictureWithFallback(Model.CurrentPage.EmptyImage,
                                PictureProfiles.SampleImage,
                                "/noimage.png")
</code></pre>

<h2 id="see-it-in-action">See it in Action!</h2>

<p>Code is nice, but think it’s much better to understand new possibilities when you see it in action!</p>

<iframe width="846" height="580" src="https://www.youtube.com/embed/PTOYiL1AABk" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen=""></iframe>

<p>Happy responsiveness!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="Image Resizer" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><category term="image resizer" /><summary type="html"><![CDATA[Latest ImageResizer library version now can also generate &lt;picture&gt; element. Thanks to lately movement by Erik and Vincent.]]></summary></entry><entry><title type="html">Localization Provider - 5th generation out!</title><link href="https://tech-fellow.eu/2018/10/18/localization-provider-5th-generation/" rel="alternate" type="text/html" title="Localization Provider - 5th generation out!" /><published>2018-10-18T01:30:00+03:00</published><updated>2018-10-18T01:30:00+03:00</updated><id>https://tech-fellow.eu/2018/10/18/localization-provider-5th-generation</id><content type="html" xml:base="https://tech-fellow.eu/2018/10/18/localization-provider-5th-generation/"><![CDATA[<p>Freshly baked v5.0 is out now. Changes in this version (some of them are breaking ones). Mostly release was focused on .Net Core AdminUI improvements and new features. As I’m preparing for something bigger for the library, so I need to do some prerequisites :)</p>

<p>General:</p>

<ul>
  <li>strong naming of all provider assemblies. You might be wondering why? <a href="https://docs.microsoft.com/en-us/dotnet/standard/library-guidance/?ref=tech-fellow.eu">because reasons</a>.</li>
  <li>Added <a href="https://github.com/dotnet/sourcelink/blob/master/README.md?ref=tech-fellow.eu">SourceLink</a> support for main library (<a href="https://www.nuget.org/packages/LocalizationProvider.Abstractions/?ref=tech-fellow.eu">“LocalizationProvider.Abstractions”</a> and “<a href="https://www.nuget.org/packages/LocalizationProvider/?ref=tech-fellow.eu">LocalizationProvider</a>”) and .Net Core (“<a href="https://www.nuget.org/packages/LocalizationProvider.AspNetCore/?ref=tech-fellow.eu">LocalizationProvider.AspNetCore</a>”). If SourceLink support will be requested for Framework libraries (Episerver and Asp.Net Mvc) - I can work on that as well.</li>
  <li>various bug fixes in main package mostly related to language proper fallback in cases of missing translation for requested language</li>
</ul>

<p>Episerver:</p>

<ul>
  <li>Add new resource manually is now back in Episerver AdminUI. Special thanks goes to <a href="https://twitter.com/ev2000?ref=tech-fellow.eu">@ev2000</a> for motivation :)</li>
</ul>

<p><img src="/assets/img/2018/10/2018-10-16_17-33-25.jpg" alt="" /></p>

<p>Asp.Net Core:</p>

<ul>
  <li>Target to .Net Core App 2.1</li>
  <li>User interface is rewritten to <a href="https://docs.microsoft.com/en-us/aspnet/core/razor-pages/ui-class?view=aspnetcore-2.1&amp;tabs=visual-studio&amp;ref=tech-fellow.eu">Razor Class Library</a></li>
  <li>You can now export resources from UI (import with diff merge is coming, that’s a bit bigger chunk of work)</li>
  <li>You can now also customize look and feel of the admin UI via custom external CSS file (UiConfigurationContext.CustomCssPath setting)</li>
  <li><code class="language-plaintext highlighter-rouge">Localized AdminUI</code> itself and added all those resources <a href="https://github.com/valdisiljuconoks/LocalizationProvider/blob/master/docs/hidden-resources.md?ref=tech-fellow.eu">as hidden</a> (so there will be less noise by default in the resource list)</li>
  <li>Proper support for role based authorization. Be sure to <a href="https://github.com/aspnet/Identity/issues/1813?ref=tech-fellow.eu">enable roles</a> in .Net Core 2.1 properly</li>
</ul>

<p>Good luck and Happy localizing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Localization Provider" /><category term="Episerver" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization" /><category term="Episerver" /><summary type="html"><![CDATA[Freshly baked v5.0 is out now. Changes in this version (some of them are breaking ones). Mostly release was focused on .Net Core AdminUI improvements and new features. As I’m preparing for something bigger for the library, so I need to do some prerequisites :)]]></summary></entry><entry><title type="html">Double Language Fallback Behavior in Episerver</title><link href="https://tech-fellow.eu/2018/09/29/double-language-fallback-behavior-in-episerver/" rel="alternate" type="text/html" title="Double Language Fallback Behavior in Episerver" /><published>2018-09-29T18:15:00+03:00</published><updated>2018-09-29T18:15:00+03:00</updated><id>https://tech-fellow.eu/2018/09/29/double-language-fallback-behavior-in-episerver</id><content type="html" xml:base="https://tech-fellow.eu/2018/09/29/double-language-fallback-behavior-in-episerver/"><![CDATA[<p>And here we are again to talk a little bit about localization stuff. Most probably you know already there are pretty neat settings when it comes to localization of the Episerver and how one should behave when resource translation is missing for requested language (or culture to be precise). You can define fallback behavior, fallback culture and maybe in the future even something else.</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre>...
  <span class="nt">&lt;localization</span> <span class="na">fallbackBehavior=</span><span class="s">"FallbackCulture"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;providers&gt;</span>
      <span class="nt">&lt;add</span> <span class="na">name=</span><span class="s">"db"</span> <span class="na">type=</span><span class="s">"DbLocalizationProvider.EPiServer.DatabaseLocaliza
      &lt;add name="</span><span class="err">languageFiles"</span> <span class="na">virtualPath=</span><span class="s">"~/Resources/LanguageFiles"</span> <span class="err">type</span>
    <span class="err">&lt;/providers</span><span class="nt">&gt;</span>
  <span class="nt">&lt;/localization&gt;</span>
<span class="nt">&lt;/episerver.framework&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>At the same time, <code class="language-plaintext highlighter-rouge">DbLocalizationProvider</code> library also allows you to configure some defaults and fallback logic. Working only with invariant culture (you can set it up to do so) could come handy when you don’t want to mess around with database and reduce resource table content. In cases when you assume that translations provider in code are invariant culture (even if texts are in English for example), you don’t want to duplicate the same values and register also the same texts in English culture. Therefore, you can configure library to work with invariant culture as default culture and also perform fallback on invariant culture, when someone is looking for non-existing or not yet translated language.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">InitLocalization</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">ConfigurationContext</span><span class="p">.</span><span class="nf">Setup</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="n">_</span><span class="p">.</span><span class="n">EnableInvariantCultureFallback</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
            <span class="n">_</span><span class="p">.</span><span class="n">DefaultResourceCulture</span> <span class="p">=</span> <span class="n">CultureInfo</span><span class="p">.</span><span class="n">InvariantCulture</span><span class="p">;</span>
            <span class="p">...</span>
        <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If we check how Episerver is treating <code class="language-plaintext highlighter-rouge">&lt;localization&gt;</code> configuration element, we can see that actually there is no invariant culture feedback (and it makes sense when you think about fallback behavior in content delivery context - what is invariant culture for the content? .. an empty page, English content or maybe master language content?!)</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ConfigurationProperty</span><span class="p">(</span><span class="s">"fallbackCulture"</span><span class="p">,</span> <span class="n">DefaultValue</span> <span class="p">=</span> <span class="s">"en"</span><span class="p">,</span> <span class="n">IsRequired</span> <span class="p">=</span> <span class="k">false</span><span class="p">)]</span>
<span class="k">public</span> <span class="n">CultureInfo</span> <span class="n">FallbackCulture</span> <span class="p">{</span> <span class="k">get</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span> <span class="k">set</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We can see that even Episerver is defaulting back to <code class="language-plaintext highlighter-rouge">en</code> language when one is not explicitly set.</p>

<p>So where is the problem?</p>

<h2 id="experiment-with-invariantculture-fallback">Experiment with InvariantCulture Fallback</h2>

<p>Anyway, we can set fallback culture to empty string, and this indeed results in fallback culture being set to <code class="language-plaintext highlighter-rouge">CultureInfo.InvariantCulture</code>. I would expect things to be working just fine..</p>

<p><img src="/assets/img/2018/09/2018-09-28_14-07-18.jpg" alt="" /></p>

<p>Episerver’s <code class="language-plaintext highlighter-rouge">LocalizationService</code> checks for the <em>real</em> fallback culture in <code class="language-plaintext highlighter-rouge">GetActualFallbackCulture</code> method. Regardless whether you ask for first level culture translations (like <code class="language-plaintext highlighter-rouge">lv</code>) or second level culture with region (like <code class="language-plaintext highlighter-rouge">lv-LV</code>), invariant culture will be “calculated” as fallback culture (because <code class="language-plaintext highlighter-rouge">this.FallbackCulture</code>  points to invariant):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="n">CultureInfo</span> <span class="nf">GetActualFallbackCulture</span><span class="p">(</span>
        <span class="n">FallbackBehaviors</span> <span class="n">fallbackBehavior</span><span class="p">,</span>
        <span class="n">CultureInfo</span> <span class="n">requestedCulture</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">if</span><span class="p">(</span><span class="n">fallbackBehavior</span><span class="p">.</span><span class="nf">HasFlag</span><span class="p">(</span><span class="n">FallbackBehaviors</span><span class="p">.</span><span class="n">FallbackCulture</span><span class="p">)</span>
       <span class="p">&amp;&amp;</span> <span class="n">requestedCulture</span> <span class="p">!=</span> <span class="k">this</span><span class="p">.</span><span class="n">FallbackCulture</span>
       <span class="p">&amp;&amp;</span> <span class="n">requestedCulture</span><span class="p">.</span><span class="n">Parent</span> <span class="p">!=</span> <span class="k">this</span><span class="p">.</span><span class="n">FallbackCulture</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="n">FallbackCulture</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="n">CultureInfo</span><span class="p">.</span><span class="n">InvariantCulture</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>After Episerver’s localization service has detected actual fallback culture for this resource translation lookup, translation retrieval is being performed in <code class="language-plaintext highlighter-rouge">LocalizationService.TryGetStringByCulture</code> method.</p>

<p>Essentially this method “climbs” up the culture “inheritance” path (well, that’s not entirely inheritance, but child/parent relationships) and tries to figure out in which culture this translation exists. So if I’m asking for <code class="language-plaintext highlighter-rouge">lv-LV</code> culture resource and there is none, Episerver’s localization service will look for <code class="language-plaintext highlighter-rouge">lv</code> culture as well, because it’s parent of <code class="language-plaintext highlighter-rouge">lv-LV</code>. Having a following code fragment:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="rouge-code"><pre><span class="p">...</span>
<span class="kt">bool</span> <span class="n">flag</span> <span class="p">=</span> <span class="k">false</span><span class="p">;</span>
<span class="k">for</span> <span class="p">(;</span> <span class="p">!</span><span class="n">CultureInfo</span><span class="p">.</span><span class="n">InvariantCulture</span><span class="p">.</span><span class="nf">Equals</span><span class="p">(</span><span class="n">culture</span><span class="p">);</span> <span class="n">culture</span> <span class="p">=</span> <span class="n">culture</span><span class="p">.</span><span class="n">Parent</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// calls underlying provider for actual string in requested language</span>
    <span class="p">...</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">localizedString</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
        <span class="k">return</span> <span class="k">true</span><span class="p">;</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">culture</span><span class="p">.</span><span class="nf">Equals</span><span class="p">(</span><span class="n">fallbackCulture</span><span class="p">))</span>
        <span class="n">flag</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">if</span> <span class="p">(!</span><span class="n">flag</span> <span class="p">&amp;&amp;</span> <span class="p">!</span><span class="n">CultureInfo</span><span class="p">.</span><span class="n">InvariantCulture</span><span class="p">.</span><span class="nf">Equals</span><span class="p">(</span><span class="n">fallbackCulture</span><span class="p">))</span>
<span class="p">{</span>
    <span class="c1">// final stage - load translation in configured fallback language</span>
<span class="p">}</span>

<span class="p">...</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As you can see, Episerver will not try to fallback to <code class="language-plaintext highlighter-rouge">CultureInfo.InvariantCulture</code> even if configured so in <code class="language-plaintext highlighter-rouge">&lt;localization&gt;</code> element.</p>

<p>What’s even worse, is that if we go back to <code class="language-plaintext highlighter-rouge">GetStringByCulture</code> method which is handling the whole retrieval process, there we can see code what happens when resource translation is not being found in requested or fallback culture (in our case - fallback culture is invariant and will not be even taken into account):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">virtual</span> <span class="kt">string</span> <span class="nf">GetStringByCulture</span><span class="p">(</span><span class="kt">string</span> <span class="n">resourceKey</span><span class="p">,</span> <span class="n">FallbackBehaviors</span> <span class="n">fallbackBehavior</span><span class="p">,</span> <span class="kt">string</span> <span class="n">fallback</span><span class="p">,</span> <span class="n">CultureInfo</span> <span class="n">culture</span><span class="p">)</span>
<span class="p">{</span>
   <span class="kt">var</span> <span class="n">actualFallbackCulture</span> <span class="p">=</span> <span class="nf">GetActualFallbackCulture</span><span class="p">(</span><span class="n">fallbackBehavior</span><span class="p">,</span>
                                                        <span class="n">culture</span><span class="p">);</span>
   <span class="k">if</span> <span class="p">(</span><span class="nf">TryGetStringByCulture</span><span class="p">(</span><span class="n">resourceKey</span><span class="p">,</span>
                             <span class="n">culture</span><span class="p">,</span>
                             <span class="n">actualFallbackCulture</span><span class="p">,</span>
                             <span class="k">out</span> <span class="kt">var</span> <span class="n">localizedString</span><span class="p">))</span>
       <span class="k">return</span> <span class="n">localizedString</span><span class="p">;</span>

   <span class="k">return</span> <span class="nf">GetMissingFallbackResourceValue</span><span class="p">(</span><span class="n">fallbackBehavior</span><span class="p">,</span>
                                          <span class="n">fallback</span><span class="p">,</span>
                                          <span class="n">resourceKey</span><span class="p">,</span>
                                          <span class="n">culture</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Code basically tells you, if neither requested (or any of its parent) nor fallback culture have translation for resource you are looking, I’m going to return you “a missing fallback resource value”:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="kt">string</span> <span class="nf">GetMissingFallbackResourceValue</span><span class="p">(</span><span class="n">FallbackBehaviors</span> <span class="n">fallbackBehavior</span><span class="p">,</span>
                                               <span class="kt">string</span> <span class="n">fallback</span><span class="p">,</span>
                                               <span class="kt">string</span> <span class="n">resourceKey</span><span class="p">,</span>
                                               <span class="n">CultureInfo</span> <span class="n">culture</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">fallback</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">fallback</span><span class="p">;</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">fallbackBehavior</span><span class="p">.</span><span class="nf">HasFlag</span><span class="p">(</span><span class="n">FallbackBehaviors</span><span class="p">.</span><span class="n">Echo</span><span class="p">))</span>
        <span class="k">return</span> <span class="n">resourceKey</span><span class="p">;</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">fallbackBehavior</span><span class="p">.</span><span class="nf">HasFlag</span><span class="p">(</span><span class="n">FallbackBehaviors</span><span class="p">.</span><span class="n">MissingMessage</span><span class="p">))</span>
        <span class="k">return</span> <span class="n">LocalizationService</span><span class="p">.</span><span class="nf">GetMissingMessage</span><span class="p">(</span><span class="n">resourceKey</span><span class="p">,</span> <span class="n">culture</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">fallbackBehavior</span><span class="p">.</span><span class="nf">HasFlag</span><span class="p">(</span><span class="n">FallbackBehaviors</span><span class="p">.</span><span class="n">Null</span><span class="p">))</span>
        <span class="k">return</span> <span class="k">null</span><span class="p">;</span>

    <span class="k">return</span> <span class="kt">string</span><span class="p">.</span><span class="n">Empty</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This code means if there is no specific Episerver localization configuration to return <code class="language-plaintext highlighter-rouge">null</code> values for the missed fallback (<code class="language-plaintext highlighter-rouge">FallbackBehaviors.Null</code>) - then empty string is returned. This makes perfect sense if you think about it - framework does not want you to have zillions of null reference exceptions all over the place where you didn’t expect it.</p>

<p>For the DbLocalizationProvider package - there has to be somehow a way to detect that resource translation is not being found, and built-in fallback also failed - so invariant translation should be fetched if configured so.</p>

<p>Everything would be great in cases when Episerver localization is configured to return <code class="language-plaintext highlighter-rouge">null</code> in case of no translation. Also built-in <code class="language-plaintext highlighter-rouge">ProviderBasedLocalizationService</code> does checking on return value for each provider it’s calling, and if return value is <code class="language-plaintext highlighter-rouge">null</code> it assumes that resource translation has not been found and continues to the next provider in the list. So the <code class="language-plaintext highlighter-rouge">string.Empty</code> is last return from the Episerver perspective.</p>

<p>But as a library author, I cannot rely on fact that site should be configured first to get fallback working. I would like to have a feature which would work in default configuration as well. There has to be way around this.</p>

<h2 id="dblocalizationprovider-double-fallback-feature">DbLocalizationProvider Double Fallback Feature</h2>

<p>Originally fallback to invariant culture was introduced in pure Asp.Net Mvc app context. But being a member of the platform, you have to behave well and need to respect surrounding behaviors and assumptions. So with some gentle pushes from colleagues think I need to support this fallback to invariant culture also when DbLocalizationProvider library is used in Episerver sites.</p>

<h3 id="cqs-and-friends">CQS and Friends</h3>

<p>W$%&amp;.tfh heck CQS has common with Episerver and localization, you may ask? I still have pending blog post about how localization provider library is built internally and how the same piece of code is reused (with slight differences sometimes) between Episerver, Asp.Net Mvc and Asp.Net Core applications.. But that’s a different story.</p>

<p>In this context, keeping long story short, basically there are 2 entries for the DbLocalizationProvider when someone is trying to get string in correct culture. By default, if one is using Episerver built-in localization service, call will end up at <code class="language-plaintext highlighter-rouge">DbLocalizationProvider.EPiServer.DatabaseLocalizationProvider</code> type, which plugged in common list of localization translation providers via <code class="language-plaintext highlighter-rouge">&lt;localization&gt;</code> element in configuration file.</p>

<p>This <code class="language-plaintext highlighter-rouge">DatabaseLocalizationProvider</code> will invoke then something called <code class="language-plaintext highlighter-rouge">GetTranslationQuery</code> which is basically player from CQS architecture - where commands, queries (sometimes also events) and relevant handlers are mix-matched all together.</p>

<p>On the another hand, there are a lot of various helpers and other extension methods that are not Episerver specific (for example, <code class="language-plaintext highlighter-rouge">typeof(Enum).Translate(..)</code>). These helper methods are located in shared part of the library - thus could be called within Episerver application context as well. Therefore, we do have <code class="language-plaintext highlighter-rouge">LocalizationProvider</code> type. Responsibility for this type is to resolve and return resource translations for various situations.</p>

<p>In order to play well together with Episerver and respect framework’s settings regarding culture fallback, <code class="language-plaintext highlighter-rouge">LocalizationProvider</code> from shared library part is not calling directly underlying services, but instead - executes <code class="language-plaintext highlighter-rouge">GetTranslationQuery</code>. Who is going to handle this query and return translation - now depends on how DbLocalizationProvider library is setup. In Episerver context there is dedicated setup &amp; init module that does this for you and appropriate Episerver specific translation retrieval handler is registered (instead of built-in one for example).</p>

<p>I know, it’s hard to explain in words, that’s why I’m saving this topic for dedicated blog post. Think it’s worth sharing.</p>

<h3 id="episervers-localizationprovider-fix-supporting-double-fallback">Episerver’s LocalizationProvider Fix Supporting Double Fallback</h3>

<p>When resource translation is asked via Episerver built-in localization service, one of the providers in the list is also <code class="language-plaintext highlighter-rouge">DatabaseLocalizationProvider</code>. This type then could be responsible for double fallback checking and supporting also scenarios with invariant cultures.</p>

<p>And as it turned out, it’s not actually that hard to implement and support double fallback.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">override</span> <span class="kt">string</span> <span class="nf">GetString</span><span class="p">(</span><span class="kt">string</span> <span class="n">originalKey</span><span class="p">,</span>
                                 <span class="kt">string</span><span class="p">[]</span> <span class="n">normalizedKey</span><span class="p">,</span>
                                 <span class="n">CultureInfo</span> <span class="n">culture</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">foundTranslation</span> <span class="p">=</span> <span class="n">_originalHandler</span><span class="p">.</span><span class="nf">Execute</span><span class="p">(</span><span class="k">new</span> <span class="n">GetTranslation</span><span class="p">.</span><span class="nf">Query</span><span class="p">(</span><span class="n">originalKey</span><span class="p">,</span>
                     <span class="n">culture</span><span class="p">,</span>
                     <span class="k">false</span><span class="p">));</span>

    <span class="k">if</span><span class="p">(</span><span class="n">foundTranslation</span> <span class="p">==</span> <span class="k">null</span>
       <span class="p">&amp;&amp;</span> <span class="n">LocalizationService</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">FallbackBehavior</span><span class="p">.</span><span class="nf">HasFlag</span><span class="p">(</span><span class="n">FallbackBehaviors</span><span class="p">.</span><span class="n">FallbackCulture</span><span class="p">)</span>
       <span class="p">&amp;&amp;</span> <span class="n">ConfigurationContext</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">EnableInvariantCultureFallback</span>
       <span class="p">&amp;&amp;</span> <span class="p">(</span><span class="nf">Equals</span><span class="p">(</span><span class="n">culture</span><span class="p">,</span> <span class="n">LocalizationService</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">FallbackCulture</span><span class="p">)</span> <span class="p">||</span> <span class="nf">Equals</span><span class="p">(</span><span class="n">culture</span><span class="p">.</span><span class="n">Parent</span><span class="p">,</span> <span class="n">CultureInfo</span><span class="p">.</span><span class="n">InvariantCulture</span><span class="p">)))</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">_originalHandler</span><span class="p">.</span><span class="nf">Execute</span><span class="p">(</span><span class="k">new</span> <span class="n">GetTranslation</span><span class="p">.</span><span class="nf">Query</span><span class="p">(</span><span class="n">originalKey</span><span class="p">,</span> <span class="n">CultureInfo</span><span class="p">.</span><span class="n">InvariantCulture</span><span class="p">,</span> <span class="k">false</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="n">foundTranslation</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And now tell me slowly, ok?! :)</p>

<p>So what happens here:</p>

<ul>
  <li>first, database localization provider tries to resolve translation in the culture that has been asked</li>
  <li>if that fails (<code class="language-plaintext highlighter-rouge">foundTranslation == null</code>) and configured fallback behavior has configuration to fallback to different culture, and it’s also configured in DbLocalizationProvider package, and requested culture is either fallback culture itself or parent of the requested culture is invariant culture - then library will explicitly look for invariant culture translation</li>
  <li>otherwise - result is returned as-is, meaning that library does not care either translation has been found or not.</li>
</ul>

<h3 id="built-in-localizationprovider-fix">Built-in LocalizationProvider Fix</h3>

<p>At the same time unfortunately library’s built-in localization provider should be fixed as well, because there are definitely cases when built-in is called directly skipping Episerver’s one - so that part has to be fixed as well.</p>

<p>When resource is retrieved via built-in provider, eventually <code class="language-plaintext highlighter-rouge">EPiServerGetTranslationHandler</code> is executed. So sounds like this is perfect place for the fix.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">Handler</span> <span class="p">:</span> <span class="n">IQueryHandler</span><span class="p">&lt;</span><span class="n">GetTranslation</span><span class="p">.</span><span class="n">Query</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">LocalizationService</span> <span class="n">_service</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">Handler</span><span class="p">(</span><span class="n">LocalizationService</span> <span class="n">service</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_service</span> <span class="p">=</span> <span class="n">service</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="kt">string</span> <span class="nf">Execute</span><span class="p">(</span><span class="n">GetTranslation</span><span class="p">.</span><span class="n">Query</span> <span class="n">query</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">foundTranslation</span> <span class="p">=</span> <span class="n">_service</span><span class="p">.</span><span class="nf">GetStringByCulture</span><span class="p">(</span><span class="n">query</span><span class="p">.</span><span class="n">Key</span><span class="p">,</span> <span class="n">query</span><span class="p">.</span><span class="n">Language</span><span class="p">);</span>

        <span class="k">if</span><span class="p">(</span><span class="kt">string</span><span class="p">.</span><span class="nf">IsNullOrEmpty</span><span class="p">(</span><span class="n">foundTranslation</span><span class="p">)</span>
           <span class="p">&amp;&amp;</span> <span class="n">service</span><span class="p">.</span><span class="n">FallbackBehavior</span><span class="p">.</span><span class="nf">HasFlag</span><span class="p">(</span><span class="n">FallbackBehaviors</span><span class="p">.</span><span class="n">FallbackCulture</span><span class="p">)</span>
           <span class="p">&amp;&amp;</span> <span class="n">query</span><span class="p">.</span><span class="n">UseFallback</span>
           <span class="p">&amp;&amp;</span> <span class="p">(</span><span class="nf">Equals</span><span class="p">(</span><span class="n">query</span><span class="p">.</span><span class="n">Language</span><span class="p">,</span> <span class="n">service</span><span class="p">.</span><span class="n">FallbackCulture</span><span class="p">))</span> <span class="p">||</span> <span class="nf">Equals</span><span class="p">(</span><span class="n">query</span><span class="p">.</span><span class="n">Language</span><span class="p">.</span><span class="n">Parent</span><span class="p">,</span> <span class="n">CultureInfo</span><span class="p">.</span><span class="n">InvariantCulture</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="k">return</span> <span class="n">_originalHandler</span><span class="p">.</span><span class="nf">Execute</span><span class="p">(</span>
                <span class="k">new</span> <span class="n">GetTranslation</span><span class="p">.</span><span class="nf">Query</span><span class="p">(</span><span class="n">query</span><span class="p">.</span><span class="n">Key</span><span class="p">,</span>
                                         <span class="n">CultureInfo</span><span class="p">.</span><span class="n">InvariantCulture</span><span class="p">,</span>
                                         <span class="k">false</span><span class="p">));</span>
        <span class="p">}</span>

        <span class="k">return</span> <span class="n">foundTranslation</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Here, the logic is quite similar to one found in Episerver’s provider fix code fragment, so think maybe it’s just worth to reuse it somehow.</p>

<p>But, built-in provider cannot just look for <code class="language-plaintext highlighter-rouge">foundTranslation == null</code> case. As we know now - Episerver <em>might</em> return back <code class="language-plaintext highlighter-rouge">string.Empty</code> even if fallback failed (in Episerver context). So here query handler unfortunately must check for <code class="language-plaintext highlighter-rouge">string.IsNullOrEmpty</code> value.</p>

<h2 id="translate-to-invariantculture-explicitly">Translate to InvariantCulture Explicitly</h2>

<p>There is a tiny nuance when you call something line this on built-in Episerver service:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="n">LocalizationService</span><span class="p">.</span><span class="nf">GetStringByCulture</span><span class="p">(</span><span class="s">"..."</span><span class="p">,</span> <span class="n">CultureInfo</span><span class="p">.</span><span class="n">InvariantCulture</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>and the same on DbLocalizationProvider library’s one:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="n">LocalizationProvider</span><span class="p">.</span><span class="nf">GetStringByCulture</span><span class="p">(</span><span class="s">"..."</span><span class="p">,</span> <span class="n">CultureInfo</span><span class="p">.</span><span class="n">InvariantCulture</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Latter will have correct value as it’s explicitly will be able to resolve invariant culture translation when asked. However, it’s not entirely true for the Episerver - knowing behavior and logic inside <code class="language-plaintext highlighter-rouge">TryGetStringByCulture</code> method - invariant culture won’t even have it’s chance to act like culture to resolve translations for.</p>

<p>So just beware that there is a difference between DbLocalizationProvider localization provider and Episerver’s localization service when working directly with invariant cultures.</p>

<p>And don’t worry about all this stuff, it’s already implemented in the library and everything should fallback as it’s designed and configured.</p>

<p>Happy double fallbacking ;)</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Localization Provider" /><category term="Episerver" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization" /><category term="Episerver" /><summary type="html"><![CDATA[And here we are again to talk a little bit about localization stuff. Most probably you know already there are pretty neat settings when it comes to localization of the Episerver and how one should behave when resource translation is missing for requested language (or culture to be precise). You can define fallback behavior, fallback culture and maybe in the future even something else.]]></summary></entry><entry><title type="html">Fixing ClientModel Validation in Asp.Net Core</title><link href="https://tech-fellow.eu/2018/09/02/clientmodel-validation-in-net-core/" rel="alternate" type="text/html" title="Fixing ClientModel Validation in Asp.Net Core" /><published>2018-09-02T01:15:00+03:00</published><updated>2018-09-02T01:15:00+03:00</updated><id>https://tech-fellow.eu/2018/09/02/clientmodel-validation-in-net-core</id><content type="html" xml:base="https://tech-fellow.eu/2018/09/02/clientmodel-validation-in-net-core/"><![CDATA[<p>Story begins with small issue registered in GitHub telling that LocalizationProvider does its job excellent when model is submitted to the server and validated there. Resources are found and used then. But localization provider is not so great when <code class="language-plaintext highlighter-rouge">data-</code> attributes are generated. Issue described that text from <code class="language-plaintext highlighter-rouge">[Required(ErrorMessage = "...")]</code> or any other validation attribute was rendered in resulting markup and localization provider was not even involved.</p>

<p>So this view model:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">UserViewModel</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"User name:"</span><span class="p">)]</span>
    <span class="p">[</span><span class="nf">Required</span><span class="p">(</span><span class="n">ErrorMessage</span> <span class="p">=</span> <span class="s">"Name of the user is required!"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">UserName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Would generate:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;form</span> <span class="na">action=</span><span class="s">"/"</span> <span class="na">method=</span><span class="s">"post"</span> <span class="na">novalidate=</span><span class="s">"novalidate"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;div&gt;</span>
        <span class="nt">&lt;label</span> <span class="na">for=</span><span class="s">"UserName"</span><span class="nt">&gt;</span>User name:<span class="nt">&lt;/label&gt;</span>
        <span class="nt">&lt;input</span> <span class="na">name=</span><span class="s">"UserName"</span> <span class="na">id=</span><span class="s">"UserName"</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">value=</span><span class="s">""</span> <span class="na">data-val-required=</span><span class="s">"Name of the user is required!"</span> <span class="na">data-val=</span><span class="s">"true"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"field-validation-valid"</span> <span class="na">data-valmsg-replace=</span><span class="s">"true"</span> <span class="na">data-valmsg-for=</span><span class="s">"UserName"</span><span class="nt">&gt;&lt;/span&gt;</span>
    <span class="nt">&lt;/div&gt;</span>
    ...
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Which looks OK from first sight, but when you change associated resource for required attribute in <a href="https://github.com/valdisiljuconoks/localization-provider-core/blob/master/docs/getting-started-adminui.md?ref=tech-fellow.eu">AdminUI</a>, changed text for that resources is not reflected back to generated markup.</p>

<p>That surprised me and I needed to look inside what’s going on when Asp.Net Core Mvc is generating markup and trying to figure out what and how to generate client model validation messages.</p>

<h2 id="how-built-in-provider-is-working">How Built-in Provider is Working</h2>

<p>So, when you would like to use default built-in provider to localize models via data annotations attributes (required, string length, etc.) this is done by configuring data annotation localization options (<code class="language-plaintext highlighter-rouge">Startup.cs</code>):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">services</span><span class="p">.</span><span class="nf">AddMvc</span><span class="p">()</span>
            <span class="p">.</span><span class="nf">AddViewLocalization</span><span class="p">()</span>
            <span class="p">.</span><span class="nf">AddDataAnnotationsLocalization</span><span class="p">();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Somewhere along the lines will be registration for <code class="language-plaintext highlighter-rouge">MvcDataAnnotationsLocalizationOptions</code> type. This type is responsible for holding the reference to a factory method for creating new string localizers (<code class="language-plaintext highlighter-rouge">IStringLocalizer</code>):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">MvcDataAnnotationsLocalizationOptions</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="n">Func</span><span class="p">&lt;</span><span class="n">Type</span><span class="p">,</span> <span class="n">IStringLocalizerFactory</span><span class="p">,</span> <span class="n">IStringLocalizer</span><span class="p">&gt;</span> <span class="n">DataAnnotationLocalizerProvider</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Simply the following lambda is being registered for this purpose:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="p">(</span><span class="n">modelType</span><span class="p">,</span> <span class="n">factory</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="n">factory</span><span class="p">.</span><span class="nf">Create</span><span class="p">(</span><span class="n">modelType</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Which is essentially just a shortcut for <code class="language-plaintext highlighter-rouge">ResourceManagerStringLocalizer</code> creation based on given model type. However <code class="language-plaintext highlighter-rouge">ResourceManagerStringLocalizer</code> is just a wrapper class around <code class="language-plaintext highlighter-rouge">System.Resources.ResourceManager</code> which is responsible to keep track of available embedded <code class="language-plaintext highlighter-rouge">.resx</code> files within the assembly and look for the resource based on resource key. More info can be found <a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization?view=aspnetcore-2.1&amp;ref=tech-fellow.eu">here</a> so I will not go deeper on this topic.</p>

<p>However, this is just how the localization features are registered within Mvc pipeline and where resources are stored.</p>

<p>Client model validation providers are registered as part of <code class="language-plaintext highlighter-rouge">services.AddMvc()</code> call usually found in <code class="language-plaintext highlighter-rouge">Startup.cs</code> and later in <code class="language-plaintext highlighter-rouge">builder.AddViews()</code> to be more precise, further down in <code class="language-plaintext highlighter-rouge">builder.AddViewServices()</code>. This type is finally responsible for registered client model validation providers: <code class="language-plaintext highlighter-rouge">Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.MvcViewOptionsSetup</code>.</p>

<p><img src="/assets/img/2018/08/seq.jpg" alt="" /></p>

<p>List of client model validator providers are stored in <code class="language-plaintext highlighter-rouge">MvcViewOptions.ClientModelValidatorProviders</code> collection.</p>

<p>There are 3 providers registered by default:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">DefaultClientModelValidatorProvider</code> - this is default implementation of the interface and provides validators in model validators metadata</li>
  <li><code class="language-plaintext highlighter-rouge">DataAnnotationsClientModelValidatorProvider</code> - data annotation attributes driven validation provider</li>
  <li><code class="language-plaintext highlighter-rouge">NumericClientModelValidatorProvider</code> - something special about <code class="language-plaintext highlighter-rouge">float</code>, <code class="language-plaintext highlighter-rouge">double</code> and <code class="language-plaintext highlighter-rouge">decimal</code> validators</li>
</ul>

<p>We are interested in the middle one.</p>

<h2 id="whats-wrong-with-built-in">What’s Wrong with Built-in?</h2>

<p>So what’s wrong with built-in provider and why I can’t just use it out of the box?</p>

<p>When provider is asked to create a validator for <a href="https://github.com/aspnet/Mvc/blob/master/src/Microsoft.AspNetCore.Mvc.DataAnnotations/Internal/DataAnnotationsClientModelValidatorProvider.cs?ref=tech-fellow.ghost.io#L52">given validator context</a> (when particular model is being validated or validation attributes being generated on client-side) - validator provider is creating <code class="language-plaintext highlighter-rouge">IStringLocalizer</code> instance based on model type alone:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre>// This will pass first non-null type (either containerType or modelType) to delegate.
// Pass the root model type(container type) if it is non null, else pass the model type.
stringLocalizer = _options.Value.DataAnnotationLocalizerProvider(
                      context.ModelMetadata.ContainerType ?? context.ModelMetadata.ModelType,
                      _stringLocalizerFactory);
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As you can see - there is no metadata available for which actually property is going to be localized. String localizer is created based on just container type (actual class within which property is validated).</p>

<p>Let’s go further - particular adapter is also created based on what kind of data annotation attribute is being validated (<code class="language-plaintext highlighter-rouge">[StringLength]</code>, <code class="language-plaintext highlighter-rouge">[Required]</code>, etc):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>var adapter = _validationAttributeAdapterProvider.GetAttributeAdapter(attribute, stringLocalizer);
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Again - there is just a information of attribute itself (with no metadata information about property itself on which attribute is being placed) and previously generated string localizer - which is created only based on container type (model class).</p>

<p>And all of the actual data annotation attribute adapters who are responsible for actually generating the error message in case of emergency - has no info about property on which validation attribute is set. All those adapters do is just generate error message based on available metadata:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">StringLengthAttributeAdapter</span> <span class="p">:</span> <span class="p">...</span>
<span class="p">{</span>
    <span class="p">...</span>
    <span class="k">public</span> <span class="k">override</span> <span class="kt">string</span> <span class="nf">GetErrorMessage</span><span class="p">(</span><span class="n">ModelValidationContextBase</span> <span class="n">validationContext</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="nf">GetErrorMessage</span><span class="p">(</span>
            <span class="n">validationContext</span><span class="p">.</span><span class="n">ModelMetadata</span><span class="p">,</span>
            <span class="n">validationContext</span><span class="p">.</span><span class="n">ModelMetadata</span><span class="p">.</span><span class="nf">GetDisplayName</span><span class="p">(),</span>
            <span class="n">Attribute</span><span class="p">.</span><span class="n">MaximumLength</span><span class="p">,</span>
            <span class="n">Attribute</span><span class="p">.</span><span class="n">MinimumLength</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>which invokes <code class="language-plaintext highlighter-rouge">GetErrorMessage</code>  method on base class:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="rouge-code"><pre><span class="k">protected</span> <span class="k">virtual</span> <span class="kt">string</span> <span class="nf">GetErrorMessage</span><span class="p">(</span>
    <span class="n">ModelMetadata</span> <span class="n">modelMetadata</span><span class="p">,</span>
    <span class="k">params</span> <span class="kt">object</span><span class="p">[]</span> <span class="n">arguments</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">modelMetadata</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">modelMetadata</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">_stringLocalizer</span> <span class="p">!=</span> <span class="k">null</span> <span class="p">&amp;&amp;</span>
        <span class="p">!</span><span class="kt">string</span><span class="p">.</span><span class="nf">IsNullOrEmpty</span><span class="p">(</span><span class="n">Attribute</span><span class="p">.</span><span class="n">ErrorMessage</span><span class="p">)</span> <span class="p">&amp;&amp;</span>
        <span class="kt">string</span><span class="p">.</span><span class="nf">IsNullOrEmpty</span><span class="p">(</span><span class="n">Attribute</span><span class="p">.</span><span class="n">ErrorMessageResourceName</span><span class="p">)</span> <span class="p">&amp;&amp;</span>
        <span class="n">Attribute</span><span class="p">.</span><span class="n">ErrorMessageResourceType</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">_stringLocalizer</span><span class="p">[</span><span class="n">Attribute</span><span class="p">.</span><span class="n">ErrorMessage</span><span class="p">,</span> <span class="n">arguments</span><span class="p">];</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="n">Attribute</span><span class="p">.</span><span class="nf">FormatErrorMessage</span><span class="p">(</span><span class="n">modelMetadata</span><span class="p">.</span><span class="nf">GetDisplayName</span><span class="p">());</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Thus as we can see, if you do have data annotation validation attribute with error message set:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">UserViewModel</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"User name:"</span><span class="p">)]</span>
    <span class="p">[</span><span class="nf">Required</span><span class="p">(</span><span class="n">ErrorMessage</span> <span class="p">=</span> <span class="s">"Name of the user is required!"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">UserName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>eventually this will end as call to <code class="language-plaintext highlighter-rouge">IStringLocalizer</code> looking for resource key:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">return</span> <span class="n">_stringLocalizer</span><span class="p">[</span><span class="s">"Name of the user is required!"</span><span class="p">,</span> <span class="n">arguments</span><span class="p">];</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Naturally that there is no such a resource with this key.</p>

<p>We have to find another way around to fix this issue.</p>

<h2 id="fixing-built-in-stuff-in-localizationprovider-way">Fixing Built-in Stuff in LocalizationProvider Way</h2>

<p>In order this shortcoming - we need to dig pretty deep in Mvc pipeline and change couple of things before we can fix localization issue mentioned at the beginning of the post. Latest version of <a href="https://www.nuget.org/packages/LocalizationProvider.AspNetCore/4.3.0?ref=tech-fellow.eu">LocalizationProvider for .Net Core</a> fixes this issue, so this post is just a recap of things that needed to be changed.</p>

<p>First things first. The most proper location for the fix would be during localization provider initialization:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">Startup</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">services</span><span class="p">.</span><span class="nf">AddDbLocalizationProvider</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
                                           <span class="p">{</span>
                                               <span class="p">...</span>
                                           <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>During this initialization code we have to add new Mvc View option configurator:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="n">services</span><span class="p">.</span><span class="nf">TryAddEnumerable</span><span class="p">(</span><span class="n">ServiceDescriptor</span><span class="p">.</span><span class="n">Transient</span><span class="p">&lt;</span><span class="n">IConfigureOptions</span><span class="p">&lt;</span><span class="n">MvcViewOptions</span><span class="p">&gt;,</span>
                          <span class="n">ConfigureMvcViews</span><span class="p">&gt;());</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Mvc View configurator is responsible now for “injecting” proper client model validator provider with support with more metadata (context in with validation is performed - capturing property name on which validation attribute is decorated).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">ConfigureMvcViews</span> <span class="p">:</span> <span class="n">IConfigureOptions</span><span class="p">&lt;</span><span class="n">MvcViewOptions</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IValidationAttributeAdapterProvider</span> <span class="n">_validationAttributeAdapterProvider</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">ConfigureMvcViews</span><span class="p">(</span><span class="n">IValidationAttributeAdapterProvider</span> <span class="n">validationAttributeAdapterProvider</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_validationAttributeAdapterProvider</span> <span class="p">=</span> <span class="n">validationAttributeAdapterProvider</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Configure</span><span class="p">(</span><span class="n">MvcViewOptions</span> <span class="n">options</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">options</span><span class="p">.</span><span class="n">ClientModelValidatorProviders</span><span class="p">.</span><span class="nf">Insert</span><span class="p">(</span>
          <span class="m">0</span><span class="p">,</span>
          <span class="k">new</span> <span class="nf">LocalizedClientModelValidator</span><span class="p">(</span><span class="n">_validationAttributeAdapterProvider</span><span class="p">));</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Type <code class="language-plaintext highlighter-rouge">LocalizedClientModelValidator</code> is now responsible for creating instances of <code class="language-plaintext highlighter-rouge">IStringLocalizer</code> type with captured proper metadata.</p>

<p>So this is essentially the code that’s needed:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">attributeAdapter</span> <span class="p">=</span> <span class="n">_validationAttributeAdapterProvider</span>
    <span class="p">.</span><span class="nf">GetAttributeAdapter</span><span class="p">(</span><span class="n">validatorMetadata</span><span class="p">,</span>
                         <span class="k">new</span> <span class="nf">ValidationStringLocalizer</span><span class="p">(</span><span class="n">type</span><span class="p">,</span>
                                                       <span class="n">context</span><span class="p">.</span><span class="n">ModelMetadata</span><span class="p">.</span><span class="n">PropertyName</span><span class="p">,</span>
                                                       <span class="n">validatorMetadata</span><span class="p">));</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We were missing <code class="language-plaintext highlighter-rouge">context.ModelMetadata.PropertyName</code> fragment.</p>

<p>And once we are aware of actual property being validated - we can now get access to already available helper classes and ask to generate resource key to look for localized resource:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">ValidationStringLocalizer</span> <span class="p">:</span> <span class="n">IStringLocalizer</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">Type</span> <span class="n">_containerType</span><span class="p">;</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">CultureInfo</span> <span class="n">_culture</span><span class="p">;</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="kt">string</span> <span class="n">_propertyName</span><span class="p">;</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">ValidationAttribute</span> <span class="n">_validatorMetadata</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">ValidationStringLocalizer</span><span class="p">(</span><span class="n">Type</span> <span class="n">containerType</span><span class="p">,</span>
                                     <span class="kt">string</span> <span class="n">propertyName</span><span class="p">,</span>
                                     <span class="n">ValidationAttribute</span> <span class="n">validatorMetadata</span><span class="p">)</span> <span class="p">:</span> <span class="p">...</span>
<span class="p">{</span>

   <span class="p">...</span>

   <span class="k">public</span> <span class="n">LocalizedString</span> <span class="k">this</span><span class="p">[</span><span class="kt">string</span> <span class="n">name</span><span class="p">]</span>
   <span class="p">{</span>
       <span class="k">get</span>
       <span class="p">{</span>
           <span class="k">return</span> <span class="n">LocalizationProvider</span><span class="p">.</span><span class="nf">GetString</span><span class="p">(</span>
                         <span class="n">ResourceKeyBuilder</span><span class="p">.</span><span class="nf">BuildResourceKey</span><span class="p">(</span><span class="n">_containerType</span><span class="p">,</span>
                                                             <span class="n">_propertyName</span><span class="p">,</span>
                                                             <span class="n">_validatorMetadata</span><span class="p">));</span>
       <span class="p">}</span>
   <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Aaand that’s it!</p>

<p>The only piece in whole pipeline was <code class="language-plaintext highlighter-rouge">ModelMetaData.PropertyName</code> that was missing from <code class="language-plaintext highlighter-rouge">IStringLocalizer</code> type which was in charge of returning localized validation error messages.</p>

<p>In order to pass in this information to actual localizer we had to change a quite a bit from the pipeline by inserting validation attribute adapter provider in client model validation provider collection and re-implementing the rest of the pipeline under that type.</p>

<p>However, fixing this bug gave me more insights and understanding about Asp.Net Core Mvc internals and view configuration and model validation in particular, meaning that I do have now a bit more info to help others.</p>

<p>Happy localizing .Net Core web apps!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="ASP.NET" /><category term="Localization" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="asp.net" /><category term="localization" /><summary type="html"><![CDATA[Story begins with small issue registered in GitHub telling that LocalizationProvider does its job excellent when model is submitted to the server and validated there. Resources are found and used then. But localization provider is not so great when data- attributes are generated. Issue described that text from [Required(ErrorMessage = "...")] or any other validation attribute was rendered in resulting markup and localization provider was not even involved.]]></summary></entry><entry><title type="html">Localizing your React Components with DbLocalizationProvider</title><link href="https://tech-fellow.eu/2018/06/03/localizing-your-react-components/" rel="alternate" type="text/html" title="Localizing your React Components with DbLocalizationProvider" /><published>2018-06-03T00:15:00+03:00</published><updated>2018-06-03T00:15:00+03:00</updated><id>https://tech-fellow.eu/2018/06/03/localizing-your-react-components</id><content type="html" xml:base="https://tech-fellow.eu/2018/06/03/localizing-your-react-components/"><![CDATA[<p>With latest hype around Episerver with no head (aka <a href="https://www.episerver.com/products/features/all-features/headless-api">headless</a>) - it’s becoming more interesting to escape casual back-end stack and see what’s happening in other fronts. And it’s not surprise that Episerver content could be consumed in other <a href="https://blog.mathiaskunto.com/2018/03/23/react-and-episerver-moving-to-episerver-headless-episerver-contentdeliveryapi-with-friendly-urls-quick-poc/">client-side platforms</a>.
So this time decided to explore a bit more <a href="https://github.com/patkleef">my colleagues</a> work and look how React is doing nowadays.<br />
Anyway at some point React component will come to conclusion that there is a need for getting some translations from the server to render localized components. And this just sounds like a great idea to enhance and improve DbLocalizationProvider package.</p>

<p><strong>Disclaimer!</strong> However this is just one of the possibilities to localize your React components. I believe there are other alternatives out there as well..</p>

<h2 id="define-localized-resources">Define Localized Resources</h2>

<p>First, we need to define where and how translations will to stored - meaning that there has to be some kind of data container.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">ComponentResources</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="n">SampleComponentResources</span> <span class="n">ComponentTranslations</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">...</span>
<span class="p">}</span>

<span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">SampleComponentResources</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">Property1</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="s">"Some translation"</span><span class="p">;</span>
    <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">Property2</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="s">"Other translation.."</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Note!</strong> Translation are not defined as expression-bodied properties (<code class="language-plaintext highlighter-rouge">public static string Property1 =&gt; "Some translation"</code>) but as casual properties with setters and getters. We will need this later when we translate object to use on client-side.</p>

<h2 id="define-interface-on-client-side">Define Interface on Client-Side</h2>

<p>If you are same as me and like strongly-typed access (instead of “stringly”-typed) then you most probably are using TypeScript for your type enforcement on client-side. For this to work as expected, first we need to define interface that will declare what types and properties are available. To make things easier and speed-up (actually to keep server-side and client-side in sync) you can use <a href="http://type.litesolutions.net/">TypeLite</a> or similar library.</p>

<p>Basically we eventually get interface definition exported similar to this:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="n">export</span> <span class="k">interface</span> <span class="nc">ComponentResources</span> <span class="p">{</span>
    <span class="n">componentTranslations</span><span class="p">:</span> <span class="n">SampleComponentResources</span><span class="p">;</span>
    <span class="p">...</span>
<span class="p">}</span>

<span class="n">export</span> <span class="k">interface</span> <span class="nc">SampleComponentResources</span> <span class="p">{</span>
    <span class="n">property1</span><span class="p">:</span> <span class="kt">string</span><span class="p">;</span>
    <span class="n">property2</span><span class="p">:</span> <span class="kt">string</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="render-translations-in-markup">Render Translations in Markup</h2>
<p>One of the easiest ways to render required resource translations in markup is via special action on let’s say <code class="language-plaintext highlighter-rouge">Global</code> controller:</p>

<pre><code class="language-razor">@{ Html.RenderAction("ReactComponentTranslations", "Global"); }
</code></pre>

<p>Action <code class="language-plaintext highlighter-rouge">ReactComponentTranslations</code> on <code class="language-plaintext highlighter-rouge">Global</code> controller is quite straight-forward. We use database localization provider <em>new feature</em> to translate whole object and not just a property of the resource class. This will give us option to return translated object with all proper translations back to the client-side.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">readonly</span> <span class="n">LocalizationProvider</span> <span class="n">_provider</span><span class="p">;</span>

<span class="k">public</span> <span class="nf">GlobalConntroller</span><span class="p">(</span><span class="n">LocalizationProvider</span> <span class="n">provider</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">_provider</span> <span class="p">=</span> <span class="n">provider</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">public</span> <span class="n">ActionResult</span> <span class="nf">ReactComponentTranslations</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="k">new</span> <span class="n">ComponentResources</span>
    <span class="p">{</span>
        <span class="n">ComponentTranslations</span> <span class="p">=</span> <span class="n">_provider</span><span class="p">.</span><span class="n">Translate</span><span class="p">&lt;</span><span class="n">SampleComponentResources</span><span class="p">&gt;();</span>
    <span class="p">};</span>

    <span class="kt">var</span> <span class="n">json</span> <span class="p">=</span> <span class="n">JsonConvert</span><span class="p">.</span><span class="nf">SerializeObject</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="k">new</span> <span class="n">JsonSerializerSettings</span>
    <span class="p">{</span>
        <span class="n">ContractResolver</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">StaticPropertyContractResolver</span><span class="p">()</span>
    <span class="p">});</span>

    <span class="k">return</span> <span class="nf">Content</span><span class="p">(</span><span class="s">$"&lt;div data-translations='</span><span class="p">{</span><span class="n">json</span><span class="p">}</span><span class="s">'&gt;&lt;/div&gt;"</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Code mentioned above will basically emit HTML element with translations from <code class="language-plaintext highlighter-rouge">ComponentResource</code> class:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;div</span> <span class="na">data-translations=</span><span class="s">'{"componentTranslations": {"property1":"..", ...}}'</span><span class="nt">&gt;&lt;/div&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="consume-translations-in-react-component">Consume Translations in React Component</h2>

<p>So now we need to read emitted translations and pass in to our React component. One way would be to do this <a href="https://reactjs.org/docs/components-and-props.html">via props</a>. However, this would require some responsibility of the “middle components” when you would like to consume translations in child of the child components. Thanks to <a href="https://github.com/eirhor">another colleague</a> who was kind enough and showed me <a href="https://reactjs.org/docs/context.html">Context API</a> from the React framework. Think this is much nicer and cleaner approach compared to for example Redux state machine.</p>

<p>Ok, let’s continue. First, we need to define function that will read translations from the element, this is not hard:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="kd">const</span> <span class="nx">getTranslations</span> <span class="o">=</span> <span class="p">():</span> <span class="nx">ComponentResources</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">element</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nb">document</span><span class="p">.</span><span class="nf">querySelector</span><span class="p">(</span><span class="dl">'</span><span class="s1">[data-translations]</span><span class="dl">'</span><span class="p">);</span>
    <span class="k">if </span><span class="p">(</span><span class="nx">element</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="nx">element</span><span class="p">.</span><span class="nf">getAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">data-translations</span><span class="dl">'</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="p">{}</span> <span class="nx">as</span> <span class="nx">ComponentResources</span><span class="p">;</span>
<span class="p">};</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Once we have translations as object in JS, we can create context out of it:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="kd">const</span> <span class="nx">TranslationsContext</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="nf">createContext</span><span class="p">(</span><span class="nf">getTranslations</span><span class="p">());</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>After creation of the context, it’s quite easy to start using it in components.
<strong>Note!</strong> That context has set it’s default value from the generated element with translations. There are few rules around default values for the contexts. As we would like to use generated translations from the server side and not override them while creating component tree - we will define only consumer of the context, omitting provider (as provide will have to provide concrete values for the context, even passing in <code class="language-plaintext highlighter-rouge">undefined</code> <a href="https://reactjs.org/docs/context.html#reactcreatecontext">will not make</a> use of default values).</p>

<h2 id="use-translations-in-your-react-component">Use Translations in your React Component</h2>
<p>The essence of getting hold of initialized resource translations is to make use that component is aware of translation context defined above and renders itself “within” context:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="rouge-code"><pre><span class="k">export</span> <span class="kd">class</span> <span class="nc">ComponentContainer</span> <span class="kd">extends</span> <span class="nc">React</span><span class="p">.</span><span class="nx">Component</span> <span class="p">{</span>
    <span class="nf">constructor</span><span class="p">(</span><span class="nx">props</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">super</span><span class="p">(</span><span class="nx">props</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="nf">render</span><span class="p">()</span> <span class="p">{</span>
        <span class="k">return</span><span class="p">(</span>
            <span class="o">&lt;</span><span class="nx">TranslationsContext</span><span class="p">.</span><span class="nx">Consumer</span><span class="o">&gt;</span>
            <span class="p">{</span> <span class="nx">t</span> <span class="o">=&gt;</span>
                <span class="o">&lt;</span><span class="nx">div</span><span class="o">&gt;</span>
                    <span class="o">&lt;</span><span class="nx">input</span> <span class="nx">type</span><span class="o">=</span><span class="dl">"</span><span class="s2">text</span><span class="dl">"</span>
                           <span class="nx">placeholder</span><span class="o">=</span><span class="dl">"</span><span class="s2">{t.componentTranslations.property1}</span><span class="dl">"</span>
                           <span class="p">...</span> <span class="o">/&gt;</span>
                <span class="o">&lt;</span><span class="sr">/div</span><span class="err">&gt;
</span>            <span class="p">}</span>
            <span class="o">&lt;</span><span class="sr">/TranslationsContext.Consumer</span><span class="err">&gt;
</span>        <span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="conclusion">Conclusion</h2>

<p>Generating server-side resource translations and passing them down to the client-side for easier access from the React components is achievable via new <a href="https://reactjs.org/docs/context.html">Context API</a>. You can use at any “depth” in the component tree and you don’t need to pollute props definitions to pass down translations from grand to child component. Code was not so terrible actually (even for elder backender as I am).</p>

<h2 id="grabbing-the-code">Grabbing the Code</h2>
<p>As usual DbLocalizationProvider packages are available on <a href="https://nuget.episerver.com/package/?id=DbLocalizationProvider.EPiServer">Episerver Nuget feed</a>.
If you do have any feedback, please leave in comments or ask on <a href="https://github.com/valdisiljuconoks/localization-provider-opti/issues">Github</a>.</p>

<p>Happy localized Reacting!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="ASP.NET" /><category term="Localization" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="asp.net" /><category term="localization" /><summary type="html"><![CDATA[With latest hype around Episerver with no head (aka headless) - it’s becoming more interesting to escape casual back-end stack and see what’s happening in other fronts. And it’s not surprise that Episerver content could be consumed in other client-side platforms. So this time decided to explore a bit more my colleagues work and look how React is doing nowadays. Anyway at some point React component will come to conclusion that there is a need for getting some translations from the server to render localized components. And this just sounds like a great idea to enhance and improve DbLocalizationProvider package.]]></summary></entry><entry><title type="html">Module Dependencies in EPiServer DeveloperTools</title><link href="https://tech-fellow.eu/2018/05/10/module-dependencies-in-episerver-developertools/" rel="alternate" type="text/html" title="Module Dependencies in EPiServer DeveloperTools" /><published>2018-05-10T23:30:00+03:00</published><updated>2018-05-10T23:30:00+03:00</updated><id>https://tech-fellow.eu/2018/05/10/module-dependencies-in-episerver-developertools</id><content type="html" xml:base="https://tech-fellow.eu/2018/05/10/module-dependencies-in-episerver-developertools/"><![CDATA[<p>After gratefully accepted invitation to contribute to the <a href="https://github.com/episerver/DeveloperTools">Episerver Developer Tools</a> package, I can safely do this:</p>

<p><img src="/assets/img/2018/05/2018-05-06_01-55-28-1.png" alt="2018-05-06_01-55-28-1" /></p>

<p>All credits to the amazing Episerver team, I’m just contributing here :) So that’s why happy to share some of the updates in latest version.</p>

<p>While reviewing performance for startup modules (either configurable or initializable ones) to find out some bottlenecks on the site..</p>

<p><img src="/assets/img/2018/05/startup-perf.png" alt="startup-perf" /></p>

<p>I had hard time to find the answer on question - what is the order/dependencies of modules in this list and how they are interconnected?</p>

<p>As I do like data visualization a lot, thought - this might be interesting data source to play around with. It would be great if you could enlist your custom modules and see what are dependencies between them.</p>

<p>So in latest version (v3.2) you have now section “Module Dependencies”.</p>

<p><img src="/assets/img/2018/05/menu.png" alt="menu" /></p>

<p>There you can see all the custom (non EPiserver) modules and their connections (dependencies in code):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">TinyMceInitialization</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ExtendedTinyMceInitialization</span> <span class="p">:</span> <span class="n">IConfigurableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">...</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is how it looks in AlloyTech site.</p>

<p><img src="/assets/img/2018/05/custom-modules.png" alt="custom-modules" /></p>

<p>Not so impressive and interesting ;)
Much more fun comes when you enable all modules (including EPiServer built-in ones):</p>

<p><img src="/assets/img/2018/05/epi-modules.png" alt="epi-modules" /></p>

<p>If you do have any feedback or questions, please visit EPiServer.DeveloperTools <a href="https://github.com/episerver/DeveloperTools">GitHub page</a>.
I’m still not quite confident with the choice of the forced directed graph library, but at least it did its job pretty OK.</p>

<p>May the forced directed graphs be with you!<br />
Happy coding!
[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><summary type="html"><![CDATA[After gratefully accepted invitation to contribute to the Episerver Developer Tools package, I can safely do this:]]></summary></entry><entry><title type="html">Localizing Asp.Net Core Applications now with AdminUI</title><link href="https://tech-fellow.eu/2018/04/28/localizing-asp-net-core-applications-now-with-adminui/" rel="alternate" type="text/html" title="Localizing Asp.Net Core Applications now with AdminUI" /><published>2018-04-28T01:30:00+03:00</published><updated>2018-04-28T01:30:00+03:00</updated><id>https://tech-fellow.eu/2018/04/28/localizing-asp-net-core-applications-now-with-adminui</id><content type="html" xml:base="https://tech-fellow.eu/2018/04/28/localizing-asp-net-core-applications-now-with-adminui/"><![CDATA[<p>Finally it’s time to release administrative user interface for complementing Asp.Net Core application localizing process.</p>

<p>It’s been a while since localization provider has been released for Asp.Net Core applications, but until now - actual translation of the resources was limited due to absence of the user interface through which editor can make adjustments to the translations.</p>

<p>I’m happy to announce that AdminUI has been rewritten to utilize Vue.js framework and to grind some of the rough edges of the library.</p>

<h2 id="installation">Installation</h2>

<p>The only thing you need to do to get started is to install following package.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>PM&gt; Install-Package LocalizationProvider.AdminUI.AspNetCore
</pre></td></tr></tbody></table></code></pre></div></div>

<p>It will also bring down all the other necessary packages for library to work correctly.</p>

<h2 id="setup--customization">Setup &amp; Customization</h2>

<p>Essentially there are 2 parts of the whole setup process:</p>

<ul>
  <li>Configure Services</li>
  <li>Configure Library</li>
</ul>

<p>Configuration of the services is part of the Asp.Net Core dependency injection process setup. So to add AdminUI to you application you need (in <code class="language-plaintext highlighter-rouge">Startup.cs</code>):</p>

<h3 id="enable-built-in-localization-support">Enable Built-In Localization Support</h3>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">services</span><span class="p">.</span><span class="nf">AddLocalization</span><span class="p">();</span>
    <span class="n">services</span><span class="p">.</span><span class="nf">AddMvc</span><span class="p">()</span>
        <span class="p">.</span><span class="nf">AddViewLocalization</span><span class="p">()</span>
        <span class="p">.</span><span class="nf">AddDataAnnotationsLocalization</span><span class="p">();</span>

    <span class="c1">// just adding English and Norwegian support</span>
    <span class="n">services</span><span class="p">.</span><span class="n">Configure</span><span class="p">&lt;</span><span class="n">RequestLocalizationOptions</span><span class="p">&gt;(</span><span class="n">opts</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">supportedCultures</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">CultureInfo</span><span class="p">&gt;</span>
                                <span class="p">{</span>
                                    <span class="k">new</span> <span class="nf">CultureInfo</span><span class="p">(</span><span class="s">"en"</span><span class="p">),</span>
                                    <span class="k">new</span> <span class="nf">CultureInfo</span><span class="p">(</span><span class="s">"no"</span><span class="p">)</span>
                                <span class="p">};</span>

        <span class="n">opts</span><span class="p">.</span><span class="n">DefaultRequestCulture</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">RequestCulture</span><span class="p">(</span><span class="s">"en"</span><span class="p">);</span>
        <span class="n">opts</span><span class="p">.</span><span class="n">SupportedCultures</span> <span class="p">=</span> <span class="n">supportedCultures</span><span class="p">;</span>
        <span class="n">opts</span><span class="p">.</span><span class="n">SupportedUICultures</span> <span class="p">=</span> <span class="n">supportedCultures</span><span class="p">;</span>
    <span class="p">});</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">void</span> <span class="nf">Configure</span><span class="p">(</span><span class="n">IApplicationBuilder</span> <span class="n">app</span><span class="p">,</span> <span class="n">IHostingEnvironment</span> <span class="n">env</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">options</span> <span class="p">=</span> <span class="n">app</span><span class="p">.</span><span class="n">ApplicationServices</span><span class="p">.</span><span class="n">GetService</span><span class="p">&lt;</span><span class="n">IOptions</span><span class="p">&lt;</span><span class="n">RequestLocalizationOptions</span><span class="p">&gt;&gt;();</span>
    <span class="n">app</span><span class="p">.</span><span class="nf">UseRequestLocalization</span><span class="p">(</span><span class="n">options</span><span class="p">.</span><span class="n">Value</span><span class="p">);</span>

<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="setup-library">Setup Library</h3>

<p>And when built-in support is configured, you can now add support for DbLocalizationProvider library (again in <code class="language-plaintext highlighter-rouge">Startup.cs</code>):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
   <span class="n">services</span><span class="p">.</span><span class="nf">AddDbLocalizationProvider</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
   <span class="p">{</span>
       <span class="p">...</span>
   <span class="p">});</span>

   <span class="n">services</span><span class="p">.</span><span class="nf">AddDbLocalizationProviderAdminUI</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
   <span class="p">{</span>
       <span class="p">...</span>
   <span class="p">});</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Through these methods you can customize behavior for the library and AdminUI component.</p>

<p>And when you are done with customization, you need to add those to the application:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">Configure</span><span class="p">(</span><span class="n">IApplicationBuilder</span> <span class="n">app</span><span class="p">,</span> <span class="n">IHostingEnvironment</span> <span class="n">env</span><span class="p">)</span>
<span class="p">{</span>
   <span class="n">app</span><span class="p">.</span><span class="nf">UseDbLocalizationProvider</span><span class="p">();</span>
   <span class="n">app</span><span class="p">.</span><span class="nf">UseDbLocalizationProviderAdminUI</span><span class="p">();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="accessing-ui">Accessing UI</h2>

<p>When everything is setup correctly and Asp.Net Core runtime does not blame you for incorrect configuration, you may access AdminUI via <code class="language-plaintext highlighter-rouge">.../localization-admin</code> url (by default).</p>

<p><img src="/assets/img/2018/04/aspnetcore-admin-ui.jpg" alt="aspnetcore-admin-ui" /></p>

<h2 id="get-more-info">Get More Info</h2>

<p>AdminUI itself will be developed further and some of the cool features (like import with merge preview) from the other target platform will be pulled over to Asp.Net Core component.</p>

<p>As usual - to find more info and to file any issue - look for <a href="https://github.com/valdisiljuconoks/localization-provider-core">Github repo</a>.</p>

<p><br />
Happy localizing!</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Localization Provider" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization" /><summary type="html"><![CDATA[Finally it’s time to release administrative user interface for complementing Asp.Net Core application localizing process.]]></summary></entry><entry><title type="html">Baking Round Shaped Apps with MediatR</title><link href="https://tech-fellow.eu/2018/03/24/baking-round-shaped-apps-with-mediatr/" rel="alternate" type="text/html" title="Baking Round Shaped Apps with MediatR" /><published>2018-03-24T14:30:00+02:00</published><updated>2018-03-24T14:30:00+02:00</updated><id>https://tech-fellow.eu/2018/03/24/baking-round-shaped-apps-with-mediatr</id><content type="html" xml:base="https://tech-fellow.eu/2018/03/24/baking-round-shaped-apps-with-mediatr/"><![CDATA[<p>Back in days I spent time to describe something that I called <a href="https://medium.com/@benorama/the-evolution-of-software-architecture-bd6ea674c477">pizza architecture</a> - <a href="https://tech-fellow.ghost.io/2016/10/31/baking-round-shaped-software-mapping-to-the-code/">showing off</a> how to organize and design applications in round shape with domain in the middle and less important transport specific channels (like web or batch environment) closer to the border of the pizza.
Originally I spent time to developer self-brewed messaging pipeline inside the application to show how internals are working in this type of architecture. And promised to convert application to use some out-of-the box solution - like <a href="https://github.com/jbogard/MediatR/">MediatR</a>.</p>

<p><img src="/assets/img/2018/03/FreshPaint-21-2016.09.25-10.45.57.png" alt="" /></p>

<p><a href="https://github.com/valdisiljuconoks/PizzaArchitecture/commit/e7256dd55fb9594037de0c5e36f19214049e1327">This PR</a> shows all the necessary changes I had to make to convert original solution to use MediatR library (+ also converted to NetCoreApp 2.0).</p>

<h2 id="naming-is-hard">Naming is Hard</h2>

<p>Naming is our industry is always hard part and we have to stick to basic English range. I personally like idea that my types express intent and are named accordingly - commands and queries. However, when we are going to switch to MediatR library, it regulates other naming schema - <code class="language-plaintext highlighter-rouge">Request</code> (aka query or command) and <code class="language-plaintext highlighter-rouge">Notification</code>. It’s easy to remember which is what by understanding that request has always result (the same way as queries and/or commands) and notification is more like fire &amp; forget. So, my definition:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">Request&lt;T&gt;</code> - under this type you might hide commands and queries. Most of the time you don’t need to distinguish between the two. You send the request to the mediator and expect results. When you don’t have any results - just use <code class="language-plaintext highlighter-rouge">Unit</code> as <code class="language-plaintext highlighter-rouge">T</code>;</li>
  <li><code class="language-plaintext highlighter-rouge">Notification</code> - under this type you might implement something similar to domain events. Using notifications you are expected to notify other parties that are interested in your business about stuff that happens inside your domain.</li>
</ul>

<h2 id="register-phase">Register Phase</h2>

<p>Look for registries:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="n">container</span><span class="p">.</span><span class="nf">Configure</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="n">_</span><span class="p">.</span><span class="nf">Scan</span><span class="p">(</span><span class="n">s</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="n">s</span><span class="p">.</span><span class="nf">LookForRegistries</span><span class="p">();</span> <span class="p">}));</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This for some reason is not really working in .Net Core 2.0 app. Registries were not found and added to the StructureMap. Instead, I had to manually add those to the list:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="n">container</span><span class="p">.</span><span class="nf">Configure</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="n">_</span><span class="p">.</span><span class="n">AddRegistry</span><span class="p">&lt;</span><span class="n">MediatorRegistrations</span><span class="p">&gt;();</span> <span class="p">}));</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="domainevent---inotification">DomainEvent -&gt; INotification</h2>

<p>When switching to MediatR library -&gt; there is no explicit different between commands, queries, domain events and other DDD terms. Instead setup is quite simple: you do have requests with potential result and you do have notifications with no result.</p>

<p>In order to migrate to MediatR library I had to rename all occurrences from <code class="language-plaintext highlighter-rouge">IDomainEvent</code> (and domain event handler) to just <code class="language-plaintext highlighter-rouge">INotification</code> (and appropriate handlers). Think this simplification is much better and you don’t need to think about whether you are dispatching event, query or command.</p>

<h2 id="messaging-pipeline---mediator-behaviors">Messaging Pipeline -&gt; Mediator Behaviors</h2>

<p>In previous post we extended mediator implementation itself and decorated it with another instance with running validation routines against passed in commands or queries. This makes sense in self-made mediator implementation. But here, when we are switching to MediatR library - it provides <a href="https://github.com/jbogard/MediatR/wiki/Behaviors">another way</a> to extend messaging pipelines and add some extra logic while handling commands or queries (requests).</p>

<h3 id="adding-behaviors-to-pipelines">Adding Behaviors to Pipelines</h3>

<p>Adding various behaviors to the messaging pipelines is quite simple and requires just a couple registrations in container.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">MediatorRegistrations</span> <span class="p">:</span> <span class="n">Registry</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">MediatorRegistrations</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="nf">For</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">IPipelineBehavior</span><span class="p">&lt;,&gt;)).</span><span class="nf">Add</span><span class="p">(</span><span class="k">typeof</span><span class="p">(...));</span>
        <span class="p">...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Behaviors are very similar to the Asp.Net middlewares sitting in the middle of the request processing pipeline and waiting for a chance to kick in.</p>

<p><strong>NB!</strong> Order of the registrations matter here as mediator will run through behaviors in order they are registered in IoC container (actually it’s how those registrations are returned from IoC container implementation). So it <em>might</em> depend from particular IoC implementation.</p>

<h3 id="input-validation-with-fluentvalidation">Input Validation with FluentValidation</h3>

<p>For instance, we can take a look at how validation is added to the overall messaging pipeline.</p>

<p>First, we need to add fluent validation registration if not done already (<code class="language-plaintext highlighter-rouge">Startup.cs</code>):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="n">IServiceProvider</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">services</span><span class="p">.</span><span class="nf">AddMvc</span><span class="p">()</span>
            <span class="p">.</span><span class="nf">AddFluentValidation</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
                <span class="p">{</span>
                    <span class="n">_</span><span class="p">.</span><span class="n">RegisterValidatorsFromAssemblyContaining</span><span class="p">&lt;</span><span class="n">Startup</span><span class="p">&gt;());</span>
                <span class="p">});</span>

    <span class="k">return</span> <span class="nf">UseStructureMapContainer</span><span class="p">(</span><span class="n">services</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then we need to add validation behavior to the pipeline (IoC registry):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nf">For</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">IPipelineBehavior</span><span class="p">&lt;,&gt;)).</span><span class="nf">Add</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">ValidationBehavior</span><span class="p">&lt;,&gt;));</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And actual implementation:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">ValidationBehavior</span><span class="p">&lt;</span><span class="n">TRequest</span><span class="p">,</span> <span class="n">TResponse</span><span class="p">&gt;</span> <span class="p">:</span> <span class="n">IPipelineBehavior</span><span class="p">&lt;</span><span class="n">TRequest</span><span class="p">,</span> <span class="n">TResponse</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IValidatorFactory</span> <span class="n">_validationFactory</span><span class="p">;</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">ILogger</span> <span class="n">_logger</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">ValidationBehavior</span><span class="p">(</span><span class="n">IValidatorFactory</span> <span class="n">validationFactory</span><span class="p">,</span>
                              <span class="n">ILoggerFactory</span> <span class="n">loggingFactory</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_validationFactory</span> <span class="p">=</span> <span class="n">validationFactory</span><span class="p">;</span>
        <span class="n">_logger</span> <span class="p">=</span> <span class="n">loggingFactory</span><span class="p">.</span><span class="nf">CreateLogger</span><span class="p">(</span><span class="s">"ValidationBehavior"</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">TResponse</span><span class="p">&gt;</span> <span class="nf">Handle</span><span class="p">(</span><span class="n">TRequest</span> <span class="n">request</span><span class="p">,</span>
                                        <span class="n">CancellationToken</span> <span class="n">cancellationToken</span><span class="p">,</span>
                                        <span class="n">RequestHandlerDelegate</span><span class="p">&lt;</span><span class="n">TResponse</span><span class="p">&gt;</span> <span class="n">next</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">validator</span> <span class="p">=</span> <span class="n">_validationFactory</span><span class="p">.</span><span class="nf">GetValidator</span><span class="p">(</span><span class="n">request</span><span class="p">.</span><span class="nf">GetType</span><span class="p">());</span>
        <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="n">validator</span><span class="p">?.</span><span class="nf">Validate</span><span class="p">(</span><span class="n">request</span><span class="p">);</span>

        <span class="k">if</span><span class="p">(</span><span class="n">result</span> <span class="p">!=</span> <span class="k">null</span> <span class="p">&amp;&amp;</span> <span class="p">!</span><span class="n">result</span><span class="p">.</span><span class="n">IsValid</span><span class="p">)</span>
            <span class="k">throw</span> <span class="k">new</span> <span class="nf">ValidationException</span><span class="p">(</span><span class="n">result</span><span class="p">.</span><span class="n">Errors</span><span class="p">);</span>

        <span class="kt">var</span> <span class="n">response</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">next</span><span class="p">();</span>
        <span class="k">return</span> <span class="n">response</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The same way as middle-wares behavior implementation receives <code class="language-plaintext highlighter-rouge">next</code> behavior and can decide whether to call it or break the circuit.</p>

<h3 id="command-pre-executepost-execute-handlers">Command Pre-Execute/Post-Execute Handlers</h3>

<p>In our custom implementation we had special command pipeline that was responsible for finding and running pre-command handlers (anyone that would like to have control before the command is carried out).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">CommandPipeline</span><span class="p">&lt;</span><span class="n">TCommand</span><span class="p">&gt;</span>
             <span class="p">:</span> <span class="n">ICommandHandler</span><span class="p">&lt;</span><span class="n">TCommand</span><span class="p">&gt;</span> <span class="k">where</span> <span class="n">TCommand</span> <span class="p">:</span> <span class="n">ICommand</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">ICommandHandler</span><span class="p">&lt;</span><span class="n">TCommand</span><span class="p">&gt;</span> <span class="n">_inner</span><span class="p">;</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IPreExecuteCommandHandler</span><span class="p">&lt;</span><span class="n">TCommand</span><span class="p">&gt;[]</span> <span class="n">_preHandlers</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">CommandPipeline</span><span class="p">(</span><span class="n">ICommandHandler</span><span class="p">&lt;</span><span class="n">TCommand</span><span class="p">&gt;</span> <span class="n">inner</span><span class="p">,</span>
                           <span class="n">IPreExecuteCommandHandler</span><span class="p">&lt;</span><span class="n">TCommand</span><span class="p">&gt;[]</span> <span class="n">preHandlers</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_inner</span> <span class="p">=</span> <span class="n">inner</span><span class="p">;</span>
        <span class="n">_preHandlers</span> <span class="p">=</span> <span class="n">preHandlers</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Handle</span><span class="p">(</span><span class="n">TCommand</span> <span class="n">command</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span><span class="p">(</span><span class="n">_preHandlers</span> <span class="p">!=</span> <span class="k">null</span> <span class="p">&amp;&amp;</span> <span class="n">_preHandlers</span><span class="p">.</span><span class="nf">Any</span><span class="p">())</span>
        <span class="p">{</span>
            <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">handler</span> <span class="k">in</span> <span class="n">_preHandlers</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="n">handler</span><span class="p">.</span><span class="nf">Handle</span><span class="p">(</span><span class="n">command</span><span class="p">);</span>
            <span class="p">}</span>
        <span class="p">}</span>

        <span class="n">_inner</span><span class="p">.</span><span class="nf">Handle</span><span class="p">(</span><span class="n">command</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now using MediatR library it’s actually pretty easy to get the same functionality (and also post processors) out of the box.</p>

<p>What we need to do is to register special built-in behavior in message pipeline via IoC registrations (in this case StructureMap registry):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">MediatorRegistrations</span> <span class="p">:</span> <span class="n">Registry</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">MediatorRegistrations</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="c1">// order of the registration matters here</span>
        <span class="nf">For</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">IPipelineBehavior</span><span class="p">&lt;,&gt;))</span>
           <span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">RequestPreProcessorBehavior</span><span class="p">&lt;,&gt;));</span>
        <span class="p">...</span>
        <span class="nf">For</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">IPipelineBehavior</span><span class="p">&lt;,&gt;))</span>
           <span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">RequestPostProcessorBehavior</span><span class="p">&lt;,&gt;));</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Both types <code class="language-plaintext highlighter-rouge">RequestPreProcessorBehavior</code> and <code class="language-plaintext highlighter-rouge">RequestPostProcessorBehavior</code> come from mediator library and is very easy to use.
The only thing left here is pre/post-handler implementation:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">NeedToExecuteBeforeCommand</span> <span class="p">:</span> <span class="n">IRequestPreProcessor</span><span class="p">&lt;</span><span class="n">Command</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="n">Task</span> <span class="nf">Process</span><span class="p">(</span><span class="n">Command</span> <span class="n">request</span><span class="p">,</span>
                        <span class="n">CancellationToken</span> <span class="n">cancellationToken</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// very complex logic goes here...</span>

        <span class="k">return</span> <span class="n">Task</span><span class="p">.</span><span class="n">CompletedTask</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Library is taking care of all the heavy generic type lifting in order to find matching handlers for given request.</p>

<h3 id="only-requesthandlers-supported-in-processing-pipeline">Only RequestHandlers Supported in Processing Pipeline</h3>

<p>From MediatR docs:</p>

<blockquote>
  <p>The pipeline behaviors are only compatible with IRequestHandler&lt;TRequest,TResponse&gt; and can’t be used with INotificationHandler<TRequest>.</TRequest></p>
</blockquote>

<p>Just to be aware that you are able to adjust behavior of the message processing pipeline if you are sending <code class="language-plaintext highlighter-rouge">Request&lt;T&gt;</code> type of the message. Notifications are not adjustable and they are just dispatched with no custom behavior attached.</p>

<h2 id="summary">Summary</h2>

<p>Implementing your own mediator and understanding all internals how it’s working was definitely fun and educational. While converting now to MediatR library - I understood that it was mistake to decorate mediator itself in original post to get custom behavior. Instead - it’s much more elegant solution to add behaviors to the processing pipeline and drip custom logic there compared to decorations around core dispatcher object. Using behaviors it’s easier to add/remove custom logic, see all custom processing behaviors in one place, easy change order and unit test those.</p>

<p>Also understood that it does not matter to be DDD compliant 100% and talk about command and queries, domain events and other terms explicitly in code. It’s easier to think about architecture in simple terms - requests and notifications. Keeping architecture simple.</p>

<p>Even if I would be using home-brewed mediator implementation in production, upon next project - it most probably would scream to be extracted and packed and reusable library. At that moment consideration about using something already ready made would come at ease.</p>

<p>If you are interested more to see the code it’s available <a href="https://github.com/valdisiljuconoks/PizzaArchitecture/tree/mediatr">in GitHub</a>.</p>

<p>Happy mediatoring! :)</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="ASP.NET" /><category term="Architecture" /><category term="Pizza Architecture" /><category term="Software Design" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="asp.net" /><category term="architecture" /><category term="pizza architecture" /><category term="software design" /><summary type="html"><![CDATA[Back in days I spent time to describe something that I called pizza architecture - showing off how to organize and design applications in round shape with domain in the middle and less important transport specific channels (like web or batch environment) closer to the border of the pizza. Originally I spent time to developer self-brewed messaging pipeline inside the application to show how internals are working in this type of architecture. And promised to convert application to use some out-of-the box solution - like MediatR.]]></summary></entry><entry><title type="html">Some smaller updates for DbLocalizationProvider</title><link href="https://tech-fellow.eu/2018/01/31/some-smaller-updates-for-dblocalizationprovider/" rel="alternate" type="text/html" title="Some smaller updates for DbLocalizationProvider" /><published>2018-01-31T23:30:00+02:00</published><updated>2018-01-31T23:30:00+02:00</updated><id>https://tech-fellow.eu/2018/01/31/some-smaller-updates-for-dblocalizationprovider</id><content type="html" xml:base="https://tech-fellow.eu/2018/01/31/some-smaller-updates-for-dblocalizationprovider/"><![CDATA[<p>Localization provider is well and alive. Lately I’ve been heads down busy with porting some of the parts over to <a href="https://tech-fellow.eu/2018/01/27/dblocalizationprovider-in-asp-net-core/">.Net Core</a> targeting .Net Standard version 2.0. Anyway just wanted to let you know some of the smaller updates and fixes for the latest version of the provider packages.</p>

<h2 id="multi-target---netfx-and-core">Multi-Target -&gt; NetFx and Core</h2>

<p>Now there are specific multi targets for .Net Framework and .Net Core for <code class="language-plaintext highlighter-rouge">and</code> packages. This was required due to reported issues when package was used context together with WebApi (to be more specific - there was weird issues when referencing <code class="language-plaintext highlighter-rouge">System.Net.Http</code> from netstandard in framework targeted project). It’s quite lengthy to explain here. Maybe another post would make it more clear.</p>

<h2 id="resourcekey-attribute-with-viewmodels">ResourceKey Attribute with ViewModels</h2>

<p>Now you can use <code class="language-plaintext highlighter-rouge">[ResourceKey]</code> attribute also with view models. This addresses some of the use cases when there is defined convention for the resource keys or there are already migrated resources from (well, guess!?!) XML files with predefined structure.
If you do have following view model:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ModelWithDataAnnotationsAndResourceKey</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">ResourceKey</span><span class="p">(</span><span class="s">"the-key"</span><span class="p">)]</span>
    <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"Something"</span><span class="p">)]</span>
    <span class="p">[</span><span class="nf">Required</span> <span class="p">(</span><span class="n">ErrorMessage</span> <span class="p">=</span> <span class="s">"This unfortunately is required"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">UserName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>then now library will respect <code class="language-plaintext highlighter-rouge">[ResourceKey]</code> attribute and will generate for instance following resources:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">the-key</code> (<code class="language-plaintext highlighter-rouge">[Display]</code> value will be used here as translation)</li>
  <li><code class="language-plaintext highlighter-rouge">the-key-Required</code> - <code class="language-plaintext highlighter-rouge">ErrorMessage</code> value will be used as translation</li>
</ul>

<h2 id="javascript-resource-handler">JavaScript Resource Handler</h2>

<p>JavaScript Resource Handler now correctly handles deep object cloning. What it means? Previously issue was with multiple client-side resource includes:</p>

<pre><code class="language-razor">&lt;head&gt;
    @Html.GetTranslations(typeof(ResourceClass))
    @Html.GetTranslations(typeof(AnotherResource))
&lt;/head&gt;
</code></pre>

<p>With this code it would result in “last wins” situation - meaning that under <code class="language-plaintext highlighter-rouge">window.jsl10n</code> key would be <strong>only</strong> last resource class - <code class="language-plaintext highlighter-rouge">AnotherResource</code>.</p>

<p>This has been fixed in latest version and all of the client-side resources are merged into single object:</p>

<p><img src="/assets/img/2018/01/2018-01-20_00-45-04.jpg" alt="" /></p>

<p>Note, that there <code class="language-plaintext highlighter-rouge">...ResouceWithSwedish..</code> but returns English text? This is just debug sample code for invariant fallback scenario :)</p>

<p>Also now <code class="language-plaintext highlighter-rouge">JsResourceHandler</code> will include also fallback for invariant culture (if it will be enabled via <code class="language-plaintext highlighter-rouge">ConfigurationContext</code>).</p>

<h2 id="editor-ui">Editor UI</h2>

<p>Now you are able to hide either <code class="language-plaintext highlighter-rouge">Table</code> or <code class="language-plaintext highlighter-rouge">Tree</code> view if you need to.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">InitLocalizationModule</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">UiConfigurationContext</span><span class="p">.</span><span class="nf">Setup</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="p">...</span>
            <span class="n">_</span><span class="p">.</span><span class="nf">DisableView</span><span class="p">(</span><span class="n">ResourceListView</span><span class="p">.</span><span class="n">Table</span><span class="p">);</span>
        <span class="p">});</span>
    <span class="p">}</span>

   <span class="p">...</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Also <code class="language-plaintext highlighter-rouge">New Resource</code> command has been removed from the UI. Now you would not be able to create new resources from UI. All discovery and synchronization of resources should happen via code.</p>

<p><img src="/assets/img/2018/01/2018-01-31_23-42-16.png" alt="" /></p>

<p><br />
Happy localizing!
[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Localization Provider" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization" /><summary type="html"><![CDATA[Localization provider is well and alive. Lately I’ve been heads down busy with porting some of the parts over to .Net Core targeting .Net Standard version 2.0. Anyway just wanted to let you know some of the smaller updates and fixes for the latest version of the provider packages.]]></summary></entry><entry><title type="html">Alternative Localization for Asp.Net Core Applications</title><link href="https://tech-fellow.eu/2018/01/27/dblocalizationprovider-in-asp-net-core/" rel="alternate" type="text/html" title="Alternative Localization for Asp.Net Core Applications" /><published>2018-01-27T23:30:00+02:00</published><updated>2018-01-27T23:30:00+02:00</updated><id>https://tech-fellow.eu/2018/01/27/dblocalizationprovider-in-asp-net-core</id><content type="html" xml:base="https://tech-fellow.eu/2018/01/27/dblocalizationprovider-in-asp-net-core/"><![CDATA[<p>This is code fragment from <a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization">official documentation</a> how to localize content using built-in functionality.</p>

<h3 id="app-content-localization">App Content Localization</h3>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">Route</span><span class="p">(</span><span class="s">"api/[controller]"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">AboutController</span> <span class="p">:</span> <span class="n">Controller</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IStringLocalizer</span><span class="p">&lt;</span><span class="n">AboutController</span><span class="p">&gt;</span> <span class="n">_localizer</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">AboutController</span><span class="p">(</span><span class="n">IStringLocalizer</span><span class="p">&lt;</span><span class="n">AboutController</span><span class="p">&gt;</span> <span class="n">localizer</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_localizer</span> <span class="p">=</span> <span class="n">localizer</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="p">[</span><span class="n">HttpGet</span><span class="p">]</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="nf">Get</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">_localizer</span><span class="p">[</span><span class="s">"About Title"</span><span class="p">];</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And if you are working with Html content that shouldn’t be escaped during rendering - you are using <code class="language-plaintext highlighter-rouge">IHtmlLocalizer</code> implementation that returns <code class="language-plaintext highlighter-rouge">LocalizedHtmlString</code> instance.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">BookController</span> <span class="p">:</span> <span class="n">Controller</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IHtmlLocalizer</span><span class="p">&lt;</span><span class="n">BookController</span><span class="p">&gt;</span> <span class="n">_localizer</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">BookController</span><span class="p">(</span><span class="n">IHtmlLocalizer</span><span class="p">&lt;</span><span class="n">BookController</span><span class="p">&gt;</span> <span class="n">localizer</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_localizer</span> <span class="p">=</span> <span class="n">localizer</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">IActionResult</span> <span class="nf">Hello</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">ViewData</span><span class="p">[</span><span class="s">"Message"</span><span class="p">]</span> <span class="p">=</span> <span class="n">_localizer</span><span class="p">[</span><span class="s">"&lt;b&gt;Hello&lt;/b&gt;&lt;i&gt; {0}&lt;/i&gt;"</span><span class="p">,</span> <span class="n">name</span><span class="p">];</span>

        <span class="k">return</span> <span class="nf">View</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="view-localization">View Localization</h3>

<p>For the view localization - there is another injectable interface <code class="language-plaintext highlighter-rouge">IViewLocalizer</code>.</p>

<pre><code class="language-razor">@inject IViewLocalizer Localizer

@{
    ViewData["Title"] = Localizer["About"];
}
</code></pre>

<h2 id="alternative-strongly-typed-dblocalizationprovider">Alternative: Strongly-Typed DbLocalizationProvider</h2>

<p>Where is my problem with built-in providers? They all are “stringly-typed”. You have to provide string as either key or translation of the resource. I’m somehow more confident strongly-typed approach where I can use “Find All Usages”, “Rename” or do any other static code operation that’s would not be entirely possible in built-in approach.</p>

<p>Over the time I’ve been busy developing alternative localization provider for Asp.Net and Episerver (it’s brilliant content management system) platforms specifically.</p>

<p>Thought getting that over to Asp.Net Core should not be hard. And it wasn’t. So here we are - <a href="https://github.com/valdisiljuconoks/LocalizationProvider">DbLocalizationProvider</a> for <a href="https://docs.microsoft.com/en-us/aspnet/core/">Asp.Net Core</a>.</p>

<h3 id="getting-started">Getting Started</h3>

<p>There are couple of things to setup first, before you will be able to start using strongly-typed localization provider.</p>

<p>First, you need to install the package (it will pull down other dependencies also).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>PM&gt; Install-Package LocalizationProvider.AspNetCore
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Second you need to setup/configure services.
In your <code class="language-plaintext highlighter-rouge">Startup.cs</code> class you need to stuff related to Mvc localization (to get required services into DI container - service collection).</p>

<p>And then <code class="language-plaintext highlighter-rouge">services.AddDbLocalizationProvider()</code>. You can pass in configuration settings class and setup provider’s behavior.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">Startup</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">Startup</span><span class="p">(</span><span class="n">IConfiguration</span> <span class="n">configuration</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">Configuration</span> <span class="p">=</span> <span class="n">configuration</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">services</span><span class="p">.</span><span class="nf">AddLocalization</span><span class="p">();</span>

        <span class="n">services</span><span class="p">.</span><span class="nf">AddMvc</span><span class="p">()</span>
                <span class="p">.</span><span class="nf">AddViewLocalization</span><span class="p">()</span>
                <span class="p">.</span><span class="nf">AddDataAnnotationsLocalization</span><span class="p">();</span>

        <span class="n">services</span><span class="p">.</span><span class="nf">AddDbLocalizationProvider</span><span class="p">(</span><span class="n">cfg</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="n">cfg</span><span class="p">...</span>
        <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>After then you will need to make sure that you start using the provider:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">Startup</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">Startup</span><span class="p">(</span><span class="n">IConfiguration</span> <span class="n">configuration</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">Configuration</span> <span class="p">=</span> <span class="n">configuration</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="p">...</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Configure</span><span class="p">(</span><span class="n">IApplicationBuilder</span> <span class="n">app</span><span class="p">,</span> <span class="n">IHostingEnvironment</span> <span class="n">env</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="p">...</span>

        <span class="n">app</span><span class="p">.</span><span class="nf">UseDbLocalizationProvider</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Using localization provider will make sure that resources are discovered and registered in the database (if this process will not be disabled via <code class="language-plaintext highlighter-rouge">AddDbLocalizationProvider()</code> method).</p>

<h3 id="app-content-localization-1">App Content Localization</h3>

<p>Localizing application content via <code class="language-plaintext highlighter-rouge">IStringLocalizer&lt;T&gt;</code> is similar as that would be done for regular Asp.Net applications.</p>

<p>You have to define resource container type:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">SampleResources</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">PageHeader</span> <span class="p">=&gt;</span> <span class="s">"This is page header"</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then you can demand <code class="language-plaintext highlighter-rouge">IStringLocalizer&lt;T&gt;</code> is any place you need that one (f.ex. in controller):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">HomeController</span> <span class="p">:</span> <span class="n">Controller</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IStringLocalizer</span><span class="p">&lt;</span><span class="n">SampleResources</span><span class="p">&gt;</span> <span class="n">_localizer</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">HomeController</span><span class="p">(</span><span class="n">IStringLocalizer</span><span class="p">&lt;</span><span class="n">SampleResources</span><span class="p">&gt;</span> <span class="n">localizer</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_localizer</span> <span class="p">=</span> <span class="n">localizer</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">IActionResult</span> <span class="nf">Index</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">smth</span> <span class="p">=</span> <span class="n">_localizer</span><span class="p">.</span><span class="nf">GetString</span><span class="p">(</span><span class="n">r</span> <span class="p">=&gt;</span> <span class="n">r</span><span class="p">.</span><span class="n">PageHeader</span><span class="p">);</span>
        <span class="k">return</span> <span class="nf">View</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As you can see - you are able to use nice strongly-typed access to the resource type: <code class="language-plaintext highlighter-rouge">_localizer.GetString(r =&gt; r.PageHeader);</code>.</p>

<p>Even if you demanded strongly-typed localizer with specified container type <code class="language-plaintext highlighter-rouge">T</code>, it’s possible to use also general/shared static resources:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">SampleResources</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">SomeCommonText</span> <span class="p">=&gt;</span> <span class="s">"Hello World!"</span><span class="p">;</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">PageHeader</span> <span class="p">=&gt;</span> <span class="s">"This is page header"</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">HomeController</span> <span class="p">:</span> <span class="n">Controller</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IStringLocalizer</span><span class="p">&lt;</span><span class="n">SampleResources</span><span class="p">&gt;</span> <span class="n">_localizer</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">HomeController</span><span class="p">(</span><span class="n">IStringLocalizer</span><span class="p">&lt;</span><span class="n">SampleResources</span><span class="p">&gt;</span> <span class="n">localizer</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_localizer</span> <span class="p">=</span> <span class="n">localizer</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">IActionResult</span> <span class="nf">Index</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">smth</span> <span class="p">=</span> <span class="n">_localizer</span><span class="p">.</span><span class="nf">GetString</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="n">SampleResources</span><span class="p">.</span><span class="n">SomeCommonText</span><span class="p">);</span>
        <span class="k">return</span> <span class="nf">View</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="view-localization-1">View Localization</h3>

<p>Regarding the views, story here is exactly the same - all built-in approach is supported:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre>@model UserViewModel
@inject IViewLocalizer Localizer
@inject IHtmlLocalizer&lt;SampleResources&gt; HtmlLocalizer

@Localizer.GetString(() =&gt; SampleResources.SomeCommonText)
@HtmlLocalizer.GetString(r =&gt; r.PageHeader)
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="data-annotations">Data Annotations</h3>

<p>Supported. Sample:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">UserViewModel</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"User name:"</span><span class="p">)]</span>
    <span class="p">[</span><span class="nf">Required</span><span class="p">(</span><span class="n">ErrorMessage</span> <span class="p">=</span> <span class="s">"Name of the user is required!"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">UserName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

    <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"Password:"</span><span class="p">)]</span>
    <span class="p">[</span><span class="nf">Required</span><span class="p">(</span><span class="n">ErrorMessage</span> <span class="p">=</span> <span class="s">"Password is kinda required :)"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Password</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>View.cshtml:</p>

<pre><code class="language-razor">@model UserViewModel

&lt;form asp-controller="Home" asp-action="Index" method="post"&gt;
    &lt;div&gt;
        &lt;label asp-for="UserName"&gt;&lt;/label&gt;
        &lt;input asp-for="UserName"/&gt;
        &lt;span asp-validation-for="UserName"&gt;&lt;/span&gt;
    &lt;/div&gt;
    &lt;div&gt;
        &lt;label asp-for="Password"&gt;&lt;/label&gt;
        &lt;input asp-for="Password" type="password"/&gt;
        &lt;span asp-validation-for="Password"&gt;&lt;/span&gt;
    &lt;/div&gt;
    ...
&lt;/form&gt;

</code></pre>

<h3 id="localization-in-libraries">Localization in Libraries</h3>

<p>You can either rely on <code class="language-plaintext highlighter-rouge">IStringLocalizer</code> implementation that’s coming from <code class="language-plaintext highlighter-rouge">Microsoft.Extensions.Localization</code> namespace and demand that one in your injections:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">using</span> <span class="nn">Microsoft.Extensions.Localization</span><span class="p">;</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">MyService</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">MyService</span><span class="p">(</span><span class="n">IStringLocalizer</span> <span class="n">localizer</span><span class="p">)</span>
    <span class="p">{</span>
       <span class="p">...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Or you can also depend on <code class="language-plaintext highlighter-rouge">LocalizationProvider</code> class defined in <code class="language-plaintext highlighter-rouge">DbLocalizationProvider</code> namespace:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">using</span> <span class="nn">DbLocalizationProvider</span><span class="p">;</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">MyService</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">MyService</span><span class="p">(</span><span class="n">LocalizationProvider</span> <span class="n">provider</span><span class="p">)</span>
    <span class="p">{</span>
       <span class="p">...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Both of these types provide similar functionality in terms how to retrieve localized content.</p>

<h3 id="changing-culture">Changing Culture</h3>

<p>Sometimes you need to get translation for other language and not primary UI one.
This is possible either via built-in method:</p>

<pre><code class="language-razor">@inject IHtmlLocalizer&lt;SampleResources&gt; Localizer

Localizer.WithCulture(new CultureInfo("no"))
         .GetString(() =&gt; SampleResources.SomeCommonText)
</code></pre>

<p>Or via additional extension method:</p>

<pre><code class="language-razor">@inject IHtmlLocalizer&lt;SampleResources&gt; Localizer

Localizer.GetStringByCulture(() =&gt; SampleResources.SomeCommonText, new Culture("no"))
</code></pre>

<h3 id="stringly-typed-localization">Stringly-Typed Localization</h3>

<p>For backward compatibility or even if you wanna go hardcore and supply resource keys manually (for reasons) stingly-typed interface is also supported:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">using</span> <span class="nn">Microsoft.Extensions.Localization</span><span class="p">;</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">MyService</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">MyService</span><span class="p">(</span><span class="n">IStringLocalizer</span> <span class="n">localizer</span><span class="p">)</span>
    <span class="p">{</span>
       <span class="kt">var</span> <span class="n">header</span> <span class="p">=</span> <span class="n">localizer</span><span class="p">[</span><span class="s">"MyProject.Resources.Header"</span><span class="p">];</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="get-more-info">Get More Info</h2>
<p>If you want to know more about <code class="language-plaintext highlighter-rouge">DbLocalizationProvider</code> features and possibilities - good starting point would be <a href="https://github.com/valdisiljuconoks/LocalizationProvider/blob/master/README.md">GitHub docs</a>.</p>

<p>If you do have any issues or trouble setting up, please file an issue in <a href="https://github.com/valdisiljuconoks/LocalizationProvider/issues">GitHub</a>.</p>

<p><br />
Happy localizing!<br />
[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Localization Provider" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization" /><summary type="html"><![CDATA[This is code fragment from official documentation how to localize content using built-in functionality.]]></summary></entry><entry><title type="html">Year in Review</title><link href="https://tech-fellow.eu/2017/12/26/year-in-review/" rel="alternate" type="text/html" title="Year in Review" /><published>2017-12-26T23:30:00+02:00</published><updated>2017-12-26T23:30:00+02:00</updated><id>https://tech-fellow.eu/2017/12/26/year-in-review</id><content type="html" xml:base="https://tech-fellow.eu/2017/12/26/year-in-review/"><![CDATA[<p>This is yet another period of the year when you pause a bit and look back. I’ve been taught to be in the present moment and not to look in the past or try to predict the future, but nonetheless it’s a way to thank you all great people around me.</p>

<p>Episerver has a great ecosystem and great community, I am very thankful to both. Spare time projects is great way to achieve something, to help other fellows and sharpen a bit your own technical and <a href="https://www.amazon.com/Soft-Skills-software-developers-manual/dp/1617292397">soft skills</a>.</p>

<p>This was immense year and I would like to thank couple of people for opportunity and motivation they gave me.</p>

<h2 id="source-for-happiness">Source for Happiness</h2>

<p>can you define what is happiness? I cannot. But I can define what is life fuel and encourage to seek one for yourself as well. It’s a moment when you truly love what you are doing and you can feel purpose of the things you have done and “impact” you have made. I don’t like word “impact”, because it sounds massive. Your actions that influence other people, words and attitude is what I call “impact”. When you have work place that’s basically makes it possible to develop a impactful action plan and implement it, that’s what I call source of happiness. When you love your doings and plans you are able to accomplish, and people with whom you can work together and technologies you would like to try out.
Thank you, <a href="https://www.getadigital.com">Geta Digital</a>.</p>

<h2 id="journey-for-dblocalizationprovider">Journey for DbLocalizationProvider</h2>

<p>When it comes to localization provider, think this was a great year for the package.
It’s been quite busy period over the year and lot of places where I somehow managed to show up and talk about the package, Episerver and <a href="https://en.wikipedia.org/wiki/Dependency_injection">other topics</a>.</p>

<p><img src="/assets/img/2017/12/2017-12-26_20-18-20.png" alt="" /></p>

<p>I would like to thank great people around me without whom that would not be possible (in <code class="language-plaintext highlighter-rouge">&lt;ul&gt;</code> order):</p>

<ul>
  <li>Allan Thræn</li>
  <li>Marija Jemuovic</li>
  <li>Jeroen Stemerdink</li>
  <li>Petri Isola</li>
  <li>Michael Knudsen</li>
  <li>Henrik Fransas</li>
</ul>

<p>And also would like to thank everyone who mailed me with just a message to appreciate effort put into the library. I also thank fellows who create issues on GitHub. It makes it all better and together we can make world a better place.</p>

<h2 id="microsoft--netstandard20">Microsoft &amp; netstandard2.0</h2>

<p>This has been incredible year for Microsoft as well. Launching .Net Standard 2.0 is just an example. Whole new world affects us in one or another way. For the localization provider and other packages this impact made couple of fundamental changes in architecture and mindset in general. Think that Microsoft has learned a lot likewise.
NetStandard affected DbLocalizationProvider architecture as well. I’ve been busy couple last weeks to make it happen on <code class="language-plaintext highlighter-rouge">netstandard2.0</code> and also add support for <code class="language-plaintext highlighter-rouge">netcoreapp2.0</code> target frameworks. This is a topic for other blog post (that’s been in progress at the moment of writing). It’s been interesting journey as well to refactor from bigger repositories pattern down to a small set of commands and queries.</p>

<h2 id="next-year-ahead">Next Year Ahead</h2>

<p>I set first goal for the next year to finish up and publish as soon as possible full support of DbLocalizationProvider for <code class="language-plaintext highlighter-rouge">netcoreapp2.0</code>. This might take a bit longer as initially planned due to fact that admin user interface just screams to be rewritten. As eventually it might be required to support 3 platforms at the same time (Episerver, Asp.Net, Asp.Net Core).</p>

<p>Next closest goal would be to write a review of great book from a great author. <a href="http://blog.cleancoder.com/">Robert Cecil Martin</a> (aka “Uncle Bob”) has some great addition to the industry and latest one is about <a href="https://www.amazon.com/Clean-Architecture-Craftsmans-Software-Structure/dp/0134494164">keeping your architecture clean</a>.</p>

<p>A great source of inspiration is opportunity to meet and greet with people you alike. Next year’s <a href="https://www.episerver.com/about/company/overview/ascend-usa/">Ascend in Las Vegas</a> is something I’ll miss a lot.</p>

<p>I’m holding MVP title for Microsoft as well and decided to meet some old fellows and friends in Seattle instead in annual <a href="https://mvp.microsoft.com/summit">Microsoft MVP Summit</a>.</p>

<p><br />
Happy New Year everyone!!
See you somewhere/somehow around the globe.</p>

<p>[<em>eoy</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Localization Provider" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization" /><category term="year review" /><summary type="html"><![CDATA[This is yet another period of the year when you pause a bit and look back. I’ve been taught to be in the present moment and not to look in the past or try to predict the future, but nonetheless it’s a way to thank you all great people around me.]]></summary></entry><entry><title type="html">Fix Logging in Azure Functions when Reusing Your Component</title><link href="https://tech-fellow.eu/2017/12/12/component-with-ilog-reused-in-azfunc/" rel="alternate" type="text/html" title="Fix Logging in Azure Functions when Reusing Your Component" /><published>2017-12-12T23:30:00+02:00</published><updated>2017-12-12T23:30:00+02:00</updated><id>https://tech-fellow.eu/2017/12/12/component-with-ilog-reused-in-azfunc</id><content type="html" xml:base="https://tech-fellow.eu/2017/12/12/component-with-ilog-reused-in-azfunc/"><![CDATA[<p>There are cases when your project follows hype and you face the case when you need to reuse your component in serverless world. This blog post is about how to fix logging (I picked <code class="language-plaintext highlighter-rouge">Common.Logging</code>, but actual implementation does not matter) when reusing some of your components in Azure Functions.</p>

<h2 id="existing-component">Existing Component</h2>

<p>Most of the time I see that transition to functions or serverless computing is not done by rewriting component that does black magic and delivers business logic, but instead - just referencing it and invoking from function. In this scenario function became as just a hosting environment for the execution of the business logic component.</p>

<p>Let’s say that we do have a component (or even list of components) that demands logging dependency via constructor injection:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="k">using</span> <span class="nn">Common.Logging</span><span class="p">;</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">SomeComponent</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">ILog</span> <span class="n">_logger</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">SomeComponent</span><span class="p">(</span><span class="n">ILog</span> <span class="n">logger</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_logger</span> <span class="p">=</span> <span class="n">logger</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">DoSomeStuff</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">_logger</span><span class="p">.</span><span class="nf">Debug</span><span class="p">(</span><span class="s">"Starting to do some stuff..."</span><span class="p">);</span>
        <span class="p">...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>In order to initialize this component and use it - we need to obtain instance of <code class="language-plaintext highlighter-rouge">ILog</code> from <code class="language-plaintext highlighter-rouge">Common.Logging</code> library. It could be also any other logging library implementation. Let’s jump to function it self and see how we can setup environment properly.</p>

<h2 id="hosting-function">Hosting Function</h2>

<p>Any Azure Function that needs to do some kind of logging can “demand” <code class="language-plaintext highlighter-rouge">TraceWriter</code> to be injected.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="s">"Function1"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">Run</span><span class="p">([</span><span class="nf">TimerTrigger</span><span class="p">(</span><span class="s">"*/5 * * * * *"</span><span class="p">)]</span>
                       <span class="n">TimerInfo</span> <span class="n">myTimer</span><span class="p">,</span>
                       <span class="n">TraceWriter</span> <span class="n">log</span><span class="p">)</span>
<span class="p">{</span>
     <span class="n">log</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">$"C# Timer trigger function executed at: </span><span class="p">{</span><span class="n">DateTime</span><span class="p">.</span><span class="n">UtcNow</span><span class="p">}</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Messages send to <code class="language-plaintext highlighter-rouge">TraceWriter</code> do appear in console (if <a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-host-json#tracing">required levels</a> for the tracing are set).</p>

<p><img src="/assets/img/2017/12/2017-12-11_00-43-45.png" alt="" /></p>

<p>So if I would construct component instance manually - supplied logger would be <code class="language-plaintext highlighter-rouge">NoOpLogger</code> (or similar type) - basically meaning that there is no logger for the component.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">svc</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SomeComponent</span><span class="p">(</span><span class="n">LogManager</span><span class="p">.</span><span class="nf">GetLogger</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">Function1</span><span class="p">)));</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We need to stick together <code class="language-plaintext highlighter-rouge">TraceLogger</code> with <code class="language-plaintext highlighter-rouge">ILog</code> and forward all logging entries to console or file (during runtime).</p>

<h2 id="creating-composition-root">Creating Composition Root</h2>

<p>Here in sample we do have just one component class that demands single dependency to <code class="language-plaintext highlighter-rouge">ILog</code> instance. However in real life there might be much more complex object graphs to compose. There are 2 options when it comes to object composition and dependency injection:</p>

<ul>
  <li>you do everything manually and be happy with <a href="http://blog.ploeh.dk/2014/06/10/pure-di/">pure DI</a></li>
  <li>or you can leverage any object composition library (aka <a href="http://blog.ploeh.dk/2012/11/06/WhentouseaDIContainer/">DI containers</a>)</li>
</ul>

<p>This time we could be lazy and go with composition library (again I picked one from my stack - <a href="http://structuremap.github.io/">StructureMap</a>).</p>

<p>We will need following ingredients:</p>

<ul>
  <li><strong>R</strong>egistration phase - when we instruct container what are our mappings between abstractions and implementations</li>
  <li><strong>R</strong>esolution phase - where we actually will be created requested service and related object graph (aka Composition Root)</li>
  <li><strong>R</strong>elease - where we let it go</li>
</ul>

<p>In my sample - registration is super simple - we just need to map single type and tell container how to obtain <code class="language-plaintext highlighter-rouge">ILog</code> instance.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">static</span> <span class="k">readonly</span> <span class="n">Lazy</span><span class="p">&lt;</span><span class="n">Container</span><span class="p">&gt;</span> <span class="n">_containerBuilder</span> <span class="p">=</span>
    <span class="k">new</span> <span class="n">Lazy</span><span class="p">&lt;</span><span class="n">Container</span><span class="p">&gt;(()</span> <span class="p">=&gt;</span>
        <span class="k">new</span> <span class="nf">Container</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span>
                     <span class="p">{</span>
                         <span class="n">_</span><span class="p">.</span><span class="n">For</span><span class="p">&lt;</span><span class="n">ILog</span><span class="p">&gt;().</span><span class="nf">AlwaysUnique</span><span class="p">()</span>
                          <span class="p">.</span><span class="nf">Use</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span> <span class="n">LogManager</span><span class="p">.</span><span class="nf">GetLogger</span><span class="p">(</span><span class="n">ctx</span><span class="p">.</span><span class="n">ParentType</span><span class="p">));</span>
                     <span class="p">})</span>
        <span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>I’m holding container initialization inside <code class="language-plaintext highlighter-rouge">Lazy&lt;T&gt;</code> here just because I don’t want to pay function startup fee - execute code and initialize container only when it’s needed.</p>

<p>In function “entry point” (<code class="language-plaintext highlighter-rouge">static Run</code> method) we do have access to <code class="language-plaintext highlighter-rouge">TraceWriter</code> instance passed in by the hosting environment. We can make use of it now.</p>

<p>To hide complexity and increase reusability - I moved logic to new <code class="language-plaintext highlighter-rouge">ServiceBuilder</code> class:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">ServiceBuilder</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">ServiceBuilder</span><span class="p">(</span><span class="n">IContainer</span> <span class="n">container</span><span class="p">,</span> <span class="n">TraceWriter</span> <span class="n">log</span><span class="p">)</span>
    <span class="p">{</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">T</span> <span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;()</span>
    <span class="p">{</span>
        <span class="p">...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>In order to maintain any disposable dependencies or more like singleton ones - it’s good idea to create child container for every usage of the container - function run. Meaning that <code class="language-plaintext highlighter-rouge">ServiceBuilder</code> needs to create child container and also implement <code class="language-plaintext highlighter-rouge">IDisposable</code> pattern - to properly release the container.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">ServiceBuilder</span> <span class="p">:</span> <span class="n">IDisposable</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">Lazy</span><span class="p">&lt;</span><span class="n">IContainer</span><span class="p">&gt;</span> <span class="n">_childContainer</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">ServiceBuilder</span><span class="p">(</span><span class="n">IContainer</span> <span class="n">container</span><span class="p">,</span> <span class="n">TraceWriter</span> <span class="n">log</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">container</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">container</span><span class="p">));</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">log</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">log</span><span class="p">));</span>

        <span class="n">_childContainer</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Lazy</span><span class="p">&lt;</span><span class="n">IContainer</span><span class="p">&gt;(</span><span class="n">container</span><span class="p">.</span><span class="n">CreateChildContainer</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Dispose</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="nf">Dispose</span><span class="p">(</span><span class="k">true</span><span class="p">);</span>
        <span class="n">GC</span><span class="p">.</span><span class="nf">SuppressFinalize</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">T</span> <span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;()</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">_childContainer</span><span class="p">.</span><span class="n">Value</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;();</span>
    <span class="p">}</span>

    <span class="k">protected</span> <span class="k">virtual</span> <span class="k">void</span> <span class="nf">Dispose</span><span class="p">(</span><span class="kt">bool</span> <span class="n">disposing</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">disposing</span><span class="p">)</span>
            <span class="n">_childContainer</span><span class="p">?.</span><span class="n">Value</span><span class="p">?.</span><span class="nf">Dispose</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>When you are dealing with disposable objects - it’s good idea to dispose those as well. Meaning that if you create dependency - in this case <code class="language-plaintext highlighter-rouge">ServiceBuilder</code>, as consumer you should but it into <code class="language-plaintext highlighter-rouge">using</code> statement. So this is how it would look in Azure Function now:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="s">"Function1"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">Run</span><span class="p">([</span><span class="nf">TimerTrigger</span><span class="p">(</span><span class="s">"*/5 * * * * *"</span><span class="p">)]</span>
                       <span class="n">TimerInfo</span> <span class="n">myTimer</span><span class="p">,</span>
                       <span class="n">TraceWriter</span> <span class="n">log</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ServiceBuilder</span><span class="p">(</span><span class="n">_containerBuilder</span><span class="p">.</span><span class="n">Value</span><span class="p">,</span> <span class="n">log</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">service</span> <span class="p">=</span> <span class="n">builder</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">SomeComponent</span><span class="p">&gt;();</span>
        <span class="n">service</span><span class="p">.</span><span class="nf">DoSomeStuff</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So all the necessary dependencies for <code class="language-plaintext highlighter-rouge">ServiceBuilder</code> are provided and passed in via constructor.</p>

<h2 id="fix-logging">Fix Logging</h2>

<p>Now - when we have <code class="language-plaintext highlighter-rouge">TraceWriter</code> available from Azure Function host and all services that will be used during function execution will be created via <code class="language-plaintext highlighter-rouge">ServiceBuilder</code> - we can fix logging and make it to use <code class="language-plaintext highlighter-rouge">TraceWriter</code> to output messages sent to <code class="language-plaintext highlighter-rouge">Common.Logging</code> library to be visible in console (if running locally) or function log files (during normal runtime).</p>

<p>For this happen we will need adapter (or actually factory) for the <code class="language-plaintext highlighter-rouge">Common.Logging</code> to create logger via that.</p>

<p>This is new constructor of <code class="language-plaintext highlighter-rouge">ServiceBuilder</code> now (here is only important line of code):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="nf">ServiceBuilder</span><span class="p">(</span><span class="n">IContainer</span> <span class="n">container</span><span class="p">,</span> <span class="n">TraceWriter</span> <span class="n">log</span><span class="p">)</span>
<span class="p">{</span>
    <span class="p">...</span>
    <span class="n">LogManager</span><span class="p">.</span><span class="n">Adapter</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">TraceWriterLoggerFactory</span><span class="p">(</span><span class="n">log</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And <code class="language-plaintext highlighter-rouge">TraceWriterLoggerFactory</code> is simple factory pattern class which is able to construct new loggers with passed in <code class="language-plaintext highlighter-rouge">TraceWriter</code> as final output.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">TraceWriterLoggerFactory</span> <span class="p">:</span> <span class="n">ILoggerFactoryAdapter</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">TraceWriter</span> <span class="n">_log</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">TraceWriterLoggerFactory</span><span class="p">(</span><span class="n">TraceWriter</span> <span class="n">log</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_log</span> <span class="p">=</span> <span class="n">log</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">ILog</span> <span class="nf">GetLogger</span><span class="p">(</span><span class="n">Type</span> <span class="n">type</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="nf">GetLogger</span><span class="p">(</span><span class="n">type</span><span class="p">.</span><span class="n">Name</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">ILog</span> <span class="nf">GetLogger</span><span class="p">(</span><span class="kt">string</span> <span class="n">key</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="k">new</span> <span class="nf">LoggerTraceWriterAdapter</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">_log</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And <code class="language-plaintext highlighter-rouge">LoggerTraceWriterAdapter</code> adapter itself is just a class that implements <code class="language-plaintext highlighter-rouge">ILog</code> interface and has A LOT of methods to write all severity messages to the output writer.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">LoggerTraceWriterAdapter</span> <span class="p">:</span> <span class="n">ILog</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="kt">string</span> <span class="n">_parentType</span><span class="p">;</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">TraceWriter</span> <span class="n">_actualLogger</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">LoggerTraceWriterAdapter</span><span class="p">(</span><span class="kt">string</span> <span class="n">parentType</span><span class="p">,</span> <span class="n">TraceWriter</span> <span class="n">actualLogger</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_parentType</span> <span class="p">=</span> <span class="n">parentType</span><span class="p">;</span>
        <span class="n">_actualLogger</span> <span class="p">=</span> <span class="n">actualLogger</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Info</span><span class="p">(</span><span class="kt">object</span> <span class="n">message</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_actualLogger</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">$"INFO </span><span class="p">{</span><span class="n">_parentType</span><span class="p">}</span><span class="s">: </span><span class="p">{</span><span class="n">message</span><span class="p">}</span><span class="s">"</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Info</span><span class="p">(</span><span class="kt">object</span> <span class="n">message</span><span class="p">,</span> <span class="n">Exception</span> <span class="n">exception</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_actualLogger</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">$"INFO </span><span class="p">{</span><span class="n">_parentType</span><span class="p">}</span><span class="s">: </span><span class="p">{</span><span class="n">message</span><span class="p">}</span><span class="s">. Exception: </span><span class="p">{</span><span class="n">exception</span><span class="p">}</span><span class="s">"</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="p">...</span>

<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="missing-features">Missing Features</h2>

<p>Using this approach there are couple of missing features as well:</p>

<ul>
  <li>at the moment there us no way to configure output format of the message (similar as you have seen probably in <code class="language-plaintext highlighter-rouge">log4net</code> config files)</li>
  <li>there is no way to configure severity levels for specific <code class="language-plaintext highlighter-rouge">ILog</code> instance (but this is possible via <code class="language-plaintext highlighter-rouge">tracing</code> element in <code class="language-plaintext highlighter-rouge">host.json</code> file).</li>
  <li>it’s not possible to configure rolling strategy for log files (but looking at Azure Function machine file system via <a href="https://github.com/projectkudu/kudu/wiki/Kudu-console">Kudu console</a> seems like log file rolling strategy is already in place)</li>
</ul>

<h2 id="summary">Summary</h2>

<p>Anyway regardless of missing features, this approach gave us opportunity to “redirect” <code class="language-plaintext highlighter-rouge">ILog</code> messages from <code class="language-plaintext highlighter-rouge">Common.Logging</code> library (which was used all over the place in our components) to leverage <code class="language-plaintext highlighter-rouge">TraceWriter</code> from Azure Functions host without rewriting any line of our components.
And also gave us possibility to unify our service composition and object graph creation. Now all necessary injections and “preparation” work is done in <code class="language-plaintext highlighter-rouge">Service Builder</code> instead of each function itself.</p>

<p>Happy logging!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Logging" /><category term="Azure Functions" /><category term=".net" /><category term="c#" /><category term="logging" /><category term="azure functions" /><summary type="html"><![CDATA[There are cases when your project follows hype and you face the case when you need to reuse your component in serverless world. This blog post is about how to fix logging (I picked Common.Logging, but actual implementation does not matter) when reusing some of your components in Azure Functions.]]></summary></entry><entry><title type="html">Episerverless = Episerver + Azure Functions</title><link href="https://tech-fellow.eu/2017/11/21/episerver-azure-functions-episerverless/" rel="alternate" type="text/html" title="Episerverless = Episerver + Azure Functions" /><published>2017-11-21T15:30:00+02:00</published><updated>2017-11-21T15:30:00+02:00</updated><id>https://tech-fellow.eu/2017/11/21/episerver-azure-functions-episerverless</id><content type="html" xml:base="https://tech-fellow.eu/2017/11/21/episerver-azure-functions-episerverless/"><![CDATA[<p>I did talk about this topic couple times solo, and also together with <a href="https://world.episerver.com/System/Users-and-profiles/Community-Profile-Card/?userid=9127cdd8-f26f-dc11-8e6c-0018717a8c82">Henrik Fransas</a> in Episerver Partner Close-up in Stockholm this year. Received lot of questions regarding source code availability and also about recordings of the session(s). Unfortunately there are no recordings of the conferences I/we were. So I decided just compile together a blog post.</p>

<h2 id="objective">Objective</h2>

<p>Idea for the conference talk(s) was to show how you can integrate Azure Functions with Episerver and how that nicely plays together.
There are zillions problems to solve with Azure Functions and also zillions of ways of doing that. However, I’ve chosen pretty straight forward problem to show how you can leverage cloud services and how to integrate those into Episerver solutions.</p>

<p><em>Problem description</em>: we are building hacker-ish style website where images are not images, but instead converted to <a href="https://en.wikipedia.org/wiki/ASCII_art">ASCII art</a> green on black background. However challenge is with editors - they are quite lazy and almost always refuse to write description of the images. Also, there has been couple of incidents when editors are uploading inappropriate content images. In these cases - administrator of the website has to be notified (notification transport channel is no important - or may change in the future).</p>

<p>For me, as one of the developers of the website, this seems to be perfect candidate for tryout of the Azure Functions and some other cloud services.</p>

<p>So let’s start with laying out components and solution architecture for this fictive website.</p>

<h2 id="solution-architecture">Solution Architecture</h2>

<p>There are 2 main players in the solution: website and cloud services. Website will act as consumer of the cloud services. Azure Functions are ideal candidate for delivering this functionality. Also Azure Cognitive Services will be good stuff when it comes to processing and analysis of images. Notification delivery will be done via Twilio service (which by the way has <a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-twilio">native support</a> in Azure Functions).</p>

<p>Following functionality could be split into separate functions (remember that function has to do only single thing and not more).</p>

<ul>
  <li><em>Functionality 1</em> - this could be as entrance gate for whole functionality. This component will be responsible for retrieving requests for ASCII art convert and image analysis</li>
  <li><em>Functionality 2</em> - this component will be responsible for asking Azure Cognitive Services to analyze image and describe it.</li>
  <li><em>Functionality 3</em> - Third link in the chain would be responsible for actually converting image to ASCII art. If we would convert image to ASCII art and then run vision analysis - most probably results would not be very intelligent.</li>
  <li><em>Functionality 4</em> - Here we could slide in service responsible for analyzing image for inappropriate content (content moderation as they call it).</li>
  <li><em>Functionality 5</em> - if somebody uploaded inadequate image (decision made by Function4) this service would make it possible to send actual notification to the administrator.</li>
</ul>

<p>Let’s try to draw architecture for our imagined solution:</p>

<p><img src="/assets/img/2017/11/overall-1.png" alt="" /></p>

<p>As you can see - inter-function communication is done either via <strong>ServiceBus</strong> or <strong>Storage Queues</strong>. These are most easiest communication channels to use to “stick” together Azure Functions.</p>

<p>ServiceBus topic functionality between function 1 and functions 2 &amp; 4 is necessary because there are multiple “consumers” of the same “signal” - that image has been uploaded for the processing. If using Storage queues there is only single “consumer” of the queue item. Once it’s handled - message disappears from the queue - making it impossible for the other function to pick it up and do stuff also. Therefore most appropriate communication mechanism here would be to use durable pub/sub - Azure ServiceBus topics.</p>

<p>For the content moderator cognitive services (to evaluate content) you will need <a href="https://contentmoderator.cognitive.microsoft.com/">signup here</a>.</p>

<h2 id="detailed-description">Detailed Description</h2>

<p>Below is more detailed description of each of the functions and related components.</p>

<h3 id="function1---accept">Function1 - Accept</h3>

<p>First function is acting as facade service for the whole image analysis and processing pipeline. Main purpose (and the only one) for this function is to capture incoming request for the image processing, “register” request and return status code to the caller. Registering request in this context means to create an item in ServiceBus topic. Topic here is required because there will be more than single consumer of the item - Function2 (proceeding with vision analysis of the image) and Function4 (proceeding with content review analysis of the image).</p>

<p>Upload (or call) of the Function1 from the Episerver is straight forward. We subscribe to media upload event in Episerver and then post image <code class="language-plaintext highlighter-rouge">byte[]</code> to the Azure Function (I know about <code class="language-plaintext highlighter-rouge">ServiceLocator</code> - I’ve been active <a href="http://www.episerver.se/events--rapporter/event/evenemangslista/episerver-partner-close-up-2017/epi-partner-close-up-20172/agenda/agenda-utvecklarspar/">preaching to avoid this</a>, but there are cases when it’s not entirely possible just because of the underlying framework).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">EventHandlerInitModule</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="n">IAsciiArtUploader</span> <span class="n">_uploader</span><span class="p">;</span>
    <span class="k">private</span> <span class="n">UrlHelper</span> <span class="n">_urlHelper</span><span class="p">;</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">canon</span> <span class="p">=</span> <span class="n">ServiceLocator</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">IContentEvents</span><span class="p">&gt;();</span>
        <span class="n">_uploader</span> <span class="p">=</span> <span class="n">ServiceLocator</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">IAsciiArtUploader</span><span class="p">&gt;();</span>
        <span class="n">_urlHelper</span> <span class="p">=</span> <span class="n">ServiceLocator</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">UrlHelper</span><span class="p">&gt;();</span>

        <span class="n">canon</span><span class="p">.</span><span class="n">CreatedContent</span> <span class="p">+=</span> <span class="n">OnImageCreated</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">canon</span> <span class="p">=</span> <span class="n">ServiceLocator</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">IContentEvents</span><span class="p">&gt;();</span>
        <span class="n">canon</span><span class="p">.</span><span class="n">CreatedContent</span> <span class="p">-=</span> <span class="n">OnImageCreated</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="k">void</span> <span class="nf">OnImageCreated</span><span class="p">(</span><span class="kt">object</span> <span class="n">sender</span><span class="p">,</span> <span class="n">ContentEventArgs</span> <span class="n">args</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(!(</span><span class="n">args</span><span class="p">.</span><span class="n">Content</span> <span class="k">is</span> <span class="n">ImageData</span> <span class="n">img</span><span class="p">))</span>
            <span class="k">return</span><span class="p">;</span>

        <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">stream</span> <span class="p">=</span> <span class="n">img</span><span class="p">.</span><span class="n">BinaryData</span><span class="p">.</span><span class="nf">OpenRead</span><span class="p">())</span>
        <span class="p">{</span>
            <span class="kt">var</span> <span class="n">bytes</span> <span class="p">=</span> <span class="n">stream</span><span class="p">.</span><span class="nf">ReadAllBytes</span><span class="p">();</span>
            <span class="n">_uploader</span><span class="p">.</span><span class="nf">Upload</span><span class="p">(</span><span class="n">img</span><span class="p">.</span><span class="n">ContentGuid</span><span class="p">.</span><span class="nf">ToString</span><span class="p">(),</span>
                             <span class="n">bytes</span><span class="p">,</span>
                             <span class="n">_urlHelper</span><span class="p">.</span><span class="nf">ContentUrl</span><span class="p">(</span><span class="n">img</span><span class="p">.</span><span class="n">ContentLink</span><span class="p">));</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>There is also a small helper class that’s dealing with physical file upload:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</pre></td><td class="rouge-code"><pre><span class="k">internal</span> <span class="k">class</span> <span class="nc">AsciiArtUploader</span> <span class="p">:</span> <span class="n">IAsciiArtUploader</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IAsciiArtServiceSettingsProvider</span> <span class="n">_settings</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">AsciiArtUploader</span><span class="p">(</span><span class="n">IAsciiArtServiceSettingsProvider</span> <span class="n">settings</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_settings</span> <span class="p">=</span> <span class="n">settings</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Upload</span><span class="p">(</span><span class="kt">string</span> <span class="n">fileId</span><span class="p">,</span> <span class="kt">byte</span><span class="p">[]</span> <span class="n">bytes</span><span class="p">,</span> <span class="kt">string</span> <span class="n">imageUrl</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">AsyncHelper</span><span class="p">.</span><span class="nf">RunSync</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="nf">CallFunctionAsync</span><span class="p">(</span><span class="n">fileId</span><span class="p">,</span> <span class="n">bytes</span><span class="p">,</span> <span class="n">imageUrl</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;</span> <span class="nf">CallFunctionAsync</span><span class="p">(</span><span class="kt">string</span> <span class="n">contentReference</span><span class="p">,</span>
        <span class="kt">byte</span><span class="p">[]</span> <span class="n">byteData</span><span class="p">,</span>
        <span class="kt">string</span> <span class="n">imageUrl</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">req</span> <span class="p">=</span> <span class="k">new</span> <span class="n">ProcessingRequest</span>
        <span class="p">{</span>
            <span class="n">FileId</span> <span class="p">=</span> <span class="n">contentReference</span><span class="p">,</span>
            <span class="n">Content</span> <span class="p">=</span> <span class="n">byteData</span><span class="p">,</span>
            <span class="n">Width</span> <span class="p">=</span> <span class="m">150</span><span class="p">,</span>
            <span class="n">ImageUrl</span> <span class="p">=</span> <span class="n">imageUrl</span>
        <span class="p">};</span>

        <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">content</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">StringContent</span><span class="p">(</span><span class="n">JsonConvert</span><span class="p">.</span><span class="nf">SerializeObject</span><span class="p">(</span><span class="n">req</span><span class="p">)))</span>
        <span class="p">{</span>
            <span class="n">content</span><span class="p">.</span><span class="n">Headers</span><span class="p">.</span><span class="n">ContentType</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">MediaTypeHeaderValue</span><span class="p">(</span><span class="s">"application/json"</span><span class="p">);</span>
            <span class="kt">var</span> <span class="n">response</span> <span class="p">=</span> <span class="k">await</span>
                <span class="n">Global</span><span class="p">.</span><span class="n">HttpClient</span><span class="p">.</span><span class="n">Value</span><span class="p">.</span><span class="nf">PostAsync</span><span class="p">(</span>
                    <span class="n">_settings</span><span class="p">.</span><span class="n">Settings</span><span class="p">.</span><span class="n">RequestFunctionUri</span><span class="p">,</span>
                    <span class="n">content</span><span class="p">).</span><span class="nf">ConfigureAwait</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>

            <span class="k">return</span> <span class="k">await</span> <span class="n">response</span><span class="p">.</span><span class="n">Content</span><span class="p">.</span><span class="nf">ReadAsStringAsync</span><span class="p">()</span>
                                         <span class="p">.</span><span class="nf">ConfigureAwait</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Class <code class="language-plaintext highlighter-rouge">IAsciiArtServiceSettingsProvider</code> is just another small helper class that’s providing various settings as it’s not quite good idea to hard-code URL to the functions or any other “dynamic” part of the required settings for the component.</p>

<p>Also, as Episerver event handler is invoked in a sync method, but we need to invoke image upload via async rest client (<code class="language-plaintext highlighter-rouge">HttpClient</code>) we need to do some black async magic:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
</pre></td><td class="rouge-code"><pre><span class="c1">/// &lt;summary&gt;</span>
<span class="c1">/// Credits:</span>
<span class="c1">/// http://stackoverflow.com/questions/9343594/how-to-call-asynchronous-method-from-synchronous-method-in-c</span>
<span class="c1">/// &lt;/summary&gt;</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">AsyncHelper</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">static</span> <span class="k">readonly</span> <span class="n">TaskFactory</span> <span class="n">MyTaskFactory</span> <span class="p">=</span>
        <span class="k">new</span> <span class="nf">TaskFactory</span><span class="p">(</span><span class="n">CancellationToken</span><span class="p">.</span><span class="n">None</span><span class="p">,</span>
            <span class="n">TaskCreationOptions</span><span class="p">.</span><span class="n">None</span><span class="p">,</span>
            <span class="n">TaskContinuationOptions</span><span class="p">.</span><span class="n">None</span><span class="p">,</span>
            <span class="n">TaskScheduler</span><span class="p">.</span><span class="n">Default</span><span class="p">);</span>

    <span class="k">public</span> <span class="k">static</span> <span class="n">TResult</span> <span class="n">RunSync</span><span class="p">&lt;</span><span class="n">TResult</span><span class="p">&gt;(</span><span class="n">Func</span><span class="p">&lt;</span><span class="n">Task</span><span class="p">&lt;</span><span class="n">TResult</span><span class="p">&gt;&gt;</span> <span class="n">func</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">MyTaskFactory</span><span class="p">.</span><span class="nf">StartNew</span><span class="p">(</span><span class="n">func</span><span class="p">)</span>
            <span class="p">.</span><span class="nf">Unwrap</span><span class="p">()</span>
            <span class="p">.</span><span class="nf">GetAwaiter</span><span class="p">()</span>
            <span class="p">.</span><span class="nf">GetResult</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">RunSync</span><span class="p">(</span><span class="n">Func</span><span class="p">&lt;</span><span class="n">Task</span><span class="p">&gt;</span> <span class="n">func</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">MyTaskFactory</span><span class="p">.</span><span class="nf">StartNew</span><span class="p">(</span><span class="n">func</span><span class="p">)</span>
            <span class="p">.</span><span class="nf">Unwrap</span><span class="p">()</span>
            <span class="p">.</span><span class="nf">GetAwaiter</span><span class="p">()</span>
            <span class="p">.</span><span class="nf">GetResult</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Note!</strong> That you might be using <code class="language-plaintext highlighter-rouge">HttpClient</code> <a href="https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/">in a wrong way</a>.</p>

<p>Interaction from the Episerver website to function in our architecture diagram is this particular fragment:</p>

<p><img src="/assets/img/2017/11/f1-1.png" alt="" /></p>

<p>Also function definition is not hard to grasp - the only purpose for the function to exist is to register incoming requests for the image processing, save it to the topic and return Http status code with the reference to saved item.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">StorageAccount</span><span class="p">(</span><span class="s">"my-storage-connection"</span><span class="p">)]</span>
<span class="p">[</span><span class="nf">ServiceBusAccount</span><span class="p">(</span><span class="s">"my-servicebus-connection"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">Function1</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="s">"Function1"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">static</span> <span class="n">HttpResponseMessage</span> <span class="nf">Run</span><span class="p">(</span>
        <span class="p">[</span><span class="nf">HttpTrigger</span><span class="p">(</span><span class="n">AuthorizationLevel</span><span class="p">.</span><span class="n">Anonymous</span><span class="p">,</span> <span class="s">"post"</span><span class="p">)]</span> <span class="n">ProcessingRequest</span> <span class="n">request</span><span class="p">,</span>
        <span class="p">[</span><span class="nf">Blob</span><span class="p">(</span><span class="s">"%input-container%/{FileId}"</span><span class="p">)]</span>                <span class="n">CloudBlockBlob</span> <span class="n">outBlob</span><span class="p">,</span>
                                                            <span class="n">TraceWriter</span> <span class="n">log</span><span class="p">,</span>
        <span class="p">[</span><span class="nf">ServiceBus</span><span class="p">(</span><span class="s">"mytopic"</span><span class="p">,</span> <span class="n">AccessRights</span><span class="p">.</span><span class="n">Manage</span><span class="p">)]</span>        <span class="k">out</span> <span class="n">BrokeredMessage</span> <span class="n">topicMessage</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">log</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">"(Fun1) Received image for processing..."</span><span class="p">);</span>

        <span class="n">AsyncHelper</span><span class="p">.</span><span class="nf">RunSync</span><span class="p">(</span><span class="k">async</span> <span class="p">()</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="k">await</span> <span class="n">outBlob</span><span class="p">.</span><span class="nf">UploadFromByteArrayAsync</span><span class="p">(</span><span class="n">request</span><span class="p">.</span><span class="n">Content</span><span class="p">,</span>
                                                   <span class="m">0</span><span class="p">,</span>
                                                   <span class="n">request</span><span class="p">.</span><span class="n">Content</span><span class="p">.</span><span class="n">Length</span><span class="p">);</span>
        <span class="p">});</span>

        <span class="kt">var</span> <span class="n">analysisRequest</span> <span class="p">=</span> <span class="k">new</span> <span class="n">AnalysisReq</span>
        <span class="p">{</span>
            <span class="n">BlobRef</span> <span class="p">=</span> <span class="n">outBlob</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span>
            <span class="n">Width</span> <span class="p">=</span> <span class="n">request</span><span class="p">.</span><span class="n">Width</span><span class="p">,</span>
            <span class="n">ImageUrl</span> <span class="p">=</span> <span class="n">request</span><span class="p">.</span><span class="n">ImageUrl</span>
        <span class="p">};</span>

        <span class="n">topicMessage</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">BrokeredMessage</span><span class="p">(</span><span class="n">analysisRequest</span><span class="p">);</span>

        <span class="k">return</span> <span class="k">new</span> <span class="nf">HttpResponseMessage</span><span class="p">(</span><span class="n">HttpStatusCode</span><span class="p">.</span><span class="n">OK</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">Content</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">StringContent</span><span class="p">(</span><span class="n">outBlob</span><span class="p">.</span><span class="n">Name</span><span class="p">)</span>
        <span class="p">};</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As you can see, creating functions with <a href="https://blogs.msdn.microsoft.com/webdev/2017/05/10/azure-function-tools-for-visual-studio-2017/">Visual Studio Azure Functions</a> templates might a bit verbose time to time. There has to be a lot of ceremony with <code class="language-plaintext highlighter-rouge">Attribute</code> classes all over the place, but somehow template engine needs to understand what kind of bindings you have for your functions and generate appropriate <code class="language-plaintext highlighter-rouge">function.json</code> <a href="https://github.com/Azure/azure-webjobs-sdk-script/wiki/function.json">file</a> at the end. Of course, there is also an option to create (and maintain) this file manually, but I prefer tooling for that.
Basically function decorations tells following:</p>

<ul>
  <li>it’s <code class="language-plaintext highlighter-rouge">HttpTrigger</code>ed function - meaning that this function is just sitting there and waiting for incoming requests. For the demo purposes this function is not authorized - so anyone can post anything, but in real-life you should definitely secure your functions <a href="https://github.com/Azure/azure-webjobs-sdk-script/wiki/Http-Functions#authentication-and-authorization">with invoke keys</a></li>
  <li>it has connection strings to storage (<code class="language-plaintext highlighter-rouge">[StorageAccount]</code>) and servicebus (<code class="language-plaintext highlighter-rouge">[ServiceBusAccount]</code>) accounts</li>
  <li>it also has a reference to Storage Blob container (well, just because image itself might not be able to store in topic item)</li>
  <li>and an output of the function <code class="language-plaintext highlighter-rouge">BrokeredMessage</code> will be produced (<code class="language-plaintext highlighter-rouge">out</code> parameter) - this will be stored in ServiceBus topic</li>
  <li>and as result of the function call <code class="language-plaintext highlighter-rouge">HttpResponseMessage</code> will be returned to the caller</li>
</ul>

<p>Interesting to note here is <code class="language-plaintext highlighter-rouge">[Blob("%input-container%/{FileId}")] CloudBlockBlob outBlob</code> argument.
If we look at incoming Http trigger parameter <code class="language-plaintext highlighter-rouge">ProcessingRequest</code> (body of the request):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre> <span class="k">public</span> <span class="k">class</span> <span class="nc">ProcessingRequest</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">ProcessingRequest</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">Width</span> <span class="p">=</span> <span class="m">100</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="kt">string</span> <span class="n">FileId</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">ImageUrl</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">int</span> <span class="n">Width</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">byte</span><span class="p">[]</span> <span class="n">Content</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>From the <code class="language-plaintext highlighter-rouge">Blob</code> attribute argument you can read is as following:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">%input-container%</code> - this is reference to the environment variables. You can reference also values from <code class="language-plaintext highlighter-rouge">settings.json</code> file as environment variables:</li>
</ul>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="p">{</span><span class="w">
  </span><span class="nl">"Values"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="err">...</span><span class="w">
    </span><span class="nl">"input-container"</span><span class="p">:</span><span class="w"> </span><span class="s2">"in-container"</span><span class="p">,</span><span class="w">
    </span><span class="err">...</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>However <code class="language-plaintext highlighter-rouge">{FileId}</code> argument is a reference to the property with the same name in incoming request (class <code class="language-plaintext highlighter-rouge">ProcessingRequest</code>). This technique is very nice and flexible. If you look at how request object was filled up in Episerver - it’s content <code class="language-plaintext highlighter-rouge">Guid</code> of media file in Episerver:</li>
</ul>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">void</span> <span class="nf">OnImageCreated</span><span class="p">(</span><span class="kt">object</span> <span class="n">sender</span><span class="p">,</span> <span class="n">ContentEventArgs</span> <span class="n">args</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">if</span> <span class="p">(!(</span><span class="n">args</span><span class="p">.</span><span class="n">Content</span> <span class="k">is</span> <span class="n">ImageData</span> <span class="n">img</span><span class="p">))</span>
        <span class="k">return</span><span class="p">;</span>

    <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">stream</span> <span class="p">=</span> <span class="n">img</span><span class="p">.</span><span class="n">BinaryData</span><span class="p">.</span><span class="nf">OpenRead</span><span class="p">())</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">bytes</span> <span class="p">=</span> <span class="n">stream</span><span class="p">.</span><span class="nf">ReadAllBytes</span><span class="p">();</span>
        <span class="n">_uploader</span><span class="p">.</span><span class="nf">Upload</span><span class="p">(</span><span class="n">img</span><span class="p">.</span><span class="n">ContentGuid</span><span class="p">.</span><span class="nf">ToString</span><span class="p">(),</span>
                         <span class="n">bytes</span><span class="p">,</span>
                         <span class="n">_urlHelper</span><span class="p">.</span><span class="nf">ContentUrl</span><span class="p">(</span><span class="n">img</span><span class="p">.</span><span class="n">ContentLink</span><span class="p">));</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>In order for this function to operate there has to be a variable with name <code class="language-plaintext highlighter-rouge">my-servicebus-connection</code> in <code class="language-plaintext highlighter-rouge">settings.json</code> (or <code class="language-plaintext highlighter-rouge">local.settings.json</code> file if you are running locally) that’s pointing to Azure ServicieBus service. And you will need to create new topic named <code class="language-plaintext highlighter-rouge">mytopic</code> (or whatever name you choose - just need to match one in decoration of the Function1).</p>

<p><img src="/assets/img/2017/11/sb-topic.png" alt="" /></p>

<h3 id="function2---analysis">Function2 - Analysis</h3>

<p>Once incoming request has been accepted and saved in ServiceBus topic - it could processed in parallel - one branch for vision analysis and ASCII art convert, another - for content review.</p>

<p><img src="/assets/img/2017/11/f1-f2-f4.png" alt="" /></p>

<p>Function2 is doing vision analysis of the image using Azure Cognitive Services. I was surprised how easy and elegant consumption of these state-of-art services are:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">StorageAccount</span><span class="p">(</span><span class="s">"my-storage-connection"</span><span class="p">)]</span>
<span class="p">[</span><span class="nf">ServiceBusAccount</span><span class="p">(</span><span class="s">"my-servicebus-connection"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">Function2</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="s">"Function2"</span><span class="p">)]</span>
    <span class="p">[</span><span class="k">return</span><span class="p">:</span> <span class="nf">Queue</span><span class="p">(</span><span class="s">"to-ascii-conversion"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">CloudQueueMessage</span><span class="p">&gt;</span> <span class="nf">Run</span><span class="p">(</span>
        <span class="p">[</span><span class="nf">ServiceBusTrigger</span><span class="p">(</span><span class="s">"mytopic"</span><span class="p">,</span> <span class="s">"to-ascii"</span><span class="p">,</span> <span class="n">AccessRights</span><span class="p">.</span><span class="n">Manage</span><span class="p">)]</span> <span class="n">AnalysisReq</span> <span class="n">request</span><span class="p">,</span>
        <span class="p">[</span><span class="nf">Blob</span><span class="p">(</span><span class="s">"%input-container%/{BlobRef}"</span><span class="p">,</span> <span class="n">FileAccess</span><span class="p">.</span><span class="n">Read</span><span class="p">)]</span>          <span class="n">Stream</span> <span class="n">inBlob</span><span class="p">,</span>
                                                                        <span class="n">TraceWriter</span> <span class="n">log</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">log</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">"(Fun2) Running image analysis..."</span><span class="p">);</span>

        <span class="kt">var</span> <span class="n">subscriptionKey</span> <span class="p">=</span> <span class="n">ConfigurationManager</span><span class="p">.</span><span class="n">AppSettings</span><span class="p">[</span><span class="s">"cognitive-services-key"</span><span class="p">];</span>
        <span class="kt">var</span> <span class="n">serviceUri</span> <span class="p">=</span> <span class="n">ConfigurationManager</span><span class="p">.</span><span class="n">AppSettings</span><span class="p">[</span><span class="s">"cognitive-services-uri"</span><span class="p">];</span>
        <span class="kt">var</span> <span class="n">client</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">VisionServiceClient</span><span class="p">(</span><span class="n">subscriptionKey</span><span class="p">,</span> <span class="n">serviceUri</span><span class="p">);</span>

        <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="k">await</span> <span class="n">client</span><span class="p">.</span><span class="nf">AnalyzeImageAsync</span><span class="p">(</span><span class="n">inBlob</span><span class="p">,</span>
                                                    <span class="k">new</span><span class="p">[]</span>
                                                    <span class="p">{</span>
                                                        <span class="n">VisualFeature</span><span class="p">.</span><span class="n">Categories</span><span class="p">,</span>
                                                        <span class="n">VisualFeature</span><span class="p">.</span><span class="n">Color</span><span class="p">,</span>
                                                        <span class="n">VisualFeature</span><span class="p">.</span><span class="n">Description</span><span class="p">,</span>
                                                        <span class="n">VisualFeature</span><span class="p">.</span><span class="n">Faces</span><span class="p">,</span>
                                                        <span class="n">VisualFeature</span><span class="p">.</span><span class="n">ImageType</span><span class="p">,</span>
                                                        <span class="n">VisualFeature</span><span class="p">.</span><span class="n">Tags</span>
                                                    <span class="p">});</span>

        <span class="kt">var</span> <span class="n">asciiArtRequest</span> <span class="p">=</span> <span class="k">new</span> <span class="n">AsciiArtRequest</span>
                              <span class="p">{</span>
                                  <span class="n">BlobRef</span> <span class="p">=</span> <span class="n">request</span><span class="p">.</span><span class="n">BlobRef</span><span class="p">,</span>
                                  <span class="n">Width</span> <span class="p">=</span> <span class="n">request</span><span class="p">.</span><span class="n">Width</span><span class="p">,</span>
                                  <span class="n">Description</span> <span class="p">=</span> <span class="kt">string</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="s">","</span><span class="p">,</span> <span class="n">result</span><span class="p">.</span><span class="n">Description</span><span class="p">.</span><span class="n">Captions</span><span class="p">.</span><span class="nf">Select</span><span class="p">(</span><span class="n">c</span> <span class="p">=&gt;</span> <span class="n">c</span><span class="p">.</span><span class="n">Text</span><span class="p">)),</span>
                                  <span class="n">Tags</span> <span class="p">=</span> <span class="n">result</span><span class="p">.</span><span class="n">Tags</span><span class="p">.</span><span class="nf">Select</span><span class="p">(</span><span class="n">t</span> <span class="p">=&gt;</span> <span class="n">t</span><span class="p">.</span><span class="n">Name</span><span class="p">).</span><span class="nf">ToArray</span><span class="p">()</span>
                              <span class="p">};</span>

        <span class="n">log</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">"(Fun2) Finished image analysis."</span><span class="p">);</span>

        <span class="k">return</span> <span class="n">asciiArtRequest</span><span class="p">.</span><span class="nf">AsQueueItem</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So what we can read form the function decorations:</p>

<ul>
  <li>again Function2 needs access to Storage and ServiceBus (to read incoming topic message) services</li>
  <li>trigger of the function is item in the topic (via <code class="language-plaintext highlighter-rouge">[ServiceBusTrigger]</code> attribute)</li>
  <li>also in the same way as Function1 - it’s possible to get reference to Blob block to retrieve actual <code class="language-plaintext highlighter-rouge">byte[]</code> for the image (with help of <code class="language-plaintext highlighter-rouge">[Blob("...")]</code> attribute)</li>
  <li>return of the function is item in the Storage queue (<code class="language-plaintext highlighter-rouge">return</code> value of the function will be used). Decoration <code class="language-plaintext highlighter-rouge">[return: Queue("...")]</code> tells Visual Studio Azure Functions tooling to generate binding for the return value of the function to post to queue named <code class="language-plaintext highlighter-rouge">to-ascii-conversion</code> in storage configured under <code class="language-plaintext highlighter-rouge">my-storage-connection</code> variable (in <code class="language-plaintext highlighter-rouge">settings.json</code> file). This is will be trigger for Function3.</li>
</ul>

<p>To work with Azure Cognitive Services you will need to install ProjectOxford package:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>PM&gt; install-package Microsoft.ProjectOxford.Vision
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Actual invocation of the Cognitive Services is easy:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="k">await</span> <span class="n">client</span><span class="p">.</span><span class="nf">AnalyzeImageAsync</span><span class="p">(...);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So having captured all available data from Cognitive Services we take those and combine together within next request for the ASCII art. I find this more flexible as next function in the chain is dependent on previous function (to fetch data from somewhere). Data messages are enriched as they flow through the application leaving no artifacts behind, but absorbing all the necessary data.</p>

<h3 id="function3---convert">Function3 - Convert</h3>

<p>When Function2 has finished its product (queue item) is placed in Storage queue upon which next function is triggered. Function3 is responsible for converting image to ASCII art and placing result in next queue (final queue).</p>

<p><img src="/assets/img/2017/11/f2-f3.png" alt="" /></p>

<p>I’ll skip actual code for converting to ASCII art (you can actually find lot of interesting implementations on the net), but will post here function itself:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">StorageAccount</span><span class="p">(</span><span class="s">"my-storage-connection"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">Function3</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="s">"Function3"</span><span class="p">)]</span>
    <span class="p">[</span><span class="k">return</span><span class="p">:</span> <span class="nf">Queue</span><span class="p">(</span><span class="s">"done-images"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">CloudQueueMessage</span><span class="p">&gt;</span> <span class="nf">Run</span><span class="p">(</span>

        <span class="p">[</span><span class="nf">QueueTrigger</span><span class="p">(</span><span class="s">"to-ascii-conversion"</span><span class="p">)]</span>                        <span class="n">AsciiArtRequest</span> <span class="n">request</span><span class="p">,</span>
        <span class="p">[</span><span class="nf">Blob</span><span class="p">(</span><span class="s">"%input-container%/{BlobRef}"</span><span class="p">,</span> <span class="n">FileAccess</span><span class="p">.</span><span class="n">Read</span><span class="p">)]</span>       <span class="n">Stream</span> <span class="n">inBlob</span><span class="p">,</span>
        <span class="p">[</span><span class="nf">Blob</span><span class="p">(</span><span class="s">"%output-container%/{BlobRef}"</span><span class="p">,</span> <span class="n">FileAccess</span><span class="p">.</span><span class="n">Write</span><span class="p">)]</span>     <span class="n">Stream</span> <span class="n">outBlob</span><span class="p">,</span>
                                                                     <span class="n">TraceWriter</span> <span class="n">log</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">log</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">"(Fun3) Starting to convert image to ASCII art..."</span><span class="p">);</span>

        <span class="kt">var</span> <span class="n">convertedImage</span> <span class="p">=</span> <span class="nf">ConvertImageToAscii</span><span class="p">(</span><span class="n">inBlob</span><span class="p">,</span> <span class="n">request</span><span class="p">.</span><span class="n">Width</span><span class="p">);</span>
        <span class="k">await</span> <span class="n">outBlob</span><span class="p">.</span><span class="nf">WriteAsync</span><span class="p">(</span><span class="n">convertedImage</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">convertedImage</span><span class="p">.</span><span class="n">Length</span><span class="p">);</span>

        <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">AsciiArtResult</span><span class="p">(</span><span class="n">request</span><span class="p">.</span><span class="n">BlobRef</span><span class="p">,</span>
                                        <span class="n">ConfigurationManager</span><span class="p">.</span><span class="n">AppSettings</span><span class="p">[</span><span class="s">"output-container"</span><span class="p">],</span>
                                        <span class="n">request</span><span class="p">.</span><span class="n">Description</span><span class="p">,</span>
                                        <span class="n">request</span><span class="p">.</span><span class="n">Tags</span><span class="p">);</span>

        <span class="n">log</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">"(Fun3) Finished converting image."</span><span class="p">);</span>

        <span class="k">return</span> <span class="n">result</span><span class="p">.</span><span class="nf">AsQueueItem</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>In this case function needs reference to input blob block (actual image that’s been uploaded in Episerver and analyzed in Cognitive Services) and also reference to output blob - where image will be stored after ASCII conversion. And also result of the function (<code class="language-plaintext highlighter-rouge">AsciiArtResult</code> object) will be placed in Storage queue named <code class="language-plaintext highlighter-rouge">done-images</code>.</p>

<h2 id="download-to-episerver">Download to Episerver</h2>

<p>Now when image is processed (analyzed and converted) - it’s time to download it back to Episerver. There had been discussions in couple of presentations whether Episerver should download the image or function should “push” processing result to Episerver. I picked solution that function is not doing anything - as just writing down result of processing. “Consuming” side (in this case Episerver) is responsible for getting that image and saving in its own blob storage.</p>

<p>So the easiest way in Episerver to do something periodically (to check for new processing results) is by implementing <a href="https://world.episerver.com/documentation/Items/Developers-Guide/Episerver-CMS/9/Scheduled-jobs/Scheduled-jobs/">scheduled jobs</a>.</p>

<p><img src="/assets/img/2017/11/f3-job-1.png" alt="" /></p>

<p>There is nothing interesting to see in scheduled job itself. I don’t like to keep lot of my stuff physically inside my scheduled job. I tend to think about it as just hosting/scheduling environment for my service. Also separate (read: service isolated from the underlying framework as much as possible) is a bit easier to test.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ScheduledPlugIn</span><span class="p">(</span><span class="n">DisplayName</span> <span class="p">=</span> <span class="s">"Download AsciiArt Images"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">DownloadAsciiArtImagesJob</span> <span class="p">:</span> <span class="n">ScheduledJobBase</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IAsciiResponseDownloader</span> <span class="n">_downloader</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">DownloadAsciiArtImagesJob</span><span class="p">(</span><span class="n">IAsciiResponseDownloader</span> <span class="n">downloader</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_downloader</span> <span class="p">=</span> <span class="n">downloader</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">override</span> <span class="kt">string</span> <span class="nf">Execute</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="nf">OnStatusChanged</span><span class="p">(</span><span class="s">$"Starting execution of </span><span class="p">{</span><span class="nf">GetType</span><span class="p">()}</span><span class="s">"</span><span class="p">);</span>

        <span class="kt">var</span> <span class="n">log</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">StringBuilder</span><span class="p">();</span>

        <span class="n">_downloader</span><span class="p">.</span><span class="nf">Download</span><span class="p">(</span><span class="n">log</span><span class="p">);</span>

        <span class="k">return</span> <span class="n">log</span><span class="p">.</span><span class="nf">ToString</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Basically job gets the access to storage queue (again, for demo purposes everyone can access that queue, but in real-life I would recommend to handle this <a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-dotnet-shared-access-signature-part-1">with SAS tokens</a>) and checks for any new items in the queue. If there is anything - this means that there is new response from ASCII art processing service app.
Almost all the business logic is hidden again in helper services.</p>

<p>Actual downloader of the image:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
</pre></td><td class="rouge-code"><pre><span class="k">internal</span> <span class="k">class</span> <span class="nc">CloudQueueAsciiResponseDownloader</span> <span class="p">:</span> <span class="n">IAsciiResponseDownloader</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IAsciiArtImageProcessor</span> <span class="n">_processor</span><span class="p">;</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IAsciiArtServiceSettingsProvider</span> <span class="n">_settingsProvider</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">CloudQueueAsciiResponseDownloader</span><span class="p">(</span>
        <span class="n">IAsciiArtServiceSettingsProvider</span> <span class="n">settingsProvider</span><span class="p">,</span>
        <span class="n">IAsciiArtImageProcessor</span> <span class="n">processor</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_settingsProvider</span> <span class="p">=</span> <span class="n">settingsProvider</span><span class="p">;</span>
        <span class="n">_processor</span> <span class="p">=</span> <span class="n">processor</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Download</span><span class="p">(</span><span class="n">StringBuilder</span> <span class="n">log</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">settings</span> <span class="p">=</span> <span class="n">_settingsProvider</span><span class="p">.</span><span class="n">Settings</span><span class="p">;</span>
        <span class="kt">var</span> <span class="n">account</span> <span class="p">=</span> <span class="n">CloudStorageAccount</span><span class="p">.</span><span class="nf">Parse</span><span class="p">(</span><span class="n">settings</span><span class="p">.</span><span class="n">StorageUrl</span><span class="p">);</span>
        <span class="kt">var</span> <span class="n">queueClient</span> <span class="p">=</span> <span class="n">account</span><span class="p">.</span><span class="nf">CreateCloudQueueClient</span><span class="p">();</span>
        <span class="kt">var</span> <span class="n">queue</span> <span class="p">=</span> <span class="n">queueClient</span><span class="p">.</span><span class="nf">GetQueueReference</span><span class="p">(</span><span class="n">settings</span><span class="p">.</span><span class="n">DoneQueueName</span><span class="p">);</span>

        <span class="kt">var</span> <span class="n">draftMsg</span> <span class="p">=</span> <span class="n">queue</span><span class="p">.</span><span class="nf">GetMessage</span><span class="p">();</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">draftMsg</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">log</span><span class="p">.</span><span class="nf">AppendLine</span><span class="p">(</span><span class="s">"No messages found in the queue"</span><span class="p">);</span>
            <span class="k">return</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="k">while</span> <span class="p">(</span><span class="n">draftMsg</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="kt">var</span> <span class="n">message</span> <span class="p">=</span> <span class="n">JsonConvert</span><span class="p">.</span><span class="n">DeserializeObject</span><span class="p">&lt;</span><span class="n">AsciiArtResult</span><span class="p">&gt;(</span><span class="n">draftMsg</span><span class="p">.</span><span class="n">AsString</span><span class="p">);</span>

            <span class="n">log</span><span class="p">.</span><span class="nf">AppendLine</span><span class="p">(</span><span class="s">$"Started processing image (</span><span class="p">{</span><span class="n">message</span><span class="p">.</span><span class="n">BlobRef</span><span class="p">}</span><span class="s">)..."</span><span class="p">);</span>

            <span class="k">try</span>
            <span class="p">{</span>
                <span class="n">_processor</span><span class="p">.</span><span class="nf">SaveAsciiArt</span><span class="p">(</span><span class="n">account</span><span class="p">,</span> <span class="n">message</span><span class="p">);</span>
                <span class="n">queue</span><span class="p">.</span><span class="nf">DeleteMessage</span><span class="p">(</span><span class="n">draftMsg</span><span class="p">);</span>

                <span class="n">log</span><span class="p">.</span><span class="nf">AppendLine</span><span class="p">(</span><span class="s">$"Finished image (</span><span class="p">{</span><span class="n">message</span><span class="p">.</span><span class="n">BlobRef</span><span class="p">}</span><span class="s">)."</span><span class="p">);</span>
            <span class="p">}</span>
            <span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">e</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="n">log</span><span class="p">.</span><span class="nf">AppendLine</span><span class="p">(</span><span class="s">$"Error occoured: </span><span class="p">{</span><span class="n">e</span><span class="p">.</span><span class="n">Message</span><span class="p">}</span><span class="s">"</span><span class="p">);</span>
            <span class="p">}</span>

            <span class="n">draftMsg</span> <span class="p">=</span> <span class="n">queue</span><span class="p">.</span><span class="nf">GetMessage</span><span class="p">();</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And once response from the image processing function app is retrieved - we need to save meta data about the image and actual ASCII art as well. This is done in response processor:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
</pre></td><td class="rouge-code"><pre><span class="k">internal</span> <span class="k">class</span> <span class="nc">AsciiArtImageProcessor</span> <span class="p">:</span> <span class="n">IAsciiArtImageProcessor</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IContentRepository</span> <span class="n">_repository</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">AsciiArtImageProcessor</span><span class="p">(</span><span class="n">IContentRepository</span> <span class="n">repository</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_repository</span> <span class="p">=</span> <span class="n">repository</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">SaveAsciiArt</span><span class="p">(</span><span class="n">CloudStorageAccount</span> <span class="n">account</span><span class="p">,</span> <span class="n">AsciiArtResult</span> <span class="n">result</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">blobClient</span> <span class="p">=</span> <span class="n">account</span><span class="p">.</span><span class="nf">CreateCloudBlobClient</span><span class="p">();</span>
        <span class="kt">var</span> <span class="n">container</span> <span class="p">=</span> <span class="n">blobClient</span><span class="p">.</span><span class="nf">GetContainerReference</span><span class="p">(</span><span class="n">result</span><span class="p">.</span><span class="n">Container</span><span class="p">);</span>
        <span class="kt">var</span> <span class="n">asciiBlob</span> <span class="p">=</span> <span class="n">container</span><span class="p">.</span><span class="nf">GetBlobReference</span><span class="p">(</span><span class="n">result</span><span class="p">.</span><span class="n">BlobRef</span><span class="p">);</span>

        <span class="kt">var</span> <span class="n">image</span> <span class="p">=</span> <span class="n">_repository</span><span class="p">.</span><span class="n">Get</span><span class="p">&lt;</span><span class="n">ImageFile</span><span class="p">&gt;(</span><span class="n">Guid</span><span class="p">.</span><span class="nf">Parse</span><span class="p">(</span><span class="n">result</span><span class="p">.</span><span class="n">BlobRef</span><span class="p">));</span>
        <span class="kt">var</span> <span class="n">writable</span> <span class="p">=</span> <span class="n">image</span><span class="p">.</span><span class="n">MakeWritable</span><span class="p">&lt;</span><span class="n">ImageFile</span><span class="p">&gt;();</span>

        <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">stream</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">MemoryStream</span><span class="p">())</span>
        <span class="p">{</span>
            <span class="n">asciiBlob</span><span class="p">.</span><span class="nf">DownloadToStream</span><span class="p">(</span><span class="n">stream</span><span class="p">);</span>
            <span class="kt">var</span> <span class="n">asciiArt</span> <span class="p">=</span> <span class="n">Encoding</span><span class="p">.</span><span class="n">UTF8</span><span class="p">.</span><span class="nf">GetString</span><span class="p">(</span><span class="n">stream</span><span class="p">.</span><span class="nf">ToArray</span><span class="p">());</span>

            <span class="n">writable</span><span class="p">.</span><span class="n">AsciiArt</span> <span class="p">=</span> <span class="n">asciiArt</span><span class="p">;</span>
            <span class="n">writable</span><span class="p">.</span><span class="n">Description</span> <span class="p">=</span> <span class="n">result</span><span class="p">.</span><span class="n">Description</span><span class="p">;</span>
            <span class="n">writable</span><span class="p">.</span><span class="n">Tags</span> <span class="p">=</span> <span class="kt">string</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="s">","</span><span class="p">,</span> <span class="n">result</span><span class="p">.</span><span class="n">Tags</span><span class="p">);</span>

            <span class="n">_repository</span><span class="p">.</span><span class="nf">Save</span><span class="p">(</span><span class="n">writable</span><span class="p">,</span> <span class="n">SaveAction</span><span class="p">.</span><span class="n">Publish</span><span class="p">,</span> <span class="n">AccessLevel</span><span class="p">.</span><span class="n">NoAccess</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now the image vision branch is completed. Let’s jump over to content review branch.</p>

<h3 id="function4---evaluate">Function4 - Evaluate</h3>

<p>For the Function4 to work, you will to signup for the content cognitive services (for now, this is done separately from Cognitive Services setup in Azure). You can signup <a href="https://contentmoderator.cognitive.microsoft.com/">here</a>.</p>

<p><img src="/assets/img/2017/11/f2-f4-cogn.png" alt="" /></p>

<p>I was expecting to have the same .Net client API libraries as for image vision services (<code class="language-plaintext highlighter-rouge">ProjectOxford</code>). But this is not true for content cognitive services. I’ll explain this more in details later in the post (when talking about targeting frameworks issues).</p>

<p>So when somebody uploads image also new message in the topic is emitted. Function4 picks it up (aside from Function2) and starts processing of the content for this image. In particular we are looking for any adult content posted. And if so - administrator should be notified.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">StorageAccount</span><span class="p">(</span><span class="s">"my-storage-connection"</span><span class="p">)]</span>
<span class="p">[</span><span class="nf">ServiceBusAccount</span><span class="p">(</span><span class="s">"my-servicebus-connection"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">Function4</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="s">"Function4"</span><span class="p">)]</span>
    <span class="p">[</span><span class="k">return</span><span class="p">:</span> <span class="nf">Queue</span><span class="p">(</span><span class="s">"to-admin-notif"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">CloudQueueMessage</span><span class="p">&gt;</span> <span class="nf">Run</span><span class="p">(</span>
        <span class="p">[</span><span class="nf">ServiceBusTrigger</span><span class="p">(</span><span class="s">"mytopic"</span><span class="p">,</span> <span class="s">"to-eval"</span><span class="p">,</span> <span class="n">AccessRights</span><span class="p">.</span><span class="n">Manage</span><span class="p">)]</span>   <span class="n">AnalysisReq</span> <span class="n">request</span><span class="p">,</span>
        <span class="p">[</span><span class="nf">Blob</span><span class="p">(</span><span class="s">"%input-container%/{BlobRef}"</span><span class="p">,</span> <span class="n">FileAccess</span><span class="p">.</span><span class="n">Read</span><span class="p">)]</span>           <span class="n">Stream</span> <span class="n">inBlob</span><span class="p">,</span>
                                                                         <span class="n">TraceWriter</span> <span class="n">log</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">log</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">"(Fun4) Running image approval analysis..."</span><span class="p">);</span>

        <span class="k">try</span>
        <span class="p">{</span>
            <span class="kt">var</span> <span class="n">subscriptionKey</span> <span class="p">=</span>
                <span class="n">ConfigurationManager</span><span class="p">.</span><span class="n">AppSettings</span><span class="p">[</span><span class="s">"cognitive-services-approval-key"</span><span class="p">];</span>

            <span class="kt">var</span> <span class="n">client</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">HttpClient</span><span class="p">();</span>

            <span class="c1">// Request headers</span>
            <span class="n">client</span><span class="p">.</span><span class="n">DefaultRequestHeaders</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="s">"Ocp-Apim-Subscription-Key"</span><span class="p">,</span> <span class="n">subscriptionKey</span><span class="p">);</span>

            <span class="c1">// Request parameters</span>
            <span class="kt">var</span> <span class="n">uri</span> <span class="p">=</span> <span class="n">ConfigurationManager</span><span class="p">.</span><span class="n">AppSettings</span><span class="p">[</span><span class="s">"cognitive-services-approval-uri"</span><span class="p">];</span>

            <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">ms</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">MemoryStream</span><span class="p">())</span>
            <span class="p">{</span>
                <span class="n">inBlob</span><span class="p">.</span><span class="nf">CopyTo</span><span class="p">(</span><span class="n">ms</span><span class="p">);</span>
                <span class="kt">var</span> <span class="n">byteArray</span> <span class="p">=</span> <span class="n">ms</span><span class="p">.</span><span class="nf">ToArray</span><span class="p">();</span>
                <span class="n">Task</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;</span> <span class="n">result</span><span class="p">;</span>

                <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">content</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ByteArrayContent</span><span class="p">(</span><span class="n">byteArray</span><span class="p">))</span>
                <span class="p">{</span>
                    <span class="n">content</span><span class="p">.</span><span class="n">Headers</span><span class="p">.</span><span class="n">ContentType</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">MediaTypeHeaderValue</span><span class="p">(</span><span class="s">"image/jpeg"</span><span class="p">);</span>
                    <span class="kt">var</span> <span class="n">response</span> <span class="p">=</span> <span class="k">await</span> <span class="n">client</span><span class="p">.</span><span class="nf">PostAsync</span><span class="p">(</span><span class="n">uri</span><span class="p">,</span> <span class="n">content</span><span class="p">);</span>
                    <span class="n">result</span> <span class="p">=</span> <span class="n">response</span><span class="p">.</span><span class="n">Content</span><span class="p">.</span><span class="nf">ReadAsStringAsync</span><span class="p">();</span>
                <span class="p">}</span>

                <span class="k">if</span><span class="p">(</span><span class="n">result</span><span class="p">.</span><span class="n">Result</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
                <span class="p">{</span>
                    <span class="kt">var</span> <span class="n">resultAsObject</span> <span class="p">=</span> <span class="n">JsonConvert</span><span class="p">.</span><span class="n">DeserializeObject</span><span class="p">&lt;</span><span class="n">ContentModeratorResult</span><span class="p">&gt;(</span><span class="n">result</span><span class="p">.</span><span class="n">Result</span><span class="p">);</span>

                    <span class="k">if</span><span class="p">(</span><span class="n">resultAsObject</span><span class="p">.</span><span class="n">IsImageAdultClassified</span><span class="p">)</span>
                    <span class="p">{</span>
                        <span class="n">log</span><span class="p">.</span><span class="nf">Warning</span><span class="p">(</span><span class="s">"(Fun4) Inappropriate content detected. Sending notification..."</span><span class="p">);</span>
                        <span class="k">return</span> <span class="n">request</span><span class="p">.</span><span class="nf">AsQueueItem</span><span class="p">();</span>
                    <span class="p">}</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span>
        <span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">e</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">log</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">"Error on Running image approval..."</span> <span class="p">+</span> <span class="n">e</span><span class="p">.</span><span class="n">Message</span><span class="p">);</span>
        <span class="p">}</span>

        <span class="k">return</span> <span class="k">null</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Very similar as for the Function2, this Function4 needs access to original image blob (via blob block reference).</p>

<p>Invocation of the content cognitive service is not so nice as for image vision services, I’ll cover this a bit later in the post. Basically we are creating new REST request to the content cognitive service endpoint and posting image for the analysis:</p>

<pre><code class="language-ccsharp">using (var content = new ByteArrayContent(byteArray))
{
    content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
    var response = await client.PostAsync(uri, content);
    result = response.Content.ReadAsStringAsync();
}

if(result.Result != null)
{
    var resultAsObject =
        JsonConvert.DeserializeObject&lt;ContentModeratorResult&gt;(result.Result);

    if(resultAsObject.IsImageAdultClassified)
    {
        log.Warning("(Fun4) Inappropriate content detected. Sending notification...");
        return request.AsQueueItem();
    }
}
</code></pre>

<p>And back we get simple type describing results (this is just a projection of whole response):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">ContentModeratorResult</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">bool</span> <span class="n">IsImageAdultClassified</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">bool</span> <span class="n">IsImageRacyClassified</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As you can see from the decorations of the function - return value of the function will be used as Storage queue item. So if you don’t want to put anything in the queue - return <code class="language-plaintext highlighter-rouge">null</code>.</p>

<h3 id="function5---notify">Function5 - Notify</h3>

<p>And the last but not least, Function5 - responsible for delivering notifications to administrator(s) if inappropriate content detected.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">StorageAccount</span><span class="p">(</span><span class="s">"my-storage-connection"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">Function5</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="s">"Function5"</span><span class="p">)]</span>
    <span class="p">[</span><span class="k">return</span><span class="p">:</span> <span class="nf">TwilioSms</span><span class="p">(</span><span class="n">AccountSidSetting</span> <span class="p">=</span> <span class="s">"twilio-account-sid"</span><span class="p">,</span>
                       <span class="n">AuthTokenSetting</span> <span class="p">=</span> <span class="s">"twilio-account-auth-token"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">static</span> <span class="n">SMSMessage</span> <span class="nf">Run</span><span class="p">(</span>
        <span class="p">[</span><span class="nf">QueueTrigger</span><span class="p">(</span><span class="s">"to-admin-notif"</span><span class="p">)]</span>         <span class="n">AnalysisReq</span> <span class="n">request</span><span class="p">,</span>
                                                 <span class="n">TraceWriter</span> <span class="n">log</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">log</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">"(Fun5) Sending SMS..."</span><span class="p">);</span>

        <span class="kt">var</span> <span class="n">baseUrl</span> <span class="p">=</span> <span class="n">ConfigurationManager</span><span class="p">.</span><span class="n">AppSettings</span><span class="p">[</span><span class="s">"base-url"</span><span class="p">];</span>
        <span class="kt">var</span> <span class="k">from</span> <span class="p">=</span> <span class="n">ConfigurationManager</span><span class="p">.</span><span class="n">AppSettings</span><span class="p">[</span><span class="s">"twilio-from-number"</span><span class="p">];</span>
        <span class="kt">var</span> <span class="n">to</span> <span class="p">=</span> <span class="n">ConfigurationManager</span><span class="p">.</span><span class="n">AppSettings</span><span class="p">[</span><span class="s">"twilio-to-number"</span><span class="p">];</span>

        <span class="k">return</span> <span class="k">new</span> <span class="n">SMSMessage</span>
        <span class="p">{</span>
            <span class="n">From</span> <span class="p">=</span> <span class="k">from</span><span class="p">,</span>
            <span class="n">To</span> <span class="p">=</span> <span class="n">to</span><span class="p">,</span>
            <span class="n">Body</span> <span class="p">=</span> <span class="s">$@"Someone uploaded an non appropriated image to your site.</span><span class="err">
</span><span class="s">    The image url Id is </span><span class="p">{</span><span class="n">request</span><span class="p">.</span><span class="n">BlobRef</span><span class="p">}</span><span class="s">,</span><span class="err">
</span><span class="s">    url is </span><span class="p">{</span><span class="n">baseUrl</span> <span class="p">+</span> <span class="n">request</span><span class="p">.</span><span class="n">ImageUrl</span><span class="p">}</span><span class="s">"</span>

        <span class="p">};</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Again for the demo purpose, <code class="language-plaintext highlighter-rouge">to</code> parameter (actual phone number to send SMS to) is hard-coded in <code class="language-plaintext highlighter-rouge">settings.json</code> file.</p>

<p>Trigger of the function is Storage queue - however, if there is no item in the queue, this function will not be invoked at all (you will not be charged if running on “consumption pricing plan”).</p>

<p><img src="/assets/img/2017/11/f4-f5.png" alt="" /></p>

<p>As you see, there is no interaction with Episerver anymore during content cognitive services branch - if inappropriate content detected - just SMS message is sent.</p>

<h2 id="challenge-with-target-frameworks">Challenge with Target Frameworks</h2>

<h3 id="upgrade-to-net-standard-20">Upgrade to .Net Standard 2.0</h3>

<p>So why there is challenge using various built-in packages for working with strongly typed bindings and other goodies out of the box? Let’s try to go through this together.</p>

<p>Imagine that we are building simple Azure Function App using Visual Studio Tools for Azure Functions (latest at the moment of writing - 15.0.30923.</p>

<p>By default with that version of templates <code class="language-plaintext highlighter-rouge">Microsoft.NET.Sdk.Functions</code> package is referenced and version is set to <code class="language-plaintext highlighter-rouge">1.0.2</code>. As you might heard, running on .Net Standard in the new thing, so let’s try to <a href="https://blogs.msdn.microsoft.com/appserviceteam/2017/09/25/develop-azure-functions-on-any-platform/">migrate there</a> (as VS Tooling has no support yet). We need to upgrade to <code class="language-plaintext highlighter-rouge">1.0.6</code> of <code class="language-plaintext highlighter-rouge">Microsoft.NET.Sdk.Functions</code> package. This is easy. And also need to change target framework in .csproj file to <code class="language-plaintext highlighter-rouge">netstandard2.0</code>.</p>

<p>I’m not after proper Nuget package restore getting some dependency errors, but oh well.. yeah… I don’t know even what that dependency is coming from, why it’s needed and most importantly why it’s not restoring for .Net Standard.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>Package 'Microsoft.AspNet.WebApi.Client 5.2.2' was restored using '.NETFramework,Version=v4.6.1'
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Also I see yellow exclamation mark besides that dependency in solution explorer.</p>

<p><img src="/assets/img/2017/11/webapi-restore-1.png" alt="" /></p>

<p>Function created in sample app is coming AS-IS from VS Tools for Azure Functions template:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">Function1</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="s">"Function1"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">Run</span><span class="p">(</span>
        <span class="p">[</span><span class="nf">TimerTrigger</span><span class="p">(</span><span class="s">"0 */5 * * * *"</span><span class="p">)]</span>    <span class="n">TimerInfo</span> <span class="n">myTimer</span><span class="p">,</span>
                                           <span class="n">TraceWriter</span> <span class="n">log</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">log</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">$"C# Timer trigger function executed at: </span><span class="p">{</span><span class="n">DateTime</span><span class="p">.</span><span class="n">Now</span><span class="p">}</span><span class="s">"</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now running this simple function app targeted against .Net Standard, gives another error:</p>

<p><img src="/assets/img/2017/11/log-error.png" alt="" /></p>

<p>Should be easy to fix according to <a href="https://github.com/Azure/Azure-Functions/issues/293">this GitHub issue</a>.
Running again but this time with <code class="language-plaintext highlighter-rouge">ILogger</code> from <code class="language-plaintext highlighter-rouge">Microsoft.Extensions.Logging</code>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">Function1</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="s">"Function1"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">Run</span><span class="p">(</span>
        <span class="p">[</span><span class="nf">TimerTrigger</span><span class="p">(</span><span class="s">"0 */5 * * * *"</span><span class="p">)]</span>    <span class="n">TimerInfo</span> <span class="n">myTimer</span><span class="p">,</span>
                                           <span class="n">ILogger</span> <span class="n">log</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">log</span><span class="p">.</span><span class="nf">LogInformation</span><span class="p">(</span><span class="s">$"C# Timer trigger function executed at: </span><span class="p">{</span><span class="n">DateTime</span><span class="p">.</span><span class="n">Now</span><span class="p">}</span><span class="s">"</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Gives exactly the same error - failing to provide binding value for <code class="language-plaintext highlighter-rouge">ILogger</code> interface.
There is also some traces on <a href="https://github.com/Azure/Azure-Functions/issues/293">GitHub repo</a> as well, and couple of issues still open (<a href="https://github.com/Azure/Azure-Functions/issues/452">#452</a> on Azure-Functions or <a href="https://github.com/Azure/azure-webjobs-sdk-script/issues/573">#573</a> on azure-webjobs-sdk-script).</p>

<p>Actually it turned out that we need to download new version of Azure Function SDK and set our project to run under that (that was not obvious at first sight).</p>

<p>Action plan here:</p>

<ul>
  <li>Download Azure Core tools (node):</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; npm i -g azure-functions-core-tools@core
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>Set project to execute within new runtime:</li>
</ul>

<p><img src="/assets/img/2017/11/new-runtime-proj-settings.png" alt="" /></p>

<p>Now we are able to resolve <code class="language-plaintext highlighter-rouge">ILogger</code> at least.</p>

<p><img src="/assets/img/2017/11/runtime-20.png" alt="" /></p>

<p>However, local run gave no results in console output. I’m not <a href="https://github.com/serilog/serilog/issues/983">the only one</a>.</p>

<p>Ok, for the logging - let’s hope it might work at some point.</p>

<p>Now we need to do some Storage and ServiceBus things. With the Storage everything is easy - it’s already part of <code class="language-plaintext highlighter-rouge">Microsoft.Azure.WebJobs</code> package (main package for doing Azure Functions - remember that functions are mode on top of webjobs). On the anther hand - to do a ServiceBus thingies - we need separate package - <code class="language-plaintext highlighter-rouge">Microsoft.Azure.WebJobs.ServiceBus</code>. For this package last available version is <code class="language-plaintext highlighter-rouge">2.1.0-beta4</code>. Which however requires <code class="language-plaintext highlighter-rouge">Microsoft.Azure.WebJobs</code> version <code class="language-plaintext highlighter-rouge">2.1.0-beta4</code>. Which will give following error if you attempt to install:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>Package 'Microsoft.Azure.WebJobs.ServiceBus 2.1.0-beta4' was restored using '.NETFramework,Version=v4.6.1' instead of the project target framework '.NETStandard,Version=v2.0'. This package may not be fully compatible with your project.
</pre></td></tr></tbody></table></code></pre></div></div>

<p>ServiceBus extensions package requires us to fallback to .Net Framework 4.6.1 at least. Ok, also not a problem. We can survive without latest and greatest.</p>

<p>Next thing - we need to talk to Content Cognitive services (preferably via strongly typed client API library and not REST interface). Let’s try to <a href="https://www.nuget.org/profiles/ProjectOxfordSDK">look for this package</a>:</p>

<p><img src="/assets/img/2017/11/oxford-sdk.png" alt="" /></p>

<p>If we look for Content Cognitive Services client API library - there is a <a href="">unofficial package</a>https://www.nuget.org/packages/Microsoft.ProjectOxford.ContentModerator.DotNetCore/) for that. But it’s targeting .Net Core (v1.1.1).</p>

<p>Not sure whether .Net Core is supported in Azure Functions runtime at all, but we cannot do that because we are constrained with <code class="language-plaintext highlighter-rouge">net461</code> target framework because of ServiceBus extension library. We switch back to .Net Framework (also remember to remove project settings not to run under Azure Runtime 2.0).</p>

<p>So I guess we will need to wait a bit still while all the packages will align and .Net Standard 2.0 will be supported everywhere.</p>

<h2 id="where-to-grab-the-stuff">Where to Grab the Stuff?</h2>

<p>If you wanna play around with source code - you can <a href="https://github.com/valdisiljuconoks/episerverless">fork one here</a>.</p>

<p>If you wanna see original presentation - you can <a href="https://github.com/valdisiljuconoks/episerverless/blob/master/presentation.pptx">grab one here</a>.</p>

<p>See in action:</p>

<iframe width="800" height="520" src="https://www.youtube.com/embed/dUlbTpRBKvU" frameborder="0" gesture="media" allowfullscreen=""></iframe>

<p>Happy functioning!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><summary type="html"><![CDATA[I did talk about this topic couple times solo, and also together with Henrik Fransas in Episerver Partner Close-up in Stockholm this year. Received lot of questions regarding source code availability and also about recordings of the session(s). Unfortunately there are no recordings of the conferences I/we were. So I decided just compile together a blog post.]]></summary></entry><entry><title type="html">LocalizationProvider - Tree View, Export and Migrations</title><link href="https://tech-fellow.eu/2017/10/10/localizationprovider-tree-view-export-and-migrations/" rel="alternate" type="text/html" title="LocalizationProvider - Tree View, Export and Migrations" /><published>2017-10-10T23:00:00+03:00</published><updated>2017-10-10T23:00:00+03:00</updated><id>https://tech-fellow.eu/2017/10/10/localizationprovider-tree-view-export-and-migrations</id><content type="html" xml:base="https://tech-fellow.eu/2017/10/10/localizationprovider-tree-view-export-and-migrations/"><![CDATA[<p>It’s been a while since last blog post about localization provider. It just means that I’ve been heads down busy with implementing some great features :)</p>

<p>Anyway - these are most probably last features before I’m switching over to .Net Core. I know that you might ask - why you need .Net Core if Episerver is still not there yet!? I’m planning to migrate to .Net Core because Episerver plugin is just small fraction of localization provider and actually you can use it outside of Episerver also - just in regular Asp.Net or Asp.Net Core website to localize standard stack.</p>

<p>These were original series over localization provider features.</p>

<ul>
  <li><a href="https://tech-fellow.eu/2016/03/16/db-localization-provider-part-1-resources-and-models/">Part 1: Resources and Models</a></li>
  <li><a href="https://tech-fellow.eu/2016/04/21/db-localization-provider-part-2-configuration-and-extensions/">Part 2: Configuration and Extensions</a></li>
  <li><a href="https://tech-fellow.eu/2017/02/22/localization-provider-import-and-export-merge/">Part 3: Import and Export</a></li>
  <li><strong>Part 4: Resource Refactoring and Migrations</strong></li>
</ul>

<p>There has been <a href="https://tech-fellow.eu/tag/localization/">many other updates</a> in between, but last part was planned to be just about migrations of resources, but turned out to include other features that you might find interesting.</p>

<p>Below is a list of some of the feature highlights from the latest version from <a href="https://www.nuget.org/packages?q=dblocalizationprovider">NuGet feed</a> and <a href="http://nuget.episerver.com/en/?search=dblocalizationprovider&amp;sort=MostDownloads&amp;page=1&amp;pageSize=10">Episerver feed</a>.</p>

<h2 id="xliff-exportimport">XLIFF Export/Import</h2>

<p>With some of the latest versions it’s now possible to export and import translations using XLIFF format.</p>

<p><img src="/assets/img/2017/10/2017-08-04_16-00-04.jpg" alt="" /></p>

<p>Developers working on projects that involve 3rd party translation companies could find this valuable. As request to add XLIFF support came just from developer in that situation. XLIFF format is supported for both - export of resources and also import. In order to add support for XLIFF format you will need to install following package - <a href="http://nuget.episerver.com/en/OtherPages/Package/?packageId=DbLocalizationProvider.AdminUI.EPiServer.Xliff">DbLocalizationProvider.AdminUI.EPiServer.Xliff</a> from Episerver nuget freed.</p>

<h2 id="tree-view">Tree View</h2>

<p>Sometimes (especially when you have huge list of resources and deep hierarchical relationships between classes, you might find it clumsy to work with resources as keys might get pretty long.</p>

<p><img src="/assets/img/2017/10/2017-10-09_22-54-56.png" alt="" /></p>

<p>Now you can switch to tree view and resources will be split into hierarchy by separator (usually <code class="language-plaintext highlighter-rouge">"."</code>) and represented to the editor in tree view way.</p>

<p><img src="/assets/img/2017/10/2017-10-09_22-56-16.png" alt="" /></p>

<p>It’s also worth mention that if you have migrated old legacy resources to db localization provider and you have enabled <code class="language-plaintext highlighter-rouge">LegacyMode</code> then XPath style resources will collapse into tree view as well - making it more pleasant for the editor to work with.</p>

<p>First you need to enable legacy mode:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">InitLocalization</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">ConfigurationContext</span><span class="p">.</span><span class="nf">Setup</span><span class="p">(</span><span class="n">cfg</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="n">cfg</span><span class="p">.</span><span class="n">ModelMetadataProviders</span><span class="p">.</span><span class="n">EnableLegacyMode</span> <span class="p">=</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="k">true</span><span class="p">;</span>
        <span class="p">});</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then collapse will work correctly in Admin UI:</p>

<p><img src="/assets/img/2017/10/2017-10-09_22-59-05-1.png" alt="" /></p>

<h2 id="migrations">Migrations</h2>

<p>Last but not least, there is now (FINALLY!) added support for refactoring scenarios for the resources (resource classes and localized models as well).
It’s been hanging around for a while on GitHub and I never had chance to implemented it properly and I was always thinking about that problem deeper as it should be.. But I finally got question in Amsterdam about this tool - “what if I misspell resource class name, what about it property name that holds a translation is wrongly named at the beginning?” Meaning that if you just rename the resource container class - all the resources underneath will be treated as new set of resources - hence, loosing already added translation (if any). There are also scenarios when developers just want to shuffle around classes and move those in appropriate namespaces. Unfortunately - as database localization provider is heavily based on class structure and metadata found there - renames or class movement around to different namespace is disaster for the localization provider.</p>

<p>There were no support for these kind of refactoring tasks util now.</p>

<p>So it latest version there are bunch of new ways to tackle this complexity of migrations of the resources preserving translations for all added languages.</p>

<p>First, this code snippet might demo you basic support for the refactorings:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="k">using</span> <span class="nn">DbLocalizationProvider.Abstractions.Refactoring</span><span class="p">;</span>

<span class="k">namespace</span> <span class="nn">DbLocalizationProvider.Tests.Refactoring</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
    <span class="p">[</span><span class="nf">RenamedResource</span><span class="p">(</span><span class="s">"OldModelClass"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">RenamedModelClass</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="kt">string</span> <span class="n">NewProperty</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>When provider will discover this resource newly generated key will be:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">DbLocalizationProvider.Abstractions.Refactoring.RenamedModelClass.NewProperty</code></li>
</ul>

<p>However, as resource class is decorated with <code class="language-plaintext highlighter-rouge">[RenamedResource]</code> attribute, there will be also another resource key discovered:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">DbLocalizationProvider.Abstractions.Refactoring.OldModelClass.NewProperty</code></li>
</ul>

<p>Meaning that latter will be used before synchronization. Provider will look for <code class="language-plaintext highlighter-rouge">..OldModelClass.NewProperty</code> resource in database and will update key to <code class="language-plaintext highlighter-rouge">..RenamedModelClass.NewProperty</code>.</p>

<p>And only then will proceed with standard resource synchronization.</p>

<p>Various kinds of refactoring scenarios are covered, starting from simple class or resource property name, ending with nested resource class property and class and namespace (for declaring type) renames. This tiny fragment from unit test suite should give you pretty clear picture of supported cases.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">DbLocalizationProvider.Tests.Refactoring</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
    <span class="p">[</span><span class="nf">RenamedResource</span><span class="p">(</span><span class="s">"OldParentContainerClassAndNamespace"</span><span class="p">,</span> <span class="n">OldNamespace</span> <span class="p">=</span> <span class="s">"In.Galaxy.Far.Far.Away"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">RenamedParentContainerClassAndNamespace</span>
    <span class="p">{</span>
        <span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
        <span class="p">[</span><span class="nf">RenamedResource</span><span class="p">(</span><span class="s">"OldNestedResourceClass"</span><span class="p">)]</span>
        <span class="k">public</span> <span class="k">class</span> <span class="nc">RenamedNestedResourceClass</span>
        <span class="p">{</span>
            <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">NewResourceKey</span> <span class="p">=&gt;</span> <span class="s">"New Resource Key"</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
        <span class="p">[</span><span class="nf">RenamedResource</span><span class="p">(</span><span class="s">"OldNestedResourceClass"</span><span class="p">)]</span>
        <span class="k">public</span> <span class="k">class</span> <span class="nc">RenamedNestedResourceClassAndProperty</span>
        <span class="p">{</span>
            <span class="p">[</span><span class="nf">RenamedResource</span><span class="p">(</span><span class="s">"OldResourceKey"</span><span class="p">)]</span>
            <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">NewResourceKey</span> <span class="p">=&gt;</span> <span class="s">"New Resource Key"</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This might come handy if you are dealing with requirements to rename resources or models and want to preserve existing translations.</p>

<p><strong>NB!</strong> Once migration is done and executed successfully, it’s recommended that you remove obsolete migrations as they might impact startup performance performing not necessary lookups in database trying to figure out which resource to rename and also because resource class looks ugly with all those attributes and ceremony.</p>

<p><br />
Happy localizing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Localization Provider" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization" /><summary type="html"><![CDATA[It’s been a while since last blog post about localization provider. It just means that I’ve been heads down busy with implementing some great features :)]]></summary></entry><entry><title type="html">Strongly Localized EPiServer Categories</title><link href="https://tech-fellow.eu/2017/08/28/strongly-localized-episerver-categories/" rel="alternate" type="text/html" title="Strongly Localized EPiServer Categories" /><published>2017-08-28T14:30:00+03:00</published><updated>2017-08-28T14:30:00+03:00</updated><id>https://tech-fellow.eu/2017/08/28/strongly-localized-episerver-categories</id><content type="html" xml:base="https://tech-fellow.eu/2017/08/28/strongly-localized-episerver-categories/"><![CDATA[<p>Initially <a href="https://nuget.episerver.com/en/OtherPages/Package/?packageId=DbLocalizationProvider.EPiServer">strongly typed localization provider</a> was not planned to be used everywhere in EPiServer, but localizing <a href="https://webhelp.episerver.com/latest/cms-admin/editing-categories.htm?Highlight=categories">categories</a> came as complimentary feature:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">LocalizedResource</span><span class="p">(</span><span class="n">KeyPrefix</span> <span class="p">=</span> <span class="s">"/categories/"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">Categories</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">ResourceKey</span><span class="p">(</span><span class="s">"category[@name=\""</span> <span class="p">+</span> <span class="k">nameof</span><span class="p">(</span><span class="n">SampleCategory</span><span class="p">)</span> <span class="p">+</span> <span class="s">"\"]/description"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">SampleCategory</span> <span class="p">=&gt;</span> <span class="s">"Some Category !"</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Still there is lot of ceremony to get things right..</p>

<p>Sick and tired of generating proper resource keys for localizing EPiServer categories? Say no more. Localization provider gives you now (within latest version) possibility to decorate your class with attribute and necessary translations will be added <a href="https://en.wikipedia.org/wiki/Magic_(programming)">automagically</a>.</p>

<p>Here is a sample category:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">MyProject</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">LocalizedCategory</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">SomeCategory</span> <span class="p">:</span> <span class="n">Category</span> <span class="p">{</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>By adding <code class="language-plaintext highlighter-rouge">[LocalizedCategory]</code> attribute to your class, provider will generate following resource key:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="s">$"/categories/category[@name=\"</span><span class="p">{</span><span class="n">categoryName</span><span class="p">}</span><span class="s">\"]/description"</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>NB!</strong> Class you decorate with <code class="language-plaintext highlighter-rouge">[LocalizedCategory]</code> must inherit from <code class="language-plaintext highlighter-rouge">EPiServer.DataAbstraction.Category</code> class.</p>

<p>This is the key EPiServer will look for when <a href="https://world.episerver.com/blogs/Linus-Ekstrom/Dates/2013/12/New-standardized-format-for-content-type-localizations/">translating categories for UI</a>.
By default <strong>class name</strong> of the category type will be taken as translation for default culture.
You can change this by setting <code class="language-plaintext highlighter-rouge">Name</code> of the category (you might receive warning - that virtual member is used in constructor):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">MyProject</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">LocalizedCategory</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">SomeCategory</span> <span class="p">:</span> <span class="n">Category</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="nf">SomeCategory</span><span class="p">()</span>
        <span class="p">{</span>
            <span class="n">Name</span> <span class="p">=</span> <span class="s">"Some Category !"</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Pst!</strong> Thinking why categories should be defined in code and why my category class should be even inheriting from EPiServer category built-in class?? You definitely wanna check out <a href="https://www.patrickvankleef.com/2016/03/28/strongly-typed-categories">blog post</a> and effort made by brilliant colleague of mine! <strong>Patrick</strong> made it possible to auto register discovered categories in EPiServer from code with no need to access UI to get the boring task done!</p>

<p>Hope this helps! Happy categorizing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Localization Provider" /><category term="Episerver" /><category term="Optimizely" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[Initially strongly typed localization provider was not planned to be used everywhere in EPiServer, but localizing categories came as complimentary feature:]]></summary></entry><entry><title type="html">Feedback Taken - EPiServer Localization Provider Updates</title><link href="https://tech-fellow.eu/2017/07/07/episerver-localization-provider-updates-2/" rel="alternate" type="text/html" title="Feedback Taken - EPiServer Localization Provider Updates" /><published>2017-07-07T14:30:00+03:00</published><updated>2017-07-07T14:30:00+03:00</updated><id>https://tech-fellow.eu/2017/07/07/episerver-localization-provider-updates-2</id><content type="html" xml:base="https://tech-fellow.eu/2017/07/07/episerver-localization-provider-updates-2/"><![CDATA[<p>Listen to the audience. I was more than lucky to be on some local user groups to talk about strongly typed localization provider for EPiServer. Feedback from the audience is more likely to be provided than awaiting comments in blog posts. You have to listen to the audience, you really have to. They are your consumers, they know more about the context and projects where and how your library might be used.</p>

<p>Over couple of last weeks I’ve been heads down busy with some of the feedback implementation. Here is a short list of updates added to latest versions of library (both parts - on <a href="http://nuget.episerver.com/en/?search=dblocalization&amp;sort=MostDownloads&amp;page=1&amp;pageSize=10">EPiServer feed</a> (v3.4) and on <a href="https://www.nuget.org/packages?q=dblocalization">NuGet feed</a> (v2.7)):</p>

<ul>
  <li>Added <a href="#tablesortinginadminui">table sorting</a> in AdminUI</li>
  <li>Added <a href="#treeviewinadminui">tree view for resources</a> in AdminUI</li>
  <li>Ability to generate resources for <a href="#additionalcultures">additional cultures</a></li>
  <li><a href="#cacheevents">Cache events</a></li>
  <li>JsResourceHandler <a href="#jsresourcehandlercachesgeneratedscript">caches generated script</a></li>
</ul>

<h2 id="table-sorting-in-adminui">Table Sorting in AdminUI</h2>

<p>– “Can I sort resources somehow? By key, translation..? Anything..?”<br />
– “..Eh.. No. Not yet..”</p>

<p>Table sorting by any column is now available. Should be much easier for the editors to find what they are looking for.</p>

<p><img src="/assets/img/2017/07/2017-07-05_23-15-59.png" alt="" /></p>

<h2 id="tree-view-in-adminui">Tree View in AdminUI</h2>

<p>Also another request from audience - make it easier for the editors to work with resources (which is quite logical request looking at current flat list with cryptic names there).</p>

<p>Now with the latest version is possible to switch to table view and work with resources there.</p>

<p><img src="/assets/img/2017/07/2017-07-05_23-21-19.png" alt="" /></p>

<p>Unfortunately some of the features (like resource delete) is not properly working yet in the tree view, for that operation - you have to switch back to flat table view and execute there.</p>

<h2 id="additional-cultures">Additional Cultures</h2>

<p>If you need to register resources for other languages as well (not only for default one), it’s possible using following attribute:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">DbLocalizationProvider.Demo</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">CommonResources</span>
    <span class="p">{</span>
        <span class="p">[</span><span class="nf">TranslationForCulture</span><span class="p">(</span><span class="s">"Navn"</span><span class="p">,</span> <span class="s">"no"</span><span class="p">)]</span>
        <span class="p">[</span><span class="nf">TranslationForCulture</span><span class="p">(</span><span class="s">"Namn"</span><span class="p">,</span> <span class="s">"sv"</span><span class="p">)]</span>
        <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">UserName</span> <span class="p">=&gt;</span> <span class="s">"Name"</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>NB!</strong> If there will be duplicate resource translations for the same language - an <strong>exception</strong> will be <strong>thrown</strong>.
Which also means - that theoretically an exception might be thrown if your default language is let’s say “en” and you have additional translations via attribute also set to “en”. So be careful.</p>

<h2 id="cache-events">Cache Events</h2>

<p>Got a request after one of my presentation from audience to <strong>expose events</strong> around cache - when item is added to the cache, when removed, etc. Reason for this was manual cache event propagation further to other nodes in the cluster.</p>

<p>Now you are able to subscribe to cache events via <code class="language-plaintext highlighter-rouge">ConfigurationContext</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="rouge-code"><pre>[assembly: OwinStartup(typeof(Startup))]

namespace DbLocalizationProvider.MvcSample
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseDbLocalizationProvider(ctx =&gt;
            {
                ...
                ctx.CacheManager.OnRemove += CacheManagerOnOnRemove;
            });
        }

        private void CacheManagerOnOnRemove(CacheEventArgs args)
        {
            // black magic happens here..
        }
    }
}
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You will be able to get info about cache event operation (<code class="language-plaintext highlighter-rouge">Insert</code>, <code class="language-plaintext highlighter-rouge">Remove</code>, etc) via <code class="language-plaintext highlighter-rouge">CacheEventArgs</code> argument.</p>

<h2 id="jsresourcehandler-caches-generated-script">JsResourceHandler caches generated script</h2>

<p>Until now every time you would be requesting <a href="https://tech-fellow.ghost.io/2017/03/20/dblocalizationprovider-step-closer-to-front-end/">translations for client-side</a> it would generate script content from fresh start. This is not great! With the help of cache events - now Javascript Resource Handler can easily cache generated script content for the requested translations and store it in memory. Every time any resource that was included in the generated script changes (either by editor or code) event is raised that will signal resource handler to invalidate particular cache entries and build up it upon next request. This greatly increases site performance!</p>

<p><br />
If you have any feedback or ideas to be added to provider - please file them in <a href="https://github.com/valdisiljuconoks/LocalizationProvider">GitHub repo</a>.</p>

<p><br />
Happy localizing..!
<br />
[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Localization Provider" /><category term="Episerver" /><category term="Optimizely" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[Listen to the audience. I was more than lucky to be on some local user groups to talk about strongly typed localization provider for EPiServer. Feedback from the audience is more likely to be provided than awaiting comments in blog posts. You have to listen to the audience, you really have to. They are your consumers, they know more about the context and projects where and how your library might be used.]]></summary></entry><entry><title type="html">Breaking Change in ImageResizer EPiServer Plugin</title><link href="https://tech-fellow.eu/2017/06/05/breaking-changes-in-imageresizer-episerver-plugin/" rel="alternate" type="text/html" title="Breaking Change in ImageResizer EPiServer Plugin" /><published>2017-06-05T14:30:00+03:00</published><updated>2017-06-05T14:30:00+03:00</updated><id>https://tech-fellow.eu/2017/06/05/breaking-changes-in-imageresizer-episerver-plugin</id><content type="html" xml:base="https://tech-fellow.eu/2017/06/05/breaking-changes-in-imageresizer-episerver-plugin/"><![CDATA[<p>Usually I don’t post small changes in separate blog post, but I think that it’s worth to mention breaking changes in latest ImageResizer (IR) plugin for EPiServer.</p>

<h2 id="before">Before</h2>

<p>If you are using <a href="https://github.com/valdisiljuconoks/ImageResizer.Plugins.EPiServerBlobReader#render-image-markup-fluent">Fluent API</a> to resize the image, then you may face inconsistency in API.
Passing in <code class="language-plaintext highlighter-rouge">null</code> or <code class="language-plaintext highlighter-rouge">ContentReference.EmptyReference</code> you will get an <code class="language-plaintext highlighter-rouge">ArgumentNullException</code> exception:</p>

<pre><code class="language-razor">@Html.ResizeImage(null, 100, 100)
</code></pre>

<p>However, if passing in <code class="language-plaintext highlighter-rouge">string.Empty</code> for the another overload - you would get back empty string:</p>

<pre><code class="language-razor">@Html.ResizeImage(string.Empty, 100, 100)
</code></pre>

<p>Why this is bad - you can read more <a href="https://www.nczonline.net/blog/2009/11/30/empty-image-src-can-destroy-your-site/">here</a>. Thx to <a href="https://github.com/kaspars-ozols">Kaspars</a> for the link.
This is inconsistent API and should be fixed.</p>

<h2 id="after">After</h2>

<p>Now (in v6.0 and after) in any case when markup could potentially end up with empty <code class="language-plaintext highlighter-rouge">src</code> attribute - <code class="language-plaintext highlighter-rouge">ResizeImage</code> <strong>will</strong> throw an exception. Both invokes will blow up:</p>

<pre><code class="language-razor">@Html.ResizeImage(null, 100, 100)
@Html.ResizeImage(string.Empty, 100, 100)
</code></pre>

<h2 id="render-with-fallback">Render with Fallback</h2>

<p>Now, to render image from the page property could be cumbersome. You also would need to check for existence of the content reference.</p>

<pre><code class="language-razor">@{
    var imageUrl = Model.ImageLink.IsNullOrEmpty()
        ? new UrlBuilder(string.Empty)
        : Html.ResizeImage(Model.ImageLink, 1600, 670);
}

&lt;div data-src="@imageUrl"&gt;
</code></pre>

<p>To make life easier, there is a new overload in the library:</p>

<pre><code class="language-razor">&lt;div data-src="@Html.ResizeImageWithFallback(Model.ImageLink, "", 1600, 670)"&gt;
</code></pre>

<p>Anyways, just <strong>be sure</strong> to pass in valid fallback image path if you still resizing for <code class="language-plaintext highlighter-rouge">img</code> element, otherwise - you still might destroy your site.</p>

<p>Happy resizing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term="Image Resizer" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="episerver" /><category term="optimizely" /><category term="image resizer" /><summary type="html"><![CDATA[Usually I don’t post small changes in separate blog post, but I think that it’s worth to mention breaking changes in latest ImageResizer (IR) plugin for EPiServer.]]></summary></entry><entry><title type="html">Updates for DbLocalizationProvider - Foreign Resources</title><link href="https://tech-fellow.eu/2017/04/27/updates-for-dblocalizationprovider-foreign-resources/" rel="alternate" type="text/html" title="Updates for DbLocalizationProvider - Foreign Resources" /><published>2017-04-27T16:45:00+03:00</published><updated>2017-04-27T16:45:00+03:00</updated><id>https://tech-fellow.eu/2017/04/27/updates-for-dblocalizationprovider-foreign-resources</id><content type="html" xml:base="https://tech-fellow.eu/2017/04/27/updates-for-dblocalizationprovider-foreign-resources/"><![CDATA[<p>Blog post about latest updates for database localization provider project. Release mainly focuses on foreign affairs - foreign, hidden and referenced resources. Read further for more info.</p>

<h2 id="foreign-resources">Foreign Resources</h2>

<p>Good <a href="http://marisks.net/">friend and colleague</a> of mine asked once: “How do I register localized resources for <a href="http://world.episerver.com/documentation/Items/Developers-Guide/Episerver-Commerce/9/Orders/order-processing/">ValidationIssue</a> enum from EPiServer Commerce assembly?” Short answer back then was - you can’t.
Until now.</p>

<p>With latest database localization provider now you can tell provider to get familiar with so called foreign resources and include those in sync process as well - even they are not decorated with <code class="language-plaintext highlighter-rouge">[LocalizedResource]</code> attribute. Actually attribute is only needed for provider to scan through and understand which types to include in sync process and which not.</p>

<p>Let’s assume for some reason you need to localize foreign resource (<code class="language-plaintext highlighter-rouge">EPiServer.Core.VersionStatus</code>) for what you don’t have source code and you cannot decorate type with required attributes. You will need to add similar code to register foreign resources:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">DbLocalizationProvider.Sample</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
    <span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">InitializationModule</span><span class="p">))]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">InitLocalization</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">ConfigurationContext</span><span class="p">.</span><span class="nf">Setup</span><span class="p">(</span><span class="n">cfg</span> <span class="p">=&gt;</span>
            <span class="p">{</span>
                <span class="p">...</span>

                <span class="n">cfg</span><span class="p">.</span><span class="n">ForeignResources</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">VersionStatus</span><span class="p">));</span>
            <span class="p">});</span>
        <span class="p">}</span>

        <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Using <code class="language-plaintext highlighter-rouge">ForeignResources</code> collection you are telling provider to include those types in resource sync process.
There are couple of extension methods as well for your convenience helping to add types to the collection.</p>

<p>Still you are able to use newly registered foreign resource in the same way as the rest of resources:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">MyCustomViewModel</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="n">VersionStatus</span> <span class="n">Status</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>



<span class="n">@model</span> <span class="n">MyCustomViewModel</span>

<span class="p">...</span><span class="n">razor</span>
<span class="n">@Html</span><span class="p">.</span><span class="nf">TranslateFor</span><span class="p">(</span><span class="n">m</span> <span class="p">=&gt;</span> <span class="n">m</span><span class="p">.</span><span class="n">Status</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Resource key naming conventions are the same as for ordinary discovered resources via <code class="language-plaintext highlighter-rouge">[LocalizedResource]</code> attribute.</p>

<h2 id="hidden-resources">Hidden Resources</h2>

<p>Sometimes you need to have some resources localizable but not visible by default in administration user interface.
No additional permissions are applied for hidden resources - they are just hidden by default from the UI.
If you need hidden &amp; <strong>restricted resources</strong> - please ping me, will see what we can do about that.</p>

<p>To register hidden resource - you just apply <code class="language-plaintext highlighter-rouge">[Hidden]</code> attribute to particular resource.</p>

<p>You can apply attribute to specific member (only that resource will be hidden from UI):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">SomeModelWithHiddenProperty</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">Hidden</span><span class="p">]</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">SomeProperty</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>

<span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
<span class="k">public</span> <span class="k">enum</span> <span class="n">SomeEnumWithHiddenResources</span>
<span class="p">{</span>
    <span class="n">None</span><span class="p">,</span>
    <span class="p">[</span><span class="n">Hidden</span><span class="p">]</span> <span class="n">Some</span><span class="p">,</span>
    <span class="n">Another</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Or you can actually apply to whole class as well (then all discovered resources from that type will be hidden):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
<span class="p">[</span><span class="n">Hidden</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">SomeModelWithHiddenPropertyOnClassLevel</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">SomeProperty</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>

<span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
<span class="p">[</span><span class="n">Hidden</span><span class="p">]</span>
<span class="k">public</span> <span class="k">enum</span> <span class="n">SomeEnumWithAllHiddenResources</span>
<span class="p">{</span>
    <span class="n">None</span><span class="p">,</span>
    <span class="n">Some</span><span class="p">,</span>
    <span class="n">Another</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Translation still works even for hidden resources.
Also, <code class="language-plaintext highlighter-rouge">[Hidden]</code> attribute can be applied to existing resources - metadata in the database will be updated to match the source code.</p>

<h2 id="referenced-resources">Referenced Resources</h2>

<p>Sometimes in your model you need to reference resource from the other - usually common shared resources.</p>

<p>Meaning that there are models with properties that are common for the project (for instance - <code class="language-plaintext highlighter-rouge">Yes</code>, <code class="language-plaintext highlighter-rouge">No</code>, <code class="language-plaintext highlighter-rouge">First name</code>, etc.). If you will just annotate view model with <code class="language-plaintext highlighter-rouge">[LocalizedModel]</code> and will have multiple models with property <code class="language-plaintext highlighter-rouge">FirstName</code> - by default all properties from all models will become localizable resources.
This might pollute your resource list with unnecessary items you would want to avoid.</p>

<p>Now you can “reference” different resource and use that instead of annotated resource.</p>

<p>For example, you have some common resources:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">DbLocalizationProvider.Sample</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">CommonResources</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">CommonProp</span> <span class="p">=&gt;</span> <span class="s">"Common Value"</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Using new attribute you can decorate your model’s property with <code class="language-plaintext highlighter-rouge">[UseResource]</code> attribute (you can also just reference resource using string - <code class="language-plaintext highlighter-rouge">"CommonProp"</code>, I prefer <code class="language-plaintext highlighter-rouge">nameof</code>):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">DbLocalizationProvider.Sample</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">ModelWithOtherResourceUsage</span>
    <span class="p">{</span>
        <span class="p">[</span><span class="nf">UseResource</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">CommonResources</span><span class="p">),</span>
                     <span class="k">nameof</span><span class="p">(</span><span class="n">CommonResources</span><span class="p">.</span><span class="n">CommonProp</span><span class="p">))]</span>
        <span class="k">public</span> <span class="kt">string</span> <span class="n">SomeProperty</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So, now if you will try to localize <code class="language-plaintext highlighter-rouge">SomeProperty</code> for this view model - common resource will be returned:</p>

<pre><code class="language-razor">@model ModelWithOtherResourceUsage

...
@Html.TranslateFor(m =&gt; m.SomeProperty)
</code></pre>

<p>Instead of <code class="language-plaintext highlighter-rouge">ModelWithOtherResourceUsage.SomeProperty</code> resource, <code class="language-plaintext highlighter-rouge">CommonResources.CommonProp</code> key will be used.
There will be no resource for key <code class="language-plaintext highlighter-rouge">ModelWithOtherResourceUsage.SomeProperty</code> registered in database.
Whenever you will change translation for <code class="language-plaintext highlighter-rouge">CommonResources.CommonProp</code> resource - it will be used everywhere you referenced it using <code class="language-plaintext highlighter-rouge">[UseResource]</code> attribute.</p>

<h2 id="where-to-get">Where to get?</h2>

<p>As usual - new version is available on <a href="https://www.nuget.org/packages?q=dblocalization">nuget.org</a> and <a href="http://nuget.episerver.com/en/?search=dblocalization&amp;sort=MostDownloads&amp;page=1&amp;pageSize=10">EPiServer feeds</a>.</p>

<p><br />
Happy localizing!<br />
[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Localization Provider" /><category term="Episerver" /><category term="Optimizely" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[Blog post about latest updates for database localization provider project. Release mainly focuses on foreign affairs - foreign, hidden and referenced resources. Read further for more info.]]></summary></entry><entry><title type="html">Disposable Dependency for Azure WebJob</title><link href="https://tech-fellow.eu/2017/04/12/disposable-dependency-for-azure-webjob/" rel="alternate" type="text/html" title="Disposable Dependency for Azure WebJob" /><published>2017-04-12T16:45:00+03:00</published><updated>2017-04-12T16:45:00+03:00</updated><id>https://tech-fellow.eu/2017/04/12/disposable-dependency-for-azure-webjob</id><content type="html" xml:base="https://tech-fellow.eu/2017/04/12/disposable-dependency-for-azure-webjob/"><![CDATA[<p>Recently we had experience with Azure WebJobs hosting system and specificely - with disposable jobs. This blog post will describe how to properly handle disposable job dependency.</p>

<h2 id="why-dependency">Why Dependency?</h2>

<p>You might ask, why I need to have dependencies for the Azure WebJob. The only purpose for WebJob would be to kick-off rest of the services and transfer control to them to do the work. According to some software architectural theories - WebJob is just the delivery mechanism, it’s a trigger for other services to step up and carry out the business task. However, in this <a href="https://tech-fellow.eu/2016/10/17/baking-round-shaped-software/">pizza’s crunchy outer edge</a>, composition of the services and other involved parties happens. Even if <strong>WebJob</strong> does not do much, it’s still the <a href="http://blog.ploeh.dk/2011/07/28/CompositionRoot/">composition root</a> which <strong>plays</strong> important <strong>role</strong> in whole application. It’s the place where composition of object graph happens.</p>

<h2 id="why-disposable-dependency">Why Disposable Dependency?</h2>

<p>There might be various types of dependencies required for the WebJob to run successfully. Some of them should be created every time requested, some of them should be singleton all the time. But some of them should be disposable.</p>

<p>By disposable - I mean that dependency is singleton while job instance is running, but gets new instance once new job is executed. So, if job <code class="language-plaintext highlighter-rouge">A</code> starts new instance of this job is created - <code class="language-plaintext highlighter-rouge">A1</code>, instance of disposable dependency <code class="language-plaintext highlighter-rouge">D</code> is also created - <code class="language-plaintext highlighter-rouge">D1</code>. If there are any service or anybody else requires this dependency, the same instance <code class="language-plaintext highlighter-rouge">D1</code> is passed to the service. But then, next time job starts - <code class="language-plaintext highlighter-rouge">A2</code> instance is created and also <code class="language-plaintext highlighter-rouge">D2</code> is being created. But <code class="language-plaintext highlighter-rouge">D2</code> is shared across all services within <code class="language-plaintext highlighter-rouge">A2</code> run cycle.</p>

<p>One of our <strong>usage for disposable dependency</strong> was tiny profiler class that we can use to collect more diagnostics data as we go along, and “dump” all stuff collected during web job run cycle to some more persistant storage. So we needed to maintain “singleton” instance behavior between various services, make it unique within every web job run cycle and have it disposable, so we could write down collected data to some storage.</p>

<p>One of the easiest way to accomplish this requirement - to utilize <a href="http://structuremap.github.io/the-container/nested-containers/">nested containers</a> in StructureMap library. Our idea was to create nested container for every job run cycle and request services from there. Meaning that we can require the same dependency over and over again from nested container - the same instance should be returned. In StructureMap - nested container itself is treated as <code class="language-plaintext highlighter-rouge">Transient</code> scoped lifetime object.</p>

<h2 id="how-azure-webjob-composes-object-graph">How Azure WebJob Composes Object Graph?</h2>

<p>Now when we know that WebJob is composition root, question is how it composes needed object graph for the job?</p>

<p>When configuring Azure WebJobs, there is possibility to setup activator that will be used to create new instances of web jobs. In this case I’m using one of my favorite IoC libs <a href="http://structuremap.github.io/">StructureMap</a>. Code is simple enough (in <code class="language-plaintext highlighter-rouge">Program.cs</code>):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
</pre></td><td class="rouge-code"><pre><span class="k">static</span> <span class="k">void</span> <span class="nf">Main</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">container</span> <span class="p">=</span> <span class="nf">ComposeContainer</span><span class="p">();</span>
    <span class="kt">var</span> <span class="n">config</span> <span class="p">=</span> <span class="k">new</span> <span class="n">JobHostConfiguration</span>
        <span class="p">{</span>
            <span class="n">JobActivator</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">StructureMapActivator</span><span class="p">(</span><span class="n">container</span><span class="p">)</span>
        <span class="p">};</span>

    <span class="k">if</span><span class="p">(</span><span class="n">DataPumpConfig</span><span class="p">.</span><span class="n">IsDevelopment</span><span class="p">)</span>
        <span class="n">config</span><span class="p">.</span><span class="nf">UseDevelopmentSettings</span><span class="p">();</span>

    <span class="n">config</span><span class="p">.</span><span class="nf">UseTimers</span><span class="p">();</span>

    <span class="kt">var</span> <span class="n">host</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">JobHost</span><span class="p">(</span><span class="n">config</span><span class="p">);</span>
    <span class="n">host</span><span class="p">.</span><span class="nf">RunAndBlock</span><span class="p">();</span>
<span class="p">}</span>

<span class="k">private</span> <span class="k">static</span> <span class="n">IContainer</span> <span class="nf">ComposeContainer</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">container</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">Container</span><span class="p">();</span>
    <span class="c1">// here you configure everything needed for your container</span>
    <span class="p">....</span>

    <span class="k">return</span> <span class="n">container</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>StructureMapActivator.cs:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">StructureMapActivator</span> <span class="p">:</span> <span class="n">IJobActivator</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">Container</span> <span class="n">_container</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">StructureMapActivator</span><span class="p">(</span><span class="n">Container</span> <span class="n">container</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span><span class="p">(</span><span class="n">container</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
            <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">container</span><span class="p">));</span>

        <span class="n">_container</span> <span class="p">=</span> <span class="n">container</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">T</span> <span class="n">CreateInstance</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">function</span> <span class="p">=</span> <span class="n">_container</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;();</span>
        <span class="k">return</span> <span class="n">function</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is the way how WebJob host can compose functions using StructureMap IoC library. Of course you can also go with <a href="http://blog.ploeh.dk/2014/06/10/pure-di/">Pure DI</a> here. It’s just a question of taste.</p>

<h2 id="how-azure-webjob-host-handles-disposable">How Azure WebJob Host Handles Disposable?</h2>

<p>Question is how Azure WebJob host handles disposable objects? Fiddling around source code of the web job hosting environment, found out that there is class named <code class="language-plaintext highlighter-rouge">FunctionInvoker&lt;T&gt;</code> that’s responsible for maintaining job instances upon demand when executing one. Code is similar to this one:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">InvokeAsync</span><span class="p">(</span><span class="kt">object</span><span class="p">[]</span> <span class="n">arguments</span><span class="p">)</span>
<span class="p">{</span>
  <span class="kt">var</span> <span class="n">instance</span> <span class="p">=</span> <span class="k">this</span><span class="p">.</span><span class="n">_instanceFactory</span><span class="p">.</span><span class="nf">Create</span><span class="p">();</span>
  <span class="k">using</span> <span class="p">((</span><span class="kt">object</span><span class="p">)</span> <span class="n">instance</span> <span class="k">as</span> <span class="n">IDisposable</span><span class="p">)</span>
    <span class="k">await</span> <span class="n">_methodInvoker</span><span class="p">.</span><span class="nf">InvokeAsync</span><span class="p">(</span><span class="n">instance</span><span class="p">,</span> <span class="n">arguments</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Meaning that if host can cast job instance to <code class="language-plaintext highlighter-rouge">IDisposable</code> - it’s then wrapped into <code class="language-plaintext highlighter-rouge">using</code> statement. This will ensure that job has possibility to release all necessary resources when disposing job instance.</p>

<p>So you can have this job for instance:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">MyDisposableJob</span> <span class="p">:</span> <span class="n">IDisposable</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">MyDisposableJob</span><span class="p">(</span><span class="n">IDisposableService</span> <span class="n">service</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="p">...</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">DoStuff</span><span class="p">([</span><span class="nf">TimerTrigger</span><span class="p">(</span><span class="s">"00:00:01"</span><span class="p">)]</span><span class="n">TimerInfo</span> <span class="n">timerInfo</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="p">...</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Dispose</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="c1">// release all held resources</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So we do have now <code class="language-plaintext highlighter-rouge">IJobActivator</code> that is responsible creating job instances and also function invoke that is responsible for releasing disposable web job instances. Question is - when exactly and how do I need to release disposable dependencies? Who is responsible for that?</p>

<h2 id="when-to-release-issue-with-ijobactivator">When to Release (Issue with IJobActivator)?</h2>

<p>Following best dependency injection practices - there is <a href="http://blog.ploeh.dk/2010/09/29/TheRegisterResolveReleasepattern/">triple “R”</a> pattern when it comes to Dependency Injection. Meaning that there has to be “<em>Register</em>”, “<em>Resolve</em>” and “<em>Release</em>” stages during host lifetime. “<em>Register</em>” might happen only once - in <code class="language-plaintext highlighter-rouge">JobHost</code> creation - when we were composing container. “<em>Resolve</em>” happens in <code class="language-plaintext highlighter-rouge">IJobActivator</code> - when host is asking to create new instance of the job. We are <strong>missing</strong> “<em>Release</em>”!</p>

<p>There has to be “<em>Release</em>” stage to properly dispose nested containers. <code class="language-plaintext highlighter-rouge">IJobActivator</code> is composition root. <code class="language-plaintext highlighter-rouge">FunctionInvoker&lt;T&gt;</code> is responsible for asking to make job instances via <code class="language-plaintext highlighter-rouge">CreateInstance()</code> method - which means there has to be “release hook” for the job activator to handle when function invoker has done its work and job is about being released (disposed).</p>

<p>Control flow is following:</p>

<p><img src="/assets/img/2017/04/Drawing1.png" alt="" /></p>

<p>So there is no explicit moment when job activator or whoever else would be able to handle job dispose event and do some black magic there. I came up with hacky workaround. Would love to hear any feedback..</p>

<h2 id="releasing-disposable-dependency">Releasing Disposable Dependency</h2>

<p>How to resolve and then release these disposable dependencies from the nested container?
Here is what I came up with. First, we need to modify a bit our <code class="language-plaintext highlighter-rouge">StructureMapActivator</code>. We need to create nested container and then resolve requested job from that container. This is needed because of “singleton” instances for dependencies within the same job execution cycle.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">StructureMapActivator</span> <span class="p">:</span> <span class="n">IJobActivator</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">Container</span> <span class="n">_container</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">StructureMapActivator</span><span class="p">(</span><span class="n">Container</span> <span class="n">container</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span><span class="p">(</span><span class="n">container</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
            <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">container</span><span class="p">));</span>

        <span class="n">_container</span> <span class="p">=</span> <span class="n">container</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">T</span> <span class="n">CreateInstance</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">nestedContainer</span> <span class="p">=</span> <span class="n">_container</span><span class="p">.</span><span class="nf">GetNestedContainer</span><span class="p">();</span>
        <span class="kt">var</span> <span class="n">function</span> <span class="p">=</span> <span class="n">nestedContainer</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;();</span>

        <span class="k">return</span> <span class="n">function</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Anyway, there - we are still missing this “<em>Release</em>” stage - there is no room for the activator to know when function invoker has done its work and job is going to be disposed.</p>

<p>Knowing that all disposable jobs are handled correctly from job host perspective  - we introduce new type of jobs: a base class for all your jobs:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">BaseFunction</span> <span class="p">:</span> <span class="n">IDisposable</span>
<span class="p">{</span>
    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Idea is that we can pass over <code class="language-plaintext highlighter-rouge">nestedContainer</code> instance to job itself and at least job instance will be responsible for releasing that container - when function invoker has done its work..</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">StructureMapActivator</span> <span class="p">:</span> <span class="n">IJobActivator</span>
<span class="p">{</span>
    <span class="p">...</span>

    <span class="k">public</span> <span class="n">T</span> <span class="n">CreateInstance</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">nestedContainer</span> <span class="p">=</span> <span class="n">_container</span><span class="p">.</span><span class="nf">GetNestedContainer</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">T</span><span class="p">).</span><span class="n">Name</span><span class="p">);</span>
        <span class="kt">var</span> <span class="n">function</span> <span class="p">=</span> <span class="n">nestedContainer</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;();</span>

        <span class="kt">var</span> <span class="n">disposableFunction</span> <span class="p">=</span> <span class="n">function</span> <span class="k">as</span> <span class="n">BaseFunction</span><span class="p">;</span>
        <span class="n">disposableFunction</span><span class="p">?.</span><span class="nf">SetChildContainer</span><span class="p">(</span><span class="n">nestedContainer</span><span class="p">);</span>

        <span class="k">return</span> <span class="n">function</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>and now we need to implement <code class="language-plaintext highlighter-rouge">SetChildContainer</code> method in our base job:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">BaseFunction</span> <span class="p">:</span> <span class="n">IDisposable</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="n">IContainer</span> <span class="n">_childContainer</span><span class="p">;</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Dispose</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">_childContainer</span><span class="p">?.</span><span class="nf">Dispose</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">SetChildContainer</span><span class="p">(</span><span class="n">IContainer</span> <span class="n">nestedContainer</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_childContainer</span> <span class="p">=</span> <span class="n">nestedContainer</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Here is our base job, we know precisely when job is being disposed - so we have possibility to hook into and release nested container when needed.</p>

<h2 id="diagnostics-tracer-as-disposable-dependency">Diagnostics Tracer as Disposable Dependency</h2>

<p>We had requirement to collect tiny diagnostics around some of the our business processes to write them down to diagnostics storage. What we did is introduced interface for the rest of the services to rely on:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">interface</span> <span class="nc">IProfilerWriter</span>
<span class="p">{</span>
    <span class="k">void</span> <span class="nf">Write</span><span class="p">(</span><span class="kt">string</span> <span class="n">message</span><span class="p">);</span>

    <span class="n">IDisposable</span> <span class="nf">Measure</span><span class="p">(</span><span class="kt">string</span> <span class="n">messagePattern</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Method <code class="language-plaintext highlighter-rouge">Measure()</code> is really useful when you would like to <strong>explicitly</strong> measure performance of some of the methods or code block. You could write:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">MyDisposableJob</span> <span class="p">:</span> <span class="n">IDisposable</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">MyDisposableJob</span><span class="p">(</span><span class="n">IDisposableService</span> <span class="n">service</span><span class="p">,</span> <span class="n">IProfilerWriter</span> <span class="n">profiler</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="p">...</span>
        <span class="n">_profiler</span> <span class="p">=</span> <span class="n">profiler</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">DoStuff</span><span class="p">([</span><span class="nf">TimerTrigger</span><span class="p">(</span><span class="s">"00:00:01"</span><span class="p">)]</span><span class="n">TimerInfo</span> <span class="n">timerInfo</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="p">...</span>
        <span class="k">using</span><span class="p">(</span><span class="n">_profiler</span><span class="p">.</span><span class="nf">Measure</span><span class="p">(</span><span class="s">"Get records took: {0}"</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="c1">// retrieve records from somewhere</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then we have profiler implementation:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">ProfilerWriter</span> <span class="p">:</span> <span class="n">IProfilerWriter</span><span class="p">,</span> <span class="n">IDisposable</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">ConcurrentDictionary</span><span class="p">&lt;</span><span class="n">DateTime</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;</span> <span class="n">_messages</span> <span class="p">=</span>
        <span class="k">new</span> <span class="n">ConcurrentDictionary</span><span class="p">&lt;</span><span class="n">DateTime</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;();</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Dispose</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="p">...</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Write</span><span class="p">(</span><span class="kt">string</span> <span class="n">message</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_messages</span><span class="p">.</span><span class="nf">TryAdd</span><span class="p">(</span><span class="n">DateTime</span><span class="p">.</span><span class="n">UtcNow</span><span class="p">,</span> <span class="n">message</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">IDisposable</span> <span class="nf">Measure</span><span class="p">(</span><span class="kt">string</span> <span class="n">messagePattern</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="k">new</span> <span class="nf">ProfilerCaptureScope</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="n">messagePattern</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>NB!</strong> Usually profiler measurements should be implemented as infrastructure code (decorators, interceptors, whatever). But sometimes you need to capture also small fraction of bigger process, so then explicitly taking samples could be effective.</p>

<p>Profiler scope class is another disposable that’s running timer once it’s created and stops it when disposed:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">ProfilerCaptureScope</span> <span class="p">:</span> <span class="n">IDisposable</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IProfilerWriter</span> <span class="n">_profiler</span><span class="p">;</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="kt">string</span> <span class="n">_messagePattern</span><span class="p">;</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">Stopwatch</span> <span class="n">_clock</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">Stopwatch</span><span class="p">();</span>

    <span class="k">public</span> <span class="nf">ProfilerCaptureScope</span><span class="p">(</span><span class="n">IProfilerWriter</span> <span class="n">profiler</span><span class="p">,</span> <span class="kt">string</span> <span class="n">messagePattern</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span><span class="p">(</span><span class="n">profiler</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
            <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">profiler</span><span class="p">));</span>

        <span class="k">if</span><span class="p">(</span><span class="kt">string</span><span class="p">.</span><span class="nf">IsNullOrWhiteSpace</span><span class="p">(</span><span class="n">messagePattern</span><span class="p">))</span>
            <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">messagePattern</span><span class="p">));</span>

        <span class="n">_profiler</span> <span class="p">=</span> <span class="n">profiler</span><span class="p">;</span>
        <span class="n">_messagePattern</span> <span class="p">=</span> <span class="n">messagePattern</span><span class="p">;</span>
        <span class="n">_clock</span><span class="p">.</span><span class="nf">Start</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="k">protected</span> <span class="k">virtual</span> <span class="k">void</span> <span class="nf">Dispose</span><span class="p">(</span><span class="kt">bool</span> <span class="n">disposing</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span><span class="p">(</span><span class="n">disposing</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">_clock</span><span class="p">.</span><span class="nf">Stop</span><span class="p">();</span>
            <span class="n">_profiler</span><span class="p">.</span><span class="nf">Write</span><span class="p">(</span><span class="kt">string</span><span class="p">.</span><span class="nf">Format</span><span class="p">(</span><span class="n">_messagePattern</span><span class="p">,</span> <span class="n">_clock</span><span class="p">.</span><span class="n">ElapsedMilliseconds</span><span class="p">));</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Dispose</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="nf">Dispose</span><span class="p">(</span><span class="k">true</span><span class="p">);</span>
        <span class="n">GC</span><span class="p">.</span><span class="nf">SuppressFinalize</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And then in <code class="language-plaintext highlighter-rouge">ProfilerWriter.Dispose()</code> method you can use any storage if you need to persist diagnostics trace for that particular job execution cycle (we are using Azure Table Storage for that). I’ll skip implementation for write here..</p>

<h2 id="proper-solution-instead-of-workaround">Proper Solution (Instead of Workaround)</h2>

<p>Wondering what would be solution for this hacky workaround? If framework is going to ask you to create new instance of anything, it has to tell you also when it has done its work and is about to release created instance.</p>

<p>New definition of <code class="language-plaintext highlighter-rouge">IJobActivator</code> interface might look like this:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">interface</span> <span class="nc">IJobActivator</span>
<span class="p">{</span>
  <span class="n">T</span> <span class="n">CreateInstance</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;();</span>

  <span class="n">ReleaseInstance</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">T</span> <span class="n">instance</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>There is explicit “<em>Resolve</em>” and “<em>Release</em>” phase you can hook into and perform your tasks.</p>

<p>Happy web jobbing! :)</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Azure" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="azure" /><summary type="html"><![CDATA[Recently we had experience with Azure WebJobs hosting system and specificely - with disposable jobs. This blog post will describe how to properly handle disposable job dependency.]]></summary></entry><entry><title type="html">DbLocalizationProvider step closer to front-end</title><link href="https://tech-fellow.eu/2017/03/21/dblocalizationprovider-step-closer-to-front-end/" rel="alternate" type="text/html" title="DbLocalizationProvider step closer to front-end" /><published>2017-03-21T15:45:00+02:00</published><updated>2017-03-21T15:45:00+02:00</updated><id>https://tech-fellow.eu/2017/03/21/dblocalizationprovider-step-closer-to-front-end</id><content type="html" xml:base="https://tech-fellow.eu/2017/03/21/dblocalizationprovider-step-closer-to-front-end/"><![CDATA[<p>Along with other smaller bug fixes, database-driven localization provider for EPiServer got closer to front-end. We joined forces together with my old pal and friend <a href="https://github.com/ArveSystad">Arve Systad</a> and made it possible to add translations to client side resources as well.</p>

<h2 id="setup">Setup</h2>

<p>So setup for the client-side resource localization with help of DbLocalizationProvider plugin is more or less straight forward. You will need to install <code class="language-plaintext highlighter-rouge">DbLocalizationProvider.EPiServer.JsResourceHandler</code> package from <a href="http://nuget.episerver.com/en/?search=localization">EPiServer feed</a> and add corresponding <code class="language-plaintext highlighter-rouge">&lt;script&gt;</code> include in your markup file to fetch translations from the server:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"/jsl10n/{beginning-of-resource-key(s)}"</span><span class="nt">&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You have to specify beginning of resource keys to fetch those from the server. For instance you have following resources defined in your code:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">MyProject</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">MyResources</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">FirstProperty</span> <span class="p">=&gt;</span> <span class="s">"One"</span><span class="p">;</span>
        <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">SecondProperty</span> <span class="p">=&gt;</span> <span class="s">"Two"</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You can use Html helper to get translations:</p>

<pre><code class="language-razor">@Html.GetTranslations(typeof(MyProject.MyResources))
</code></pre>

<p>However if you have more than single resource container type:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">MyProject</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">MyResources</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">FirstProperty</span> <span class="p">=&gt;</span> <span class="s">"One"</span><span class="p">;</span>
        <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">SecondProperty</span> <span class="p">=&gt;</span> <span class="s">"Two"</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">AlternativeResources</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">ThirdProperty</span> <span class="p">=&gt;</span> <span class="s">"Three"</span><span class="p">;</span>
        <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">FothProperty</span> <span class="p">=&gt;</span> <span class="s">"Four"</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>following resources will be registered:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre>MyProject.MyResources.FirstProperty
MyProject.MyResources.SecondProperty
MyProject.AlternativeResources.ThirdProperty
MyProject.AlternativeResources.FothProperty
</pre></td></tr></tbody></table></code></pre></div></div>

<p>To include all resources from those classes, you will need to specify <em>parent</em> container name:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"/jsl10n/MyProject"</span><span class="nt">&gt;&lt;/script&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>All resources from both classes will be retrieved:</p>

<p><img src="/assets/img/2017/03/2017-03-19_23-54-26.png" alt="" /></p>

<p>Resources retrieved in this way are accessible via <code class="language-plaintext highlighter-rouge">jsl10n</code> global variable:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;script </span><span class="na">type=</span><span class="s">"text/javascript"</span><span class="nt">&gt;</span>
   <span class="nf">alert</span><span class="p">(</span><span class="nb">window</span><span class="p">.</span><span class="nx">jsl10n</span><span class="p">.</span><span class="nx">MyProject</span><span class="p">.</span><span class="nx">AlternativeResources</span><span class="p">.</span><span class="nx">ThirdProperty</span><span class="p">);</span>
<span class="nt">&lt;/script&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>NB!</strong> Notice that naming notation of the resource is exactly the same as it’s on the server-side. This notation should reduce confusion and make is less problematic to switch from server-side code to front-end, and vice versa.</p>

<h2 id="aliases">Aliases</h2>

<p>Sometimes it’s required to split resources into different groups and have access to them separately. Also the same problem will occur when you would like to retrieve resources from two different namespaces in single page. Therefore aliasing particular group of resources might come handy. You have to specify <code class="language-plaintext highlighter-rouge">alias</code> query string parameter:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"/jsl10n/MyProject.MyResources?alias=m"</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"/jsl10n/MyProject.AlternativeResources?alias=ar"</span><span class="nt">&gt;&lt;/script&gt;</span>

<span class="nt">&lt;script </span><span class="na">type=</span><span class="s">"text/javascript"</span><span class="nt">&gt;</span>
   <span class="nf">alert</span><span class="p">(</span><span class="nb">window</span><span class="p">.</span><span class="nx">m</span><span class="p">.</span><span class="nx">MyProject</span><span class="p">.</span><span class="nx">MyResources</span><span class="p">.</span><span class="nx">FirstProperty</span><span class="p">);</span>

   <span class="nf">alert</span><span class="p">(</span><span class="nb">window</span><span class="p">.</span><span class="nx">ar</span><span class="p">.</span><span class="nx">MyProject</span><span class="p">.</span><span class="nx">AlternativeResources</span><span class="p">.</span><span class="nx">ForthProperty</span><span class="p">);</span>
<span class="nt">&lt;/script&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="explicit-translation-culture">Explicit Translation Culture</h2>

<p>Sometimes it’s also necessary to fetch translations for other language. This is possible specifying <code class="language-plaintext highlighter-rouge">lang</code> query parameter.</p>

<p>For single container translations:</p>

<pre><code class="language-razor">@Html.GetTranslations(typeof(MyProject.MyResources), new CultureInfo("en").Name)
</code></pre>

<p>Or for multiple containers:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"/jsl10n/MyProject?lang=no"</span><span class="nt">&gt;&lt;/script&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Note:</strong> Those resources that do not have translation in requested language will not be emitted in resulting <code class="language-plaintext highlighter-rouge">json</code> response.</p>

<p>Happy front-end localization!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Localization Provider" /><category term="Episerver" /><category term="Optimizely" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[Along with other smaller bug fixes, database-driven localization provider for EPiServer got closer to front-end. We joined forces together with my old pal and friend Arve Systad and made it possible to add translations to client side resources as well.]]></summary></entry><entry><title type="html">Small Enhancement for Feature Folders</title><link href="https://tech-fellow.eu/2017/03/08/small-enhancement-for-feature-folders/" rel="alternate" type="text/html" title="Small Enhancement for Feature Folders" /><published>2017-03-08T15:45:00+02:00</published><updated>2017-03-08T15:45:00+02:00</updated><id>https://tech-fellow.eu/2017/03/08/small-enhancement-for-feature-folders</id><content type="html" xml:base="https://tech-fellow.eu/2017/03/08/small-enhancement-for-feature-folders/"><![CDATA[<p>Great colleague of mine <a href="https://github.com/marisks">Māris Krivtežs</a> wrote <a href="http://marisks.net/2017/02/03/razor-view-engine-for-feature-folders/">blog post</a> about feature folders describing code organization into folders by features or functional areas rather than technology or different grouping.</p>

<p>However, one of cons from Maris’ approach we couldn’t reconcile with - name of the sub-feature folder needs to follow Mvc controller naming convention.</p>

<blockquote>
  <p>“Another issue is related to the sub-feature folder naming. Sub-feature folder still should be called with <strong>the same</strong> name <strong>as a controller.</strong>”</p>
</blockquote>

<p>So I made tiny adjustment to the view engine worth sharing. Adjusted code is below.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">SiteViewEngine</span> <span class="p">:</span> <span class="n">RazorViewEngine</span>
<span class="p">{</span>
    <span class="cm">/*
     Placeholders:
     *      {2} - Name of the Mvc area
     *      {1} - Name of the controller
     *      {0} - Name of the action (name of the partial view)
     */</span>

    <span class="k">public</span> <span class="nf">SiteViewEngine</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">featureFolders</span> <span class="p">=</span> <span class="k">new</span> <span class="p">[]</span>
        <span class="p">{</span>
            <span class="s">"~/Features/{0}.cshtml"</span><span class="p">,</span>
            <span class="s">"~/Features/{1}{0}.cshtml"</span><span class="p">,</span>
            <span class="s">"~/Features/{1}/{0}.cshtml"</span><span class="p">,</span>
            <span class="s">"~/Features/{1}/Views/{0}.cshtml"</span><span class="p">,</span>
            <span class="s">"~/Features/{1}/Views/{1}.cshtml"</span><span class="p">,</span>
        <span class="p">}</span>
        <span class="p">.</span><span class="nf">Union</span><span class="p">(</span><span class="nf">SubFeatureFolders</span><span class="p">(</span><span class="s">"~/Features"</span><span class="p">))</span>
        <span class="p">.</span><span class="nf">ToArray</span><span class="p">();</span>

        <span class="n">ViewLocationFormats</span> <span class="p">=</span> <span class="n">ViewLocationFormats</span>
                              <span class="p">.</span><span class="nf">Union</span><span class="p">(</span><span class="n">featureFolders</span><span class="p">)</span>
                              <span class="p">.</span><span class="nf">ToArray</span><span class="p">();</span>

        <span class="n">PartialViewLocationFormats</span> <span class="p">=</span> <span class="n">PartialViewLocationFormats</span>
                                     <span class="p">.</span><span class="nf">Union</span><span class="p">(</span><span class="n">featureFolders</span><span class="p">)</span>
                                     <span class="p">.</span><span class="nf">ToArray</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;</span> <span class="nf">SubFeatureFolders</span><span class="p">(</span><span class="kt">string</span> <span class="n">rootFolder</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">rootPath</span> <span class="p">=</span> <span class="n">HostingEnvironment</span><span class="p">.</span><span class="nf">MapPath</span><span class="p">(</span><span class="n">rootFolder</span><span class="p">);</span>
        <span class="k">if</span><span class="p">(</span><span class="n">rootPath</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
            <span class="k">return</span> <span class="n">Enumerable</span><span class="p">.</span><span class="n">Empty</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;();</span>

        <span class="kt">var</span> <span class="n">featureFolders</span> <span class="p">=</span> <span class="n">Directory</span><span class="p">.</span><span class="nf">GetDirectories</span><span class="p">(</span><span class="n">rootPath</span><span class="p">)</span>
                                      <span class="p">.</span><span class="nf">Select</span><span class="p">(</span><span class="n">GetDirectory</span><span class="p">);</span>

        <span class="kt">var</span> <span class="n">features</span> <span class="p">=</span> <span class="n">featureFolders</span><span class="p">.</span><span class="nf">Select</span><span class="p">(</span><span class="n">a</span> <span class="p">=&gt;</span> <span class="k">new</span>
                        <span class="p">{</span>
                            <span class="n">a</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span>
                            <span class="n">Features</span> <span class="p">=</span> <span class="n">Directory</span><span class="p">.</span><span class="nf">GetDirectories</span><span class="p">(</span><span class="n">a</span><span class="p">.</span><span class="n">FullName</span><span class="p">)</span>
                                                <span class="p">.</span><span class="nf">Select</span><span class="p">(</span><span class="n">GetDirectoryName</span><span class="p">)</span>
                        <span class="p">});</span>

        <span class="k">return</span> <span class="n">features</span><span class="p">.</span><span class="nf">SelectMany</span><span class="p">(</span><span class="n">feature</span> <span class="p">=&gt;</span>
                <span class="p">{</span>
                    <span class="k">return</span> <span class="k">new</span><span class="p">[]</span>
                    <span class="p">{</span>
                        <span class="s">$"</span><span class="p">{</span><span class="n">rootFolder</span><span class="p">}</span><span class="s">/</span><span class="p">{</span><span class="n">feature</span><span class="p">.</span><span class="n">Name</span><span class="p">}</span><span class="s">/0.cshtml"</span><span class="p">,</span>
                        <span class="s">$"</span><span class="p">{</span><span class="n">rootFolder</span><span class="p">}</span><span class="s">/</span><span class="p">{</span><span class="n">feature</span><span class="p">.</span><span class="n">Name</span><span class="p">}</span><span class="s">/10.cshtml"</span><span class="p">,</span>
                        <span class="s">$"</span><span class="p">{</span><span class="n">rootFolder</span><span class="p">}</span><span class="s">/</span><span class="p">{</span><span class="n">feature</span><span class="p">.</span><span class="n">Name</span><span class="p">}</span><span class="s">/Views/10.cshtml"</span><span class="p">,</span>
                        <span class="s">$"</span><span class="p">{</span><span class="n">rootFolder</span><span class="p">}</span><span class="s">/</span><span class="p">{</span><span class="n">feature</span><span class="p">.</span><span class="n">Name</span><span class="p">}</span><span class="s">/Views/1/0.cshtml"</span>
                    <span class="p">}</span>
                    <span class="p">.</span><span class="nf">Union</span><span class="p">(</span>
                       <span class="n">feature</span><span class="p">.</span><span class="n">Features</span>
                              <span class="p">.</span><span class="nf">SelectMany</span><span class="p">(</span><span class="n">subFfeature</span> <span class="p">=&gt;</span> <span class="k">new</span><span class="p">[]</span>
                              <span class="p">{</span>
                                <span class="s">$"</span><span class="p">{</span><span class="n">rootFolder</span><span class="p">}</span><span class="s">/</span><span class="p">{</span><span class="n">feature</span><span class="p">.</span><span class="n">Name</span><span class="p">}</span><span class="s">/</span><span class="p">{</span><span class="n">subFfeature</span><span class="p">}</span><span class="s">/0.cshtml"</span><span class="p">,</span>
                                <span class="s">$"</span><span class="p">{</span><span class="n">rootFolder</span><span class="p">}</span><span class="s">/</span><span class="p">{</span><span class="n">feature</span><span class="p">.</span><span class="n">Name</span><span class="p">}</span><span class="s">/</span><span class="p">{</span><span class="n">subFfeature</span><span class="p">}</span><span class="s">/10.cshtml"</span><span class="p">,</span>
                                <span class="s">$"</span><span class="p">{</span><span class="n">rootFolder</span><span class="p">}</span><span class="s">/</span><span class="p">{</span><span class="n">feature</span><span class="p">.</span><span class="n">Name</span><span class="p">}</span><span class="s">/</span><span class="p">{</span><span class="n">subFfeature</span><span class="p">}</span><span class="s">/Views/1/0.cshtml"</span><span class="p">,</span>
                                <span class="s">$"</span><span class="p">{</span><span class="n">rootFolder</span><span class="p">}</span><span class="s">/</span><span class="p">{</span><span class="n">feature</span><span class="p">.</span><span class="n">Name</span><span class="p">}</span><span class="s">/</span><span class="p">{</span><span class="n">subFfeature</span><span class="p">}</span><span class="s">/Views/10.cshtml"</span>
                              <span class="p">}));</span>
                <span class="p">});</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="kt">string</span> <span class="nf">GetDirectoryName</span><span class="p">(</span><span class="kt">string</span> <span class="n">path</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="nf">GetDirectory</span><span class="p">(</span><span class="n">path</span><span class="p">).</span><span class="n">Name</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="n">DirectoryInfo</span> <span class="nf">GetDirectory</span><span class="p">(</span><span class="kt">string</span> <span class="n">path</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="k">new</span> <span class="nf">DirectoryInfo</span><span class="p">(</span><span class="n">path</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Basically I got rid of <code class="language-plaintext highlighter-rouge">{1}</code> placeholder in sub-feature segment, and instead just scanning folder structure and registering view path locations dynamically depending on folder structure there.</p>

<p><strong>NB!</strong> All of the disadvantages and cons from Maris’ post still applies (like view name uniqueness, Visual Studio complaints and others).</p>

<p>Below you can see various combinations of possible conventions and feature folder organizations in Visual Studio (that might give you more clear overview of possibilities):</p>

<p><img src="/assets/img/2017/03/ff.png" alt="" /></p>

<p>I’ll revisit <a href="https://github.com/valdisiljuconoks/MvcAreasForEPiServer">Mvc Areas for EPiServer</a> package once again, and will write about how to use these feature folders together with Mvc Areas to get even more flexibility in your projects.</p>

<p>Happy slicing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Architecture" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="architecture" /><summary type="html"><![CDATA[Great colleague of mine Māris Krivtežs wrote blog post about feature folders describing code organization into folders by features or functional areas rather than technology or different grouping.]]></summary></entry><entry><title type="html">Localization Provider - Import and Export (Merge)</title><link href="https://tech-fellow.eu/2017/02/23/localization-provider-import-and-export-merge/" rel="alternate" type="text/html" title="Localization Provider - Import and Export (Merge)" /><published>2017-02-23T00:35:00+02:00</published><updated>2017-02-23T00:35:00+02:00</updated><id>https://tech-fellow.eu/2017/02/23/localization-provider-import-and-export-merge</id><content type="html" xml:base="https://tech-fellow.eu/2017/02/23/localization-provider-import-and-export-merge/"><![CDATA[<p>It’s been awhile since last update for <strong>DbLocalizationProvider</strong> for EPiServer. Anyway things been in my backlog. Period around New Year is not the most productive for me :) This blog post will describe some of the interesting stuff I’ve been lately busy with.</p>

<h2 id="export--import---view-diff">Export &amp; Import - View Diff</h2>

<p>Once upon a time I got sick of merging and importing new resources from staging environment (with adjusted translations by editors) into production database where on the other hand editors already made changes to existing resources. Up till now import process only supported <em>partial import</em> or <em>full import</em>. Partial import was dealing with only new resources (those ones that were not in target database), however full import - on the other hand - was used to flush everything and import stuff from exported file. Kinda worked, but it was v0.1 of this export/import component. Pretty green.</p>

<p>Updates to this story was one of the main focus for this upcoming version. Eventually if you are importing resources from other environment, now your import experience might look like this:</p>

<p><img src="/assets/img/2017/02/dblocexportimport.png" alt="" /></p>

<p>To share the code would be overkill here in this post. Better sit back and relax watching import in action. Enjoy!</p>

<iframe src="https://player.vimeo.com/video/205294678" width="800" height="520" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>
<p><a href="https://vimeo.com/205294678">DbLocalizationProvider - Export_Import</a> from <a href="https://vimeo.com/user49426707">Valdis Iljuconoks</a> on <a href="https://vimeo.com">Vimeo</a>.</p>

<h2 id="resource-keys-for-enum">Resource Keys for Enum</h2>

<p>Sometimes (usage for me was EPiServer visitor groups) you just need to control naming for each individual <code class="language-plaintext highlighter-rouge">Enum</code> item. Now you can do that with <code class="language-plaintext highlighter-rouge">[ResourceKey]</code> attribute. Hope code explains how it might look:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">LocalizedResource</span><span class="p">(</span><span class="n">KeyPrefix</span> <span class="p">=</span> <span class="s">"/this/is/prefix/"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">enum</span> <span class="n">ThisIsMyStatus</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">ResourceKey</span><span class="p">(</span><span class="s">"nothing"</span><span class="p">)]</span>
    <span class="n">None</span><span class="p">,</span>

    <span class="p">[</span><span class="nf">ResourceKey</span><span class="p">(</span><span class="s">"something"</span><span class="p">)]</span>
    <span class="n">Some</span><span class="p">,</span>

    <span class="p">[</span><span class="nf">ResourceKey</span><span class="p">(</span><span class="s">"anything"</span><span class="p">)]</span>
    <span class="n">Any</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>For instance you have following visitor group criteria:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
</pre></td><td class="rouge-code"><pre>
<span class="k">namespace</span> <span class="nn">My.Project.Namespace</span>
<span class="p">{</span>

<span class="p">[</span><span class="nf">VisitorGroupCriterion</span><span class="p">(..,</span>
    <span class="n">LanguagePath</span> <span class="p">=</span> <span class="s">"/visitorgroupscriterias/usernamecriterion"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">UsernameCriterion</span> <span class="p">:</span> <span class="n">CriterionBase</span><span class="p">&lt;</span><span class="n">UsernameCriterionModel</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="p">...</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">UsernameCriterionModel</span> <span class="p">:</span> <span class="n">CriteriaPackModelBase</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">Required</span><span class="p">]</span>
    <span class="p">[</span><span class="nf">DojoWidget</span><span class="p">(</span><span class="n">SelectionFactoryType</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="n">EnumSelectionFactory</span><span class="p">))]</span>
    <span class="k">public</span> <span class="n">UsernameValueCondition</span> <span class="n">Condition</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

    <span class="k">public</span> <span class="kt">string</span> <span class="n">Value</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">enum</span> <span class="n">UsernameValueCondition</span>
<span class="p">{</span>
    <span class="n">Matches</span><span class="p">,</span>
    <span class="n">StartsWith</span><span class="p">,</span>
    <span class="n">EndsWith</span><span class="p">,</span>
    <span class="n">Contains</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So EPiServer will look after resources with following key:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>/enums/my/project/namespace/usernamecriterion/usernamevaluecondition
</pre></td></tr></tbody></table></code></pre></div></div>

<p>and then name of the <code class="language-plaintext highlighter-rouge">Enum</code>. So you can control this and decorate each enum member with <code class="language-plaintext highlighter-rouge">ResourceKey</code> attribute to generate specific keys if needed.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">My.Project.Namespace</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">LocalizedResource</span><span class="p">(</span><span class="n">KeyPrefix</span> <span class="p">=</span> <span class="s">"/enums/my/project/namespace/usernamecriterion/usernamevaluecondition"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">enum</span> <span class="n">UsernameValueCondition</span>
    <span class="p">{</span>
        <span class="p">[</span><span class="nf">ResourceKey</span><span class="p">(</span><span class="s">"matches"</span><span class="p">)]</span>
        <span class="n">Matches</span><span class="p">,</span>
        <span class="p">[</span><span class="nf">ResourceKey</span><span class="p">(</span><span class="s">"startswith"</span><span class="p">)]</span>
        <span class="n">StartsWith</span><span class="p">,</span>
        <span class="p">[</span><span class="nf">ResourceKey</span><span class="p">(</span><span class="s">"endswith"</span><span class="p">)]</span>
        <span class="n">EndsWith</span><span class="p">,</span>
        <span class="p">[</span><span class="nf">ResourceKey</span><span class="p">(</span><span class="s">"contains"</span><span class="p">)]</span>
        <span class="n">Contains</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Maybe it’s worth just to create new attribute - like <code class="language-plaintext highlighter-rouge">[EPiServerEnumResource]</code> or something - namespace and member resource key calculations would be done for me?! I know - I’m lazy.. Sorry..</p>

<h2 id="class-fields">Class Fields</h2>

<p>This is smaller update, but still important. Developer writing code below would expect at least one resource to be generated. But it would not happen (with older library versions).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">My.Project.Namespace</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">MyResources</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="k">static</span> <span class="n">PageHeader</span> <span class="p">=</span> <span class="s">"This is page header"</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Seems legit, but issue here is that <code class="language-plaintext highlighter-rouge">PageHeader</code> is class field and not property.
Thanks to my <a href="https://github.com/klavsi">colleague</a> who discovered this. He just forgot to add “<code class="language-plaintext highlighter-rouge">&gt;</code>” symbol at the end of the assignment to convert from field to property:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">My.Project.Namespace</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">MyResources</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="k">static</span> <span class="n">PageHeader</span> <span class="p">=&gt;</span> <span class="s">"This is page header"</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now this has been fixed and class fields are also supported. Static and instance ones.</p>

<h2 id="distributed-concurrency-issue">Distributed Concurrency Issue</h2>

<p>Everything went great and localization provider proved to be solid and developer friendly approach to localize EPiServer (and not only EPiServer - provider <a href="https://www.nuget.org/packages/LocalizationProvider/">runs outside of it just fine</a>) applications. Until we deployed application with new pending resources to Azure deployment slot with more than 1 instance.. At the end duplicate resource keys were registered. Thanks to another <a href="https://github.com/ajuris">colleague</a> for giving some hints. So over the weekend while testing <strong>10</strong> concurrent instances with <strong>10,000</strong> resources - I came also to some performance issues. However, not sure if this might ever be actual real life case tho… At least stress testing gave some ideas how to improve performance in “normal” cases with just a few hundred resources. Startup performance boost average is about <strong>30%</strong>.</p>

<p>I’m still struggling a bit with the best approach for distributed concurrency and how to properly address it, but at least - duplicate resource keys (which would be disaster) should not be registered.</p>

<h2 id="more-info">More info</h2>

<ul>
  <li><a href="https://tech-fellow.eu/2016/03/16/db-localization-provider-part-1-resources-and-models/">Part 1: Resources and Models</a></li>
  <li><a href="https://tech-fellow.eu/2016/04/21/db-localization-provider-part-2-configuration-and-extensions/">Part 2: Configuration and Extensions</a></li>
  <li><strong>Part 3: Import and Export</strong></li>
  <li><a href="https://tech-fellow.eu/2017/10/10/localizationprovider-tree-view-export-and-migrations/">Part 4: Resource Refactoring and Migrations</a></li>
</ul>

<p>Happy localizing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Localization Provider" /><category term="Episerver" /><category term="Optimizely" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[It’s been awhile since last update for DbLocalizationProvider for EPiServer. Anyway things been in my backlog. Period around New Year is not the most productive for me :) This blog post will describe some of the interesting stuff I’ve been lately busy with.]]></summary></entry><entry><title type="html">Scheduled Jobs Updates</title><link href="https://tech-fellow.eu/2016/12/28/scheduled-jobs-updates/" rel="alternate" type="text/html" title="Scheduled Jobs Updates" /><published>2016-12-28T22:45:00+02:00</published><updated>2016-12-28T22:45:00+02:00</updated><id>https://tech-fellow.eu/2016/12/28/scheduled-jobs-updates</id><content type="html" xml:base="https://tech-fellow.eu/2016/12/28/scheduled-jobs-updates/"><![CDATA[<p>Some great updates have been delivered to EPiServer Scheduled Jobs infrastructure within <a href="http://world.episerver.com/releases/episerver---update-143/">version 10.3</a>.
In this blog post we will review some of the important changes.</p>

<h2 id="scanning-process">Scanning Process</h2>

<p>Property <code class="language-plaintext highlighter-rouge">IsStoppable</code> is now calculated during scanning process. Scheduled jobs scanner detects whether job is stoppable or not. If so - it’s written down to the database and used later when job is being triggered.</p>

<p>Also - now with v10.3 you don’t need to inherit from base class (<code class="language-plaintext highlighter-rouge">EPiServer.Scheduler.ScheduledJobBase</code>). In this case all you need is to have static <code class="language-plaintext highlighter-rouge">string Execute()</code> method:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ScheduledPlugIn</span><span class="p">(</span><span class="n">DisplayName</span> <span class="p">=</span> <span class="s">"My Custom Job"</span>
                 <span class="n">GUID</span> <span class="p">=</span> <span class="s">"..."</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">MyCustomJob</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="nf">Execute</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="p">...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Not really sure why you would like to escape <code class="language-plaintext highlighter-rouge">ScheduledJobBase</code> class and just have simple class with execution method tho.</p>

<p>Use case that pops in my mind could be when you want to reduce dependency on EPiServer infrastructure and libraries and have just simple class that serves as shell for the actual service or component. In this case scheduled job would become tiny fraction of <a href="https://tech-fellow.eu/2016/10/17/baking-round-shaped-software/">outer thin slice of the system</a> - with almost no dependencies on underlying execution engine.</p>

<h2 id="job-factory---di-friendly">Job Factory - DI Friendly!</h2>

<p>Finally! Another great addition is <code class="language-plaintext highlighter-rouge">IScheduledJobFactory</code> interface and corresponding implementation. As you might guess from the name of the type - it’s factory for the scheduled jobs.</p>

<p>It’s possible to override this factory with our own stuff, but mostly all of necessary functionality is there.</p>

<p>Most importantly - factory is DI (<a href="https://en.wikipedia.org/wiki/Dependency_injection">Dependency Injection</a>) aware now!
So you can write (not only specific to “method invocation based” jobs - with static <code class="language-plaintext highlighter-rouge">string Execute()</code> method):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ScheduledPlugIn</span><span class="p">(</span><span class="n">DisplayName</span> <span class="p">=</span> <span class="s">"My Custom Job"</span>
                 <span class="n">GUID</span> <span class="p">=</span> <span class="s">"..."</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">MyCustomJob</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">MyCustomJob</span><span class="p">(</span><span class="n">IContentTypeRepository</span> <span class="n">repo</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="p">...</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="nf">Execute</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="p">...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now you will not need to use <a href="http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/">ServiceLocator anti-pattern</a> anymore in scheduled jobs. It was not <a href="http://marisks.net/2016/12/01/dependency-injection-in-episerver/">good design</a>.</p>

<h2 id="execution-model-changes">Execution Model Changes</h2>

<p>Another great change in v10.3 is addition of <code class="language-plaintext highlighter-rouge">IScheduledJobExecutor</code> interface and corresponding implementation. This guy makes sure that job is executed correctly, keeps track of running jobs and gives opportunity to cancel (aka <em>Stop</em>) the job.</p>

<p>It doesn’t matter anymore how you execute the job (scheduler or manually) - with the help of this new interface now both modes are the same. You specify trigger options when you are firing the job (<code class="language-plaintext highlighter-rouge">User</code> - manual execution):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="n">IScheduledJobExecutor</span> <span class="n">_executor</span><span class="p">;</span>

<span class="p">...</span>

<span class="n">_executor</span><span class="p">.</span><span class="nf">StartAsync</span><span class="p">(</span><span class="n">jobInstance</span><span class="p">,</span>
                     <span class="k">new</span> <span class="n">JobExecutionOptions</span>
                     <span class="p">{</span>
                         <span class="n">Trigger</span> <span class="p">=</span> <span class="n">ScheduledJobTrigger</span><span class="p">.</span><span class="n">User</span>
                     <span class="p">});</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Among other things, you can also specify whether you want to execute job asynchronous (default) or wait for the results immediately:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="n">IScheduledJobExecutor</span> <span class="n">_executor</span><span class="p">;</span>

<span class="p">...</span>

<span class="n">_executor</span><span class="p">.</span><span class="nf">StartAsync</span><span class="p">(</span><span class="n">jobInstance</span><span class="p">,</span>
                     <span class="k">new</span> <span class="n">JobExecutionOptions</span>
                     <span class="p">{</span>
                         <span class="n">Trigger</span> <span class="p">=</span> <span class="n">ScheduledJobTrigger</span><span class="p">.</span><span class="n">User</span><span class="p">,</span>
                         <span class="n">RunSynchronously</span> <span class="p">=</span> <span class="k">true</span>
                     <span class="p">});</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="rename-jobs-safely">Rename Jobs Safely</h2>

<p>– <em>What is hardest thing in IT?</em><br />
– <em>Right, naming!</em></p>

<p>To name scheduled job with first shot is pretty challenging and almost impossible :)</p>

<p>Before EPiServer v10.3 renaming of the scheduled jobs resulted in orphan jobs - ghost ones that are hanging around as obsolete records in the database and make unwanted noise in jobs listing. You can of course delete them from <a href="http://nuget.episerver.com/en/OtherPages/Package/?packageId=TechFellow.ScheduledJobOverview">scheduled jobs overview plugin</a> safely, but still - not so nice!</p>

<p>Now with support of <code class="language-plaintext highlighter-rouge">[ScheduledPlugIn(GUID=...)]</code> attribute it’s possible to rename jobs safely without worrying to make stale data in the database.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ScheduledPlugIn</span><span class="p">(</span><span class="n">DisplayName</span> <span class="p">=</span> <span class="s">"My Custom Job"</span>
                 <span class="n">GUID</span> <span class="p">=</span> <span class="s">"ac034ea9-91d0-471b-821d-456b9072b465"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">MyCustomJob</span>
<span class="p">{</span>
    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We all are good copy/pasters. But, you will get an exception if you will forget to change <code class="language-plaintext highlighter-rouge">GUID</code> of the copied job.</p>

<h2 id="measure-execution-cycle">Measure Execution Cycle</h2>

<p>Precise measure of job run cycle in some cases could be pretty important performance indicator. Now with latest version update it’s possible to get statistics about how long each run cycle took. It’s available in log viewer.</p>

<p><img src="/assets/img/2016/12/2016-12-28_17-45-42.png" alt="" /></p>

<h2 id="increased-log-size">Increased Log Size</h2>

<p>If job runs frequently - last 100 log entries might be not sufficient. Now this limitation is gone and you can jump back to history far enough.</p>

<h2 id="some-final-thoughts">Some Final Thoughts</h2>

<p>Awesome to see improvements in stable infrastructure components as well. However - here are some thoughts from my side.</p>

<ul>
  <li>
    <p>Still waiting for something similar as <a href="https://github.com/valdisiljuconoks/TechFellow.ScheduledJobOverview">ScheduledJobs Overview</a> plugin already built-in into EPiServer platform. This is one of the issue among others.</p>
  </li>
  <li>
    <p>Would be helpful to see last job’s run cycle duration somewhere in job’s details page. Fortunately, this is visible in jobs overview page:</p>
  </li>
</ul>

<p><img src="/assets/img/2016/12/2016-12-28_17-44-56.png" alt="" /></p>

<ul>
  <li>Not sure why scanning process is kicked off from the attribute (<code class="language-plaintext highlighter-rouge">EPiServer.PlugIn.ScheduledPlugInAttribute</code>) and not some scanner implementation. As scheduled job is just yet another plugin for EPiServer - might be that this is coming from Plug-In system.</li>
</ul>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">ScheduledPlugInAttribute</span> <span class="p">:</span> <span class="n">PlugInAttribute</span>
<span class="p">{</span>
    <span class="k">internal</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">ServiceLocator</span><span class="p">.</span><span class="n">Current</span>
                      <span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">IScheduledJobScanner</span><span class="p">&gt;()</span>
                      <span class="p">.</span><span class="nf">Scan</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Even more, I couldn’t find any references to <code class="language-plaintext highlighter-rouge">Start()</code> and <code class="language-plaintext highlighter-rouge">AsyncStart()</code> methods within EPiServer code. Most probably they are invoked dynamically via method invocation. Which is even worse. But that’s a topic for another blog post..</p>

<p>Back to the <code class="language-plaintext highlighter-rouge">[ScheduledPlugIn]</code>. As we know - attributes are just metadata. It should <a href="http://blog.ploeh.dk/2014/06/13/passive-attributes/">not have any behavior</a>.</p>

<ul>
  <li>I’m missing some nice overview of duration of last X cycles. That would help me to look for patterns and/or peeks in job execution cycles. Fortunately, <a href="https://github.com/valdisiljuconoks/TechFellow.ScheduledJobOverview">overview plugin</a> has one :)</li>
</ul>

<p><img src="/assets/img/2016/12/2016-12-28_17-45-22.png" alt="" /></p>

<p>Happy scheduling!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Localization Provider" /><category term="Episerver" /><category term="Optimizely" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[Some great updates have been delivered to EPiServer Scheduled Jobs infrastructure within version 10.3. In this blog post we will review some of the important changes.]]></summary></entry><entry><title type="html">Customize Css styles loaded from EPiServer.Forms.Samples</title><link href="https://tech-fellow.eu/2016/12/26/customize-css-styles-loaded-from-episerver-forms-samples/" rel="alternate" type="text/html" title="Customize Css styles loaded from EPiServer.Forms.Samples" /><published>2016-12-26T23:45:00+02:00</published><updated>2016-12-26T23:45:00+02:00</updated><id>https://tech-fellow.eu/2016/12/26/customize-css-styles-loaded-from-episerver-forms-samples</id><content type="html" xml:base="https://tech-fellow.eu/2016/12/26/customize-css-styles-loaded-from-episerver-forms-samples/"><![CDATA[<p>This blog post will describe a way how to customize styles and scripts loaded by <code class="language-plaintext highlighter-rouge">EPiServer.Forms.Samples</code> package.</p>

<h2 id="background">Background</h2>

<p>Unfortunately EPiServer.Forms package does not have <code class="language-plaintext highlighter-rouge">DateTime</code> picker available in standard package. So you need to download and reference sample package that contains reference scripts and form elements for some additional stuff. Among others one of them is date time picker. It’s based on jQuery UI.</p>

<p>More or less everything is OK, until you need to customize look &amp; feel of the date time picker.</p>

<p>The way how it’s implemented in the sample package - is via <code class="language-plaintext highlighter-rouge">IViewModeExternalResources</code> interface. In the end it loads up bunch of style sheet files:</p>

<p><img src="/assets/img/2016/12/2016-12-26_23-18-02.png" alt="" /></p>

<p>Now the problem is that it’s not always accepted to have built-in jQuery UI styles and project requires its own styling for date time picker of any other form element from that package.</p>

<h2 id="solution-1">Solution 1</h2>

<p>One of the way is to decompile source code from the package and reference it in the project directly. Or just fork <a href="https://github.com/episerver/EPiServer.Forms.Samples">GitHub repo</a> and copy over all files.</p>

<h2 id="solution-2">Solution 2</h2>

<p>Looking into <code class="language-plaintext highlighter-rouge">IViewModeExternalResources</code> interface usage code (EPiServer is looking for all instances using <code class="language-plaintext highlighter-rouge">ServiceLocator.GetAllInstances&lt;T&gt;</code>). Which means that we can’t just write something like:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="n">container</span><span class="p">.</span><span class="n">For</span><span class="p">&lt;</span><span class="n">IViewModeExternalResources</span><span class="p">&gt;().</span><span class="n">Use</span><span class="p">&lt;</span><span class="n">CustomResources</span><span class="p">&gt;();</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This would just make EPiServer to use both: <code class="language-plaintext highlighter-rouge">EPiServer.Forms.Samples.ViewModeExternalResources</code> and <code class="language-plaintext highlighter-rouge">CustomResources</code> providers.</p>

<p>Will not even mention that <code class="language-plaintext highlighter-rouge">EPiServer.Forms.Samples.ViewModeExternalResources</code> uses <code class="language-plaintext highlighter-rouge">[ServiceConfiguration]</code> attribute, which is pretty <a href="http://marisks.net/2016/12/01/dependency-injection-in-episerver/">hard to spot</a>.</p>

<p>Straight forward solution for this problem is to “replace” existing mode resource provider with your own custom one. For this you can use StructureMap’s <code class="language-plaintext highlighter-rouge">IContainer.Inject()</code> method, but it’s not recommended.</p>

<p>Instead, there is better approach. You can decorate interface with your own “interceptor”.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">InitializationModule1</span> <span class="p">:</span> <span class="n">IConfigurableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureContainer</span><span class="p">(</span><span class="n">ServiceConfigurationContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">context</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="nf">Configure</span><span class="p">(</span>
            <span class="n">cfg</span> <span class="p">=&gt;</span>
                    <span class="n">cfg</span><span class="p">.</span><span class="n">For</span><span class="p">&lt;</span><span class="n">IViewModeExternalResources</span><span class="p">&gt;()</span>
                       <span class="p">.</span><span class="n">DecorateAllWith</span><span class="p">&lt;</span><span class="n">CustomResources</span><span class="p">&gt;());</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">CustomResources</span> <span class="p">:</span> <span class="n">IViewModeExternalResources</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">Tuple</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;&gt;</span> <span class="n">Resources</span>
    <span class="p">{</span>
        <span class="k">get</span>
        <span class="p">{</span>
            <span class="p">...</span>

            <span class="k">yield</span> <span class="k">return</span> <span class="k">new</span> <span class="n">Tuple</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;(</span>
                <span class="s">"css"</span><span class="p">,</span>
                <span class="s">"/ClientResources/custom.css"</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Key line is this:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="n">context</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="nf">Configure</span><span class="p">(</span>
    <span class="n">cfg</span> <span class="p">=&gt;</span>
            <span class="n">cfg</span><span class="p">.</span><span class="n">For</span><span class="p">&lt;</span><span class="n">IViewModeExternalResources</span><span class="p">&gt;()</span>
               <span class="p">.</span><span class="n">DecorateAllWith</span><span class="p">&lt;</span><span class="n">CustomResources</span><span class="p">&gt;());</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>NB!</strong> The only downside now - all <code class="language-plaintext highlighter-rouge">IViewModeExternalResources</code> instances will be “intercepted”. This might lead to some different issues when referencing other packages that do view mode client resource registration.</p>

<p>To fix this, you can check for the inner (“actual intercepted”) provider and do replacement only if correct provider is being intercepted.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">CustomResources</span> <span class="p">:</span> <span class="n">IViewModeExternalResources</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IViewModeExternalResources</span> <span class="n">_inner</span><span class="p">;</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="kt">bool</span> <span class="n">_replace</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">CustomResources</span><span class="p">(</span><span class="n">IViewModeExternalResources</span> <span class="n">inner</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_inner</span> <span class="p">=</span> <span class="n">inner</span><span class="p">;</span>
        <span class="k">if</span><span class="p">(</span><span class="n">inner</span> <span class="k">is</span> <span class="n">ViewModeExternalResources</span><span class="p">)</span>
            <span class="n">_replace</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">Tuple</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;&gt;</span> <span class="n">Resources</span>
    <span class="p">{</span>
        <span class="k">get</span>
        <span class="p">{</span>
            <span class="k">if</span><span class="p">(!</span><span class="n">_replace</span><span class="p">)</span>
                <span class="k">return</span> <span class="n">_inner</span><span class="p">.</span><span class="n">Resources</span><span class="p">;</span>

            <span class="k">return</span> <span class="k">new</span><span class="p">[]</span>
            <span class="p">{</span>
                <span class="k">new</span> <span class="n">Tuple</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;(</span><span class="s">"css"</span><span class="p">,</span>
                                          <span class="s">"/ClientResources/custom.css"</span><span class="p">)</span>
            <span class="p">};</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is pretty easy way to “replace” default styles for form elements that are not part of original package and those scripts and resources are loaded via resource provider that is “compiled into” .dll file.</p>

<p>Happy forming!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[This blog post will describe a way how to customize styles and scripts loaded by EPiServer.Forms.Samples package.]]></summary></entry><entry><title type="html">Playing with Fire - Part 2, updates for DbLocalizationProvider for EPiServer</title><link href="https://tech-fellow.eu/2016/12/04/playing-with-fire-part-2-updates-for-dblocalizationprovider-for-episerver/" rel="alternate" type="text/html" title="Playing with Fire - Part 2, updates for DbLocalizationProvider for EPiServer" /><published>2016-12-04T00:35:00+02:00</published><updated>2016-12-04T00:35:00+02:00</updated><id>https://tech-fellow.eu/2016/12/04/playing-with-fire-part-2-updates-for-dblocalizationprovider-for-episerver</id><content type="html" xml:base="https://tech-fellow.eu/2016/12/04/playing-with-fire-part-2-updates-for-dblocalizationprovider-for-episerver/"><![CDATA[<p>Story continues with fire and localization cases inside EPiServer sites. This time smaller update for database localization provider, but still - worth sharing.</p>

<h2 id="support-for-custom-attributes">Support for Custom Attributes</h2>

<p>Currently database provider supports and understands just a few <code class="language-plaintext highlighter-rouge">System.Attribute</code> child classes:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">[LocalizedModel]</code> - this is main marking attribute for making sure that provider resource sync process will pickup decorated class and scan resources there;</li>
  <li><code class="language-plaintext highlighter-rouge">[LocalizedResource]</code> - this is similar as <code class="language-plaintext highlighter-rouge">LocalizedModel</code>, but makes sure that resources discovered at this class will take localized resource semantics. <a href="https://tech-fellow.eu/2016/03/16/db-localization-provider-part-1-resources-and-models/">Read more here</a> about differences;</li>
  <li><code class="language-plaintext highlighter-rouge">[ResourceKey]</code> - this attribute will make sure that particular resource gets specified key, instead of auto-generated from the synchronizer. This comes handy when you need to control under which key resource will be registered (usually because of some EPiServer built-in conventions for translating their UI - page types or categories for instance);</li>
  <li><code class="language-plaintext highlighter-rouge">[Include]</code> - this attribute will make sure that particular property decorated with this will be added to the discovered resource list from that class;</li>
  <li><code class="language-plaintext highlighter-rouge">[Ignore]</code> - this is exactly opposite to <code class="language-plaintext highlighter-rouge">[Include]</code> attribute;</li>
  <li><code class="language-plaintext highlighter-rouge">[Display]</code> or <code class="language-plaintext highlighter-rouge">[DisplayName]</code> - these are attributes mostly used during model metadata generation via Asp.Net pipeline. So when you write <code class="language-plaintext highlighter-rouge">@Html.EditorFor(m =&gt; m.Username)</code>, either <code class="language-plaintext highlighter-rouge">[Display]</code> or <code class="language-plaintext highlighter-rouge">[DisplayName]</code> attribute will be used to get label for that field;</li>
  <li><code class="language-plaintext highlighter-rouge">[StringLength]</code>, <code class="language-plaintext highlighter-rouge">[Required]</code> or any other <code class="language-plaintext highlighter-rouge">ValidationAttribute</code> (from <code class="language-plaintext highlighter-rouge">System.ComponentModel.DataAnnotations</code> namespace) - these attributes will play their roles during model metadata generation process deep inside Asp.Net pipeline when somebody will ask for editor markup using <code class="language-plaintext highlighter-rouge">@Html.EditorFor(m =&gt; ...)</code>. Data validation attributes will make sure that all necessary Html attributes are added to the field input element for client-side validation library to pick it up.</li>
</ul>

<p>Almost each of these attributes have additional properties to control and adjust scanning and registration process.
However - it’s still not enough.</p>

<p>Sometimes there is need for arbitrary attribute to be recognized by the provider.</p>

<h3 id="helptext-scenario">[HelpText] Scenario</h3>

<p>In particular, there was requirement in one of our projects to add help text or small hint block for visitors to understand more about the meaning of the input field.</p>

<p><img src="/assets/img/2016/12/2016-12-04_00-24-40.png" alt="" /></p>

<p>One of the potential solution for this case that we were thinking about - to generate resources with specifc key conventions (like <code class="language-plaintext highlighter-rouge">/Form/HelpTexts/{FieldName}</code>) using existing <code class="language-plaintext highlighter-rouge">[ResourceKey]</code> attributes. And then inside field editor or display templates ask localization provider for a specific key:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="p">...</span>
<span class="n">@LocalizationService</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="nf">GetString</span><span class="p">(</span><span class="s">$"/Form/HelpTexts/</span><span class="p">{</span><span class="n">ViewData</span><span class="p">.</span><span class="n">ModelMetadata</span><span class="p">.</span><span class="n">PropertyName</span><span class="p">}</span><span class="s">"</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As this seems to be viable solution, it doesn’t feel right… Whole idea of the database localization provider for EPiServer was to replace “<em>stringly</em> typed access for the resources” to “<strong>strongly</strong> typed one”. And now - just to support additional custom attributes we would need to jump back to stringly interface.</p>

<p>So this requires some tweaks in the library.</p>

<h3 id="implementation-details">Implementation Details</h3>

<p>So what’s now supported is something called <code class="language-plaintext highlighter-rouge">CustomAttributeDescriptors</code> (you can guess where naming comes from).
The way you would ask localization provider to include your own <code class="language-plaintext highlighter-rouge">System.Attribite</code> classes in scanning and discovery process - is by adding descriptors to configuration context. The most convenient way - via EPiServer <a href="http://world.episerver.com/documentation/developer-guides/CMS/initialization/">initialization module</a>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">WebModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">InitLocalization</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">ConfigurationContext</span><span class="p">.</span><span class="nf">Setup</span><span class="p">(</span><span class="n">cfg</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="n">cfg</span><span class="p">.</span><span class="n">DiagnosticsEnabled</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
            <span class="n">cfg</span><span class="p">.</span><span class="n">CustomAttributes</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span>
            <span class="p">{</span>
                <span class="k">new</span> <span class="nf">CustomAttributeDescriptor</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">HelpTextAttribute</span><span class="p">))</span>
            <span class="p">};</span>
        <span class="p">});</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Or if you use localization provider outside of EPiServer site:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">Startup</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Configuration</span><span class="p">(</span><span class="n">IAppBuilder</span> <span class="n">app</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">app</span><span class="p">.</span><span class="nf">UseDbLocalizationProvider</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="n">ctx</span><span class="p">.</span><span class="n">ConnectionName</span> <span class="p">=</span> <span class="s">"..."</span><span class="p">;</span>
            <span class="n">ctx</span><span class="p">.</span><span class="n">CustomAttributes</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span>
            <span class="p">{</span>
                <span class="k">new</span> <span class="nf">CustomAttributeDescriptor</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">HelpTextAttribute</span><span class="p">))</span>
            <span class="p">};</span>
        <span class="p">});</span>

        <span class="n">app</span><span class="p">.</span><span class="nf">Map</span><span class="p">(</span><span class="s">"/localization-admin"</span><span class="p">,</span> <span class="n">b</span> <span class="p">=&gt;</span> <span class="n">b</span><span class="p">.</span><span class="nf">UseDbLocalizationProviderAdminUI</span><span class="p">());</span>
    <span class="p">}</span>
<span class="p">}</span>

</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now we added <code class="language-plaintext highlighter-rouge">[HelpText]</code> to localization provider list of custom attributes.
Attribute definition itself is nothing than simple C# class:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">HelpTextAttribute</span> <span class="p">:</span> <span class="n">Attribute</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>How you use new attribute? Simply decorate property with it:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">MyProject.Models</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">HomeViewModel</span>
    <span class="p">{</span>
        <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"User name:"</span><span class="p">)]</span>
        <span class="p">[</span><span class="nf">UIHint</span><span class="p">(</span><span class="s">"Username"</span><span class="p">)]</span>
        <span class="p">[</span><span class="n">HelpText</span><span class="p">]</span>
        <span class="k">public</span> <span class="kt">string</span> <span class="n">Username</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Resource key naming convention by default is the same as for other attributes - <code class="language-plaintext highlighter-rouge">$"{FQN of the property}-{attribute type name}"</code>. So new resource key for help text will be: <code class="language-plaintext highlighter-rouge">MyProject.Models.HomeViewModel.Username-HelpText</code>.</p>

<p><strong>NB!</strong> Well actually resource key name depends on whether you registering resources for child classes within its own context or preserving base class context. Read more about these semantics <a href="https://tech-fellow.eu/2016/11/03/playing-with-fire-localized-episerver-view-models/">here</a>.</p>

<p>Now question is how we can access translation for this custom attribute resource?
I made few helper methods for easier retrieval.
Imagine that you are inside your field’s (view model property) display or editor template and you need to retrieve this help text, a resource based on <code class="language-plaintext highlighter-rouge">[HelpText]</code> attribute. It’s easy.</p>

<p>Index.cshtml:</p>

<pre><code class="language-razor">...
@Html.EditorFor(m =&gt; m.Username)
</code></pre>

<p>Username.cshtml (because of <code class="language-plaintext highlighter-rouge">[UIHint]</code>):</p>

<pre><code class="language-razor">@model string

...
&lt;div&gt;
    @Html.TranslateFor(m =&gt; m, typeof(HelpTextAttribute))
&lt;/div&gt;
</code></pre>

<p>That’s it. Pretty easy, ah?! :)</p>

<h3 id="optional-helptext">Optional HelpText</h3>

<p>With solution above there is a small catch. By default all properties where <code class="language-plaintext highlighter-rouge">[HelpText]</code> was used - resource translation will be generated (by default - last segment after <code class="language-plaintext highlighter-rouge">.</code> from the resource key).</p>

<p>However, another requirement in the project was to support <em>optional</em> resources - if translation is specified for the resource in specific culture - then visitor will see hint text, otherwise - no hint button should be generated.</p>

<p>With 1st version of custom attributes solution - this problem cannot be solved. So there has to be some adjustments.</p>

<p>When you are registering custom attribute descriptor - you can actually specify translation existence.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">WebModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">InitLocalization</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">ConfigurationContext</span><span class="p">.</span><span class="nf">Setup</span><span class="p">(</span><span class="n">cfg</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="n">cfg</span><span class="p">.</span><span class="n">CustomAttributes</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span>
            <span class="p">{</span>
                <span class="k">new</span> <span class="nf">CustomAttributeDescriptor</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">HelpTextAttribute</span><span class="p">),</span> <span class="k">false</span><span class="p">)</span>
            <span class="p">};</span>
        <span class="p">});</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Note last parameter for <code class="language-plaintext highlighter-rouge">CustomAttributeDescriptor</code> constructor:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="p">{</span>
    <span class="k">new</span> <span class="nf">CustomAttributeDescriptor</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">HelpTextAttribute</span><span class="p">),</span> <span class="k">false</span><span class="p">)</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Last parameter controls whether translation should (<code class="language-plaintext highlighter-rouge">true</code>) or should not (<code class="language-plaintext highlighter-rouge">false</code>) be generated for this resource.</p>

<p>By specifying <code class="language-plaintext highlighter-rouge">false</code> - resource itself will be discovered and registered, but translation will be empty. Which gives possibility for editors to add translation for that resource if needed.
This means that in your field template you can check for this and if translation is not empty, only then render markup for the hint.</p>

<p>Username.cshtml:</p>

<pre><code class="language-razor">@{
    var hint = Html.TranslateFor(m =&gt; m, typeof(HelpTextAttribute));
}
@if (hint != MvcHtmlString.Empty)
{
    &lt;div class="hint-text"&gt;@hint&lt;/div&gt;
}
</code></pre>

<p>Needless to say, that <code class="language-plaintext highlighter-rouge">[Dislay(Description = "...")</code> attribute usage is <a href="https://tech-fellow.eu/2016/06/06/episerver-dblocalizationprovider-fresh-2-0-is-out/#displaydescription">also supported</a> out of the box. So you can just look for description of the field inside your templates:</p>

<pre><code class="language-razor">@ViewData.ModelMetadata.Description
</code></pre>

<p>Field description follows the same mechanics as custom attributes - you can leave it empty (<code class="language-plaintext highlighter-rouge">""</code>) and no translation will be added for that resource.</p>

<p>Happy localizing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Localization Provider" /><category term="Episerver" /><category term="Optimizely" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[Story continues with fire and localization cases inside EPiServer sites. This time smaller update for database localization provider, but still - worth sharing.]]></summary></entry><entry><title type="html">EPiServer DbLocalizationProvider - fresh 2.0 is out!</title><link href="https://tech-fellow.eu/2016/11/03/episerver-dblocalizationprovider-fresh-2-0-is-out/" rel="alternate" type="text/html" title="EPiServer DbLocalizationProvider - fresh 2.0 is out!" /><published>2016-11-03T20:05:00+02:00</published><updated>2016-11-03T20:05:00+02:00</updated><id>https://tech-fellow.eu/2016/11/03/episerver-dblocalizationprovider-fresh-2-0-is-out</id><content type="html" xml:base="https://tech-fellow.eu/2016/11/03/episerver-dblocalizationprovider-fresh-2-0-is-out/"><![CDATA[<h2 id="why">Why?</h2>

<p>You might ask, but changes I guess is the only constant thing in this industry. DbLocalizationProvider is witnessing new version and some cool features covered in more details below. Also internally provider survived quite huge refactoring activities, while I was redesigning from central services and repositories to more granular command and queries. But that’s the story for another blog post.</p>

<h2 id="new-features-in-20">New Features in 2.0</h2>

<p>Here goes the list of new features available in version 2.0. List is not sorted in any order.</p>

<h3 id="translate-systemenum">Translate System.Enum</h3>

<p>It’s quite often that you do have a enumeration in the domain to ensure that your entity might have value only from predefined list of values - like <code class="language-plaintext highlighter-rouge">Document.Status</code> or <code class="language-plaintext highlighter-rouge">PurchaseOrder.Shipment.Status</code>. These values are usually defined as <code class="language-plaintext highlighter-rouge">System.Enum</code>. And it’s also quite often case when you need to render a list of these available values on the page or anywhere else for the user of the application to choose from. Now in 2.0 enumeration translation is easily available.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
<span class="k">public</span> <span class="k">enum</span> <span class="n">DocumentStatus</span>
<span class="p">{</span>
    <span class="n">None</span><span class="p">,</span>
    <span class="n">New</span><span class="p">,</span>
    <span class="n">Pending</span><span class="p">.</span>
    <span class="n">Active</span><span class="p">,</span>
    <span class="n">Closed</span>
<span class="p">}</span>

<span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">Document</span>
<span class="p">{</span>
    <span class="p">...</span>

    <span class="k">public</span> <span class="n">DocumentStatus</span> <span class="n">Status</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now you can use following snippet to give end-user localized dropdown list of available document statuses:</p>

<pre><code class="language-razor">@using DbLocalizationProvider
@model Document

@{
    var statuses = Enum.GetValues(typeof(DocumentStatus))
                       .Cast&lt;DocumentStatus&gt;()
                       .Select(s =&gt; new SelectListItem
                                        {
                                            Value = s.ToString(),
                                            Text = s.Translate()
                                        });
}

@Html.DropDownListFor(m =&gt; m.Status, statuses)
</code></pre>

<p>Or if you just need to output current status of the document to the end-user:</p>

<pre><code class="language-razor">@using DbLocalizationProvider
@model Document

@Model.Status.Translate()
</code></pre>

<h3 id="templates-with-placeholders">Templates with Placeholders</h3>

<p>Index based <code class="language-plaintext highlighter-rouge">string.Format</code> style arguments for localized message is very nice and flexible approach. However - it’s readable most probably only by developer or somebody who understands why first element starts with <code class="language-plaintext highlighter-rouge">{0}</code> and not <code class="language-plaintext highlighter-rouge">{1}</code>.
When you need to give access to the resources to editors or anybody else with even enough technical background, you might receive questions back - “What is <code class="language-plaintext highlighter-rouge">{0}</code> and what will be placed in <code class="language-plaintext highlighter-rouge">{4}</code>?” Pretty tricky question if you need to open source code and look for passed in format arguments.</p>

<p>Now in v2.0 you can pass in anonymous object with named properties and use those in your localized resource.</p>

<p>For example, greeting message for end-users (I really hate these kind of greetings.. so simple to invest in vocative case):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">StartPageResources</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">GreetingMessage</span> <span class="p">=&gt;</span> <span class="s">"Hi {Firstname} {Lastname}, where would you like to click today?"</span><span class="p">;</span>
<span class="p">}</span>


<span class="n">@Html</span><span class="p">.</span><span class="nf">Translate</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="n">StartPageResources</span><span class="p">.</span><span class="n">GreetingMessage</span><span class="p">,</span> <span class="k">new</span> <span class="p">{</span> <span class="n">Firstname</span> <span class="p">=</span> <span class="s">"John"</span><span class="p">,</span> <span class="n">Lastname</span> <span class="p">=</span> <span class="s">"Doe"</span> <span class="p">})</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Or you may have a view model as basis for some translated message, so you can pass in directly that model:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">Document</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Nr</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Author</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>

<span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">DocumentResources</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">SharedTo</span> <span class="p">=&gt;</span> <span class="s">"{Author}, somebody shared your '{Nr}' document!"</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">...</span>

<span class="n">@model</span> <span class="n">Document</span>

<span class="n">@Html</span><span class="p">.</span><span class="nf">Translate</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="n">StartPageResources</span><span class="p">.</span><span class="n">GreetingMessage</span><span class="p">,</span> <span class="n">Model</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now it should be much easier for the editors to understand what value goes in which placeholders.</p>

<h3 id="custom-resource-keys">Custom Resource Keys</h3>

<p>Back in time <a href="http://world.episerver.com/blogs/Linus-Ekstrom/Dates/2013/12/New-standardized-format-for-content-type-localizations/">Linus blogged</a> about new standardized way to localize Cms content types and properties. As originally EPiServer is based on Xml and XPath resource key conventions - there was no support in DbLocalizationProvider to make it happen and supply these specially generated resource keys via strongly typed resources.</p>

<p>Now in v2.0 you can do that by specifying <code class="language-plaintext highlighter-rouge">ResourceKey</code> directly on property of the <code class="language-plaintext highlighter-rouge">PageType</code>:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="p">...</span>
<span class="k">using</span> <span class="nn">DbLocalizationProvider</span><span class="p">;</span>

<span class="p">[</span><span class="nf">ContentType</span><span class="p">(</span><span class="n">GUID</span> <span class="p">=</span> <span class="s">"...."</span><span class="p">)]</span>
<span class="p">[</span><span class="nf">LocalizedModel</span><span class="p">(</span><span class="n">KeyPrefix</span> <span class="p">=</span> <span class="s">"/contenttypes/startpage/"</span><span class="p">)]</span>
<span class="p">[</span><span class="nf">ResourceKey</span><span class="p">(</span><span class="s">"name"</span><span class="p">,</span> <span class="n">Value</span> <span class="p">=</span> <span class="s">"This is StartPage!"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">StartPage</span> <span class="p">:</span> <span class="n">PageData</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">ResourceKey</span><span class="p">(</span><span class="s">"properties/headertitle/caption"</span><span class="p">,</span> <span class="n">Value</span> <span class="p">=</span> <span class="s">"Title of the page"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">virtual</span> <span class="kt">string</span> <span class="n">HeaderTitle</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This class should register 2 resources with following keys (that will be picked up by EPiServer automatically):</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">/contenttypes/startpage/name</code></li>
  <li><code class="language-plaintext highlighter-rouge">/contenttypes/startpage/properties/headertitle/caption</code></li>
</ul>

<p>You may also need to specify descriptions or any other resources for that Cms content type property, you can have multiple <code class="language-plaintext highlighter-rouge">ResourceKey</code> attributes:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="p">...</span>
<span class="k">using</span> <span class="nn">DbLocalizationProvider</span><span class="p">;</span>

<span class="p">[</span><span class="nf">ContentType</span><span class="p">(</span><span class="n">GUID</span> <span class="p">=</span> <span class="s">"...."</span><span class="p">)]</span>
<span class="p">[</span><span class="nf">LocalizedModel</span><span class="p">(</span><span class="n">KeyPrefix</span> <span class="p">=</span> <span class="s">"/contenttypes/startpage/"</span><span class="p">)]</span>
<span class="p">[</span><span class="nf">ResourceKey</span><span class="p">(</span><span class="s">"name"</span><span class="p">,</span> <span class="n">Value</span> <span class="p">=</span> <span class="s">"This is StartPage!"</span><span class="p">)]</span>
<span class="p">[</span><span class="nf">ResourceKey</span><span class="p">(</span><span class="s">"description"</span><span class="p">,</span> <span class="n">Value</span> <span class="p">=</span> <span class="s">"This is StartPage!"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">StartPage</span> <span class="p">:</span> <span class="n">PageData</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">ResourceKey</span><span class="p">(</span><span class="s">"properties/headertitle/caption"</span><span class="p">,</span> <span class="n">Value</span> <span class="p">=</span> <span class="s">"Title of the page"</span><span class="p">)]</span>
    <span class="p">[</span><span class="nf">ResourceKey</span><span class="p">(</span><span class="s">"properties/headertitle/help"</span><span class="p">,</span> <span class="n">Value</span> <span class="p">=</span> <span class="s">"Enter some meaningful title of the page"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">virtual</span> <span class="kt">string</span> <span class="n">HeaderTitle</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="support-for-nullable-properties">Support for Nullable properties</h3>

<p>This is pretty small addition, but previously in 1.x version nullable properties where not supported.
Now following property will be discovered and added to localized resources:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">Document</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="n">DateTime</span><span class="p">?</span> <span class="n">DeletedWhen</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Following data types are treated as simple and thus - added to list of resources to synchronize:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">typeof(Enum)</code>,</li>
  <li><code class="language-plaintext highlighter-rouge">typeof(string)</code>,</li>
  <li><code class="language-plaintext highlighter-rouge">typeof(char)</code>,</li>
  <li><code class="language-plaintext highlighter-rouge">typeof(Guid)</code>,</li>
  <li><code class="language-plaintext highlighter-rouge">typeof(bool)</code>,</li>
  <li><code class="language-plaintext highlighter-rouge">typeof(byte)</code>,</li>
  <li><code class="language-plaintext highlighter-rouge">typeof(short)</code>,</li>
  <li><code class="language-plaintext highlighter-rouge">typeof(int)</code>,</li>
  <li><code class="language-plaintext highlighter-rouge">typeof(long)</code>,</li>
  <li><code class="language-plaintext highlighter-rouge">typeof(float)</code>,</li>
  <li><code class="language-plaintext highlighter-rouge">typeof(double)</code>,</li>
  <li><code class="language-plaintext highlighter-rouge">typeof(decimal)</code>,</li>
  <li><code class="language-plaintext highlighter-rouge">typeof(sbyte)</code>,</li>
  <li><code class="language-plaintext highlighter-rouge">typeof(ushort)</code>,</li>
  <li><code class="language-plaintext highlighter-rouge">typeof(uint)</code>,</li>
  <li><code class="language-plaintext highlighter-rouge">typeof(ulong)</code>,</li>
  <li><code class="language-plaintext highlighter-rouge">typeof(DateTime)</code>,</li>
  <li><code class="language-plaintext highlighter-rouge">typeof(DateTimeOffset)</code>,</li>
  <li><code class="language-plaintext highlighter-rouge">typeof(TimeSpan)</code></li>
</ul>

<p>And their <code class="language-plaintext highlighter-rouge">Nullable&lt;&gt;</code> counterpart.</p>

<h3 id="displaydescription--">[Display(Description = “…”)]</h3>

<p>Also small addition to <code class="language-plaintext highlighter-rouge">ModelMetadataProvider</code> infrastructure available for Asp.Net Mvc pipeline. Now you can also localize description for the property via <code class="language-plaintext highlighter-rouge">DataAnnotations</code> attributes:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">MyProject</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">MyViewModel</span>
    <span class="p">{</span>
        <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"Login name"</span><span class="p">,</span> <span class="n">Description</span> <span class="p">=</span> <span class="s">"Login name for the user is email."</span><span class="p">)]</span>
        <span class="k">public</span> <span class="kt">string</span> <span class="n">Username</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Will generate following resource <code class="language-plaintext highlighter-rouge">MyProject.MyViewModel.Username-Description</code> <em>only</em> if <code class="language-plaintext highlighter-rouge">Description</code> property of <code class="language-plaintext highlighter-rouge">Display</code> attribute will not be <code class="language-plaintext highlighter-rouge">string.Empty</code>. You can localize it via AdminUI and set new value if needed.</p>

<p>When you need to use this value in your display or editor templates you can access it via <code class="language-plaintext highlighter-rouge">ViewData</code>:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;div&gt;</span>
    ...
    <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"field-description"</span><span class="nt">&gt;</span>@ViewData.ModelMetadata.Description<span class="nt">&lt;/span&gt;</span>
    ...
<span class="nt">&lt;/div&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="mark-required-fields">Mark Required Fields</h3>

<p><em>NB!</em> This is experimental feature, so feedback is welcome.
Got a request from one of our projects to indicate all required fields in the system with some sort of prefix (e.g., asterix <code class="language-plaintext highlighter-rouge">"*"</code> or anything like that). We were considering to create some HtmlHelper extensions for this and revisit its usage across the pages. However, using new DbLocalizationProvider all calls for model metadata is going through <code class="language-plaintext highlighter-rouge">ModelMetadataProvider</code> infrastructure and there is single point of responsibility for providing value for code snippet like this <code class="language-plaintext highlighter-rouge">@Html.LabelFor(...)</code>.</p>

<p>So I decided to add this experimental feature to the localization provider to give single configuration option for the developers to enable this requirement. Might not be directly related to responsibility of localization provider, that’s why it’s still experimental and not sure whether a good idea to add it here. Anyhow, here is the way how to achieve this:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">LocalizedResources</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">Common</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">RequiredIndicator</span> <span class="p">=&gt;</span> <span class="s">" *"</span><span class="p">;</span>
<span class="p">}</span>

<span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">SetupLocalization</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">ConfigurationContext</span><span class="p">.</span><span class="nf">Setup</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="n">ctx</span><span class="p">.</span><span class="n">ModelMetadataProviders</span><span class="p">.</span><span class="n">MarkRequiredFields</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
            <span class="n">ctx</span><span class="p">.</span><span class="n">ModelMetadataProviders</span><span class="p">.</span><span class="n">RequiredFieldResource</span> <span class="p">=</span>
                <span class="p">()</span> <span class="p">=&gt;</span> <span class="n">Common</span><span class="p">.</span><span class="n">RequiredIndicator</span><span class="p">;</span>
        <span class="p">});</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">MyViewModel</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">Required</span><span class="p">]</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Username</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now running in this context, if you type in:</p>

<pre><code class="language-razor">@model MyViewModel

@Html.Label(m =&gt; m.Username)
</code></pre>

<p>With no modifications to default resource translations, it should output:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;label</span> <span class="na">for=</span><span class="s">"..."</span><span class="nt">&gt;</span>Username *<span class="nt">&lt;/label&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="upgrade-from-version-1x">Upgrade from version 1.x</h2>

<p>If this is the case and you are using 1.x version, first of all - I would like to thank you for trying it out!</p>

<p>Secondly, I tried to make upgrade as transparent as possible for the developers using 1.x.</p>

<p>So currently, you should have following packages installed:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">DbLocalizationProvider</code>, <code class="language-plaintext highlighter-rouge">v1.3.2</code></li>
  <li><code class="language-plaintext highlighter-rouge">DbLocalizationProvider.AdminUI</code>, <code class="language-plaintext highlighter-rouge">v1.3.0</code></li>
</ul>

<p>So you should look for newer versions for these packages:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">DbLocalizationProvider</code>, <code class="language-plaintext highlighter-rouge">v1.3.3</code></li>
  <li><code class="language-plaintext highlighter-rouge">DbLocalizationProvider.AdminUI</code>, <code class="language-plaintext highlighter-rouge">v1.3.1</code></li>
</ul>

<p>These latest versions are so called ghost packages that do not have any content, but have proper references to new dependencies of new package names. By upgrading to this version, you should also get pulled down additional packages:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">DbLocalizationProvider.EPiServer</code>, <code class="language-plaintext highlighter-rouge">v2.0.0</code></li>
  <li><code class="language-plaintext highlighter-rouge">DbLocalizationProvider.AdminUI.EPiServer</code>, <code class="language-plaintext highlighter-rouge">v2.0.0</code></li>
  <li><code class="language-plaintext highlighter-rouge">LocalizationProvider</code>, <code class="language-plaintext highlighter-rouge">v2.0.0</code></li>
</ul>

<p>Latter package is related with new feature to host localization provider outside of EPiServer.</p>

<p>So theoretically you can remove old versions of <code class="language-plaintext highlighter-rouge">DbLocalizationProvider</code> and also <code class="language-plaintext highlighter-rouge">DbLocalizationProvider.AdminUI</code> packages.</p>

<p>Also, by completely removing old <code class="language-plaintext highlighter-rouge">DbLocalizationProvider*</code> packages and adding directly <code class="language-plaintext highlighter-rouge">DbLocalizationProvider.EPiServer</code> and/or <code class="language-plaintext highlighter-rouge">DbLocalizationProvider.AdminUI.EPiServer</code> you should be on the safe side.</p>

<h2 id="hosting-outside-of-episerver">Hosting outside of EPiServer</h2>

<p>I guess the most important feature of new 2.0 version is ability to host it outside of the EPiServer.</p>

<p>So you should be able to add reference to <a href="https://www.nuget.org/packages/LocalizationProvider/">LocalizatioProvider package</a> in pure vanilla Asp.Net Mvc project and you are settle and ready to go. Of course, if you will need to configure and tweak library, that’s available as usual - via <code class="language-plaintext highlighter-rouge">AppBuilder</code> interface (for instance here, to specify which database connection string to use):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">assembly</span><span class="p">:</span> <span class="nf">OwinStartup</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">Startup</span><span class="p">))]</span>

<span class="k">namespace</span> <span class="nn">DbLocalizationProvider.MvcSample</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">Startup</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="k">void</span> <span class="nf">Configuration</span><span class="p">(</span><span class="n">IAppBuilder</span> <span class="n">app</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">app</span><span class="p">.</span><span class="nf">UseDbLocalizationProvider</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span>
            <span class="p">{</span>
                <span class="n">ctx</span><span class="p">.</span><span class="n">ConnectionName</span> <span class="p">=</span> <span class="s">"MyConnectionString"</span><span class="p">;</span>
            <span class="p">});</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

</pre></td></tr></tbody></table></code></pre></div></div>

<p>The only show stopper currently is that I’m not finished with AdminUI for Mvc projects. Just need to put final pieces together and publish.</p>

<p>New blog post will be published once package will become available.</p>

<h2 id="thanks">Thanks!</h2>

<p>Thanks for taking time to read through and probably trying out <code class="language-plaintext highlighter-rouge">DbLocalizationProvider</code> library.</p>

<p>If you have any comments, suggestion, feedback, complaints - please leave it on <a href="https://github.com/valdisiljuconoks/LocalizationProvider">GitHub</a>.</p>

<p>Happy localizing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Localization Provider" /><category term="Episerver" /><category term="Optimizely" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[Why?]]></summary></entry><entry><title type="html">Playing with Fire - Localized EPiServer View Models</title><link href="https://tech-fellow.eu/2016/11/03/playing-with-fire-localized-episerver-view-models/" rel="alternate" type="text/html" title="Playing with Fire - Localized EPiServer View Models" /><published>2016-11-03T20:05:00+02:00</published><updated>2016-11-03T20:05:00+02:00</updated><id>https://tech-fellow.eu/2016/11/03/playing-with-fire-localized-episerver-view-models</id><content type="html" xml:base="https://tech-fellow.eu/2016/11/03/playing-with-fire-localized-episerver-view-models/"><![CDATA[<p>Recently released driven localization provider for EPiServer had main focus on more complex view models along the other smaller bug fixes and features.</p>

<p>And specifically - there were few unsupported scenarios for the view models with base/parent class.</p>

<p>Here is the list of all new features in <strong>v2.1</strong>.</p>

<h2 id="extract-abstractions">Extract Abstractions</h2>

<p>Until now, if I do need to decorate some of the resources that are located in some <a href="https://tech-fellow.eu/2016/10/30/baking-round-shaped-software-mapping-to-the-code/">core area assembly</a> - you need to reference <code class="language-plaintext highlighter-rouge">DbLocalizationProvider</code> library that had some undesired dependencies (for instance, why do I need to reference <code class="language-plaintext highlighter-rouge">Owin</code> assembly in my core area project). Now <code class="language-plaintext highlighter-rouge">DbLocalizationProvider.Abstractions</code> is extracted and it contains only bare minimum for the resource attribution and controlling resource discovery and naming conventions. So if you need just to mark resources somewhere in inner circle projects - you can just reference <code class="language-plaintext highlighter-rouge">DbLocalizationProvider.Abstractions</code> <a href="https://www.nuget.org/packages/LocalizationProvider.Abstractions/">package</a>.</p>

<h2 id="register-only-included-resources">Register Only Included Resources</h2>

<p>Sometimes when you do your own class that has a lot of properties, or class that inherits from some other class with lots of properties, and you need to register just a few of the resources.</p>

<p>Let’s look at sample. Image you have following class:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">Sample</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">MyPage</span> <span class="p">:</span> <span class="n">PageData</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="kt">string</span> <span class="n">SomeProperty</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="s">"Default translation"</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>What will happen is - along the <code class="language-plaintext highlighter-rouge">Sample.MyPage.SomeProperty</code> registration, <strong>all</strong> <code class="language-plaintext highlighter-rouge">PageData</code> public properties will be discovered and registered as well. This might not be desired - will be huge noise and bunch of unnecessary properties (well, maybe sometimes inherited <code class="language-plaintext highlighter-rouge">PageData</code> properties needs to be translated). And as you don’t have access to source code of the <code class="language-plaintext highlighter-rouge">PageData</code> type - you can’t really set <code class="language-plaintext highlighter-rouge">[Ignore]</code> attributes there either.</p>

<p>Anyway - there is a solution for this problem. You can ask resource scanner to include only those resources that are marked explicitly with <code class="language-plaintext highlighter-rouge">[Include]</code> attribute. Here is code:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">Sample</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">LocalizedModel</span><span class="p">(</span><span class="n">OnlyIncluded</span> <span class="p">=</span> <span class="k">true</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">MyPage</span> <span class="p">:</span> <span class="n">PageData</span>
    <span class="p">{</span>
        <span class="p">[</span><span class="n">Include</span><span class="p">]</span>
        <span class="k">public</span> <span class="kt">string</span> <span class="n">SomeProperty</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="s">"Default translation"</span><span class="p">;</span>

        <span class="k">public</span> <span class="kt">string</span> <span class="n">ThisWillBeIgnored</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="s">"Whatever"</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Only <code class="language-plaintext highlighter-rouge">Sample.MyPage.SomeProperty</code> resource will be registered from this type.</p>

<h2 id="register-only-my-resources">Register Only “My” Resources</h2>

<h3 id="background-for-feature">Background for Feature</h3>

<p>This feature will make sure that only translation resources on current <code class="language-plaintext highlighter-rouge">Type</code> will be registered. It’s supported in “ordinary” case and also with “generics”. Read on.</p>

<p>Motivation behind this feature was case when there was base viewmodel class with lot of properties that are registered as resources and also at the same time lot child viewmodels. As result with existing set of features was fact that resources from base class was registered as many times as there were child classes. Basically - every time scanner will discover child class - all parent/base properties were also registered. But within that child class “context”.</p>

<p>For example:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">BaseViewModel</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">CustomMessage</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="s">"Some value"</span><span class="p">;</span>
<span class="p">}</span>

<span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">HomeViewModel</span> <span class="p">:</span> <span class="n">BaseViewModel</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"Also your email"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Username</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>

<span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ArticleViewModel</span> <span class="p">:</span> <span class="n">BaseViewModel</span>
<span class="p">{</span>
    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Following resources will be registered:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>HomeViewModel.CustomMessage
HomeViewModel.Username
ArticleViewModel.CustomMessage
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Sometimes you just want to “freeze” property definition container type and only register base class resources once.</p>

<p>This feature does exactly that.</p>

<h3 id="for-non-generic-models">For Non-Generic Models</h3>

<p>To use this feature you need to set attribute property <code class="language-plaintext highlighter-rouge">Inherited</code> to <code class="language-plaintext highlighter-rouge">false</code> - <code class="language-plaintext highlighter-rouge">[LocalizedModel(Inherited = false)]</code>. This will instruct scanner to preserve property definition container type.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">BaseViewModel</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"This is message"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Message</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

    <span class="k">public</span> <span class="kt">string</span> <span class="n">CustomMessage</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="s">"Some value"</span><span class="p">;</span>
<span class="p">}</span>

<span class="p">[</span><span class="nf">LocalizedModel</span><span class="p">(</span><span class="n">Inherited</span> <span class="p">=</span> <span class="k">false</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">HomeViewModel</span> <span class="p">:</span> <span class="n">BaseViewModel</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"Also your email"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Username</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Following resources will be registered this time:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>BaseViewModel.Message
BaseViewModel.CustomMessage
HomeViewModel.Username
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So when you will try to use this new property somewhere during “runtime”:</p>

<pre><code class="language-razor">@model HomeViewModel

@Html.TranslateFor(() =&gt; m.CustomMessage)
</code></pre>

<p>Localization provider will look for resource with key <code class="language-plaintext highlighter-rouge">BaseViewModel.CustomMessage</code> and not for the key <code class="language-plaintext highlighter-rouge">HomeViewModel.CustomMessage</code> (even if <code class="language-plaintext highlighter-rouge">TranslateFor()</code> context is current view model - <code class="language-plaintext highlighter-rouge">HomeViewModel</code>). This is because while scanning and registering resources - provider discovered that <code class="language-plaintext highlighter-rouge">HomeViewModel</code> does not want to register inherited resources from the parent class(-es).</p>

<p>By applying this feature you prevent pollution of the resources.</p>

<h3 id="playing-with-fire---generic-models">Playing with Fire - Generic Models</h3>

<p>The tricky part starts when viewmodels are defined as generic types. And this is the time when database localization provider starts playing with fire :)
For instance, let’s have following view model defined:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">Sample</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">BaseOpenViewModel</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;</span>
    <span class="p">{</span>
        <span class="p">[</span><span class="n">Display</span><span class="p">]</span>
        <span class="p">[</span><span class="n">Required</span><span class="p">]</span>
        <span class="k">public</span> <span class="kt">string</span> <span class="n">BaseProperty</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">}</span>

    <span class="p">[</span><span class="nf">LocalizedModel</span><span class="p">(</span><span class="n">Inherited</span> <span class="p">=</span> <span class="k">false</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">SampleViewModelWithClosedBase</span> <span class="p">:</span> <span class="n">BaseOpenViewModel</span><span class="p">&lt;</span><span class="n">SomeType</span><span class="p">&gt;</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="kt">string</span> <span class="n">ChildProperty</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>By default following resource keys will be discovered:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>Sample.BaseOpenViewModel`1.BaseProperty
Sample.BaseOpenViewModel`1.BaseProperty-Required
Sample.SampleViewModelWithClosedBase.ChildProperty
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now image that we are asking for a label for the parent class property:</p>

<pre><code class="language-razor">@model SampleViewModelWithClosedBase

@Html.LabelFor(m =&gt; m.BaseProperty)
</code></pre>

<p>Method call <code class="language-plaintext highlighter-rouge">LabelFor()</code> will go through Asp.Net Mvc model meta data provider. Container type for the requested property will be <code class="language-plaintext highlighter-rouge">SampleViewModelWithClosedBase</code>, well because that’s the model of the view.
Metadata provider will recognize that container type has attribute with <code class="language-plaintext highlighter-rouge">Inherited</code> property set to <code class="language-plaintext highlighter-rouge">false</code>. Which essentially means that if property is not found on the given container type “level”, property definition should be searched within upper levels - through the inheritance chain up to the very base type - <code class="language-plaintext highlighter-rouge">System.Object</code>.</p>

<p>At the runtime while metadata provider tries to find parent type where property is defined, in this case parent will be <code class="language-plaintext highlighter-rouge">BaseOpenViewModel&lt;SomeType&gt;</code> and not <code class="language-plaintext highlighter-rouge">BaseOpenViewModel&lt;T&gt;</code> as it was discovered during scanning process.</p>

<p>In other words: parent class is <strong>open generic</strong> during scanning, but <strong>closed generic</strong> when resource translation is requested afterwards. Interesting - but at the same time pretty simple to resolve. We need to ignore type parameter and look only for actual type definition. Fortunately this type information in available from .Net Framework. We just need to consume it and act accordingly.</p>

<p>This code fragment will look for resource with key <code class="language-plaintext highlighter-rouge">Sample.BaseOpenViewModel.BaseProperty</code> despite that model of the view is <code class="language-plaintext highlighter-rouge">SampleViewModelWithClosedBase</code>:</p>

<pre><code class="language-razor">@model SampleViewModelWithClosedBase

@Html.LabelFor(m =&gt; m.BaseProperty)
</code></pre>

<h2 id="log-missing-keys">Log Missing Keys</h2>

<p>Many thanks to my friend <a href="http://world.episerver.com/blogs/sorby/">Petter Sørby</a> from BVN/EPiServer for a great idea and copyright of the feature.</p>

<p>I just couldn’t image better place to add diagnostics.</p>

<p>If you want to see which keys are missing (it’s unlikely that you will hit this problem if you are following “<em>strongly-typed</em>” approach and avoid “<em>stringly-typed</em>”), then you just need to enable diagnostics for database localization provider and then grep your EPiServer log files. You can enable diagnostics my adding following line somewhere in your initialization modules:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">using</span> <span class="nn">DbLocalizationProvider</span><span class="p">;</span>

<span class="p">...</span>

<span class="n">ConfigurationContext</span><span class="p">.</span><span class="nf">Setup</span><span class="p">(</span><span class="n">cfg</span> <span class="p">=&gt;</span>
                          <span class="p">{</span>
                              <span class="n">cfg</span><span class="p">.</span><span class="n">DiagnosticsEnabled</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
                          <span class="p">});</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Also maybe some other stuff will be added to be logged under this setting.</p>

<h2 id="episerver-v10">EPiServer v10</h2>

<p>Support for EPiServer v10 is coming soon! Pretty close.</p>

<p>Happy localizing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Localization Provider" /><category term="Episerver" /><category term="Optimizely" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[Recently released driven localization provider for EPiServer had main focus on more complex view models along the other smaller bug fixes and features.]]></summary></entry><entry><title type="html">Baking Round Shaped Software - Mapping to the Code</title><link href="https://tech-fellow.eu/2016/10/31/baking-round-shaped-software-mapping-to-the-code/" rel="alternate" type="text/html" title="Baking Round Shaped Software - Mapping to the Code" /><published>2016-10-31T14:30:00+02:00</published><updated>2016-10-31T14:30:00+02:00</updated><id>https://tech-fellow.eu/2016/10/31/baking-round-shaped-software-mapping-to-the-code</id><content type="html" xml:base="https://tech-fellow.eu/2016/10/31/baking-round-shaped-software-mapping-to-the-code/"><![CDATA[<p>This part of the round shaped software blog posts as promised will be about mapping the theoretical terms and ideas mentioned in <a href="https://tech-fellow.eu/2016/10/17/baking-round-shaped-software/">previous post</a> to the actual code fragments and components.</p>

<p><img src="/assets/img/2016/10/code.png" alt="" /></p>

<h2 id="application-for-the-post">Application for the Post</h2>

<p>To move further and map theory to the code, I’ve created really simple sample application for managing the users. To demonstrate mediator internals and round shaped architecture - we will stick with hand crafted mediator. Mediator will be able to handle commands, queries and events.</p>

<p><img src="/assets/img/2016/10/2016-10-29_23-29-02-1.png" alt="" /></p>

<p>In the application you can:</p>

<ul>
  <li>enlist existing users (for the sake of simplicity - users will be stored in memory)</li>
  <li>create new user</li>
  <li>handle event for the newly created user (this might be handy if you need to notify somebody else about the fact)</li>
</ul>

<p>Sample application is based on <a href="https://www.asp.net/core">Asp.Net Core Framework</a>.</p>

<h2 id="notes-about-ddd">Notes About DDD</h2>
<p>Some notes regarding Domain Driven Design (DDD).</p>

<h3 id="handlers-as-application-services">Handlers as Application Services</h3>
<p>We had discussions about where handlers belong. It looks like handlers should be located in the outermost circle - somewhere in UI - it’s not part of the domain. It’s partially true. Handlers are not part of the domain. But neither they are part of the user interface. User interface is just a delivery mechanism.</p>

<p>For me - handlers look alike process orchestrators, like application services, like <a href="http://ebi.readthedocs.io/en/latest/index.html">Interactors</a>. They provide fuel for the use cases - only handlers know which use case they are handling, which domain services and models they need to operate with or upon to carry out use case. Handlers are implemented <strong>medium agnostic</strong>. They should not care from which delivery mechanism they were accessed.</p>

<h3 id="feature-slicing-in-ddd-context">Feature Slicing in DDD Context</h3>

<p>Slicing by features is one of the concept how to organize larger code bases, even in round shaped softwares. For the sake of simplicity - I left all the source code in single assembly, but sliced it by feature folders. In real application, code organization should be split at least into 2 group of projects:</p>

<ul>
  <li><em>user interface project</em> - this project would contain all delivery mechanism related stuff - like forms, views, controllers, all that stuff. Organization by feature folders here would make it more organized.</li>
  <li><em>core domain project (each for every feature)</em> - these projects would contain core domain logic for each feature, including use cases, handlers, services, events, domain models, etc.</li>
</ul>

<p>References (dependencies) should point from delivery mechanism projects inwards to domain projects (center of the architecture).</p>

<h2 id="web-is-delivery-mechanism">Web is Delivery Mechanism</h2>

<p>From the architecture perspective - I still think that web is just a delivery mechanism, ceremony layer around business core area. But don’t get me wrong - I love web, I love JavaScript (sometimes) and love Ajax and Json, and the rest of the <a href="https://hackernoon.com/how-it-feels-to-learn-javascript-in-2016-d3a717dd577f#.9futv0n7m">zoo inhabitants</a>. But still - looking from another side of the fence - web is just yet another consumer of the application, just another incoming channel - like unit tests, or integration tests (if you have one), batch processes, scheduled jobs or somebody else.</p>

<p><img src="/assets/img/2016/10/FreshPaint-22-2016.10.09-08.49.12-1.png" alt="" /></p>

<p>Delivery mechanism might be changed from version X to Y, it might be refactored from WebForms to Asp.Net Mvc. It even might be supplemented by another user interface (like mobile or watch, or anything else). Despite all the changes around, the core is main reason why application exists. It’s your main focus as developer/architect.</p>

<h2 id="code-definitions">Code Definitions</h2>

<p>As we covered in <a href="https://tech-fellow.ghost.io/2016/10/17/baking-round-shaped-software/">previous post</a> there are 3 types of messages that could be passed through mediator:</p>

<ul>
  <li><em>commands</em> - something that mutes state of the application;</li>
  <li><em>queries</em> - something that does not mutate state of the application, but returns value instead;</li>
  <li><em>events</em> - something that notifies other parties of the fact inside the domain;</li>
</ul>

<h3 id="commands-queries-and-events">Commands, Queries and Events</h3>

<p>Code definition for each of them is pretty straight forward.</p>

<p>For the commands, queries and events in sample application here - it’s more like marker interfaces.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">interface</span> <span class="nc">ICommand</span> <span class="p">{</span> <span class="p">}</span>

<span class="k">public</span> <span class="k">interface</span> <span class="nc">IQuery</span><span class="p">&lt;</span><span class="k">out</span> <span class="n">TResult</span><span class="p">&gt;</span> <span class="p">{</span> <span class="p">}</span>

<span class="k">public</span> <span class="k">interface</span> <span class="nc">IDomainEvent</span> <span class="p">{</span> <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Regarding of commonly shared attributes for all message types - is really up to you and project, how constraint you want to be regarding messages going through the system and what kind of common characteristics are shared across all message types. Currently interfaces for message types are more like marker interfaces, but they may contain various properties that all messages of particular type must implement. For instance all events should have occourance date and time:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">interface</span> <span class="nc">IDomainEvent</span>
<span class="p">{</span>
    <span class="n">DateTime</span> <span class="n">OccouredAt</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="message-handlers">Message Handlers</h3>

<p>On the other end - there are handlers for each type of the message.</p>

<p>For commands:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">interface</span> <span class="nc">ICommandHandler</span><span class="p">&lt;</span><span class="k">in</span> <span class="n">TCommand</span><span class="p">&gt;</span>
                                <span class="k">where</span> <span class="n">TCommand</span> <span class="p">:</span> <span class="n">ICommand</span>
<span class="p">{</span>
    <span class="k">void</span> <span class="nf">Handle</span><span class="p">(</span><span class="n">TCommand</span> <span class="n">command</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>One for queries:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">interface</span> <span class="nc">IQueryHandler</span><span class="p">&lt;</span><span class="k">in</span> <span class="n">TQuery</span><span class="p">,</span> <span class="k">out</span> <span class="n">TResult</span><span class="p">&gt;</span>
                              <span class="k">where</span> <span class="n">TQuery</span> <span class="p">:</span> <span class="n">IQuery</span><span class="p">&lt;</span><span class="n">TResult</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="n">TResult</span> <span class="nf">Handle</span><span class="p">(</span><span class="n">TQuery</span> <span class="n">query</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And for events:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">interface</span> <span class="nc">IDomainEventHandler</span><span class="p">&lt;</span><span class="k">in</span> <span class="n">TEvent</span><span class="p">&gt;</span>
                                    <span class="k">where</span> <span class="n">TEvent</span> <span class="p">:</span> <span class="n">IDomainEvent</span>
<span class="p">{</span>
    <span class="k">void</span> <span class="nf">Handle</span><span class="p">(</span><span class="n">TEvent</span> <span class="n">@event</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Most of them are all the same: incoming message type passed to <code class="language-plaintext highlighter-rouge">Handle()</code> method.
Note that these are just abstractions still. No concrete command or handler is shown yet.</p>

<h3 id="the-mediator">The Mediator</h3>

<p>Last piece in the puzzle is component that will “glue” together message types with corresponding handlers.
From source code perspective, mediator is an interface exposed to consumers, so they can use mediator to handle specific messags. Execution of the message means finding specific handler (or maybe more handler<strong>s</strong>) for this specific message and asking handler to handle the message.</p>

<p>Mediator interface is defined as following:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">interface</span> <span class="nc">IMediator</span>
<span class="p">{</span>
    <span class="k">void</span> <span class="n">Execute</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">T</span> <span class="n">command</span><span class="p">)</span> <span class="k">where</span> <span class="n">T</span> <span class="p">:</span> <span class="n">ICommand</span><span class="p">;</span>

    <span class="k">void</span> <span class="n">Publish</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">T</span> <span class="n">@event</span><span class="p">)</span> <span class="k">where</span> <span class="n">T</span> <span class="p">:</span> <span class="n">IDomainEvent</span><span class="p">;</span>

    <span class="n">TResult</span> <span class="n">Query</span><span class="p">&lt;</span><span class="n">TResult</span><span class="p">&gt;(</span><span class="n">IQuery</span><span class="p">&lt;</span><span class="n">TResult</span><span class="p">&gt;</span> <span class="n">query</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Note that there is separate method to execute each type of the message - one for commands, one for queries and last for events. We will return back to this later, when concrete messages will be passed around the system.</p>

<h2 id="di-container-setup-aka-register-phase">DI Container Setup aka “Register Phase”</h2>

<p>“Registration Phase” In <a href="http://blog.ploeh.dk/2010/09/29/TheRegisterResolveReleasepattern/">RRR pattern</a> is quite important just because that’s the place where composition root will look for mappings from the requested abstrations to the concrete implementations. Maybe in sample applications it’s better to use <a href="http://blog.ploeh.dk/2014/06/10/pure-di/">Pure DI</a>, but I’ll stick with my favorite container - <a href="http://structuremap.github.io/">StructureMap (SM)</a> - just for convenience and also to demonstrate some of the cool features modern containers could offer.</p>

<h3 id="setup-iserviceprovider">Setup IServiceProvider</h3>

<p><a href="http://structuremap.github.io/">StructureMap</a> is powerful enough to find types my any mean (I’m pretty sure that other containers can do that as well - I’m just not so deep into other containers to blog about that in more details).</p>

<p>So let’s start with swapping out default <code class="language-plaintext highlighter-rouge">IServiceProvider</code> (we need to replace Asp.Net Core default one to enable more black magic in type scanning and object wiring process).</p>

<p>We need to add following code in <code class="language-plaintext highlighter-rouge">ConfigureServices()</code> method in <code class="language-plaintext highlighter-rouge">Startup.cs</code>:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="n">IServiceProvider</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="nf">UseStructureMapContainer</span><span class="p">(</span><span class="n">services</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">private</span> <span class="n">IServiceProvider</span> <span class="nf">UseStructureMapContainer</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
    <span class="p">....</span>

    <span class="kt">var</span> <span class="n">container</span> <span class="p">=</span> <span class="k">new</span> <span class="n">StructureMap</span><span class="p">.</span><span class="nf">Container</span><span class="p">();</span>

    <span class="n">container</span><span class="p">.</span><span class="nf">Populate</span><span class="p">(</span><span class="n">services</span><span class="p">);</span>
    <span class="n">container</span><span class="p">.</span><span class="nf">Configure</span><span class="p">(</span><span class="n">config</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">config</span><span class="p">.</span><span class="nf">Scan</span><span class="p">(</span><span class="n">scanner</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="n">scanner</span><span class="p">.</span><span class="nf">TheCallingAssembly</span><span class="p">();</span>
            <span class="n">scanner</span><span class="p">.</span><span class="nf">WithDefaultConventions</span><span class="p">();</span>
            <span class="n">scanner</span><span class="p">.</span><span class="nf">LookForRegistries</span><span class="p">();</span>
        <span class="p">});</span>
    <span class="p">});</span>

    <span class="k">return</span> <span class="n">container</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">IServiceProvider</span><span class="p">&gt;();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="scanning-for-handlers">Scanning for Handlers</h3>

<p>When we have StructureMap registries in place, we can add SM registry to register mediator types in container.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">MediatorRegistrations</span> <span class="p">:</span> <span class="n">Registry</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">MediatorRegistrations</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="nf">Scan</span><span class="p">(</span><span class="n">scanner</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="n">scanner</span><span class="p">.</span><span class="nf">TheCallingAssembly</span><span class="p">();</span>
            <span class="n">scanner</span><span class="p">.</span><span class="nf">WithDefaultConventions</span><span class="p">();</span>

            <span class="n">scanner</span><span class="p">.</span><span class="nf">AddAllTypesOf</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">ICommandHandler</span><span class="p">&lt;&gt;));</span>
            <span class="n">scanner</span><span class="p">.</span><span class="nf">AddAllTypesOf</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">IQueryHandler</span><span class="p">&lt;,&gt;));</span>
            <span class="n">scanner</span><span class="p">.</span><span class="nf">AddAllTypesOf</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">IDomainEventHandler</span><span class="p">&lt;&gt;));</span>
        <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This SM feature (<code class="language-plaintext highlighter-rouge">AddAllTypesOf()</code>) will make sure that <strong>all</strong> types will be registered in the DI container.</p>

<h3 id="register-handler-factories">Register Handler Factories</h3>

<p>DI container will have information about list of handlers for various message types. However - during runtime it will be required to create instance of those handlers. For this reason - we need to register additional types - abstract factory and concrete message type handler factories. Under the hood handler factories will use abstract type factory. Let’s just see the code.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">MediatorRegistrations</span> <span class="p">:</span> <span class="n">Registry</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">MediatorRegistrations</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="nf">Scan</span><span class="p">(...);</span>

        <span class="n">For</span><span class="p">&lt;</span><span class="n">IAbstractFactory</span><span class="p">&gt;().</span><span class="n">Use</span><span class="p">&lt;</span><span class="n">AbstractFactory</span><span class="p">&gt;()</span>
                               <span class="p">.</span><span class="nf">ContainerScoped</span><span class="p">();</span>
        <span class="n">For</span><span class="p">&lt;</span><span class="n">IQueryHandlerFactory</span><span class="p">&gt;().</span><span class="n">Use</span><span class="p">&lt;</span><span class="n">QueryHandlerFactory</span><span class="p">&gt;()</span>
                                   <span class="p">.</span><span class="nf">ContainerScoped</span><span class="p">();</span>
        <span class="n">For</span><span class="p">&lt;</span><span class="n">ICommandHandlerFactory</span><span class="p">&gt;().</span><span class="n">Use</span><span class="p">&lt;</span><span class="n">CommandHandlerFactory</span><span class="p">&gt;()</span>
                                     <span class="p">.</span><span class="nf">ContainerScoped</span><span class="p">();</span>
        <span class="n">For</span><span class="p">&lt;</span><span class="n">IDomainEventHandlerFactory</span><span class="p">&gt;().</span><span class="n">Use</span><span class="p">&lt;</span><span class="n">DomainEventHandlerFactory</span><span class="p">&gt;()</span>
                                         <span class="p">.</span><span class="nf">ContainerScoped</span><span class="p">();</span>

        <span class="p">...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><a href="http://structuremap.github.io/the-container/nested-containers/">Container scoped</a> instances (<code class="language-plaintext highlighter-rouge">ContainerScoped()</code>) is needed for disposable dependencies. Every time for new web request nested container is created. Which will ensure that types created via <code class="language-plaintext highlighter-rouge">AbstractTypeFactory</code> are disposed at the end of the request. I don’t need to do that manually - as SM manages nested containers automatically.</p>

<h3 id="abstract-type-factory">Abstract Type Factory</h3>

<p>Abstract type factory actually is just a wrapper around <code class="language-plaintext highlighter-rouge">HttpContext.RequestServices</code>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">interface</span> <span class="nc">IAbstractFactory</span>
<span class="p">{</span>
    <span class="kt">object</span> <span class="nf">GetService</span><span class="p">(</span><span class="n">Type</span> <span class="n">serviceType</span><span class="p">);</span>
    <span class="n">T</span> <span class="n">GetService</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;();</span>
    <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="kt">object</span><span class="p">&gt;</span> <span class="nf">GetServices</span><span class="p">(</span><span class="n">Type</span> <span class="n">serviceType</span><span class="p">);</span>
    <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;</span> <span class="n">GetServices</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;();</span>
<span class="p">}</span>

<span class="k">internal</span> <span class="k">class</span> <span class="nc">AbstractFactory</span> <span class="p">:</span> <span class="n">IAbstractFactory</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IHttpContextAccessor</span> <span class="n">_contextAccessor</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">AbstractFactory</span><span class="p">(</span><span class="n">IHttpContextAccessor</span> <span class="n">contextAccessor</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span><span class="p">(</span><span class="n">contextAccessor</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
            <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">contextAccessor</span><span class="p">));</span>

        <span class="n">_contextAccessor</span> <span class="p">=</span> <span class="n">contextAccessor</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="kt">object</span> <span class="nf">GetService</span><span class="p">(</span><span class="n">Type</span> <span class="n">serviceType</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">_contextAccessor</span><span class="p">.</span><span class="n">HttpContext</span><span class="p">.</span><span class="n">RequestServices</span><span class="p">.</span><span class="nf">GetService</span><span class="p">(</span><span class="n">serviceType</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">T</span> <span class="n">GetService</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;()</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">_contextAccessor</span><span class="p">.</span><span class="n">HttpContext</span><span class="p">.</span><span class="n">RequestServices</span><span class="p">.</span><span class="n">GetService</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;();</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="kt">object</span><span class="p">&gt;</span> <span class="nf">GetServices</span><span class="p">(</span><span class="n">Type</span> <span class="n">serviceType</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">_contextAccessor</span><span class="p">.</span><span class="n">HttpContext</span><span class="p">.</span><span class="n">RequestServices</span><span class="p">.</span><span class="nf">GetServices</span><span class="p">(</span><span class="n">serviceType</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;</span> <span class="n">GetServices</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;()</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">_contextAccessor</span><span class="p">.</span><span class="n">HttpContext</span><span class="p">.</span><span class="n">RequestServices</span><span class="p">.</span><span class="n">GetServices</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="command-handler-factory">Command Handler Factory</h3>

<p>Specific message type handler factories are pretty simple (they mostly rely on the given <code class="language-plaintext highlighter-rouge">AbstractTypeFactory</code>).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="rouge-code"><pre><span class="k">internal</span> <span class="k">interface</span> <span class="nc">ICommandHandlerFactory</span>
<span class="p">{</span>
    <span class="n">ICommandHandler</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;</span> <span class="n">GetHandler</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">T</span> <span class="n">command</span><span class="p">)</span> <span class="k">where</span> <span class="n">T</span> <span class="p">:</span> <span class="n">ICommand</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">internal</span> <span class="k">class</span> <span class="nc">CommandHandlerFactory</span> <span class="p">:</span> <span class="n">ICommandHandlerFactory</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IAbstractFactory</span> <span class="n">_abstractFactory</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">CommandHandlerFactory</span><span class="p">(</span><span class="n">IAbstractFactory</span> <span class="n">abstractFactory</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span><span class="p">(</span><span class="n">abstractFactory</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
            <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">abstractFactory</span><span class="p">));</span>

        <span class="n">_abstractFactory</span> <span class="p">=</span> <span class="n">abstractFactory</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">ICommandHandler</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;</span> <span class="n">GetHandler</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">T</span> <span class="n">command</span><span class="p">)</span> <span class="k">where</span> <span class="n">T</span> <span class="p">:</span> <span class="n">ICommand</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">_abstractFactory</span><span class="p">.</span><span class="n">GetService</span><span class="p">&lt;</span><span class="n">ICommandHandler</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;&gt;();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>It’s a lot of ceremony to just create types at the runtime, but that’s the life :)</p>

<p>While it’s quite easy to create <code class="language-plaintext highlighter-rouge">ICommandHandler</code> handler factories, dealing with <code class="language-plaintext highlighter-rouge">IQueryHandler</code> and <code class="language-plaintext highlighter-rouge">IDomainEventHandler</code> requires more special treatment.</p>

<h3 id="note-about-covariance-for-queryhandlers">Note About Covariance for QueryHandlers</h3>

<p>Challenge here with <code class="language-plaintext highlighter-rouge">IQueryHandler&lt;IQuery&lt;TResult&gt;&gt;</code> handlers is related with generics.</p>

<p>Let’s see what happens when we need to create handler for <code class="language-plaintext highlighter-rouge">Commands</code>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="n">ICommandHandler</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;</span> <span class="n">GetHandler</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">T</span> <span class="n">command</span><span class="p">)</span> <span class="k">where</span> <span class="n">T</span> <span class="p">:</span> <span class="n">ICommand</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="n">_abstractFactory</span><span class="p">.</span><span class="n">GetService</span><span class="p">&lt;</span><span class="n">ICommandHandler</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;&gt;();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Concrete type of the command is passed as generic type parameter. Meaning that specific handler will be requested from the container, e.g., <code class="language-plaintext highlighter-rouge">ICommandHandler&lt;CreateUser&gt;</code>. This type will be present - due to <code class="language-plaintext highlighter-rouge">AddAllTypesOf()</code> - so called <a href="http://structuremap.github.io/generics/">closing open generics</a>.</p>

<p>The same principle for closing open generics applies to query handlers. Now look at potential factory method to create the instance of query handler:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="n">IQueryHandler</span><span class="p">&lt;</span><span class="n">TQuery</span><span class="p">,</span> <span class="n">TResult</span><span class="p">&gt;</span> <span class="n">GetHandler</span><span class="p">&lt;</span><span class="n">TQuery</span><span class="p">,</span> <span class="n">TResult</span><span class="p">&gt;(</span><span class="n">IQuery</span><span class="p">&lt;</span><span class="n">TResult</span><span class="p">&gt;</span> <span class="n">query</span><span class="p">)</span>
                                                 <span class="k">where</span> <span class="n">TQuery</span> <span class="p">:</span> <span class="n">IQuery</span><span class="p">&lt;</span><span class="n">TResult</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="p">....</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>First of, there is no type parameter to identify for which query the handler is required (e.g., concrete type of the query - <code class="language-plaintext highlighter-rouge">GetAllUsers.Query</code>). We do have only <code class="language-plaintext highlighter-rouge">IQuery&lt;TResult&gt;</code> type information. It means that we need to create target handler type “dynamically” and pass it to container.</p>

<p>Even if we could use this approach to create type of the target handler and ask underlying abstract type factory (using <em>untyped</em> method overload) to give us back handler instance:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">handlerType</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="n">IQueryHandler</span><span class="p">&lt;,&gt;).</span><span class="nf">MakeGenericType</span><span class="p">(</span><span class="n">query</span><span class="p">.</span><span class="nf">GetType</span><span class="p">(),</span> <span class="k">typeof</span><span class="p">(</span><span class="n">TResult</span><span class="p">));</span>
<span class="kt">var</span> <span class="n">handler</span> <span class="p">=</span> <span class="n">_abstractFactory</span><span class="p">.</span><span class="nf">GetService</span><span class="p">(</span><span class="n">handlerType</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>There is no way we would be able to cast received <code class="language-plaintext highlighter-rouge">System.Object</code> back to <code class="language-plaintext highlighter-rouge">IQueryHandler&lt;,&gt;</code>. It’s just not the way C# works for covariant interfaces.</p>

<p>Therefore, I’m just relying on <a href="https://twitter.com/jbogard">smart guy</a> here.
Method for create <code class="language-plaintext highlighter-rouge">IQueryHandler&lt;,&gt;</code> instances and further work with that handler, there is <a href="https://github.com/jbogard/MediatR/blob/master/src/MediatR/Internal/RequestHandlerWrapper.cs">pretty neat</a> way to encapsulate that and return intermediate type:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="n">QueryHandlerWrapper</span><span class="p">&lt;</span><span class="n">TResult</span><span class="p">&gt;</span> <span class="n">GetHandler</span><span class="p">&lt;</span><span class="n">TResult</span><span class="p">&gt;(</span><span class="n">IQuery</span><span class="p">&lt;</span><span class="n">TResult</span><span class="p">&gt;</span> <span class="n">query</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">handlerType</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="n">IQueryHandler</span><span class="p">&lt;,&gt;)</span>
                          <span class="p">.</span><span class="nf">MakeGenericType</span><span class="p">(</span><span class="n">query</span><span class="p">.</span><span class="nf">GetType</span><span class="p">(),</span> <span class="k">typeof</span><span class="p">(</span><span class="n">TResult</span><span class="p">));</span>
    <span class="kt">var</span> <span class="n">handlerWrapperType</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="n">QueryHandlerWrapper</span><span class="p">&lt;,&gt;)</span>
                                 <span class="p">.</span><span class="nf">MakeGenericType</span><span class="p">(</span><span class="n">query</span><span class="p">.</span><span class="nf">GetType</span><span class="p">(),</span> <span class="k">typeof</span><span class="p">(</span><span class="n">TResult</span><span class="p">));</span>

    <span class="kt">var</span> <span class="n">handler</span> <span class="p">=</span> <span class="n">_abstractFactory</span><span class="p">.</span><span class="nf">GetService</span><span class="p">(</span><span class="n">handlerType</span><span class="p">);</span>

    <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="p">(</span><span class="n">QueryHandlerWrapper</span><span class="p">&lt;</span><span class="n">TResult</span><span class="p">&gt;)</span> <span class="n">Activator</span><span class="p">.</span><span class="nf">CreateInstance</span><span class="p">(</span><span class="n">handlerWrapperType</span><span class="p">,</span> <span class="n">handler</span><span class="p">);</span>

    <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And the wrapper class:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="rouge-code"><pre><span class="k">internal</span> <span class="k">abstract</span> <span class="k">class</span> <span class="nc">QueryHandlerWrapper</span><span class="p">&lt;</span><span class="n">TResult</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">abstract</span> <span class="n">TResult</span> <span class="nf">Handle</span><span class="p">(</span><span class="n">IQuery</span><span class="p">&lt;</span><span class="n">TResult</span><span class="p">&gt;</span> <span class="n">query</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">internal</span> <span class="k">class</span> <span class="nc">QueryHandlerWrapper</span><span class="p">&lt;</span><span class="n">TQuery</span><span class="p">,</span> <span class="n">TResult</span><span class="p">&gt;</span>
               <span class="p">:</span> <span class="n">QueryHandlerWrapper</span><span class="p">&lt;</span><span class="n">TResult</span><span class="p">&gt;</span> <span class="k">where</span> <span class="n">TQuery</span> <span class="p">:</span> <span class="n">IQuery</span><span class="p">&lt;</span><span class="n">TResult</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IQueryHandler</span><span class="p">&lt;</span><span class="n">TQuery</span><span class="p">,</span> <span class="n">TResult</span><span class="p">&gt;</span> <span class="n">_inner</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">QueryHandlerWrapper</span><span class="p">(</span><span class="n">IQueryHandler</span><span class="p">&lt;</span><span class="n">TQuery</span><span class="p">,</span> <span class="n">TResult</span><span class="p">&gt;</span> <span class="n">inner</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_inner</span> <span class="p">=</span> <span class="n">inner</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">override</span> <span class="n">TResult</span> <span class="nf">Handle</span><span class="p">(</span><span class="n">IQuery</span><span class="p">&lt;</span><span class="n">TResult</span><span class="p">&gt;</span> <span class="n">query</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">_inner</span><span class="p">.</span><span class="nf">Handle</span><span class="p">((</span><span class="n">TQuery</span><span class="p">)</span> <span class="n">query</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>I could go into more details here on why this is needed, but I guess that might span across multiple blog posts.</p>

<h3 id="generic-event-dispatch">Generic Event Dispatch</h3>

<p>Similar situation is for domain event dispatch. Imagine when you are manipulating aggregate root, calling one service, then another one, then call some other stuff. As the result of all the manipulations there will be a collected of domain events. Events should be dispatched at some point.</p>

<p>From the code perspective it means that mediator will receive collection of generic <code class="language-plaintext highlighter-rouge">IDomainEvent</code> and somehow will need to find <strong>concrete</strong> handler for underlying domain event. Do you think approach like this will work here?</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="c1">// similar method as for commands</span>
<span class="k">public</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">IDomainEventHandler</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;&gt;</span> <span class="n">GetHandlers</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">T</span> <span class="n">@event</span><span class="p">)</span> <span class="k">where</span> <span class="n">T</span> <span class="p">:</span> <span class="n">IDomainEvent</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="n">_abstractFactory</span><span class="p">.</span><span class="n">GetServices</span><span class="p">&lt;</span><span class="n">IDomainEventHandler</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;&gt;();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Generic type parameter <code class="language-plaintext highlighter-rouge">T</code> will be <code class="language-plaintext highlighter-rouge">IDomainEvent</code>. What would you expect this method to return?</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="n">factory</span><span class="p">.</span><span class="n">GetServices</span><span class="p">&lt;</span><span class="n">IDomainEventHandler</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;&gt;();</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is ambiguous. Which handlers exactly you need? Mediator has information only about <code class="language-plaintext highlighter-rouge">IDomainEvent</code>. Do you want me to return all handlers for all events?</p>

<p>Again, I can just rely on <a href="https://github.com/jbogard/MediatR/blob/master/src/MediatR/Internal/RequestHandlerWrapper.cs">smart people</a> here and follow their solutions.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">DomainEventHandlerWrapper</span><span class="p">&gt;</span> <span class="n">GetHandlers</span><span class="p">&lt;</span><span class="n">TEvent</span><span class="p">&gt;(</span><span class="n">TEvent</span> <span class="n">@event</span><span class="p">)</span>
                                                         <span class="k">where</span> <span class="n">TEvent</span> <span class="p">:</span> <span class="n">IDomainEvent</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">handlerType</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="n">IDomainEventHandler</span><span class="p">&lt;&gt;)</span>
                          <span class="p">.</span><span class="nf">MakeGenericType</span><span class="p">(</span><span class="n">@event</span><span class="p">.</span><span class="nf">GetType</span><span class="p">());</span>
    <span class="kt">var</span> <span class="n">wrapperType</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="n">DomainEventHandlerWrapper</span><span class="p">&lt;&gt;)</span>
                          <span class="p">.</span><span class="nf">MakeGenericType</span><span class="p">(</span><span class="n">@event</span><span class="p">.</span><span class="nf">GetType</span><span class="p">());</span>

    <span class="kt">var</span> <span class="n">handlerWrappers</span> <span class="p">=</span> <span class="n">_abstractFactory</span>
                              <span class="p">.</span><span class="nf">GetServices</span><span class="p">(</span><span class="n">handlerType</span><span class="p">)</span>
                              <span class="p">.</span><span class="nf">Select</span><span class="p">(</span><span class="n">handler</span> <span class="p">=&gt;</span> <span class="n">Activator</span><span class="p">.</span><span class="nf">CreateInstance</span><span class="p">(</span><span class="n">wrapperType</span><span class="p">,</span> <span class="n">handler</span><span class="p">))</span>
                              <span class="p">.</span><span class="n">Cast</span><span class="p">&lt;</span><span class="n">DomainEventHandlerWrapper</span><span class="p">&gt;().</span><span class="nf">ToList</span><span class="p">();</span>

    <span class="k">return</span> <span class="n">handlerWrappers</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now we have all the required factories in place and we can even hide them with <code class="language-plaintext highlighter-rouge">internal</code>. I recognize this whole code as just a ceremony required to properly create handlers based on information that you have at that given moment.</p>

<h2 id="mediator-internals">Mediator Internals</h2>

<p>Now as we know how parts are assembled together and our mediator is built, we can advance further and see how mediator works internally.</p>

<p><img src="/assets/img/2016/10/FreshPaint-24-2016.10.05-11.55.33-1.png" alt="" /></p>

<p>We are particularly interested in how messages will be handled.</p>

<h3 id="imediator-implementation">IMediator Implementation</h3>

<p>Internal working of the mediator is also straight forward - all it has to do is understand incoming message type, find the handler for this message type and pass control over to <code class="language-plaintext highlighter-rouge">Handle()</code> method. Single responsibility. Other interesting responsibilities we will add later in the blog post.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</pre></td><td class="rouge-code"><pre><span class="k">internal</span> <span class="k">class</span> <span class="nc">DefaultMediator</span> <span class="p">:</span> <span class="n">IMediator</span>
<span class="p">{</span>
    <span class="p">...</span>

    <span class="k">public</span> <span class="nf">DefaultMediator</span><span class="p">(</span><span class="n">IQueryHandlerFactory</span> <span class="n">queryHandlerFactory</span><span class="p">,</span>
                           <span class="n">ICommandHandlerFactory</span> <span class="n">commandHandlerFactory</span><span class="p">,</span>
                           <span class="n">IDomainEventHandlerFactory</span> <span class="n">eventHandlerFactory</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="p">...</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="n">Execute</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">T</span> <span class="n">command</span><span class="p">)</span> <span class="k">where</span> <span class="n">T</span> <span class="p">:</span> <span class="n">ICommand</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">handler</span> <span class="p">=</span> <span class="n">_commandHandlerFactory</span><span class="p">.</span><span class="nf">GetHandler</span><span class="p">(</span><span class="n">command</span><span class="p">);</span>
        <span class="k">if</span><span class="p">(</span><span class="n">handler</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
            <span class="k">throw</span> <span class="k">new</span> <span class="nf">InvalidOperationException</span><span class="p">(...);</span>

        <span class="n">handler</span><span class="p">.</span><span class="nf">Handle</span><span class="p">(</span><span class="n">command</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="n">Publish</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">T</span> <span class="n">@event</span><span class="p">)</span> <span class="k">where</span> <span class="n">T</span> <span class="p">:</span> <span class="n">IDomainEvent</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">handlers</span> <span class="p">=</span> <span class="n">_eventHandlerFactory</span><span class="p">.</span><span class="nf">GetHandlers</span><span class="p">(</span><span class="n">@event</span><span class="p">);</span>
        <span class="k">if</span><span class="p">(</span><span class="n">handlers</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
            <span class="k">return</span><span class="p">;</span>

        <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">handler</span> <span class="k">in</span> <span class="n">handlers</span><span class="p">)</span>
            <span class="n">handler</span><span class="p">.</span><span class="nf">Handle</span><span class="p">(</span><span class="n">@event</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">TResult</span> <span class="n">Query</span><span class="p">&lt;</span><span class="n">TResult</span><span class="p">&gt;(</span><span class="n">IQuery</span><span class="p">&lt;</span><span class="n">TResult</span><span class="p">&gt;</span> <span class="n">query</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">handler</span> <span class="p">=</span> <span class="n">_queryHandlerFactory</span><span class="p">.</span><span class="nf">GetHandler</span><span class="p">(</span><span class="n">query</span><span class="p">);</span>
        <span class="k">if</span><span class="p">(</span><span class="n">handler</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
            <span class="k">throw</span> <span class="k">new</span> <span class="nf">InvalidOperationException</span><span class="p">(...);</span>

        <span class="k">return</span> <span class="n">handler</span><span class="p">.</span><span class="nf">Handle</span><span class="p">(</span><span class="n">query</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Following best DI practices - we require that somebody passes in <code class="language-plaintext highlighter-rouge">IMediator</code> interface in our Asp.Net controllers:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">readonly</span> <span class="n">IMediator</span> <span class="n">_mediator</span><span class="p">;</span>

<span class="k">public</span> <span class="nf">UserManagementController</span><span class="p">(</span><span class="n">IMediator</span> <span class="n">mediator</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">_mediator</span> <span class="p">=</span> <span class="n">mediator</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>It’s composition root (in Asp.Net Mvc case it’s controller factory) who is responsible for building object graph and finding all required dependencies.</p>

<h3 id="query---list-users">Query - List Users</h3>

<p>Let’s start with the simplest one - we need to enlist all the users from the database and show on the screen?</p>

<p>First of all, we need to define use case class - something that will represent the query itself:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">GetAllUsersList</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">Query</span> <span class="p">:</span> <span class="n">IQuery</span><span class="p">&lt;</span><span class="n">ICollection</span><span class="p">&lt;</span><span class="n">User</span><span class="p">&gt;&gt;</span> <span class="p">{</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Class <code class="language-plaintext highlighter-rouge">GetAllUsersList</code> represents use case as such and <code class="language-plaintext highlighter-rouge">Query</code> class represents query message type.</p>

<p>From the very outer layer of the application - from the Asp.Net controller - code to get user list is nothing else as calling mediator and then mapping results back to the view model.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="n">ActionResult</span> <span class="nf">List</span><span class="p">(</span><span class="n">GetAllUsersList</span><span class="p">.</span><span class="n">Query</span> <span class="n">query</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="n">_mediator</span><span class="p">.</span><span class="nf">Query</span><span class="p">(</span><span class="n">query</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">model</span> <span class="p">=</span> <span class="k">new</span> <span class="n">GetAllUsersList</span><span class="p">.</span><span class="nf">ViewModel</span><span class="p">(</span><span class="n">result</span><span class="p">);</span>

    <span class="k">return</span> <span class="nf">View</span><span class="p">(</span><span class="n">model</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>View model is also part of the use case in this sample application:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">GetAllUsersList</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">Query</span> <span class="p">:</span> <span class="n">IQuery</span><span class="p">&lt;</span><span class="n">ICollection</span><span class="p">&lt;</span><span class="n">User</span><span class="p">&gt;&gt;</span> <span class="p">{</span> <span class="p">}</span>

    <span class="k">public</span> <span class="k">class</span> <span class="nc">ViewModel</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="nf">ViewModel</span><span class="p">(</span><span class="n">ICollection</span><span class="p">&lt;</span><span class="n">User</span><span class="p">&gt;</span> <span class="n">users</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">if</span><span class="p">(</span><span class="n">users</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
                <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">users</span><span class="p">));</span>

            <span class="n">Users</span> <span class="p">=</span> <span class="n">users</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="k">public</span> <span class="n">ICollection</span><span class="p">&lt;</span><span class="n">User</span><span class="p">&gt;</span> <span class="n">Users</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">private</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>For the sake of simplicity viewmodel contains the same collection of users received from the query handler. In real life application most probably here could be mapping from domain model to viewmodel. From my experience usually viewmodels are superset of domain model - they contain more information, they are enriched and crafted for particular view needs.</p>

<p>If we just execute this code above - we will get an exception from the mediator complaining that there is no handler defined for <code class="language-plaintext highlighter-rouge">GetAllUsersList.Query</code> query. It’s time to add handler (also as member of <code class="language-plaintext highlighter-rouge">GetAllUsersList</code> use case class):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">GetAllUsersList</span>
<span class="p">{</span>
    <span class="p">...</span>

    <span class="k">public</span> <span class="k">class</span> <span class="nc">Handler</span> <span class="p">:</span> <span class="n">IQueryHandler</span><span class="p">&lt;</span><span class="n">Query</span><span class="p">,</span> <span class="n">ICollection</span><span class="p">&lt;</span><span class="n">User</span><span class="p">&gt;&gt;</span>
    <span class="p">{</span>
        <span class="k">private</span> <span class="k">readonly</span> <span class="n">IUserStorage</span> <span class="n">_storage</span><span class="p">;</span>

        <span class="k">public</span> <span class="nf">Handler</span><span class="p">(</span><span class="n">IUserStorage</span> <span class="n">storage</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="n">_storage</span> <span class="p">=</span> <span class="n">storage</span><span class="p">;</span>
            <span class="p">}</span>

        <span class="k">public</span> <span class="n">ICollection</span><span class="p">&lt;</span><span class="n">User</span><span class="p">&gt;</span> <span class="nf">Handle</span><span class="p">(</span><span class="n">Query</span> <span class="n">command</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">return</span> <span class="n">_storage</span><span class="p">.</span><span class="n">Users</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Note that handlers are just another piece in the system that can require dependencies. Previously described <code class="language-plaintext highlighter-rouge">AbstractTypeFactory</code> together with <code class="language-plaintext highlighter-rouge">QueryHandlerFactory</code> are able to create handlers via <code class="language-plaintext highlighter-rouge">IServiceProvider</code> giving all required dependencies if needed.</p>

<p>Let’s see how we can add new user.</p>

<h3 id="command---create-user">Command - Create User</h3>

<p>Start with outer most layer of the application - Mvc controller. Method that draws form on the screen is really boring:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="n">ActionResult</span> <span class="nf">Create</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">model</span> <span class="p">=</span> <span class="k">new</span> <span class="n">CreateUser</span><span class="p">.</span><span class="nf">Command</span><span class="p">();</span>
    <span class="k">return</span> <span class="nf">View</span><span class="p">(</span><span class="n">model</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>I’m not a UI designer :)</p>

<p><img src="/assets/img/2016/10/2016-10-29_07-00-51.png" alt="" /></p>

<p>Note about viewmodel in create operation. If you look at the Mvc action - the model of the view is used the same <code class="language-plaintext highlighter-rouge">CreateUser.Command</code> class. Viewmodel and command classes are exactly the same - there is no reason to split apart. But in real life - most probably viewmodel will be used to draw rich UI and command object will be used to carry only data required to execute this command.</p>

<p>Now let’s look at postback handler - Mvc action with <code class="language-plaintext highlighter-rouge">[HttpPost]</code> attribute:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">HttpPost</span><span class="p">]</span>
<span class="k">public</span> <span class="n">ActionResult</span> <span class="nf">Create</span><span class="p">(</span><span class="n">CreateUser</span><span class="p">.</span><span class="n">Command</span> <span class="n">command</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">_mediator</span><span class="p">.</span><span class="nf">Execute</span><span class="p">(</span><span class="n">command</span><span class="p">);</span>

    <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nf">RedirectToActionJson</span><span class="p">(</span><span class="s">"List"</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Note that I’m already expecting <code class="language-plaintext highlighter-rouge">CreateUser.Command</code> as parameter for the action. Even if initially form would be drawn using viewmodel class as model, I would still expect <code class="language-plaintext highlighter-rouge">CreateUser.Command</code> as parameter. Why would I receive viewmodel from which I would need to create command and then execute the command. Does not make sense. I’m expecting command as parameter.</p>

<p>Why there is <code class="language-plaintext highlighter-rouge">RedirectToActionJson()</code> return statement?! We will get to that in “<em>Client-Side Communications via Ajax</em>” chapter.</p>

<p>Now let’s look at use case class.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">CreateUser</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">Command</span> <span class="p">:</span> <span class="n">ICommand</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="kt">string</span> <span class="n">Username</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
        <span class="k">public</span> <span class="kt">string</span> <span class="n">Email</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
        <span class="k">public</span> <span class="kt">string</span> <span class="n">FirstName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
        <span class="k">public</span> <span class="kt">string</span> <span class="n">LastName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And this is the event handler:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">CreateUser</span>
<span class="p">{</span>
    <span class="p">...</span>

    <span class="k">public</span> <span class="k">class</span> <span class="nc">Handler</span> <span class="p">:</span> <span class="n">ICommandHandler</span><span class="p">&lt;</span><span class="n">Command</span><span class="p">&gt;</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="nf">Handler</span><span class="p">(</span><span class="n">IUserStorage</span> <span class="n">storage</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="p">...</span>
        <span class="p">}</span>

        <span class="k">public</span> <span class="k">void</span> <span class="nf">Handle</span><span class="p">(</span><span class="n">Command</span> <span class="n">command</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="c1">// perform some business logic</span>
            <span class="kt">var</span> <span class="n">newUser</span> <span class="p">=</span> <span class="n">User</span><span class="p">.</span><span class="nf">Create</span><span class="p">(</span><span class="n">command</span><span class="p">.</span><span class="n">Username</span><span class="p">,</span>
                                    <span class="n">command</span><span class="p">.</span><span class="n">Email</span><span class="p">,</span>
                                    <span class="n">command</span><span class="p">.</span><span class="n">FirstName</span><span class="p">,</span>
                                    <span class="n">command</span><span class="p">.</span><span class="n">LastName</span><span class="p">);</span>

            <span class="n">_storage</span><span class="p">.</span><span class="n">Users</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">newUser</span><span class="p">);</span>
            <span class="n">_storage</span><span class="p">.</span><span class="nf">Save</span><span class="p">(</span><span class="n">newUser</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Here <code class="language-plaintext highlighter-rouge">IUserStorage</code> is simulation of the repository that will be able to store and retrieve users. In this sample composition root injects <code class="language-plaintext highlighter-rouge">InMemoryStorage</code> class - that contains user list in memory. We can pretend that underlying storage has collection of <code class="language-plaintext highlighter-rouge">User</code> where you can add new ones. Small downside is that list resets everytime we restart the app :)</p>

<p>We haven’t seen <code class="language-plaintext highlighter-rouge">User</code> domain object model so far. Let’s take a look.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">User</span>
<span class="p">{</span>
    <span class="k">protected</span> <span class="nf">User</span><span class="p">()</span> <span class="p">{</span> <span class="p">}</span>
    <span class="k">public</span> <span class="n">Guid</span> <span class="n">Id</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">private</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Username</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">private</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Email</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">private</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">FirstName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">private</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">LastName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">private</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

    <span class="k">public</span> <span class="k">static</span> <span class="n">User</span> <span class="nf">Create</span><span class="p">(</span><span class="kt">string</span> <span class="n">username</span><span class="p">,</span> <span class="kt">string</span> <span class="n">email</span><span class="p">,</span>
                              <span class="kt">string</span> <span class="n">firstName</span><span class="p">,</span> <span class="kt">string</span> <span class="n">lastName</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="p">...</span>
        <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="k">new</span> <span class="n">User</span>
                     <span class="p">{</span>
                         <span class="n">Id</span> <span class="p">=</span> <span class="n">Guid</span><span class="p">.</span><span class="nf">NewGuid</span><span class="p">(),</span>
                         <span class="n">Username</span> <span class="p">=</span> <span class="n">username</span><span class="p">,</span>
                         <span class="n">Email</span> <span class="p">=</span> <span class="n">email</span><span class="p">,</span>
                         <span class="n">FirstName</span> <span class="p">=</span> <span class="n">firstName</span><span class="p">,</span>
                         <span class="n">LastName</span> <span class="p">=</span> <span class="n">lastName</span>
                     <span class="p">};</span>
        <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Nothing fancy - ordinary C# class with some functionality.</p>

<p>As described earlier - we need to send email notification to newly created users. Creation of the user and sending email notification looks like two different things that would be nice to split and isolate one from another. For this reason we can use domain events to notify other use cases or other features about what just happened. As you can see here - there is no event dispatch in command handler.</p>

<h3 id="domain-event---user-created">Domain Event - User Created</h3>

<p>There are two type of messages - one of them are just executed and that’s it. Another part needs to communicate with other components, notify other use cases in other features, etc.
For this reason mediator provides so called event broadcasting (or dispatch).</p>

<p>My understanding regarding domain events is: aggregate root is responsible for “<strong>raising</strong>” events and somebody is responsible for “<strong>dispatching</strong>” them. <em>Raising</em> here actually means that the aggregate root is responsible for registering events in some event collection. They will not be immediately dispatched. While performing operations on aggregate root - events are just collected. Once operation is performed and aggregate root needs to be persisted to the underlying store - so to say, operation will be finalized, there has to be somebody who is responsible to dispatch these collected events, find appropriate handlers and give them control to handle the event. So pattern is called - <a href="https://lostechies.com/jimmybogard/2010/03/30/strengthening-your-domain-the-double-dispatch-pattern/"><strong>double dispatch</strong></a> pattern.</p>

<p>Let’s see how this will look in the code.</p>

<p>First of all, we need to define where events will be stored. For this I chose aggregate root.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">AggregateRoot</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="n">ICollection</span><span class="p">&lt;</span><span class="n">IDomainEvent</span><span class="p">&gt;</span> <span class="n">Events</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">IDomainEvent</span><span class="p">&gt;();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As we now have a place where to “<em>raise</em>” events - we need to update our <code class="language-plaintext highlighter-rouge">User</code> class.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">User</span> <span class="p">:</span> <span class="n">AggregateRoot</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="n">User</span> <span class="nf">Create</span><span class="p">(</span><span class="kt">string</span> <span class="n">username</span><span class="p">,</span> <span class="kt">string</span> <span class="n">email</span><span class="p">,</span>
                              <span class="kt">string</span> <span class="n">firstName</span><span class="p">,</span> <span class="kt">string</span> <span class="n">lastName</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="k">new</span> <span class="n">User</span>
                     <span class="p">{</span>
                         <span class="n">Id</span> <span class="p">=</span> <span class="n">Guid</span><span class="p">.</span><span class="nf">NewGuid</span><span class="p">(),</span>
                         <span class="p">....</span>
                     <span class="p">};</span>

        <span class="n">result</span><span class="p">.</span><span class="n">Events</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">new</span> <span class="nf">UserCreatedEvent</span><span class="p">(</span><span class="n">username</span><span class="p">,</span>  <span class="n">email</span><span class="p">));</span>
        <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Why we need double dispatch of events? One of the reasons is that directly dispatching events from the domain model to handlers makes them to execute immediately. Events are usually with side effects. So it makes testing quite a bit simpler. We can call operations on domain model and then inspect <code class="language-plaintext highlighter-rouge">Events</code> collection afterwards.</p>

<p>It really depends on the project and particular application architecture, but I tend to think that this “somebody” most of the time is component that pushes new mutated state of the domain model back to the underlying storage. Either you follow <code class="language-plaintext highlighter-rouge">IRepository</code> pattern or you do manual database access (it actually does not matter) - you have to choose a place where events will be  dispatched.</p>

<p>In our sample application event dispatcher will be done by mediator (with the help from <code class="language-plaintext highlighter-rouge">IDomainEventHandlerFactory</code>).
Let’s say that there is <code class="language-plaintext highlighter-rouge">Save()</code> method that needs to be called to push data back to the underlying storage. So this is perfect place to do dispatch.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</pre></td><td class="rouge-code"><pre><span class="k">internal</span> <span class="k">class</span> <span class="nc">InMemoryUserStorage</span> <span class="p">:</span> <span class="n">IUserStorage</span>
<span class="p">{</span>
    <span class="p">...</span>

    <span class="k">public</span> <span class="nf">InMemoryUserStorage</span><span class="p">(</span><span class="n">IMediator</span> <span class="n">mediator</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="p">...</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Save</span><span class="p">(</span><span class="n">AggregateRoot</span> <span class="n">root</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// simulation of the actual database call</span>
        <span class="c1">// ...</span>

        <span class="c1">// dispatch of the events</span>
        <span class="k">if</span><span class="p">(!</span><span class="n">root</span><span class="p">.</span><span class="n">Events</span><span class="p">.</span><span class="nf">Any</span><span class="p">())</span>
            <span class="k">return</span><span class="p">;</span>

        <span class="k">while</span> <span class="p">(</span><span class="n">root</span><span class="p">.</span><span class="n">Events</span><span class="p">.</span><span class="nf">Any</span><span class="p">())</span>
        <span class="p">{</span>
            <span class="kt">var</span> <span class="n">@event</span> <span class="p">=</span> <span class="n">root</span><span class="p">.</span><span class="n">Events</span><span class="p">.</span><span class="nf">FirstOrDefault</span><span class="p">();</span>
            <span class="k">if</span><span class="p">(</span><span class="n">@event</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
                <span class="k">continue</span><span class="p">;</span>

            <span class="n">_mediator</span><span class="p">.</span><span class="nf">Publish</span><span class="p">(</span><span class="n">@event</span><span class="p">);</span>
            <span class="n">root</span><span class="p">.</span><span class="n">Events</span><span class="p">.</span><span class="nf">Remove</span><span class="p">(</span><span class="n">@event</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Depending on your implementation of data access - this might be some hook in <a href="https://www.pluralsight.com/courses/efarchitecture">Entity Framework based repository</a>. If it’s your case then implementation of the dispatching hook could look like this:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">override</span> <span class="kt">int</span> <span class="nf">SaveChanges</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">events</span> <span class="p">=</span> <span class="n">ChangeTracker</span><span class="p">.</span><span class="n">Entries</span><span class="p">&lt;</span><span class="n">AggregateRoot</span><span class="p">&gt;()</span>
                              <span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">po</span> <span class="p">=&gt;</span> <span class="n">po</span><span class="p">.</span><span class="n">Events</span><span class="p">.</span><span class="nf">Any</span><span class="p">())</span>
                              <span class="p">.</span><span class="nf">ToList</span><span class="p">();</span>
    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Or maybe you might go EF interceptor way. Depends on your preferences and practices.</p>

<h3 id="domain-events-vs-application-events">Domain Events vs Application Events</h3>

<p>From the DDD theory there should be two type of events - domain events and application events. Latter is optional. From my experience and using mediator as pattern - I rarely need to implement application events, mostly domain events. However - in this architecture I don’t see any objection why domain and application events couldn’t co-exist. Domain is responsible for “raising” domain events. Somebody is responsible for dispatching those domain events. If you need to implement application wide events - I would go with approach where corresponding use case handler is responsible for dispatching application events. Being a process orchestrator, only handler knows when process has started, when ended or when process transits into different state.
If needed, handler can demand <code class="language-plaintext highlighter-rouge">IMediator</code> instance via constructor injection and use that to dispatch application events. I think it’s perfectly fine if handler has it’s own dependencies.</p>

<p><strong>Update</strong>: as one attentive reader pointed out - to request the same <code class="language-plaintext highlighter-rouge">IMediator</code> interface to dispatch either domain or application events might violate <a href="https://en.wikipedia.org/wiki/Interface_segregation_principle">ISP</a> principle. Better would be to require something like <code class="language-plaintext highlighter-rouge">IEventDispatcher&lt;T&gt;</code> or something like that.</p>

<h2 id="client-server-communications-via-ajax">Client-Server Communications via Ajax</h2>

<p>While we were reviewing Mvc action body there was note about *-Json return types from the actions.</p>

<p>Btw, why there is <code class="language-plaintext highlighter-rouge">return this.RedirectToActionJson("List")</code> and not something like this <code class="language-plaintext highlighter-rouge">return this.RedirectToActionJson(() =&gt; List(new GetAllUsersList.Query()));</code>? Because I’m too lazy now to implement proper <code class="language-plaintext highlighter-rouge">LambdaEpxression</code> walker and generate Url with action name and all passed arguments. Let smarter guys do it.</p>

<p>Main reason for this is that all forms are sent back to the server via Ajax pipeline. There is no full page postback. Why? Here are some reasons:</p>

<ul>
  <li>You don’t need to deal with <code class="language-plaintext highlighter-rouge">ModelState</code> object in your Mvc actions anymore. No more ridiculous checks for <code class="language-plaintext highlighter-rouge">ModelState.IsValid</code> all over the place. Invalid model state is infrastructure thingy, I don’t need to think about it in my Mvc action. Does it makes sense to continue to execute Mvc action if <code class="language-plaintext highlighter-rouge">ModelState</code> is not valid? From the experience I almost always see code that returns the same <code class="language-plaintext highlighter-rouge">View(model)</code> is state is invalid, otherwise continues with actual business process. For me - it’s unnecessary noise.</li>
  <li>If it happens so that client made a request with <code class="language-plaintext highlighter-rouge">ModelState.IsValid = false</code>, I can return this model state with all the found errors back to the client as <code class="language-plaintext highlighter-rouge">JSON</code> object. You might think why that’s needed? Image if I do have all invalid posted data back as traversable data tree - I can do some black magic and provide nice and rich user interface to go through all the invalid input fields with <code class="language-plaintext highlighter-rouge">&lt;&lt;</code> and <code class="language-plaintext highlighter-rouge">&gt;&gt;</code> links (this was actually real requirement in one of the projects).</li>
  <li>Most of the time viewmodel that was used to render the page is “more rich” compared to one that is posted back (I’m referring to the filled in classifiers dropdowns and other enrichments). Using classical postback handling - I will need to “enrich” again received view model in order to return it back to the client (in both error and success cases) within the view. Using Ajax - I don’t even need to think about it. Page is never actually posted back to the server, meaning that I don’t need to redraw page once again.</li>
</ul>

<p>Client side code is not complex. Here is snapshot:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
</pre></td><td class="rouge-code"><pre><span class="nf">$</span><span class="p">(</span><span class="nf">function </span><span class="p">()</span> <span class="p">{</span>
    <span class="kd">var</span> <span class="nx">redirect</span> <span class="o">=</span> <span class="nf">function </span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">data</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span>
        <span class="k">if </span><span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">redirect</span><span class="p">)</span> <span class="p">{</span>
            <span class="nb">window</span><span class="p">.</span><span class="nx">location</span> <span class="o">=</span> <span class="nx">data</span><span class="p">.</span><span class="nx">redirect</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="nb">window</span><span class="p">.</span><span class="nf">scrollTo</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
            <span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nf">reload</span><span class="p">();</span>
        <span class="p">}</span>
    <span class="p">};</span>
    <span class="kd">var</span> <span class="nx">showException</span> <span class="o">=</span> <span class="nf">function </span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">data</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">responseJSON</span><span class="p">);</span>
        <span class="nf">alert</span><span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nb">Error</span><span class="p">);</span>
    <span class="p">};</span>
    <span class="kd">var</span> <span class="nx">highlightErrors</span> <span class="o">=</span> <span class="nf">function </span><span class="p">(</span><span class="nx">response</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">var</span> <span class="nx">data</span> <span class="o">=</span> <span class="nx">response</span><span class="p">.</span><span class="nx">responseJSON</span><span class="p">;</span>
        <span class="nx">$</span><span class="p">.</span><span class="nf">each</span><span class="p">(</span><span class="nb">Object</span><span class="p">.</span><span class="nf">keys</span><span class="p">(</span><span class="nx">data</span><span class="p">),</span>
            <span class="nf">function </span><span class="p">(</span><span class="nx">ix</span><span class="p">,</span> <span class="nx">el</span><span class="p">)</span> <span class="p">{</span>
                <span class="kd">var</span> <span class="nx">errors</span> <span class="o">=</span> <span class="nx">data</span><span class="p">[</span><span class="nx">el</span><span class="p">].</span><span class="nx">Errors</span><span class="p">,</span>
                    <span class="nx">fieldId</span> <span class="o">=</span> <span class="nx">el</span><span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="dl">'</span><span class="s1">.</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">_</span><span class="dl">'</span><span class="p">);</span>
                <span class="k">if </span><span class="p">(</span><span class="nx">errors</span><span class="p">.</span><span class="nx">length</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
                    <span class="kd">var</span> <span class="nx">$field</span> <span class="o">=</span> <span class="nf">$</span><span class="p">(</span><span class="dl">'</span><span class="s1">#</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">fieldId</span><span class="p">);</span>
                    <span class="nx">$field</span><span class="p">.</span><span class="nf">closest</span><span class="p">(</span><span class="dl">'</span><span class="s1">.form-group</span><span class="dl">'</span><span class="p">).</span><span class="nf">addClass</span><span class="p">(</span><span class="dl">'</span><span class="s1">has-error</span><span class="dl">'</span><span class="p">);</span>
                    <span class="nx">$field</span><span class="p">.</span><span class="nf">next</span><span class="p">(</span><span class="dl">'</span><span class="s1">.field-validation-valid</span><span class="dl">'</span><span class="p">).</span><span class="nf">text</span><span class="p">(</span><span class="nx">errors</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">ErrorMessage</span><span class="p">);</span>
                <span class="p">}</span>
            <span class="p">});</span>
    <span class="p">};</span>
    <span class="kd">var</span> <span class="nx">$form</span> <span class="o">=</span> <span class="nf">$</span><span class="p">(</span><span class="dl">'</span><span class="s1">form.ajax-form[method=post]</span><span class="dl">'</span><span class="p">);</span>
    <span class="nx">$form</span><span class="p">.</span><span class="nf">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">submit</span><span class="dl">'</span><span class="p">,</span>
        <span class="nf">function </span><span class="p">()</span> <span class="p">{</span>
            <span class="kd">var</span> <span class="nx">$submitButton</span> <span class="o">=</span> <span class="nf">$</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nf">find</span><span class="p">(</span><span class="dl">'</span><span class="s1">input[type=submit]</span><span class="dl">'</span><span class="p">);</span>
            <span class="nx">$submitButton</span><span class="p">.</span><span class="nf">attr</span><span class="p">(</span><span class="dl">'</span><span class="s1">disabled</span><span class="dl">'</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
            <span class="nf">$</span><span class="p">(</span><span class="nb">window</span><span class="p">).</span><span class="nf">unbind</span><span class="p">();</span>
            <span class="nx">$</span><span class="p">.</span><span class="nf">ajax</span><span class="p">({</span>
                <span class="na">url</span><span class="p">:</span> <span class="nx">$form</span><span class="p">.</span><span class="nf">attr</span><span class="p">(</span><span class="dl">'</span><span class="s1">action</span><span class="dl">'</span><span class="p">),</span>
                <span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">post</span><span class="dl">'</span><span class="p">,</span>
                <span class="na">headers</span><span class="p">:</span> <span class="p">{</span>
                    <span class="dl">'</span><span class="s1">X-Ajax-Form</span><span class="dl">'</span><span class="p">:</span> <span class="kc">true</span>
                <span class="p">},</span>
                <span class="na">data</span><span class="p">:</span> <span class="k">new</span> <span class="nc">FormData</span><span class="p">(</span><span class="k">this</span><span class="p">),</span>
                <span class="na">cache</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
                <span class="na">processData</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
                <span class="na">contentType</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
                <span class="na">dataType</span><span class="p">:</span> <span class="dl">'</span><span class="s1">json</span><span class="dl">'</span><span class="p">,</span>
                <span class="na">statusCode</span><span class="p">:</span> <span class="p">{</span>
                    <span class="mi">200</span><span class="p">:</span> <span class="nx">redirect</span><span class="p">,</span>
                    <span class="mi">400</span><span class="p">:</span> <span class="nx">highlightErrors</span><span class="p">,</span>
                    <span class="mi">500</span><span class="p">:</span> <span class="nx">showException</span>
                <span class="p">},</span>
                <span class="na">complete</span><span class="p">:</span> <span class="nf">function </span><span class="p">()</span> <span class="p">{</span>
                    <span class="nx">$submitButton</span><span class="p">.</span><span class="nf">attr</span><span class="p">(</span><span class="dl">'</span><span class="s1">disabled</span><span class="dl">'</span><span class="p">,</span> <span class="kc">false</span><span class="p">);</span>
                <span class="p">}</span>
            <span class="p">});</span>
            <span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
        <span class="p">});</span>
<span class="p">});</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Basically what it does is:</p>

<ul>
  <li>if forms has class <code class="language-plaintext highlighter-rouge">ajax-form</code> it will be submitted via ajax;</li>
  <li>all form data is being serialized and posted to the server via ajax (no actual postback happens);</li>
  <li>then depending on result of the Http request Javascript does something</li>
  <li>on <em>success</em> (<code class="language-plaintext highlighter-rouge">200</code>) - redirect to some target page</li>
  <li><em>bad request</em> (<code class="language-plaintext highlighter-rouge">400</code> - usually validation errors) - highlight errors on the form</li>
  <li>in case or <em>server error</em> (<code class="language-plaintext highlighter-rouge">500</code>) - show the error.</li>
</ul>

<p>To generate proper responses back from the server, we will need to add input validation. This we will do in “<em>Extending Message Pipeline</em>” chapter.</p>

<h2 id="extending-messaging-pipeline">Extending Messaging Pipeline</h2>

<p>Remember that mediator in our pizza architecture is central gatekeeper - nobody can pass this guy to reach inner circle - core of the application.</p>

<p><img src="/assets/img/2016/10/FreshPaint-5-2016.10.30-11.30.04.png" alt="" /></p>

<p>We can use this in our advantage and add some interesting mixins there.</p>

<h3 id="adding-input-validation">Adding Input Validation</h3>

<p>Let’s say that it would be nice to have some sort of input value validation before passing it further to domain model. One of the way how to achieve this would be to decorate all viewmodels/command/whatever with <code class="language-plaintext highlighter-rouge">DataAnnotation</code> attributes and let the Asp.Net Mvc model binder to do the job and then inpsect <code class="language-plaintext highlighter-rouge">ModelState</code>. I probably go with this solution if the only consumer of the domain logic would the Asp.Net Mvc application. That would mean that I can push all validation stuff to Asp.Net level and not think about it in inner circles. But it’s rarely the case in bigger enterprise applications - where consumers of the the same domain logic might be coming from different places (scheduled batch processes, unit tests, maybe integration tests, etc).</p>

<p>Another way how to implement validation is - by extending mediator messaging pipeline. As all messages go through this channel - we can add some inspectors to do the validation.</p>

<p>Let’s start with message type validators. I choose here <a href="https://www.nuget.org/packages/FluentValidation/6.2.0">FluentValidation</a>, but it’s really up to your preferences.</p>

<p>Let’s add <code class="language-plaintext highlighter-rouge">CreateUser.Command</code> validator:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">Validator</span> <span class="p">:</span> <span class="n">AbstractValidator</span><span class="p">&lt;</span><span class="n">Command</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">Validator</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="nf">RuleFor</span><span class="p">(</span><span class="n">t</span> <span class="p">=&gt;</span> <span class="n">t</span><span class="p">.</span><span class="n">Username</span><span class="p">).</span><span class="nf">NotEmpty</span><span class="p">();</span>
        <span class="nf">RuleFor</span><span class="p">(</span><span class="n">t</span> <span class="p">=&gt;</span> <span class="n">t</span><span class="p">.</span><span class="n">Email</span><span class="p">).</span><span class="nf">EmailAddress</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then we will need to extend mediator pipeline to call this validator if somebody tries to execute <code class="language-plaintext highlighter-rouge">CreateUser</code> command.</p>

<p>With the power of polymorphism, DI and IoC containers, it’s quite easy. We decorate default mediator and wrap it with mediator that understands how to execute validations (<code class="language-plaintext highlighter-rouge">IValidatorFactory</code> is required by <code class="language-plaintext highlighter-rouge">FluentValidation</code> library):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">MediatorRegistrations</span> <span class="p">:</span> <span class="n">Registry</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">MediatorRegistrations</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="nf">Scan</span><span class="p">(</span><span class="n">scanner</span> <span class="p">=&gt;</span>
             <span class="p">{</span>
                 <span class="p">...</span>
             <span class="p">});</span>

        <span class="n">For</span><span class="p">&lt;</span><span class="n">IValidatorFactory</span><span class="p">&gt;().</span><span class="n">Use</span><span class="p">&lt;</span><span class="n">ServiceProviderValidatorFactory</span><span class="p">&gt;().</span><span class="nf">Singleton</span><span class="p">();</span>

        <span class="n">For</span><span class="p">&lt;</span><span class="n">IMediator</span><span class="p">&gt;().</span><span class="n">DecorateAllWith</span><span class="p">&lt;</span><span class="n">MediatorWithValidation</span><span class="p">&gt;();</span>
        <span class="n">For</span><span class="p">&lt;</span><span class="n">IMediator</span><span class="p">&gt;().</span><span class="n">Use</span><span class="p">&lt;</span><span class="n">DefaultMediator</span><span class="p">&gt;().</span><span class="nf">ContainerScoped</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And mediator with validations:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
</pre></td><td class="rouge-code"><pre><span class="k">internal</span> <span class="k">class</span> <span class="nc">MediatorWithValidation</span> <span class="p">:</span> <span class="n">IMediator</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">MediatorWithValidation</span><span class="p">(</span><span class="n">IMediator</span> <span class="n">inner</span><span class="p">,</span> <span class="n">IValidatorFactory</span> <span class="n">factory</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_inner</span> <span class="p">=</span> <span class="n">inner</span><span class="p">;</span>
        <span class="n">_factory</span> <span class="p">=</span> <span class="n">factory</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">TResult</span> <span class="n">Query</span><span class="p">&lt;</span><span class="n">TResult</span><span class="p">&gt;(</span><span class="n">IQuery</span><span class="p">&lt;</span><span class="n">TResult</span><span class="p">&gt;</span> <span class="n">query</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">validator</span> <span class="p">=</span> <span class="n">_factory</span><span class="p">.</span><span class="nf">GetValidator</span><span class="p">(</span><span class="n">query</span><span class="p">.</span><span class="nf">GetType</span><span class="p">());</span>
        <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="n">validator</span><span class="p">?.</span><span class="nf">Validate</span><span class="p">(</span><span class="n">query</span><span class="p">);</span>

        <span class="k">if</span><span class="p">((</span><span class="n">result</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span> <span class="p">&amp;&amp;</span> <span class="p">!</span><span class="n">result</span><span class="p">.</span><span class="n">IsValid</span><span class="p">)</span>
            <span class="k">throw</span> <span class="k">new</span> <span class="nf">ValidationException</span><span class="p">(</span><span class="n">result</span><span class="p">.</span><span class="n">Errors</span><span class="p">);</span>

        <span class="k">return</span> <span class="n">_inner</span><span class="p">.</span><span class="nf">Query</span><span class="p">(</span><span class="n">query</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="n">Execute</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">T</span> <span class="n">command</span><span class="p">)</span> <span class="k">where</span> <span class="n">T</span> <span class="p">:</span> <span class="n">ICommand</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">validator</span> <span class="p">=</span> <span class="n">_factory</span><span class="p">.</span><span class="nf">GetValidator</span><span class="p">(</span><span class="n">command</span><span class="p">.</span><span class="nf">GetType</span><span class="p">());</span>
        <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="n">validator</span><span class="p">?.</span><span class="nf">Validate</span><span class="p">(</span><span class="n">command</span><span class="p">);</span>

        <span class="k">if</span><span class="p">((</span><span class="n">result</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span> <span class="p">&amp;&amp;</span> <span class="p">!</span><span class="n">result</span><span class="p">.</span><span class="n">IsValid</span><span class="p">)</span>
            <span class="k">throw</span> <span class="k">new</span> <span class="nf">ValidationException</span><span class="p">(</span><span class="n">result</span><span class="p">.</span><span class="n">Errors</span><span class="p">);</span>

        <span class="n">_inner</span><span class="p">.</span><span class="nf">Execute</span><span class="p">(</span><span class="n">command</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="n">Publish</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">T</span> <span class="n">@event</span><span class="p">)</span> <span class="k">where</span> <span class="n">T</span> <span class="p">:</span> <span class="n">IDomainEvent</span>
    <span class="p">{</span>
        <span class="n">_inner</span><span class="p">.</span><span class="nf">Publish</span><span class="p">(</span><span class="n">@event</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>When validation will fail in the new extended pipeline, <code class="language-plaintext highlighter-rouge">ValidationException</code> exception will be thrown. To handle this correctly and set Http response code to <code class="language-plaintext highlighter-rouge">400</code> we will need custom filter added to the Mvc filters collection.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="n">IServiceProvider</span> <span class="nf">UseStructureMapContainer</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
    <span class="p">...</span>
    <span class="n">services</span><span class="p">.</span><span class="nf">AddMvc</span><span class="p">()</span>
            <span class="p">.</span><span class="nf">AddMvcOptions</span><span class="p">(</span><span class="n">config</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="n">config</span><span class="p">.</span><span class="n">Filters</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">ExceptionToJsonFilter</span><span class="p">));</span>
    <span class="p">...</span>
<span class="p">})</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">ExceptionToJsonFilter</span> <span class="p">:</span> <span class="n">IExceptionFilter</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">OnException</span><span class="p">(</span><span class="n">ExceptionContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">validationException</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">Exception</span> <span class="k">as</span> <span class="n">ValidationException</span><span class="p">;</span>

        <span class="k">if</span><span class="p">(</span><span class="n">validationException</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
            <span class="nf">FormatValidationResponse</span><span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="n">validationException</span><span class="p">);</span>
        <span class="k">else</span>
            <span class="nf">FormatErrorResponse</span><span class="p">(</span><span class="n">context</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="p">....</span>
    <span class="k">private</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">FormatValidationResponse</span><span class="p">(</span><span class="n">ExceptionContext</span> <span class="n">context</span><span class="p">,</span>
                                                 <span class="n">ValidationException</span> <span class="n">validationException</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">validationException</span><span class="p">.</span><span class="n">Errors</span><span class="p">.</span><span class="nf">AddToModelState</span><span class="p">(</span><span class="n">context</span><span class="p">.</span><span class="n">ModelState</span><span class="p">);</span>

        <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="k">new</span> <span class="n">ContentResult</span>
                     <span class="p">{</span>
                         <span class="n">Content</span> <span class="p">=</span>
                             <span class="n">JsonConvert</span><span class="p">.</span><span class="nf">SerializeObject</span><span class="p">(</span><span class="n">context</span><span class="p">.</span><span class="n">ModelState</span><span class="p">),</span>
                         <span class="n">ContentType</span> <span class="p">=</span> <span class="s">"application/json"</span>
                     <span class="p">};</span>

        <span class="n">context</span><span class="p">.</span><span class="n">Result</span> <span class="p">=</span> <span class="n">result</span><span class="p">;</span>
        <span class="n">context</span><span class="p">.</span><span class="n">HttpContext</span><span class="p">.</span><span class="n">Response</span><span class="p">.</span><span class="n">StatusCode</span> <span class="p">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="n">HttpStatusCode</span><span class="p">.</span><span class="n">BadRequest</span><span class="p">;</span>
    <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Why</strong> decorate? Well - it makes clear, that we need to split concerns. Actual (inner) mediator should not be aware of any validation as such - it might or might not be enabled in the application. The validator mediator is just another plugin in overall messaging pipeline. Using this approach - you can add different cross-cutting concerns as well, like logging, performance counters, unit of work.</p>

<h3 id="command-pre-execute-handlers">Command Pre-Execute Handlers</h3>

<p>You can decorate whole <code class="language-plaintext highlighter-rouge">IMediator</code> interface - to change behavior for all message types. But at the same time, you can decorate and wrap only particular message type pipeline. For instance - <code class="language-plaintext highlighter-rouge">Command</code> pipeline alone:</p>

<p>Define pre-execute handler interface:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">interface</span> <span class="nc">IPreExecuteCommandHandler</span><span class="p">&lt;</span><span class="k">in</span> <span class="n">TCommand</span><span class="p">&gt;</span>
                                          <span class="k">where</span> <span class="n">TCommand</span> <span class="p">:</span> <span class="n">ICommand</span>
<span class="p">{</span>
    <span class="k">void</span> <span class="nf">Handle</span><span class="p">(</span><span class="n">TCommand</span> <span class="n">command</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then we need to fill up container with proper registrations:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">MediatorRegistrations</span> <span class="p">:</span> <span class="n">Registry</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">MediatorRegistrations</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="nf">Scan</span><span class="p">(</span><span class="n">scanner</span> <span class="p">=&gt;</span>
             <span class="p">{</span>
                 <span class="p">...</span>
                 <span class="n">scanner</span><span class="p">.</span><span class="nf">AddAllTypesOf</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">IPreExecuteCommandHandler</span><span class="p">&lt;&gt;));</span>
             <span class="p">});</span>

        <span class="p">...</span>
        <span class="nf">For</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">ICommandHandler</span><span class="p">&lt;&gt;)).</span><span class="nf">DecorateAllWith</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">CommandPipeline</span><span class="p">&lt;&gt;));</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We know already decorator pattern. Here we are wrapping all <code class="language-plaintext highlighter-rouge">ICommandHandler</code> instances with this guy:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">CommandPipeline</span><span class="p">&lt;</span><span class="n">TCommand</span><span class="p">&gt;</span> <span class="p">:</span> <span class="n">ICommandHandler</span><span class="p">&lt;</span><span class="n">TCommand</span><span class="p">&gt;</span>
                            <span class="k">where</span> <span class="n">TCommand</span> <span class="p">:</span> <span class="n">ICommand</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">ICommandHandler</span><span class="p">&lt;</span><span class="n">TCommand</span><span class="p">&gt;</span> <span class="n">_inner</span><span class="p">;</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IPreExecuteCommandHandler</span><span class="p">&lt;</span><span class="n">TCommand</span><span class="p">&gt;[]</span> <span class="n">_preHandlers</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">CommandPipeline</span><span class="p">(</span><span class="n">ICommandHandler</span><span class="p">&lt;</span><span class="n">TCommand</span><span class="p">&gt;</span> <span class="n">inner</span><span class="p">,</span>
                           <span class="n">IPreExecuteCommandHandler</span><span class="p">&lt;</span><span class="n">TCommand</span><span class="p">&gt;[]</span> <span class="n">preHandlers</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_inner</span> <span class="p">=</span> <span class="n">inner</span><span class="p">;</span>
        <span class="n">_preHandlers</span> <span class="p">=</span> <span class="n">preHandlers</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Handle</span><span class="p">(</span><span class="n">TCommand</span> <span class="n">command</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span><span class="p">(</span><span class="n">_preHandlers</span> <span class="p">!=</span> <span class="k">null</span> <span class="p">&amp;&amp;</span> <span class="n">_preHandlers</span><span class="p">.</span><span class="nf">Any</span><span class="p">())</span>
        <span class="p">{</span>
            <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">handler</span> <span class="k">in</span> <span class="n">_preHandlers</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="n">handler</span><span class="p">.</span><span class="nf">Handle</span><span class="p">(</span><span class="n">command</span><span class="p">);</span>
            <span class="p">}</span>
        <span class="p">}</span>

        <span class="n">_inner</span><span class="p">.</span><span class="nf">Handle</span><span class="p">(</span><span class="n">command</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And we are ready to go. Here is fake pre-execute command handler:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">NeedToExecuteBeforeCommand</span> <span class="p">:</span> <span class="n">IPreExecuteCommandHandler</span><span class="p">&lt;</span><span class="n">Command</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Handle</span><span class="p">(</span><span class="n">Command</span> <span class="n">command</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// do some voodoo black magic here</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Btw, notice that I do not touch original mediator, nor any other related class. This is power of composition and goes hand by hand with Open/Closed Principle from <a href="https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)">S.O.L.I.D</a>.</p>

<h2 id="ootb---mediatr">OOTB - MediatR</h2>

<p>Reading all posts you might be wondering is there any Out-Of-The-Box solution for dealing with these kind of patterns? Yes, fortunately there are smart guys working on library called <a href="https://github.com/jbogard/MediatR">MediatR</a>. Awesome people and smart techies. Will post soon the same application based on <code class="language-plaintext highlighter-rouge">MediatR</code> library. You don’t need to think about lot of details then, but concepts remain the same.</p>

<h2 id="summary">Summary</h2>

<p>Wuhuuu… This post is tremendously long! I wanted to dump all my thoughts, all ideas and other concerns in single post. Sorry about that. If it’s hard to read and too much - please give me feedback - I’ll split it up..</p>

<p>Anyway - main idea here in these series of blog posts is to show how can you think about software architecture from different angle, look at set of requirements and business rules from the software maintainer perspective. If you are concerned about the future of the software you are building, you should think about how to make it more maintainable, extendable and readable. Just for your future you. With the power of DI, various patterns and practices - I believe that it is possible.</p>

<h2 id="source-code">Source Code</h2>

<p>We have proverb that “<em>seeing in action is worth thousand words</em>”. Show me the code!
It’s available here in <a href="https://github.com/valdisiljuconoks/PizzaArchitecture">GitHub</a>. Fork it down and see for yourself. Give me feedback of what you think!</p>

<p><br />
Happy baking round shaped software!
[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Architecture" /><category term="Pizza Architecture" /><category term="Software Design" /><category term=".net" /><category term="c#" /><category term="architecture" /><category term="pizza architecture" /><category term="software design" /><summary type="html"><![CDATA[This part of the round shaped software blog posts as promised will be about mapping the theoretical terms and ideas mentioned in previous post to the actual code fragments and components.]]></summary></entry><entry><title type="html">ImageResizer Plugin for EPiServer v10</title><link href="https://tech-fellow.eu/2016/10/31/imageresizer-plugin-for-episerver-v10/" rel="alternate" type="text/html" title="ImageResizer Plugin for EPiServer v10" /><published>2016-10-31T10:30:00+02:00</published><updated>2016-10-31T10:30:00+02:00</updated><id>https://tech-fellow.eu/2016/10/31/imageresizer-plugin-for-episerver-v10</id><content type="html" xml:base="https://tech-fellow.eu/2016/10/31/imageresizer-plugin-for-episerver-v10/"><![CDATA[<p>ImageResizer.Net Plugin for EPiServer v10 <strong>is released</strong>. <code class="language-plaintext highlighter-rouge">ImageResizer.Plugins.EPiServerBlobReader</code> got version 5.0.0.</p>

<p>“Old” NuGet package for EPiServer 9.x is updated with upper version constraint fix. Now plugin package v4.2 has upper EPiServer version set under v10 exclusive.</p>

<h2 id="note-about-image-preview">Note About Image Preview</h2>

<p>That was quite “interesting” experience to realize changes in <code class="language-plaintext highlighter-rouge">EPiServer.Web.BlobHttpHandler</code>. This is eventually the guy who is responsible for returning Blob back to the client. A bit more details below.</p>

<h3 id="background">Background</h3>

<p>First of all a bit background. Images in EPiServer EditUI gets different Url than on website “runtime”. If image is <code class="language-plaintext highlighter-rouge">/globalassets/image1.jpg</code> then when you will ask <code class="language-plaintext highlighter-rouge">Url.ContentUrl()</code> in EPiServer EditUI it will become something like <code class="language-plaintext highlighter-rouge">/episerver/cms/Content/globalassets/image1.jpg,,x_y?epieditmode=False....</code>. Here is nothing fancy, but as far as I understand - ImageResizer (IR) does not kick in for the Urls containing commas “<code class="language-plaintext highlighter-rouge">,</code>”. I opened <a href="https://github.com/imazen/resizer/issues/195">GitHub issue</a> for them. Awaiting authors response.</p>

<h3 id="solution-more-like-workaround">“Solution” (more like Workaround)</h3>

<p>While debugging and joggling with internals and decompiled code in <code class="language-plaintext highlighter-rouge">EPiServer.Web.BlobHttpHandler</code>, I came to the conclusion that there are changes how handler decides what to do with requested <code class="language-plaintext highlighter-rouge">Blob</code>.</p>

<p>While ImageResizer haven’t provided official reply on issue for handling urls with command “<code class="language-plaintext highlighter-rouge">,</code>”, we have to remove “<code class="language-plaintext highlighter-rouge">,,x_y</code>” part from the Url to give possibility for IR to kick in and do proper image resizing even in EditUI mode.</p>

<p>There also have been <a href="https://github.com/valdisiljuconoks/ImageResizer.Plugins.EPiServerBlobReader/issues/10">lengthy discussions over GitHub</a> about this issue and whether to implement it or not.</p>

<p>That’s what I would at least expect being an editor, and developer. Using built-in templates like (<code class="language-plaintext highlighter-rouge">Image.cshtml</code> in AlloyTech):</p>

<pre><code class="language-razor">@model EPiServer.Core.ContentReference
@if (Model != null)
{
    &lt;img src="@Url.ContentUrl(Model)" alt="" /&gt;
}
</code></pre>

<p>I would expect that image acts properly if I apply IR commands to it. Even for instance using own helpers:</p>

<pre><code class="language-razor">@using ImageResizer.Plugins.EPiServer

&lt;img src="@Html.ResizeImage(Model.CurrentPage.MainImage, 100, 100)"/&gt;
</code></pre>

<h3 id="the-issue-with-unpublished-images">The Issue with Unpublished Images</h3>

<p>Unfortunately there is logic inside <code class="language-plaintext highlighter-rouge">BlobHttpHandler</code> that determines what to do with Blob after it’s being retrieved from underlying store. Method is call <code class="language-plaintext highlighter-rouge">ProccessBlobRequest()</code>. I can’t paste whole EPiServer source code here due to copyright issues, but snippet looks something like this (inside this <code class="language-plaintext highlighter-rouge">ProccessBlobRequest()</code>):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">evaluator</span> <span class="p">=</span> <span class="n">ServiceLocator</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">IRoutableEvaluator</span><span class="p">&gt;();</span>
<span class="k">if</span> <span class="p">(</span><span class="n">content</span> <span class="p">==</span> <span class="k">null</span> <span class="p">||</span> <span class="p">!</span><span class="n">evaluator</span><span class="p">.</span><span class="nf">IsRoutable</span><span class="p">(</span><span class="n">content</span><span class="p">))</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="k">false</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>By returning <code class="language-plaintext highlighter-rouge">false</code> from this method, <code class="language-plaintext highlighter-rouge">BlobHttpHandler</code> decides to return <code class="language-plaintext highlighter-rouge">404</code> status code for the whole Http request - resulting in <code class="language-plaintext highlighter-rouge">File not found</code> error.</p>

<p>And the issue is inside this <code class="language-plaintext highlighter-rouge">IsRoutable()</code> method. Request is “routable” to current content if:</p>

<ul>
  <li>if current content is published</li>
  <li><strong>or</strong> current context mode is <code class="language-plaintext highlighter-rouge">Edit</code> or <code class="language-plaintext highlighter-rouge">Preview</code>.</li>
</ul>

<p>As we are removing <code class="language-plaintext highlighter-rouge">,,x_y</code> segment from the Url while serving images due to lack of IR to kick-in -&gt; we are losing ContextMode and EPiServer now thinks that context mode is <code class="language-plaintext highlighter-rouge">Default</code>.</p>

<p>As result - if image is not yet published (or you are browsing next draft of the content) - image will not be rendered in Preview.</p>

<p><strong>However</strong>, sometimes I got image rendered within the same circumstances. It is pretty weird.</p>

<p>I’m not quite sure where exactly is the issue and even more - how to resolve this.</p>

<p>Anyway, 99% of cases seems to be working as expected.
Would be awesome if somebody from product team could comment on this issue. Thanks!</p>

<p>Happy resizing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term="Optimizely" /><category term="Episerver" /><category term=".NET" /><category term="C#" /><category term="Image Resizer" /><category term="add-on" /><category term="optimizely" /><category term="episerver" /><category term=".net" /><category term="c#" /><category term="image resizer" /><summary type="html"><![CDATA[ImageResizer.Net Plugin for EPiServer v10 is released. ImageResizer.Plugins.EPiServerBlobReader got version 5.0.0.]]></summary></entry><entry><title type="html">Baking Round Shaped Software</title><link href="https://tech-fellow.eu/2016/10/17/baking-round-shaped-software/" rel="alternate" type="text/html" title="Baking Round Shaped Software" /><published>2016-10-17T14:00:00+03:00</published><updated>2016-10-17T14:00:00+03:00</updated><id>https://tech-fellow.eu/2016/10/17/baking-round-shaped-software</id><content type="html" xml:base="https://tech-fellow.eu/2016/10/17/baking-round-shaped-software/"><![CDATA[<p>This is the story how I discovered clean, understandable and maintainable software architecture. Why it’s round shape and not pentagon, hexagon or any other *-gon shape? In this blog post I’ll guide you through my journey. This part will cover theoretical side. Next blog post will map it to the code.</p>

<h2 id="classical-architecture">Classical Architecture</h2>

<p>Agree that we all have been taught about N-tier/layer application software in high schools, universities or between the pages of some software development magazine?!</p>

<p><img src="/assets/img/2016/10/FreshPaint-19-2016.09.25-01.36.28.png" alt="" /></p>

<p>Where order and most importantly dependency direction was stressed as one of the essential characteristics of the 3-layer architecture.
Effectively if you attribute each of the line, you read like following:</p>

<ul>
  <li>user interface (UI)</li>
  <li>business logic (BL)</li>
  <li>data access layer (DAL)</li>
</ul>

<p><img src="/assets/img/2016/10/FreshPaint-19-2016.09.25-01.37.22.png" alt="" /></p>

<p>With top down dependency direction. Main motivation behind this architecture style was encapsulation and software design practices - user interface (or outermost layer on top) is allowed to call only layer immediately underneath - business logic. Nobody was allowed to bypass and reach other layers directly. That’s why user interface layer does not have a reference to data access layer (not able to call any methods from that layer). All control flow had to go through business logic layer.</p>

<h3 id="dependency-inversion-in-classical-architecture">Dependency Inversion in Classical Architecture</h3>

<p>If you are software developer, you most probably have heard about <a href="http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod">s.o.l.i.d. principles</a>. If not - you should continue after reading about those. So if we apply last of the principle (<em>Dependency Inversion Principle</em>) to this picture - we get new architecture where DAL references BL. Data Access Layer now acts as supplier of required functionality for BL (for instance, <code class="language-plaintext highlighter-rouge">I...Repository</code> implementation, if you go with repositories patterns). New image looks now like this:</p>

<p><img src="/assets/img/2016/10/FreshPaint-19-2016.09.25-01.39.22.png" alt="" /></p>

<p>Having main essence of the application - the core of the business - in the middle of the picture, this reminds me of <strong>port &amp; adapter</strong> software architecture style. Usually this type of architecture is represented in shape of hexag because of <a href="http://alistair.cockburn.us/Hexagonal+architecture">original author drew</a> it like that. Reasons behind this are still unclear for me.</p>

<p><img src="/assets/img/2016/10/FreshPaint-0-2016.10.02-01.37.35.png" alt="" /></p>

<p>However, it has nothing in common with having six edges. Simple applications might have just 2 edges. On one side you have primary ports (through which outer world is talking to the application), and on the other side secondary ports (through which application is talking to required services by business logic). Is it still hexagonal shape?</p>

<p>Now looking at shape above, I don’t think that usually adapters are so thin that could be represented as simple edge of the hexagon. Usually adapters have their own tiny (sometimes huge) frameworks built-in (imagine Asp.Net Mvc as an adapter - it’s thick enough to be draw at least bigger than a thin line).</p>

<p>Evaluating image further.. If you are reading about clean architectures, hexagonals or ports and adapters, you might notice that long time ago <a href="https://twitter.com/jeffreypalermo">Jeffry Palermo</a> introduced something called <a href="http://jeffreypalermo.com/blog/the-onion-architecture-part-1/"><em>“Onion Architecture”</em></a>. Vegetable was not chosen accidentally - architecture really reminds an onion with its layers.
Using our knowledge about onions - we can redraw our top down image with 3 layers into the round shaped figure.</p>

<p><img src="/assets/img/2016/10/FreshPaint-0-2016.09.25-02.26.39.png" alt="" /></p>

<p>It actually does not matter whether architecture is represented as N-tier layers, hexagonal or round shape with layers - <a href="http://blog.ploeh.dk/2013/12/03/layers-onions-ports-adapters-its-all-the-same/">they are all the same</a>.</p>

<h2 id="horizontal-layering-and-vertical-slicing">Horizontal Layering and Vertical Slicing</h2>

<p>Question here is simple. Are you developing software following these tasks in their order:</p>

<ul>
  <li>Create DB schema</li>
  <li>Create SPs for queries</li>
  <li>Create DAL objects to call SPs</li>
  <li>Create BL objects to access DAL</li>
  <li>Create UI screens</li>
</ul>

<p>This list of tasks really reminds me a list of layers from classical architecture (despite their mutual dependencies).
Maybe decade ago development of the application should happen in precise order as mentioned above, just because database team was not the same as business logic team and graphical user interface team. Maybe even they were sitting in different floors or buildings.</p>

<p>Nowadays situation has changed. Usually we are asked to perform task from the beginning till the end, ignoring that it might span multiple layers. We are forced to be <a href="http://www.laurencegellert.com/2012/08/what-is-a-full-stack-developer/">full stack developers</a>.</p>

<p>Full stack developer follows tasks by the brought functionality - or <strong>use cases</strong>:</p>

<ul>
  <li>User can create a profile</li>
  <li>User can edit his/her profile</li>
  <li>Administrator can see list of users</li>
  <li>…</li>
</ul>

<p>The set or group of use cases related to the same functional area - we call them <strong>features</strong>. In a web application, from the source code organizational perspective - it <a href="https://github.com/ardalis/OrganizingAspNetCore">does not matter</a> either. You can organize by <code class="language-plaintext highlighter-rouge">MvcAreas</code> or just by <code class="language-plaintext highlighter-rouge">Features/</code> folders, or come up with your own approach. <em>Web is <a href="https://shonnlyga.wordpress.com/2015/11/28/the-web-is-just-a-delivery-mechanism/">just a delivery mechanism</a></em>.</p>

<p>Taking step back, revisiting our architecture image, now we can draw it like this:</p>

<p><img src="/assets/img/2016/10/FreshPaint-19-2016.09.25-02.06.20.png" alt="" /></p>

<p>Features are spanning across multiple layers. There are no horizontal boundaries anymore - application is composed from the set of functionality across different layers. All together they provide business value to the consumers of the application.</p>

<p>Looking back at dependency inverted image, we can redraw that with vertical slicing applied. Each feature or vertical slice will have its core or business logic, something in user interface and something for the underlying storage.</p>

<p><img src="/assets/img/2016/10/FreshPaint-18-2016.10.09-08.25.32.png" alt="" /></p>

<p>Now let’s take even more steps back to our “onion” or rounded shape architecture drawing, the best way I found to squeeze in features or vertical slices - is to cross shape from edge to edge.</p>

<p><img src="/assets/img/2016/10/FreshPaint-21-2016.09.25-02.33.54.png" alt="" /></p>

<p>This figure now reminds me something, but we definitely will get there, hang on.</p>

<h2 id="feature-under-magnifying-glass">Feature Under Magnifying Glass</h2>

<p>You might be wondering, what happens inside particular feature and how code is organized there?</p>

<p><img src="/assets/img/2016/10/FreshPaint-21-2016.09.25-02.34.38.png" alt="" /></p>

<p>Well, to abstract a bit, we can assume that we are looking at web based application that reacts on external initiators - answering on incoming requests (however this architecture is not limited only to web based applications).</p>

<p><img src="/assets/img/2016/10/FreshPaint-0-2016.09.25-05.47.14.png" alt="" /></p>

<p>First, request hits outermost application boundary - <strong>edge of the application</strong>. User interface area still acts as adapter before request is passed further - deeper and closer to the <strong>core of the application</strong>.</p>

<h3 id="inside-vs-outside">Inside vs Outside</h3>

<p>Despite all the great features, rich set of functionality in the Asp.Net Mvc web application framework, web in general and user interface in particularly is considered to be only <em><a href="(https://shonnlyga.wordpress.com/2015/11/28/the-web-is-just-a-delivery-mechanism/)">delivery mechanism</a></em>. A way of communication for the consumer of the application. Web is just a bunch of request and responses transmitted over the wire using network protocol.
Notice that I’m not using term “user” of the application? It might be confused with the physical person who is interacting with the system. Therefore “consumer” is much more accurate term here - especially when it’s clearly possible that other applications or for example unit tests (or other type of tests) are using and interacting with the application.</p>

<p><img src="/assets/img/2016/10/FreshPaint-22-2016.10.09-08.49.12.png" alt="" /></p>

<p>There might be various techniques and patterns on what exactly is done with incoming request before it’s forwarded further, but let’s assume for now - it’s Asp.Net Mvc model binder that constructs incoming action parameter(s) from the <code class="language-plaintext highlighter-rouge">HttpRequest</code>. And then passes the model further to the matched Asp.Net Mvc action.
Now the code in the action method has to “do something” with this model. There has to be somebody who is capable of handling this. Component that will be used to forward incoming “model” (actually the model here should be either “command” or “query”) to appropriate handler - is called <a href="https://en.wikipedia.org/wiki/Mediator_pattern"><strong>Mediator</strong></a>.</p>

<h2 id="the-mediator">The Mediator</h2>

<p>Uncle Bob calls this component <a href="https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html">an interactor</a>, but the name actually is less important compared to role it’s playing in the architecture. Mediator main responsibility is to forward incoming model (either “command” or “query”) to the appropriate handler.
Initiator of the process does not know anything about who and how the “command” or “query” will be handled. Or maybe will not be handled at all. Handler does not know anything about the initiator either. So initiator and handler are tightened together in <em>loosely coupled</em> way.</p>

<p><img src="/assets/img/2016/10/FreshPaint-24-2016.10.05-11.55.33.png" alt="" /></p>

<p>Mediator is acting as <strong>main gatekeeper</strong> to enter into the <em>blissful core area</em>, to pass through and get to the business logic area.</p>

<p>What happens next, once request reached handler, depends - it depends on the handler, on requirements for particular use case or environment context of the given moment.
It’s quite natural that handler might need to reach out secondary port(s) - fulfil and execute the request.</p>

<p><img src="/assets/img/2016/10/FreshPaint-24-2016.10.05-11.58.38.png" alt="" /></p>

<p>You wonder why user interface (<strong>UI</strong>) is at the same level as data access layer (<strong>DAL</strong>)? Well, just think about. It really does not matter anymore where exactly you physically locate each of these components or adapters - as long as dependency graph direction is inwards to the core of the application.</p>

<h3 id="messaging-pipeline">Messaging Pipeline</h3>

<p>There are few types, terms and involved parties in the mediator messaging pipeline.</p>

<p><img src="/assets/img/2016/10/FreshPaint-26-2016.10.11-11.47.20.png" alt="" /></p>

<p>Mediator message pipeline consists of following building components:</p>

<ul>
  <li><strong><em>Initiator</em></strong> - this is code fragment or block who needs to execute particular type of the message (see below). Usually initiator gets mediator instance somehow (preferably via injection), creates instance of message (also could delegate creation of the message to some 3rd party factory if it’s complex enough) and gives message instance to mediator for further dispatching.</li>
  <li><strong><em>Handler</em></strong> - handler sits on the other end of the pipeline and just waits for incoming message to handle. There is separate handler for each type of message (could be physically merged into single type if that makes sense in given case). Handler does not know who initiated and sent the message. And it does not need to have this knowledge.</li>
</ul>

<p>There are few distinguishable types of messages that mediator should be capable of passing around and finding handlers for them:</p>

<ul>
  <li><strong><em>Command</em></strong> - are messages that represent to execute some use case in the business logic area. Commands usually are used for use cases when initiator does not care about result of the execution of the use case. Execution method for the command message types in the code has to return <code class="language-plaintext highlighter-rouge">void</code>. This will make sure that you will not mix <a href="http://martinfowler.com/bliki/CommandQuerySeparation.html">commands with queries</a> all together. It’s important to understand that commands <strong>mutates</strong> state of the application.</li>
  <li><strong><em>Query</em></strong> - query does not mutate state of the application. It has to be side-effect free. It’s collects data, gathers all required pieces and fragments and <strong>composes</strong> the <strong>result</strong> of the query to be passed back to the initiator of the message.</li>
  <li><strong><em>Event</em></strong> - events are similar to the command message type. However - I tend to think about events differently compared to commands - while commands should have only single handler (it makes so much more sense if you clearly understand who is going to handle your command) there might be more than single handler (very similar to classical .Net event system - just without all the ceremony required by events in the Framework).</li>
</ul>

<h3 id="handler-isolation">Handler Isolation</h3>

<p>The alerted reader might have noticed a flaw - if you are on the same level as DAL, does it mean that you can call DAL components directly?
<a href="http://blog.ploeh.dk/2011/07/28/CompositionRoot/">Composition root</a> (preferably located close to the application entry point - UI) “<em>needs</em>” to know almost about all types in the domain. Easiest way is to reference all necessary assemblies in UI project and then compose object graph as needed. Which also means that theoretically UI code has access to DAL code. And that would mean that UI component could call DAL component directly bypassing the business logic (BL).</p>

<p>It’s actually a matter of team’s self-disciple and agreed rules while developing the application. But anyway fortunately we <a href="http://blog.falafel.com/use-types-from-project-without-referencing/">do have solution</a> for this as well from <a href="http://ardalis.com/">Steve Smith</a>. Or you can use <a href="http://www.ndepend.com/">NDepend</a> tool to review dependencies, or maybe even run <a href="https://msdn.microsoft.com/en-us/library/dd418995.aspx">Layer Diagram</a> inside Visual Studio.</p>

<h3 id="reaching-out-other-features">Reaching Out Other Features</h3>

<p>Rarely application is made out of just a single feature. Often application needs to reach out other features - cross its own boundaries.</p>

<p><img src="/assets/img/2016/10/FreshPaint-24-2016.10.11-11.49.38.png" alt="" /></p>

<p>Similarly as incoming request is passed further to the handler via mediator, command handler can use same mediator approach to pass <code class="language-plaintext highlighter-rouge">DomainEvent</code> further to other components that are interested. Components could be located “<em>inside</em>” the same feature or across the border.</p>

<p>Cool thing about domain events - they are connecting features in loosely coupled way and there might be more than single event handler.</p>

<p><img src="/assets/img/2016/10/FreshPaint-24-2016.10.11-11.50.03.png" alt="" /></p>

<p>There even might be cases when nobody is interested in the happenings inside particular feature - and that’s also perfectly fine.</p>

<h3 id="implementing-cross-cutting-concerns">Implementing Cross-Cutting Concerns</h3>

<p>Now when we do have single messaging pipeline how outer world can reach inside of the application - it’s time to look at possible extensibility.</p>

<p>Usually samples about extensibility are showing how to add logging for the application or similar cross-cutting concern. I’ll not map particular cross-cutting concern to the code in this post (that will be the topic for the next blog post). But this time just make a sketch on how to extend pipeline and add some interesting cross-cutting concerns.</p>

<p>As all the messages are passed through mediator pipeline to land somewhere in the core, we can extend this pipeline and augment it with necessary additional functionality. Let’s just assume we need to add validation to the whole application. Easy! Just decorate pipeline and handle errors in outer area of the application - in user interface. There is precisely designed place in the application to do these types of augmentation - the Composition Root. This time <a href="http://structuremap.github.io/">StructureMap</a> sample:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="p">...</span>
<span class="n">For</span><span class="p">&lt;</span><span class="n">IMediator</span><span class="p">&gt;().</span><span class="n">DecorateAllWith</span><span class="p">&lt;</span><span class="n">MediatorWithValidation</span><span class="p">&gt;();</span>
<span class="p">...</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then you might need to add performance counters for your messaging pipeline, or authorization or maybe even auditing. Piece of cake.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="p">...</span>
<span class="n">For</span><span class="p">&lt;</span><span class="n">IMediator</span><span class="p">&gt;().</span><span class="n">DecorateAllWith</span><span class="p">&lt;</span><span class="n">MediatorWithValidation</span><span class="p">&gt;();</span>
<span class="n">For</span><span class="p">&lt;</span><span class="n">IMediator</span><span class="p">&gt;().</span><span class="n">DecorateAllWith</span><span class="p">&lt;</span><span class="n">MediatorWithPerfCounters</span><span class="p">&gt;();</span>
<span class="n">For</span><span class="p">&lt;</span><span class="n">IMediator</span><span class="p">&gt;().</span><span class="n">DecorateAllWith</span><span class="p">&lt;</span><span class="n">MediatorWithAuthorization</span><span class="p">&gt;();</span>
<span class="p">...</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>It’s not only possible to extend <code class="language-plaintext highlighter-rouge">Mediator</code> itself, but also pipeline of particular type of messages. For instance, adding transactions (Tx) to all command handlers:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nf">For</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">ICommandHandler</span><span class="p">&lt;,&gt;)).</span><span class="n">DecorateAllWith</span><span class="p">&lt;</span><span class="n">RequestPipelineWithTx</span><span class="p">&gt;();</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You can go on and on. Basically - what you are creating here is called “<strong><em>Russian Doll Model</em></strong>” - you decorate decorator that decorates another decorator that eventually decorates original component. Neat!</p>

<h2 id="pizza-architecture">“Pizza Architecture”</h2>

<p>When stepping back and looking at whole picture (all features in bounded context), the round shape reminds me of something close and familiar to developers.</p>

<p><img src="/assets/img/2016/10/FreshPaint-21-2016.09.25-10.45.57.png" alt="" /></p>

<p>I called it <strong>“Pizza Architecture”</strong>.
<br />
You take layered architecture, inverse dependencies, try to squeeze it inside hexagonal shape, does not fit perfectly, take round baking pan, add topping, sprinkles and slice application by features. And whola! What you get is something that really reminds <em>pizza</em>.</p>

<p>I couldn’t be wrong, internet is almost right..</p>

<p><img src="/assets/img/2016/10/pizza2.PNG" alt="" /></p>

<h2 id="coming-soon">Coming Soon!</h2>

<p>In the next post I will take a closer look at a sample application where I will map concrete code fragments to particular architectural terms mentioned here.</p>

<p>Happy baking!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Architecture" /><category term="Pizza Architecture" /><category term="Software Design" /><category term=".net" /><category term="c#" /><category term="architecture" /><category term="pizza architecture" /><category term="software design" /><summary type="html"><![CDATA[This is the story how I discovered clean, understandable and maintainable software architecture. Why it’s round shape and not pentagon, hexagon or any other *-gon shape? In this blog post I’ll guide you through my journey. This part will cover theoretical side. Next blog post will map it to the code.]]></summary></entry><entry><title type="html">Configure EPiServer Media Auto Publish on Upload</title><link href="https://tech-fellow.eu/2016/09/23/configure-episerver-media-auto-publish-on-upload/" rel="alternate" type="text/html" title="Configure EPiServer Media Auto Publish on Upload" /><published>2016-09-23T13:00:00+03:00</published><updated>2016-09-23T13:00:00+03:00</updated><id>https://tech-fellow.eu/2016/09/23/configure-episerver-media-auto-publish-on-upload</id><content type="html" xml:base="https://tech-fellow.eu/2016/09/23/configure-episerver-media-auto-publish-on-upload/"><![CDATA[<p>In this post we will enhance media auto-publish option to gain more control over what’s going to be automatically published and what will stay for manual publishing.</p>

<p>EPiServer gives site admins option to configure whether media file gets automatically published when uploading to Blob storage.</p>

<p>This is very nice, but the problem is - this setting is <em>global</em>. It means either all media files get automatically published, or none - on/off.</p>

<p><img src="/assets/img/2016/09/2016-09-22_15-41-31-1.png" alt="" /></p>

<p>For one of our customers requirement was to delay publish only certain file extensions (usually <code class="language-plaintext highlighter-rouge">.pdf</code> files with some data that will be valid only from certain date - usually in the future).</p>

<p>1st attempt was to try to see through what’s going on during file upload. Browsing through <code class="language-plaintext highlighter-rouge">FileUploadController</code> type (one is responsible for logic what happens during file upload), I realized that it’s not so easy to extend that guy (for instance, constructor demands <code class="language-plaintext highlighter-rouge">ContentService</code> class and not <code class="language-plaintext highlighter-rouge">IContentService</code> interface). Which makes overall difficult to intercept, decorate and do something with that dependency.</p>

<p>Another much simpler way is to subscribe to <code class="language-plaintext highlighter-rouge">SavedContent</code> event and check whether media should be published or not.</p>

<h2 id="handling-the-event">Handling the Event</h2>

<p>So let’s start with event handler itself. This is pretty straightforward initializable module, that subscribes to <code class="language-plaintext highlighter-rouge">IContentEvent.CreatedContent</code> event and handles auto-publishing there.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">MediaAutoPublishHandler</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">events</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">Locate</span><span class="p">.</span><span class="n">Advanced</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">IContentEvents</span><span class="p">&gt;();</span>
        <span class="n">events</span><span class="p">.</span><span class="n">CreatedContent</span> <span class="p">+=</span> <span class="n">OnContentSaved</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">events</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">Locate</span><span class="p">.</span><span class="n">Advanced</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">IContentEvents</span><span class="p">&gt;();</span>
        <span class="n">events</span><span class="p">.</span><span class="n">CreatedContent</span> <span class="p">-=</span> <span class="n">OnContentSaved</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="k">void</span> <span class="nf">OnContentSaved</span><span class="p">(</span><span class="kt">object</span> <span class="n">sender</span><span class="p">,</span> <span class="n">ContentEventArgs</span> <span class="n">args</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">targetMedia</span> <span class="p">=</span> <span class="n">args</span><span class="p">.</span><span class="n">Content</span> <span class="k">as</span> <span class="n">MediaData</span><span class="p">;</span>
        <span class="k">if</span><span class="p">(</span><span class="n">targetMedia</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
            <span class="k">return</span><span class="p">;</span>

        <span class="nf">TryToPublishWhenContentIsCreated</span><span class="p">(</span><span class="n">targetMedia</span><span class="p">,</span>
                                         <span class="n">ServiceLocator</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">CurrentProject</span><span class="p">&gt;(),</span>
                                         <span class="n">ServiceLocator</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">IContentRepository</span><span class="p">&gt;());</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="k">void</span> <span class="nf">TryToPublishWhenContentIsCreated</span>
                       <span class="p">(</span><span class="n">MediaData</span> <span class="n">content</span><span class="p">,</span>
                        <span class="n">CurrentProject</span> <span class="n">currentProject</span><span class="p">,</span>
                        <span class="n">IContentRepository</span> <span class="n">contentRepository</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span><span class="p">(</span><span class="n">MediaAutoPublishOptions</span><span class="p">.</span><span class="n">ShouldAutoPublishCallback</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
            <span class="k">return</span><span class="p">;</span>

        <span class="c1">// apply logic only to checkout media files</span>
        <span class="k">if</span><span class="p">(</span><span class="n">content</span><span class="p">.</span><span class="n">Status</span> <span class="p">!=</span> <span class="n">VersionStatus</span><span class="p">.</span><span class="n">CheckedOut</span><span class="p">)</span>
            <span class="k">return</span><span class="p">;</span>

        <span class="c1">// skip auto publish in we are in EPiServer project currently</span>
        <span class="kt">var</span> <span class="n">isInsideProject</span> <span class="p">=</span> <span class="n">currentProject</span><span class="p">.</span><span class="n">ProjectId</span><span class="p">.</span><span class="n">HasValue</span><span class="p">;</span>
        <span class="k">if</span><span class="p">(</span><span class="n">isInsideProject</span><span class="p">)</span>
            <span class="k">return</span><span class="p">;</span>

        <span class="kt">var</span> <span class="n">shouldPublish</span> <span class="p">=</span> <span class="n">MediaAutoPublishOptions</span><span class="p">.</span><span class="nf">ShouldAutoPublishCallback</span><span class="p">(</span><span class="n">content</span><span class="p">);</span>

        <span class="k">if</span><span class="p">(</span><span class="n">shouldPublish</span><span class="p">)</span>
            <span class="n">contentRepository</span><span class="p">.</span><span class="nf">Save</span><span class="p">(</span><span class="n">content</span><span class="p">.</span><span class="nf">CreateWritableClone</span><span class="p">()</span> <span class="k">as</span> <span class="n">IContent</span><span class="p">,</span>
                                   <span class="n">SaveAction</span><span class="p">.</span><span class="n">Publish</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This was boring part.</p>

<p>It’s the handler of the event that’s doing all the work.
Magic is in following 2 types.
Auto-publish configuration that just holds a lambda delegate:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">MediaAutoPublishOptions</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="n">Func</span><span class="p">&lt;</span><span class="n">MediaData</span><span class="p">,</span> <span class="kt">bool</span><span class="p">&gt;</span> <span class="n">ShouldAutoPublishCallback</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And configuration of the media auto-publisher. This guy will determine whether current content should be published or not.</p>

<p>Why it’s lambda and defined in the code? Because here - you can go to configuration file and look for your extensions of the file and maybe auto-publish based on media type (<code class="language-plaintext highlighter-rouge">.png</code> vs <code class="language-plaintext highlighter-rouge">.pdf</code> for instance), you can call webservice to check, you can check for time and date and not publish any media on 1st of January, or call grandpapa and ask him. Code opens much more flexibility and extensibility.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">MediaAutoPublishConfigurator</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// we would like to publish only images, other media needs manual publish</span>
        <span class="n">MediaAutoPublishOptions</span><span class="p">.</span><span class="n">ShouldAutoPublishCallback</span> <span class="p">=</span>
             <span class="n">content</span> <span class="p">=&gt;</span> <span class="n">content</span> <span class="k">is</span> <span class="n">ImageData</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="see-in-action">See in Action</h2>

<p>Ordinary media file upload.</p>

<iframe src="https://player.vimeo.com/video/183892146" width="800" height="468" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>

<p>No auto-publish on any type if currently editor is inside the project.</p>

<iframe src="https://player.vimeo.com/video/183893166" width="800" height="468" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>

<p>Happy delayed publishing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[In this post we will enhance media auto-publish option to gain more control over what’s going to be automatically published and what will stay for manual publishing.]]></summary></entry><entry><title type="html">Apply DisplayOptions for EPiServer.Forms Elements</title><link href="https://tech-fellow.eu/2016/09/05/apply-displayoption-for-episerver-forms-elements/" rel="alternate" type="text/html" title="Apply DisplayOptions for EPiServer.Forms Elements" /><published>2016-09-05T16:30:00+03:00</published><updated>2016-09-05T16:30:00+03:00</updated><id>https://tech-fellow.eu/2016/09/05/apply-displayoption-for-episerver-forms-elements</id><content type="html" xml:base="https://tech-fellow.eu/2016/09/05/apply-displayoption-for-episerver-forms-elements/"><![CDATA[<p>Would you like to use <code class="language-plaintext highlighter-rouge">DisplayOptions</code> feature also for EPiServer.Forms?</p>

<p><img src="/assets/img/2016/09/2016-08-31_11-52-33.png" alt="" /></p>

<p>In this blog post I’m gonna show you how to do that.</p>

<h2 id="background">Background</h2>

<p>It’s really great to see platform evolving and adding new features. But unfortunately - I must say that <code class="language-plaintext highlighter-rouge">EPiServer.Forms</code> are pretty close for modification (which is good) but at the same time - not so open for extensions, that’s why we will need to modify some of the built-in templates to get this done.</p>

<h2 id="getting-started">Getting Started</h2>

<ul>
  <li>
    <p>First of all, we will need to pull down a small package (<a href="http://nuget.episerver.com/en/OtherPages/Package/?packageId=EPiBootstrapArea.Forms">EPiBootstrapArea.Forms</a>) for this to work.
This is small library that is available as part of <a href="https://github.com/valdisiljuconoks/EPiBootstrapArea">EPiBootstrapArea</a> project.</p>
  </li>
  <li>
    <p>Second, we need to extract one built-in forms element template for modifications. Template is located at <code class="language-plaintext highlighter-rouge">{project-root}\packages\EPiServer.Forms.3.0.0.0\</code> and then <code class="language-plaintext highlighter-rouge">Content\modules\_protected\EPiServer.Forms\EPiServer.Forms.zip</code>. And you need to search for <code class="language-plaintext highlighter-rouge">\Views\ElementBlocks\FormContainerBlock.ascx</code> inside that <code class="language-plaintext highlighter-rouge">.zip</code> file.</p>
  </li>
  <li>
    <p>Then you need to copy over this <code class="language-plaintext highlighter-rouge">.ascx</code> file to your project’s shared components views folder: <code class="language-plaintext highlighter-rouge">{web-project}\Views\Shared\ElementBlocks\</code> (you most probably will need to create new folder over there).</p>
  </li>
</ul>

<h2 id="modifying-the-template">Modifying the Template</h2>

<p>To get things working we have to modify built-in template of EPiServer. As it seems like straightforward and easy way to customize - this approach has <strong>huge downside</strong>. Upon next EPiServer update - there is no guarantee that built-in templates are not changed from previous installed version. Which also means that upgrade process is “doable”, but will probably cost more than usual and you have to keep in mind all the time - to peek into templates and look for changes.</p>

<p>When we are over this mental challenge, we need to add two things to the template:</p>

<p>a) add required <code class="language-plaintext highlighter-rouge">using</code>:</p>

<pre><code class="language-aspnet">...
&lt;%@ import namespace="EPiBootstrapArea.Forms" %&gt;
...
</code></pre>

<p>b) then we need to go to <code class="language-plaintext highlighter-rouge">Ln 110</code> and change from this:</p>

<pre><code class="language-aspnet">&lt;%
    Html.RenderFormElements(i, step.Elements);
%&gt;
</code></pre>

<p>to this:</p>

<pre><code class="language-aspnet">&lt;%
    Html.RenderFormElements(i, step.Elements, Model);
%&gt;
</code></pre>

<p>This is extension method coming from <code class="language-plaintext highlighter-rouge">EPiBootstrapArea.Forms</code> package.</p>

<p>Or alternatively - you can <a href="https://github.com/valdisiljuconoks/EPiBootstrapArea/blob/master/tests/EPiBootstrapArea.SampleWeb/Views/Shared/ElementBlocks/FormContainerBlock.ascx">download this file</a> from GitHub repo test project.</p>

<p>You may ask - why this is needed? Basically - original code was iterating over forms elements collection and calling content renderer directly in the loop. There is almost no place for customization and replacement (maybe I’m wrong - please comment,if you know better way to avoid these modifications). I’m overriding this method with my own implementation - also passing in <code class="language-plaintext highlighter-rouge">Model</code> e.g. <code class="language-plaintext highlighter-rouge">FormContainerBlock</code>.
In this case <code class="language-plaintext highlighter-rouge">Model</code> is needed because we need to access original <code class="language-plaintext highlighter-rouge">ContentAreaItem</code> that was used as form element base. There display option - selected by the editor - is available. By knowing which display mode was selected, library can wrap particular form element inside new markup element with proper Bootstrap classes (or even maybe with <a href="https://github.com/valdisiljuconoks/EPiBootstrapArea#customize-generated-css-classes">custom Css classes</a>).</p>

<h2 id="result">Result</h2>

<p>By referencing this small new package - as expected - editors are able to use display options also for form elements in on-page edit mode:</p>

<p><img src="/assets/img/2016/09/2016-09-02_12-37-35.png" alt="" /></p>

<p>The following markup for this particular form element will be something like this:</p>

<p><img src="/assets/img/2016/09/2016-09-02_12-43-55.png" alt="" /></p>

<p>If you have any issues, problems or feedback - please, leave it on <a href="https://github.com/valdisiljuconoks/EPiBootstrapArea/issues">GitHub repo</a>.</p>

<p>Happy forming!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[Would you like to use DisplayOptions feature also for EPiServer.Forms?]]></summary></entry><entry><title type="html">EPiServer Twitter Bootstrap Content Area Renderer Updates</title><link href="https://tech-fellow.eu/2016/09/01/episerver-twitter-bootstrap-content-area-renderer-updates/" rel="alternate" type="text/html" title="EPiServer Twitter Bootstrap Content Area Renderer Updates" /><published>2016-09-01T11:30:00+03:00</published><updated>2016-09-01T11:30:00+03:00</updated><id>https://tech-fellow.eu/2016/09/01/episerver-twitter-bootstrap-content-area-renderer-updates</id><content type="html" xml:base="https://tech-fellow.eu/2016/09/01/episerver-twitter-bootstrap-content-area-renderer-updates/"><![CDATA[<p>Here comes small updates for the Content Area renderer in the latest version:</p>

<ul>
  <li>Now <code class="language-plaintext highlighter-rouge">EPiServer.Forms</code> are supported</li>
  <li>Possibility to have your own Css classes</li>
  <li><code class="language-plaintext highlighter-rouge">DisplayOption</code> is now available in block template as well (if needed)</li>
  <li>Some smaller bug fixes</li>
</ul>

<h2 id="naming-challenges">Naming Challenges</h2>

<p>As you might know - I’m still struggling with naming of this package. Originally it was planned to be as <code class="language-plaintext highlighter-rouge">Twitter Bootstrap Content Area Renderer</code>, but apparently over time package feature set deviated from original idea as now package gives so much more than just adding necessary Css classes to the content area items.
But naming is hard, so I’ll just leave it here :)</p>

<h2 id="support-for-episerverforms">Support for EPiServer.Forms</h2>

<p>With the latest package version + a smaller new package (EPiBootstrapArea.Forms) now <code class="language-plaintext highlighter-rouge">DisplayOption</code> can be applied to EPiServer Forms elements as well.</p>

<p><img src="/assets/img/2016/08/2016-08-31_11-52-33-2.png" alt="" /></p>

<p>How this is done - I guess it needs separate blog post. Will publish soon.</p>

<h2 id="add-your-own-css-classes">Add Your Own Css Classes</h2>

<p>Latest version now also gives you possibility to add your own Css classes for the cases when Bootstrap ones are not the thing you were looking for.</p>

<p>So all you need to do is to provide your own Css class pattern while registering your <a href="https://github.com/valdisiljuconoks/EPiBootstrapArea#register-custom-provider">custom display options</a>:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">DisplayModeFallbackCustomProvider</span> <span class="p">:</span> <span class="n">DisplayModeFallbackDefaultProvider</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">override</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">DisplayModeFallback</span><span class="p">&gt;</span> <span class="nf">GetAll</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">original</span> <span class="p">=</span> <span class="k">base</span><span class="p">.</span><span class="nf">GetAll</span><span class="p">();</span>

        <span class="n">original</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">new</span> <span class="n">DisplayModeFallback</span>
        <span class="p">{</span>
            <span class="n">Name</span> <span class="p">=</span> <span class="s">"This is from code (1/12)"</span><span class="p">,</span>
            <span class="n">Tag</span> <span class="p">=</span> <span class="s">"one-12th-from-code"</span><span class="p">,</span>
            <span class="n">LargeScreenWidth</span> <span class="p">=</span> <span class="m">1</span><span class="p">,</span>
            <span class="n">LargeScreenCssClassPattern</span> <span class="p">=</span> <span class="s">"large-{0}"</span><span class="p">,</span>
            <span class="n">MediumScreenWidth</span> <span class="p">=</span> <span class="m">2</span><span class="p">,</span>
            <span class="n">MediumScreenCssClassPattern</span><span class="p">=</span><span class="s">"medium-{0}-the-size"</span><span class="p">,</span>
            <span class="n">SmallScreenWidth</span> <span class="p">=</span> <span class="m">3</span><span class="p">,</span>
            <span class="n">SmallScreenCssClassPattern</span> <span class="p">=</span> <span class="s">"small-{0}"</span><span class="p">,</span>
            <span class="n">ExtraSmallScreenWidth</span> <span class="p">=</span> <span class="m">4</span><span class="p">,</span>
            <span class="n">ExtraSmallScreenCssClassPattern</span> <span class="p">=</span> <span class="s">"xs"</span>
        <span class="p">});</span>

        <span class="k">return</span> <span class="n">original</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>In turn, this will produce following Css classes for the particular content area item with selected display option:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"... large-1 medium-2-the-size small-3 xs ..."</span><span class="nt">&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Of course <code class="language-plaintext highlighter-rouge">1</code>, <code class="language-plaintext highlighter-rouge">2</code>, <code class="language-plaintext highlighter-rouge">3</code> and <code class="language-plaintext highlighter-rouge">4</code> are fictive numbers, but still - I guess you understood the pattern and its usage.</p>

<p>Btw, if you will mismatch <code class="language-plaintext highlighter-rouge">string.Format()</code> placeholders and use for instance <code class="language-plaintext highlighter-rouge">{5}</code> - no Css class will be added for particular screen form factor.</p>

<h2 id="get-selected-displayoption">Get Selected DisplayOption</h2>

<p>Sometimes it’s required to access selected <code class="language-plaintext highlighter-rouge">DisplayOption</code> from the block template itself - one of the application case was that template needed to make decision about markup generated based on selected display mode (no only just applying necessary Css classes to content area item wrapping element). You might need to write some clumsy code to get to this information.. But not anymore :) Now you can just use following code to retrieve selected <code class="language-plaintext highlighter-rouge">DisplayOption</code> for current item (<code class="language-plaintext highlighter-rouge">SampleBlock.cshtml</code>):</p>

<pre><code class="language-razor">@using EPiBootstrapArea
@model SampleBlock

...

@Html.GetDisplayOption(Model)
</code></pre>

<p>Happy bootstrapping!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[Here comes small updates for the Content Area renderer in the latest version:]]></summary></entry><entry><title type="html">Specify Default DisplayOption in the Content Area</title><link href="https://tech-fellow.eu/2016/05/09/specify-default-displayoption-in-the-content-area/" rel="alternate" type="text/html" title="Specify Default DisplayOption in the Content Area" /><published>2016-05-09T11:30:00+03:00</published><updated>2016-05-09T11:30:00+03:00</updated><id>https://tech-fellow.eu/2016/05/09/specify-default-displayoption-in-the-content-area</id><content type="html" xml:base="https://tech-fellow.eu/2016/05/09/specify-default-displayoption-in-the-content-area/"><![CDATA[<p>Time to time when working on various projects we come across requirement to control somehow which <code class="language-plaintext highlighter-rouge">DisplayOption</code> will be selected as default, once content is placed inside particular <code class="language-plaintext highlighter-rouge">ContentArea</code>.</p>

<p><img src="/assets/img/2016/05/2016-05-08_22-46-18-2.png" alt="" /></p>

<p>As most of our projects are running under <strong>Twitter Bootstrap</strong> system - this is ideal feature request for <a href="http://nuget.episerver.com/en/OtherPages/Package/?packageId=EPiBootstrapArea">EPiServer Bootstrap Content Area</a> plugin. As I’m always trying to be developer friendly - I would like to be able to define these default display option rules in the code. And finally <strong>version 3.3</strong> got these features.</p>

<h2 id="default-displayoption-for-block">Default DisplayOption for Block</h2>

<p>So now with latest version you can specify which display option to use if block is dropped inside content area:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="k">using</span> <span class="nn">EPiBootstrapArea</span><span class="p">;</span>

<span class="k">public</span> <span class="k">static</span> <span class="n">Class</span> <span class="n">ContentAreaTags</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">const</span> <span class="kt">string</span> <span class="n">HalfWidth</span> <span class="p">=</span> <span class="s">"half-width"</span><span class="p">;</span>
<span class="p">}</span>

<span class="p">[</span><span class="nf">DefaultDisplayOption</span><span class="p">(</span><span class="n">ContentAreaTags</span><span class="p">.</span><span class="n">HalfWidth</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">SomeBlock</span> <span class="p">:</span> <span class="n">BlockData</span>
<span class="p">{</span>
    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Constant <code class="language-plaintext highlighter-rouge">"half-width"</code> is <code class="language-plaintext highlighter-rouge">Tag</code> of the display option registered within EPiServer bootstrap content area renderer (either <a href="https://github.com/valdisiljuconoks/EPiBootstrapArea/blob/master/Providers/DisplayModeFallbackDefaultProvider.cs">by code</a> or <a href="https://github.com/valdisiljuconoks/EPiBootstrapArea/blob/master/IDisplayModeFallbackProvider.cs">manually</a>).</p>

<p>This attribute will make sure that if block is dropped inside content area - display option registered with tag <code class="language-plaintext highlighter-rouge">"half-width"</code> is used.</p>

<p>Editor of course can override this and set display option explicitly.</p>

<p><img src="/assets/img/2016/05/2016-05-09_18-12-42.png" alt="" /></p>

<h2 id="default-displayoption-for-content-area">Default DisplayOption for Content Area</h2>

<p>The same attribute can be used in <code class="language-plaintext highlighter-rouge">ContentArea</code> property definition:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">using</span> <span class="nn">EPiBootstrapArea</span><span class="p">;</span>

<span class="p">[</span><span class="nf">ContentType</span><span class="p">(</span><span class="n">DisplayName</span><span class="p">...]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">StandardPage</span> <span class="p">:</span> <span class="n">PageData</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">DefaultDisplayOption</span><span class="p">(</span><span class="n">ContentAreaTags</span><span class="p">.</span><span class="n">HalfWidth</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">virtual</span> <span class="n">ContentArea</span> <span class="n">MainContentArea</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Using this attribute - you are ensuring that any content dropped inside this particular content area will use display option tagged as “half-width” if editor haven’t specified otherwise.</p>

<h2 id="default-displayoption-for-tagged-block">Default DisplayOption for Tagged Block</h2>

<p><a href="http://world.episerver.com/documentation/Items/Developers-Guide/Episerver-CMS/9/Rendering/Selecting-template-based-on-tag/">Template tags</a> is pretty powerful way to customize the same block to render differently based on where exactly it’s placed.</p>

<p>Let’s assume that we do have a block definition:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">SomeBlock</span> <span class="p">:</span> <span class="n">BlockData</span>
<span class="p">{</span>
    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And we are rendering content area on the page with specific tag:</p>

<pre><code class="language-razor">...
@Html.PropertyFor(m =&gt; m.MainContentArea, new { tag = "ca-tag" })
...
</code></pre>

<p>And let’s say we do have a requirement - if this block is placed inside <em>tagged</em> content area - we need to use different display option compared to default display option that might be specified for content areas without any tags. Fortunately this feature is available in <code class="language-plaintext highlighter-rouge">EpiBootstrapArea</code> plugin.</p>

<p>Now you can specify default display option for specific <code class="language-plaintext highlighter-rouge">tag</code> (<code class="language-plaintext highlighter-rouge">"cs-tag"</code>):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">using</span> <span class="nn">EPiBootstrapArea</span><span class="p">;</span>

<span class="p">[</span><span class="nf">DefaultDisplayOptionForTag</span><span class="p">(</span><span class="s">"ca-tag"</span><span class="p">,</span> <span class="n">ContentAreaTags</span><span class="p">.</span><span class="n">OneThirdWidth</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">SomeBlock</span> <span class="p">:</span> <span class="n">BlockData</span>
<span class="p">{</span>
    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now <code class="language-plaintext highlighter-rouge">ContentAreaTags.OneThirdWidth</code> display option should be used by default if editor drops block inside content area and do not specify display option explicitly.</p>

<p>You can also mix-match with default display option and default display option for tagged cases:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">using</span> <span class="nn">EPiBootstrapArea</span><span class="p">;</span>

<span class="p">[</span><span class="nf">DefaultDisplayOption</span><span class="p">(</span><span class="n">ContentAreaTags</span><span class="p">.</span><span class="n">HalfWidth</span><span class="p">)]</span>
<span class="p">[</span><span class="nf">DefaultDisplayOptionForTag</span><span class="p">(</span><span class="s">"ca-tag"</span><span class="p">,</span> <span class="n">ContentAreaTags</span><span class="p">.</span><span class="n">OneThirdWidth</span><span class="p">)]</span>
<span class="p">[</span><span class="nf">DefaultDisplayOptionForTag</span><span class="p">(</span><span class="s">"ca-tag-other"</span><span class="p">,</span> <span class="n">ContentAreaTags</span><span class="p">.</span><span class="n">ThreeQuartersWidth</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">SomeBlock</span> <span class="p">:</span> <span class="n">BlockData</span>
<span class="p">{</span>
    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>NB!</strong> This feature is not yet available for ContentArea property definition. You can use only <code class="language-plaintext highlighter-rouge">DefaultDisplayOption</code> there at the moment.</p>

<h2 id="block-vs-contentarea-displayoption">Block vs ContentArea DisplayOption</h2>

<p>In cases when there are conflicts between block’s definition and content area definition, block’s definition always wins.
Let’s take a look at same. We do have following definitions:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="rouge-code"><pre><span class="k">using</span> <span class="nn">EPiBootstrapArea</span><span class="p">;</span>

<span class="p">[</span><span class="nf">DefaultDisplayOption</span><span class="p">(</span><span class="n">ContentAreaTags</span><span class="p">.</span><span class="n">HalfWidth</span><span class="p">)]</span>
<span class="p">[</span><span class="nf">DefaultDisplayOptionForTag</span><span class="p">(</span><span class="s">"ca-tag"</span><span class="p">,</span> <span class="n">ContentAreaTags</span><span class="p">.</span><span class="n">OneThirdWidth</span><span class="p">)]</span>
<span class="p">[</span><span class="nf">DefaultDisplayOptionForTag</span><span class="p">(</span><span class="s">"ca-tag-other"</span><span class="p">,</span> <span class="n">ContentAreaTags</span><span class="p">.</span><span class="n">ThreeQuartersWidth</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">SomeBlock</span> <span class="p">:</span> <span class="n">BlockData</span>
<span class="p">{</span>
    <span class="p">...</span>
<span class="p">}</span>

<span class="p">[</span><span class="nf">ContentType</span><span class="p">(</span><span class="n">DisplayName</span><span class="p">...]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">StandardPage</span> <span class="p">:</span> <span class="n">PageData</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">DefaultDisplayOption</span><span class="p">(</span><span class="n">ContentAreaTags</span><span class="p">.</span><span class="n">FullWidth</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">virtual</span> <span class="n">ContentArea</span> <span class="n">MainContentArea</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">...</span>
<span class="p">}</span>

<span class="n">@Html</span><span class="p">.</span><span class="nf">PropertyFor</span><span class="p">(</span><span class="n">m</span> <span class="p">=&gt;</span> <span class="n">m</span><span class="p">.</span><span class="n">MainContentArea</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Content area is requesting content to take <code class="language-plaintext highlighter-rouge">ContentAreaTags.FullWidth</code> display option by default, but block is specifying that by default it will occupy only <code class="language-plaintext highlighter-rouge">ContentAreaTags.HalfWidth</code>.</p>

<p>In this case when instance of <code class="language-plaintext highlighter-rouge">SomeBlock</code> block is dropped on this content area, it will use <code class="language-plaintext highlighter-rouge">ContentAreaTags.HalfWidth</code> as default display option.</p>

<p>Happy tagging!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[Time to time when working on various projects we come across requirement to control somehow which DisplayOption will be selected as default, once content is placed inside particular ContentArea.]]></summary></entry><entry><title type="html">DbLocalizationProvider - Part 2 - Configuration and Extensions</title><link href="https://tech-fellow.eu/2016/04/22/db-localization-provider-part-2-configuration-and-extensions/" rel="alternate" type="text/html" title="DbLocalizationProvider - Part 2 - Configuration and Extensions" /><published>2016-04-22T21:05:00+03:00</published><updated>2016-04-22T21:05:00+03:00</updated><id>https://tech-fellow.eu/2016/04/22/db-localization-provider-part-2-configuration-and-extensions</id><content type="html" xml:base="https://tech-fellow.eu/2016/04/22/db-localization-provider-part-2-configuration-and-extensions/"><![CDATA[<p>In this blog post we are going through some of the configuration options available for DbLocalizationProvider for EPiServer. You might be wondering what can and should be configurable for localization provider in the context of the EPiServer, but there are few things.</p>

<h2 id="configuration-setup-for-libraries">Configuration Setup for Libraries</h2>

<p>Developing libraries as an author you always need to keep in mind your consuming projects and usage scenarios, need to think about how your library will be setup, used and extended if needed.</p>

<p>I really liked <a href="http://blog.ploeh.dk/2014/05/19/di-friendly-library/">Mark Seeman’s blog posts</a> about developing libraries and frameworks and what you should keep in mind as an author. Libraries are something that might or might not be used in target project and adding a package of the library shouldn’t affect projects behavior. Consuming project’s codebase should be able to <em>use</em> library <em>if</em>, <em>when</em> and <em>how</em> needed.</p>

<h2 id="configuring-dblocalizationprovider">Configuring DbLocalizationProvider</h2>

<p>By default if you install the package, some of the things have been setup for you already, however - you have a possibility to change that.</p>

<p>As I wrote in <a href="https://tech-fellow.eu/2016/02/22/create-your-library-configuration-api-for-episerver/">blog post</a> about creating configuration API for you library, expected approach for EPiServer to setup library would be through initializable module interface:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="p">...</span>
<span class="k">using</span> <span class="nn">DbLocalizationProvider</span><span class="p">;</span>

<span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">InitializationModule1</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">ConfigurationContext</span><span class="p">.</span><span class="nf">Setup</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span> <span class="p">...</span> <span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Type <code class="language-plaintext highlighter-rouge">ConfigurationContext</code> is coming from <code class="language-plaintext highlighter-rouge">DbLocalizationProvider</code> and is used as settings container to configure and setup localization provider. Following setup properties are available:</p>

<ul>
  <li>
    <p><code class="language-plaintext highlighter-rouge">DiscoverAndRegisterResources</code> - this setting will control whether library does localized models and resource lookup and discovery during application startup. Sometimes you just don’t want to spend time on discovery process (it might come handy in cases when you know that there will be no new resources or models added to the codebase). Scanning and registration process is enabled by default;</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">DefaultResourceCulture</code> - while scanning the resources or models, default value will be written to the database and initial translation for particular resource. If default culture is not set, by default library will try to use <code class="language-plaintext highlighter-rouge">ContentLanguage.PreferredCulture</code>, if that fails - <code class="language-plaintext highlighter-rouge">English</code> will be used as initial translation culture:</p>
  </li>
</ul>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="n">ConfigurationContext</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">DefaultResourceCulture</span> <span class="p">!=</span> <span class="k">null</span>
    <span class="p">?</span> <span class="n">ConfigurationContext</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">DefaultResourceCulture</span><span class="p">.</span><span class="n">Name</span>
    <span class="p">:</span> <span class="p">(</span><span class="n">ContentLanguage</span><span class="p">.</span><span class="n">PreferredCulture</span> <span class="p">!=</span> <span class="k">null</span> <span class="p">?</span> <span class="n">ContentLanguage</span><span class="p">.</span><span class="n">PreferredCulture</span><span class="p">.</span><span class="n">Name</span> <span class="p">:</span> <span class="s">"en"</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>
    <p><code class="language-plaintext highlighter-rouge">PopulateCacheOnStartup</code> - after scanning, discovery and registration process has ended (if one was enabled), this setting will control whether cache will be populated during the startup. Enabled by default. If cache pre-population is disabled, library will “eventually” fill up cache with resources “on-demand” when somebody will be asking for particular resource, one will be added to the cache afterwards;</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">ReplaceModelMetadataProviders</code> - one of the cool features of <code class="language-plaintext highlighter-rouge">DbLocalizationProvider</code> library is that it also “plugs in” in Asp.Net Model Metadata pipeline and can replace default model’s metadata providers to fetch localization resources necessary for things like <code class="language-plaintext highlighter-rouge">Html.LabelFor(m =&gt; m.Username)</code>. This configuration setting allows you to disable this replacement and continue with whatever providers you might have in your project. This setting is enabled by default.</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">UseCachedModelMetadataProviders</code> - cached model metadata provider gives you performance by caching model metadata and avoiding scanning of the attributes and building metadata every time somebody needs to generate label (e.g. <code class="language-plaintext highlighter-rouge">Html.LabelFor(m =&gt; m.Username)</code>) or any other metadata dependent element. <strong>NB!</strong> However there is a catch using cached model metadata provider - it’s not aware of multi-language cases. Meaning that - once model metadata is cached - it is not changed anymore (cache is not invalidated). Which also means, if you have multi-language project and user changes UI language, Asp.Net Mvc model metadata provider pipeline will not call metadata provider once again to get new <code class="language-plaintext highlighter-rouge">DisplayName</code> for the model property - because it’s already cached. So <strong>recommendation</strong> here is - if you have only single language, you can enable cached model metadata provider which will give you some performance boost, but otherwise - in multi-language projects - this should not be enabled. This configuration setting is disabled by default.</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">EnableLegacyMode</code> - legacy mode configuration setting is used in cases when you migrated from EPiServer XPath based resources to DbLocalizationProvider using MigrationTool.</p>
  </li>
</ul>

<p>For example, when you had some sort of hacked model metadata annotations (there are <a href="http://world.episerver.com/blogs/devabees/Dates/2014/3/Integrating-LocalizationService-with-MVC-DataAnnotations/">few ways</a> to achieve this) using EPiServer’s XPath based access to resources:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">MyViewModel</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">LocalizedDisplayName</span><span class="p">(</span><span class="s">"/path/to/langauge/resource"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Username</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>and you used DbLocalizationProvider MigrationTool to generate resources in database. As you might add <code class="language-plaintext highlighter-rouge">DbLocalizationProvider</code> library to existing project, there could be lot of resources that would need refactoring.
However after migrating resources from XML files to database, resource keys still remain in EPiServer XPath notation.</p>

<p>Your new model might look like this:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">MyViewModel</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"/path/to/language/resource"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Username</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Setting <code class="language-plaintext highlighter-rouge">EnableLegacyMode</code> configuration key to <code class="language-plaintext highlighter-rouge">true</code> this will ensure that <code class="language-plaintext highlighter-rouge">DbLocalizationProvider</code> library will also try to find resource translation using EPiServer’s XPath notation that is used in the attribute. Meaning that you don’t need to move translation from XPath resource to <em>actual</em> resource (e.g. <code class="language-plaintext highlighter-rouge">LocalizationSample.Models.MyViewModel.Username</code>). This setting is disabled by default.</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">EnableLocalization</code> - this configuration setting is lambda expression. If lambda expression returns <code class="language-plaintext highlighter-rouge">true</code>, actual translation for requested language is returned, otherwise - resource key is return.
This configuration setting is used in cases when editor needs to understand what kind of resource is used in particular location on the page or anywhere else.</li>
</ul>

<p>You might wondering why this setting is <code class="language-plaintext highlighter-rouge">LambdaExpression</code> or <code class="language-plaintext highlighter-rouge">Func&lt;bool&gt;</code> to be more precise?!
<code class="language-plaintext highlighter-rouge">Expression</code> type setting key will give possibility to enable or disable localization during runtime if that’s needed.</p>

<p>One of the possibility how to configure this setting would be to use for instance <code class="language-plaintext highlighter-rouge">FeatureSwitch</code> library to provide runtime switching possibility for editors. In this case, setting setup might look like this:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span> <span class="p">(</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">LocalizationInitialization</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">ConfigurationContext</span><span class="p">.</span><span class="nf">Setup</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="n">ctx</span><span class="p">.</span><span class="n">EnableLocalization</span> <span class="p">=</span> <span class="n">CheckLocalization</span><span class="p">;</span>
        <span class="p">});</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>

    <span class="k">private</span> <span class="kt">bool</span> <span class="nf">CheckLocalization</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="p">!</span><span class="n">FeatureContext</span><span class="p">.</span><span class="n">IsEnabled</span><span class="p">&lt;</span><span class="n">DisableLocalization</span><span class="p">&gt;();</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="p">[</span><span class="nf">QueryString</span><span class="p">(</span><span class="n">Key</span> <span class="p">=</span> <span class="s">"localization-disabled"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">DisableLocalization</span> <span class="p">:</span> <span class="n">BaseFeature</span> <span class="p">{</span> <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>Here is a small demo video:</p>

<iframe src="https://player.vimeo.com/video/163752727" width="800" height="520" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>

<h2 id="more-info">More info</h2>

<p>Other posts in this series:</p>

<ul>
  <li><a href="https://tech-fellow.eu/2016/03/16/db-localization-provider-part-1-resources-and-models/">Part 1: Resources and Models</a></li>
  <li><strong>Part 2: Configuration and Extensions</strong></li>
  <li><a href="https://tech-fellow.eu/2017/02/22/localization-provider-import-and-export-merge/">Part 3: Import and Export</a></li>
  <li><a href="https://tech-fellow.eu/2017/10/10/localizationprovider-tree-view-export-and-migrations/">Part 4: Resource Refactoring and Migrations</a></li>
</ul>

<p>If you have any ideas, thoughts or complaints, please leave them in <a href="https://github.com/valdisiljuconoks/LocalizationProvider/">GitHub repo</a> or in comments section below.</p>

<p>Happy localizing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Localization Provider" /><category term="Episerver" /><category term="Optimizely" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[In this blog post we are going through some of the configuration options available for DbLocalizationProvider for EPiServer. You might be wondering what can and should be configurable for localization provider in the context of the EPiServer, but there are few things.]]></summary></entry><entry><title type="html">DbLocalizationProvider - Part 1 - Resources and Models</title><link href="https://tech-fellow.eu/2016/03/16/db-localization-provider-part-1-resources-and-models/" rel="alternate" type="text/html" title="DbLocalizationProvider - Part 1 - Resources and Models" /><published>2016-03-16T20:05:00+02:00</published><updated>2016-03-16T20:05:00+02:00</updated><id>https://tech-fellow.eu/2016/03/16/db-localization-provider-part-1-resources-and-models</id><content type="html" xml:base="https://tech-fellow.eu/2016/03/16/db-localization-provider-part-1-resources-and-models/"><![CDATA[<h1 id="resources-and-models">Resources and Models</h1>

<p>This is first post about more details inside DbLocalizationProvider for EPiServer. In this post we will go through localization approach for arbitrary resources that can be used from the code to provide some message to the user or anywhere else where localization is required.
Another type of localization target is model. By model we can assume any kind of class that is used to render a page, or collect posted back data from the user. Usually models are decorated with various data annotation attributes indicating underlying data type or required validation procedures attached to the model properties.</p>

<h2 id="why-different-types">Why Different Types?</h2>

<p>You may ask why need to differentiate these types as they seems to be the same - subject for the localization?
Main reason why these types need to be different is for the scanning and discovery process.
Localized resources are just a bunch of strings that you target for localization. They are similar to language files known today for EPiServer developers.
However - models are more complex subject for localization as additional metadata needs to be taken into account.</p>

<h2 id="localized-resources">Localized Resources</h2>

<p>As described above localized resource is straight forward type that contains set of properties that you can use to provide simple message to the user or any other “consumer” that might be localized by editors.</p>

<p>Simple definition of the resource is following:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">MyProject</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">MyPageResources</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">ThisIsErrorMessage</span> <span class="p">=&gt;</span> <span class="s">"This is default value from code"</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Localized resource is simple POCO type that contains properties for localization.
Usage of this resource class is also straight forward (assuming that you want to translate some message in the Razor view):</p>

<pre><code class="language-razor">@Html.Translate(() =&gt; MyProject.MyPageResources.ThisIsErrorMessage)
</code></pre>

<p>Localized resource scanning process that is executed at the app startup will look for types decorated with <code class="language-plaintext highlighter-rouge">[LocalizedResource]</code> and register it within localization storage (by default database configured under <code class="language-plaintext highlighter-rouge">EPiServerDB</code> connection string).</p>

<p>Key for the localized resource is calculated as <code class="language-plaintext highlighter-rouge">FQN</code> (“Fully Qualified Name”) of each property.
After scanning process there should be new resource with key:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>MyProject.MyPageResources.ThisIsErrorMessage
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If property return type is <code class="language-plaintext highlighter-rouge">string</code> library will try to get value for resource translation and will save it for EPiServer’s <code class="language-plaintext highlighter-rouge">ContentLanguage.PreferredCulture</code> while scanning and registration process executes. If <code class="language-plaintext highlighter-rouge">ContentLanguage.PreferredCulture</code> cannot be determined at time of scanning – translation will be registered for “English” language.</p>

<p>When <code class="language-plaintext highlighter-rouge">Html.Translate(() =&gt; ...)</code> method is invoked with <code class="language-plaintext highlighter-rouge">LambdaExpression</code> this localization extension method “calculates” FQN for given property (<code class="language-plaintext highlighter-rouge">MemberAccessExpression</code>) and resource with this key is searched in the storage.</p>

<h3 id="nested-localized-resources">Nested Localized Resources</h3>

<p>Localized resources are not limited to “single level” container properties. It means that you can design your resource hierarchy as you wish and what makes more sense for your project and editors.</p>

<p>So for instance you may have following structure for your resources:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">MyProject</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">MyPageResources</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">ThisIsErrorMessage</span> <span class="p">=&gt;</span> <span class="s">"This is default value from code"</span><span class="p">;</span>
        <span class="k">public</span> <span class="k">static</span> <span class="n">HeaderResources</span> <span class="n">Header</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>

        <span class="k">public</span> <span class="k">class</span> <span class="nc">HeaderResources</span>
        <span class="p">{</span>
            <span class="k">public</span> <span class="kt">string</span> <span class="n">HelloMessage</span> <span class="p">=&gt;</span> <span class="s">"Well, hello there!"</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

</pre></td></tr></tbody></table></code></pre></div></div>

<p>This approach avoids to “pollute” global namespace with types that have really narrow usages - only to group related properties under related parent resource. Scanning this kind of structure, following keys will be discovered:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>MyProject.MyPageResources.ThisIsErrorMessage
MyProject.MyPageResources.Header.HelloMessage
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Scanning process makes sure that resource keys for nested resources “follows” usage context.
<strong>NB!</strong> Note that there is no <code class="language-plaintext highlighter-rouge">static</code> keyword added to <code class="language-plaintext highlighter-rouge">HelloMessage</code> property in type <code class="language-plaintext highlighter-rouge">HeaderResources</code>.</p>

<p>For example, how you might use nested resource is following:</p>

<pre><code class="language-razor">@Html.Translate(() =&gt; MyPageResources.Header.HelloMessage)
</code></pre>

<p>Last part of the <code class="language-plaintext highlighter-rouge">LambdaExpression</code> (e.g. <code class="language-plaintext highlighter-rouge">.HelloMessage</code>) is accessible (“compilable”) <strong>only if</strong> property <code class="language-plaintext highlighter-rouge">HelloMessage</code> for type <code class="language-plaintext highlighter-rouge">HeaderResources</code> is marked as “instance property” (no <code class="language-plaintext highlighter-rouge">static</code> property).</p>

<p>If you define <code class="language-plaintext highlighter-rouge">static</code> property accessor for <code class="language-plaintext highlighter-rouge">HelloMessage</code> like this:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">MyProject</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">MyPageResources</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="k">static</span> <span class="n">HeaderResources</span> <span class="n">Header</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>

        <span class="k">public</span> <span class="k">class</span> <span class="nc">HeaderResources</span>
        <span class="p">{</span>
            <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">HelloMessage</span> <span class="p">=&gt;</span> <span class="s">"Well, hello there!"</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then usage (“path” to property) is different:</p>

<pre><code class="language-razor">@Html.Translate(() =&gt; MyPageResources.HeaderResources.HelloMessage)
</code></pre>

<p>Which makes it difficult to find correct path to corresponding resources.
So library tries to follow usage of the resource from code perspective and makes it easier for editor and developer to understand the context and usage of the localized resource.</p>

<h2 id="localized-models">Localized Models</h2>

<p>What about localized models? Models are types that we tend to use as <code class="language-plaintext highlighter-rouge">ViewModels</code> in classical Mvc architecture.
These types are decorated with various data annotation attributes for display names, underlying data types or sometimes even <code class="language-plaintext highlighter-rouge">UIHints</code> to instruct Asp.Net Mvc pipeline how to render the page for this viewmodel, or how to validate incoming page postback represented with this viewmodel.</p>

<p>From localization resource scanning and discovery process perspective localized models need to be treated a bit differently. Scanning process needs to discover and register properties, its display names and related validation attributes.</p>

<p>This is pretty simple view model decorated with <code class="language-plaintext highlighter-rouge">[LocalizedModel]</code> for provider to recognize and register:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">MyProject</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">MyViewModel</span>
    <span class="p">{</span>
        <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"Username or email"</span><span class="p">)]</span>
        <span class="k">public</span> <span class="kt">string</span> <span class="n">UserName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>In this case (when only <code class="language-plaintext highlighter-rouge">Display</code> attribute is added) only single resource key will be discovered:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>MyProject.MyViewModel.UserName
</pre></td></tr></tbody></table></code></pre></div></div>

<p>After you decorate your viewmodel with <code class="language-plaintext highlighter-rouge">[LocalizedModel]</code> you can use all built-in Asp.Net Mvc helper methods to render your page:</p>

<pre><code class="language-razor">@model MyViewModel

@Html.LabelFor(m =&gt; m.UserName)
</code></pre>

<h3 id="localized-model-validation">Localized Model Validation</h3>

<p>As you might expect - all built-in Asp.Net Mvc model validation (or correctly would be to call it “Data Annotation Validation” as it’s not Mvc specific) is supported as well.
You just need to add necessary validation attributes on top of the properties and you are ready to go:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">MyProject</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">MyViewModel</span>
    <span class="p">{</span>
        <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"Username or email"</span><span class="p">)]</span>
        <span class="p">[</span><span class="nf">Required</span><span class="p">(</span><span class="n">ErrorMessage</span> <span class="p">=</span> <span class="s">"Username is required"</span><span class="p">)]</span>
        <span class="p">[</span><span class="nf">StringLength</span><span class="p">(</span><span class="m">5</span><span class="p">)]</span>
        <span class="k">public</span> <span class="kt">string</span> <span class="n">UserName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Following resource keys will be discovered:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>MyProject.MyViewModel.Username                // for [Display]
MyProject.MyViewModel.Username-Required       // for [Required]
MyProject.MyViewModel.Username-StringLength   // for [StringLength]
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As expected you can use built-in Mvc helpers to render your page:</p>

<pre><code class="language-razor">@model MyViewModel

...
@Html.LabelFor(m =&gt; m.UserName)
@Html.ValidationMessageFor(m =&gt; m.UserName)
@Html.EditorFor(m =&gt; m.UserName)
</code></pre>

<p>Library will plugin its own model metadata providers and will make sure that proper resource is picked-up when Asp.Net Mvc pipeline will ask for metadata for particular model.</p>

<p>There are few configuration settings for DbLocalizationProvider library that you might use to control is and how model metadata providers are plugged in Asp.Net Mvc pipeline (will be covered in “Part 2: Configuration and Extensions”).</p>

<h3 id="nested-models">Nested Models</h3>

<p>Single level, single hierarchy models rarely exist in real life. That’s why nested models are no exception for DbLocalizationProvider library.</p>

<p>You may have seen this kind of view model:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">MyProject</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">MyViewModel</span>
    <span class="p">{</span>
        <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"Username or email"</span><span class="p">)]</span>
        <span class="p">[</span><span class="nf">Required</span><span class="p">(</span><span class="n">ErrorMessage</span> <span class="p">=</span> <span class="s">"Username is required"</span><span class="p">)]</span>
        <span class="p">[</span><span class="nf">StringLength</span><span class="p">(</span><span class="m">5</span><span class="p">)]</span>
        <span class="k">public</span> <span class="kt">string</span> <span class="n">UserName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

        <span class="k">public</span> <span class="n">AddressModel</span> <span class="n">BillingAddress</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">}</span>

    <span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">AddressModel</span>
    <span class="p">{</span>
        <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"Line 1"</span><span class="p">)]</span>
        <span class="p">[</span><span class="n">Required</span><span class="p">]</span>
        <span class="k">public</span> <span class="kt">string</span> <span class="n">Line1</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If nested model (<code class="language-plaintext highlighter-rouge">AddressModel</code>) is also decorated with <code class="language-plaintext highlighter-rouge">[LocalizedModel]</code> it will be included in scanning and discovery process and its properties will be registered in localization resource storage.</p>

<p>On sample model above following resource keys will be registered:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre>MyProject.MyViewModel.UserName
MyProject.MyViewModel.UserName-Required
MyProject.MyViewModel.UserName-StringLength

MyProject.AddressModel.Line1
MyProject.AddressModel.Line1-Required
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now you can use nested models and they are localized as well. Sample usage:</p>

<pre><code class="language-razor">@model MyViewModel

@Html.LabelFor(m =&gt; m.UserName)
@Html.ValidationMessageFor(m =&gt; m.UserName)
@Html.EditorFor(m =&gt; m.UserName)

@Html.LabelFor(m =&gt; m.BillingAddress.Line1)
@Html.ValidationMessageFor(m =&gt; m.BillingAddress.Line1)
@Html.EditorFor(m =&gt; m.BillingAddress.Line1)
</code></pre>

<p><strong>NB!</strong> Note that resource key names for property <code class="language-plaintext highlighter-rouge">BillingAddress</code> are different as it was for nested resources.
You might expect that resource key should be <code class="language-plaintext highlighter-rouge">MyProject.MyViewModel.BillingAddress.Line1</code>, but actually it’s: <code class="language-plaintext highlighter-rouge">MyProject.AddressModel.Line1</code>.</p>

<p>This is related to how Asp.Net Mvc framework is building model metadata structures.
When you use following helper method:</p>

<pre><code class="language-razor">@Html.LabelFor(m =&gt; m.BillingAddress.Line1)
</code></pre>

<p>metadata for nested property <code class="language-plaintext highlighter-rouge">Line1</code> of type <code class="language-plaintext highlighter-rouge">AddressModel</code> defined as property <code class="language-plaintext highlighter-rouge">BillingAddress</code> for type <code class="language-plaintext highlighter-rouge">MyViewModel</code> is required. Asp.Net Mvc model metadata provider infrastructure will give us <code class="language-plaintext highlighter-rouge">AddressModel</code> as “container type” for the requested <code class="language-plaintext highlighter-rouge">Line1</code> property. In other words from model metadata provider perspective Asp.Net Mvc does not care how model was declared in the view model (whether is has property name <code class="language-plaintext highlighter-rouge">BillingAddress</code> or <code class="language-plaintext highlighter-rouge">ShippingAddress</code>) - it’s using <em>actual</em> type (<code class="language-plaintext highlighter-rouge">AddressModel</code>) as container type and not preserving “context” where it was declared.
That’s why it’s pointless to keep context about how property was declared as what matters is only actual model container type - the nested viewmodel.</p>

<h3 id="episerver-compatibility-mode">EPiServer Compatibility Mode</h3>

<p>If you follow <a href="http://world.episerver.com/blogs/devabees/Dates/2014/3/Integrating-LocalizationService-with-MVC-DataAnnotations/">Martin’s approach</a> it’s possible eventually to define your viewmodel with following attributes:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">MyProject</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">MyViewModel</span>
    <span class="p">{</span>
        <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"/mypageview/myviewmodel/username"</span><span class="p">)]</span>
        <span class="p">[</span><span class="nf">Required</span><span class="p">(</span><span class="n">ErrorMessage</span> <span class="p">=</span> <span class="s">"/mypageview/myviewmodel/username-required"</span><span class="p">)]</span>
        <span class="p">[</span><span class="nf">StringLength</span><span class="p">(</span><span class="m">5</span><span class="p">,</span> <span class="n">ErrorMessage</span> <span class="p">=</span> <span class="s">"/mypageview/myviewmodel/username-length"</span><span class="p">)]</span>
        <span class="k">public</span> <span class="kt">string</span> <span class="n">UserName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>However doing this, it’s required to add bunch of adapters and later register them to the Asp.Net Mvc validation attribute adapter collection. I’m too lazy and I want everything to be working out of the box with no extra effort.</p>

<p>If you already have EPiServer <a href="http://world.episerver.com/documentation/Items/Developers-Guide/Episerver-CMS/9/Globalization/Localization-service/">Language Files</a> then you have these keys in Xml files as well.</p>

<p>First step to migrate existing language files to new DbLocalizationProvider is to use <a href="http://nuget.episerver.com/en/OtherPages/Package/?packageId=DbLocalizationProvider.MigrationTool">DbLocalizationProvider Migration Tool</a>.</p>

<p>Once you have exported resources from Xml files and imported them into new provider you will have already resources with following keys (most probably among the other ones):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>/mypageview/myviewmodel/username
/mypageview/myviewmodel/username-required
/mypageview/myviewmodel/username-length
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then upon 1st request to the application (when scanning and discovery process will kick in) your viewmodel with <code class="language-plaintext highlighter-rouge">[LocalizedModel]</code> annotation will be picked up, and all properties will be registered in resource storage.
So once application finished initialization, you will end up with following resource keys:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre>/mypageview/myviewmodel/username
/mypageview/myviewmodel/username-required
/mypageview/myviewmodel/username-length

MyProject.MyViewModel.UserName
MyProject.MyViewModel.UserName-Required
MyProject.MyViewModel.UserName-StringLength
</pre></td></tr></tbody></table></code></pre></div></div>

<p>It looks like duplication, but that’s what library knows about your model.</p>

<p>Translations for new resources are taken either from <code class="language-plaintext highlighter-rouge">Name = "..."</code> property in case of <code class="language-plaintext highlighter-rouge">[DisplayAttribute]</code> or <code class="language-plaintext highlighter-rouge">ErrorMessage = "..."</code> in case of some kind of <code class="language-plaintext highlighter-rouge">ValidationAttribute</code>. Translations will be following:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>MyProject.MyViewModel.UserName = "/mypageview/myviewmodel/username"
MyProject.MyViewModel.UserName-Required = "/mypageview/myviewmodel/username-required"
MyProject.MyViewModel.UserName-StringLength = "/mypageview/myviewmodel/username-length"
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Once <code class="language-plaintext highlighter-rouge">LegacyMode</code> is enabled (it’s <strong>enabled by default</strong>, but you may turn it off – more info in “Part 2: Configuration and Extensions”), library will make sure that actual translation for property <code class="language-plaintext highlighter-rouge">UserName</code> of viewmodel <code class="language-plaintext highlighter-rouge">MyViewModel</code> is taken from EPiServer’s <code class="language-plaintext highlighter-rouge">LocalizationService</code> with key <code class="language-plaintext highlighter-rouge">/mypageview/myviewmodel/username</code>. Which means that you don’t need to make bunch of new translations to make new provider working, but instead new provider will try to work in legacy mode and will try to look for “XPath resource” as it’s used in EPiServer if using built-in Xml language files.</p>

<h3 id="additional-model-attributes">Additional Model Attributes</h3>

<p>There are 2 additional attributes you can use to instruct scanning and discovery process how it’s registering resources for your model:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">[Include]</code> - attribute defined as <code class="language-plaintext highlighter-rouge">DbLocalizationProvider.Sync.IncludeAttribute</code></li>
  <li><code class="language-plaintext highlighter-rouge">[Ignore]</code> - defined as <code class="language-plaintext highlighter-rouge">EPiServer.DataAnnotations.IgnoreAttribute</code></li>
</ul>

<p><code class="language-plaintext highlighter-rouge">Ignore</code> attribute is kind of self-documenting. Once applied to the property - you are instructing library not to register any resources associated with this property. It will be just completely ignored.</p>

<p><code class="language-plaintext highlighter-rouge">Include</code> attribute usage is more interesting.
Let’s say you have following viewmodel:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">MyProject</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">MyViewModel</span>
    <span class="p">{</span>
        <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"Username or email"</span><span class="p">)]</span>
        <span class="p">[</span><span class="nf">Required</span><span class="p">(</span><span class="n">ErrorMessage</span> <span class="p">=</span> <span class="s">"Username is required"</span><span class="p">)]</span>
        <span class="p">[</span><span class="nf">StringLength</span><span class="p">(</span><span class="m">5</span><span class="p">)]</span>
        <span class="k">public</span> <span class="kt">string</span> <span class="n">UserName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

        <span class="k">public</span> <span class="n">AddressModel</span> <span class="n">BillingAddress</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">}</span>

    <span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">AddressModel</span>
    <span class="p">{</span>
        <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"Line 1"</span><span class="p">)]</span>
        <span class="p">[</span><span class="n">Required</span><span class="p">]</span>
        <span class="k">public</span> <span class="kt">string</span> <span class="n">Line1</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And you would like to use following markup in your view (for instance creating section for billing address with title):</p>

<pre><code class="language-razor">@model MyViewModel

...
&lt;div class="block-section"&gt;
    &lt;div class="title"&gt;@Html.DisplayNameFor(m =&gt; m.BillingAddress)&lt;/div&gt;
    ...
&lt;/div&gt;
...
</code></pre>

<p>However, you will end up with not localized <code class="language-plaintext highlighter-rouge">&lt;div&gt;</code> element content for the title.
By default library will not include “declaring property” localization resource, but instead resources for <code class="language-plaintext highlighter-rouge">AddressModel</code> will be registered. Usage for nested viewmodels is usually something like this:</p>

<p>Index.cshtml:</p>

<pre><code class="language-razor">@model MyViewModel

...
@Html.LabelFor(m =&gt; m.UserName)
...

@Html.Partial("Address", m.BillingAddress)     @* or you can use any of partials approach *@
...
</code></pre>

<p>Address.cshtml:</p>

<pre><code class="language-razor">@model AddressModel

@Html.LabelFor(m =&gt; m.Line1)
</code></pre>

<p>From this case, it’s obvious that there is no need to “pollute” resource list with translation for “declaring property” of nested viewmodel.
But if you need to translate also “declaring property” you can do this by decorating this property with <code class="language-plaintext highlighter-rouge">[Include]</code> attribute:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">MyProject</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">MyViewModel</span>
    <span class="p">{</span>
        <span class="p">...</span>

        <span class="p">[</span><span class="n">Include</span><span class="p">]</span>
        <span class="k">public</span> <span class="n">AddressModel</span> <span class="n">BillingAddress</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This attribute will make sure that you have resource with key <code class="language-plaintext highlighter-rouge">MyProject.MyViewModel.BillingAddress</code> and then you can use this resource to localize “declaring property” with the following code:</p>

<pre><code class="language-razor">@model MyViewModel

@Html.DisplayNameFor(m =&gt; m.BillingAddress)
</code></pre>

<h2 id="whats-next">What’s Next?</h2>

<p>More blog posts in this series (<em>upcoming</em>):</p>

<ul>
  <li><strong>Part 1: Resources and Models</strong></li>
  <li><a href="https://tech-fellow.eu/2016/04/21/db-localization-provider-part-2-configuration-and-extensions/">Part 2: Configuration and Extensions</a></li>
  <li><a href="https://tech-fellow.eu/2017/02/22/localization-provider-import-and-export-merge/">Part 3: Import and Export</a></li>
  <li><a href="https://tech-fellow.eu/2017/10/10/localizationprovider-tree-view-export-and-migrations/">Part 4: Resource Refactoring and Migrations</a></li>
</ul>

<p>If you have any ideas, suggestions or complaints please post them to library’s <a href="https://github.com/valdisiljuconoks/LocalizationProvider/issues">GitHub repo</a>.</p>

<p>Happy localizing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Localization Provider" /><category term="Episerver" /><category term="Optimizely" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[Resources and Models]]></summary></entry><entry><title type="html">EPiServer Database Localization Provider - Released!</title><link href="https://tech-fellow.eu/2016/03/01/episerver-database-localization-provider-released/" rel="alternate" type="text/html" title="EPiServer Database Localization Provider - Released!" /><published>2016-03-01T20:05:00+02:00</published><updated>2016-03-01T20:05:00+02:00</updated><id>https://tech-fellow.eu/2016/03/01/episerver-database-localization-provider-released</id><content type="html" xml:base="https://tech-fellow.eu/2016/03/01/episerver-database-localization-provider-released/"><![CDATA[<p>Why on the Earth I would ever want to change my EPiServer localization system?
EPiServer provides you with a way to organize localization resources using set of Xml files. Working on multi-lingual projects and seeing how support teams are struggling and bored with changing resource value - thought: there has to be space for improvement..</p>

<h3 id="we-dont-need-localization">We don’t need localization</h3>

<p>Lately I’ve been working more and more with international sites where single language is not the case at all.</p>

<blockquote>
  <p>Localization is not needed - because we have only single language.</p>
</blockquote>

<p>In my opinion this is absolutely no excuse - even if project requires just single language, at some point editors will ask to change some of the texts somewhere on the website, change value of the resource. If texts are coded inside the views, services and controllers - does it mean that every time editor will ask for the change you may end up with new version roll-out?!</p>

<p>Example when taking localization into account is pretty important, even usage is in single language sites. This is extremely important if you are building library that is close to the core.</p>

<p>Localization of the EPiServer Commerce workflows..</p>

<p><img src="/assets/img/2016/03/2016-02-27_20-15-17-1.png" alt="" /></p>

<p>I want to show precise error message what happened in workflow to the end-user and also give editors possibility to change this message to anything meaningful for end-users.</p>

<p>And I don’t want to download workflow source code project, rebuild it and use my own version only because my site is multi-lingual.</p>

<h3 id="noise-in-the-model">Noise in the Model</h3>

<p>Yes.. I’ve been there and made my own set of overridden <code class="language-plaintext highlighter-rouge">DataAnnotation</code> attributes to be applied for the model in order to get localized strings out of <code class="language-plaintext highlighter-rouge">LocalizationService</code> and pass them back to Mvc model meta data provider for further usage.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">LoginViewModel</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">LocalizedDisplay</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"/login/viewmodel/username"</span><span class="p">)]</span>
    <span class="p">[</span><span class="nf">LocalizedRequired</span><span class="p">(</span><span class="n">ErrorMessage</span> <span class="p">=</span> <span class="s">"/login/viewmodel/username-required"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">UserName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This of course does not look sexy and there is a lot of “noise” in the model. I don’t see <em>the model</em> any more, I see some stuff around it that makes sure proper error message is shown on the form. It’s stuff for <a href="http://blog.ploeh.dk/2013/12/03/layers-onions-ports-adapters-its-all-the-same/">adapter or port</a> not on my level, I don’t need it here - my domain. Validation attributes is something that’s interesting for the domain modeler.</p>

<h3 id="eh-can-you-change-this">Eh.. Can You change this?</h3>

<p>Even working on single language sites I often receive requests to change text from “<code class="language-plaintext highlighter-rouge">xxx</code>” to “<code class="language-plaintext highlighter-rouge">yyyy</code>”.</p>

<p>Then after a while:</p>

<p>– <em>Can you change this text “yyyy” now to “zzzz”, please?</em></p>

<p>– Of course, no problem.</p>

<p>..</p>

<p>– <em>Everything looks OK, but you know - we found some grammar mistake. Can you change this again?</em></p>

<p>..</p>

<p>– <em>You know, is it possible for us to change these localization resources ourselves?</em></p>

<p>– Of course, here you go a Xml file you will need to translate.</p>

<p><img src="/assets/img/2016/03/2016-02-27_20-47-00.png" alt="" /></p>

<p>– <em>Whew… We spent whole day translating those damn resources. But anyway -&gt; here you go!</em></p>

<p><img src="/assets/img/2016/03/2016-02-27_20-52-03.png" alt="" /></p>

<p>..</p>

<p>– <em>And by the way, how can we overview all our translation resources and see what messages are not translated and which have wrong translations?</em></p>

<h3 id="attempts-to-solve-this">Attempts to Solve this</h3>

<p>Martin Pickering <a href="http://world.episerver.com/blogs/devabees/Dates/2014/3/Integrating-LocalizationService-with-MVC-DataAnnotations/">tried to squeeze in MVC Data Annotation subsystem</a> to fetch resources out of Localization Service and localize either display name or validation messages during runtime.</p>

<p>This makes it possible to have more “pure” models in your code base:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">LoginViewModel</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"/login/username"</span><span class="p">)]</span>
    <span class="p">[</span><span class="nf">Required</span><span class="p">(</span><span class="n">ErrorMessage</span> <span class="p">=</span> <span class="s">"/login/username-required"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">UserName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>However - I find it still “noisy” enough to continue searching for better solution.
I know that I’m in LoginViewModel, I know that I’m on the <code class="language-plaintext highlighter-rouge">UserName</code> property and also I know that I need to show <code class="language-plaintext highlighter-rouge">DisplayName</code> for this property if somebody will ask me <code class="language-plaintext highlighter-rouge">@Html.DisplayNameFor(m =&gt; m.UserName)</code> or even when asking for validation message <code class="language-plaintext highlighter-rouge">@Html.ValidationMessageFor(m =&gt; m.UserName)</code> - I know that this property is required and maybe has some other .</p>

<p>One of the greatest plugins seen so far is from my old fellow and friend and EMVP - Jeroen Stemerdink - <a href="https://github.com/jstemerdink/EPi.Libraries.Localization/tree/master/EPi.Libraries.Localization">EPi.Libraries.Localization</a>.</p>

<p>However, Jeroen’s solution is ideal when it comes to editor story - editing UI, permissions, search everything is in sort in place already. But I missed a bit developer experience story here - how I as a developer am able start generating new resources, how do I easily reference these resources in my services, etc.</p>

<p>I was trying to solve these challenges and put localization provider on steroids - in this new <strong>Database Driven Localization Provider</strong> (<code class="language-plaintext highlighter-rouge">DbLocalizationProvider</code>).</p>

<h2 id="getting-started">Getting Started</h2>
<p>Localization Provider consists from few components:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">DbLocalizationProvider</code> - this is core package and gives you EPiServer localization provider, <code class="language-plaintext highlighter-rouge">DataAnnotation</code> attributes, model and resource synchronization process and other core features.</li>
  <li><code class="language-plaintext highlighter-rouge">DbLocalizationProvider.AdminUI</code> - administrator user interface for editors and administrators to overview resources, make translations, import / export and do other management stuff.</li>
  <li><code class="language-plaintext highlighter-rouge">DbLocalizationProvider.MigrationTool</code> - tool gives you possibility to generate JSON format data out of Xml language files later to import these resources into this new DbLocalizationProvider.</li>
</ul>

<h3 id="installing-provider">Installing Provider</h3>

<p>Installation nowadays can’t be more simpler as just adding NuGet package(s).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>PM&gt; Install-Package DbLocalizationProvider
PM&gt; Install-Package DbLocalizationProvider.AdminUI
PM&gt; Install-Package DbLocalizationProvider.MigrationTool
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>NB!</strong> Currently <code class="language-plaintext highlighter-rouge">DbLocalizationProvider</code> NuGet package has naïve <code class="language-plaintext highlighter-rouge">web.config</code> transformation file assuming that <code class="language-plaintext highlighter-rouge">&lt;episerver.framework&gt;</code> section is not extracted into separate file (this was usual case for older versions of AlloyTech sample sites).</p>

<p>New localization provider needs to be “registered” and added to the list of the localization providers configured for EPiServer Framework. Section may look like this:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;episerver.framework&gt;</span>
  ..
  <span class="nt">&lt;localization&gt;</span>
    <span class="nt">&lt;providers&gt;</span>
      <span class="nt">&lt;add</span> <span class="na">name=</span><span class="s">"db"</span>
           <span class="na">type=</span><span class="s">"DbLocalizationProvider.DatabaseLocalizationProvider, DbLocalizationProvider"</span> <span class="nt">/&gt;</span>
      <span class="nt">&lt;add</span> <span class="na">name=</span><span class="s">"languageFiles"</span> <span class="na">virtualPath=</span><span class="s">"~/lang"</span>
           <span class="na">type=</span><span class="s">"EPiServer.Framework.Localization.XmlResources.FileXmlLocalizationProvider, EPiServer.Framework"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;/providers&gt;</span>
  <span class="nt">&lt;/localization&gt;</span>
  ..
<span class="nt">&lt;/episerver.framework&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>NB!</strong> If you do have extracted <code class="language-plaintext highlighter-rouge">&lt;episerver.framework&gt;</code> section into separate file (usually <code class="language-plaintext highlighter-rouge">episerver.framework.config</code>), please clean-up web.config after NuGet package installation and move content of the <code class="language-plaintext highlighter-rouge">&lt;localization&gt;</code> section to that separate physical file.</p>

<h2 id="dblocalizationprovider-features">DbLocalizationProvider Features</h2>

<p>All resources in DbLocalizationProvider system are divided into 2 groups:</p>

<ul>
  <li><strong>Resources</strong> - localized resources are just list of key / value pairs. You may have a key for the resource and value is its translation in specific language. Resources are designed as just POCO objects.</li>
  <li><strong>Models</strong> - models are usually view models that may have <code class="language-plaintext highlighter-rouge">DataAnnotation</code> attributes attached to them (like, <code class="language-plaintext highlighter-rouge">Display</code>, <code class="language-plaintext highlighter-rouge">Required</code>, etc).</li>
</ul>

<h3 id="localized-resources">Localized Resources</h3>

<p>Localized resource is straight forward way to define list of properties that are localizable. Localized resource is simple POCO class that defines list of properties:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">MySampleProject</span> <span class="p">{</span>

    <span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">MyResources</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">SampleResource</span> <span class="p">=&gt;</span> <span class="s">"This is default value"</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So what happens now is that localization provider knows that there is a resource that needs to be registered in data storage. This scanning and discovery of the types is done during startup (more about this will be in “<em>Part 1: Model and Resource Discovery Process</em>”).</p>

<p>Localization Provider scanning process looks for <code class="language-plaintext highlighter-rouge">[LocalizedResource]</code> attributes and registers these classes in its internal type list for further inspection and discovery.</p>

<p>If we take a look at resource class definition key (unique identifier of the resource) is defined as: <code class="language-plaintext highlighter-rouge">{namespace}.{container-type}.{property-name}</code>. So in this case key of the resource is: <code class="language-plaintext highlighter-rouge">MySampleProject.MyResources.SampleResource</code>.</p>

<p>Now when you have your resource registered and discovered - default value for the preferred content language (<code class="language-plaintext highlighter-rouge">ContentLanguage.PreferredCulture</code> value during application startup) is <code class="language-plaintext highlighter-rouge">"This is default value"</code>. Later of course editors via AdminUI will be able to change this.</p>

<p>Now, you may use one of the ways to output this resource to the end-users:</p>

<pre><code class="language-razor">@using DbLocalizationProvider

&lt;div&gt;
    @Html.Translate(() =&gt; MyResources.SampleResource)
&lt;/div&gt;
</code></pre>

<h3 id="nested-localized-resources">Nested Localized Resources</h3>

<p>Btw, these kind of resource definitions are also supported:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">MySampleProject</span> <span class="p">{</span>

    <span class="p">[</span><span class="n">LocalizedResource</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">MyResources</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">SampleResource</span> <span class="p">=&gt;</span> <span class="s">"This is default value"</span><span class="p">;</span>
        <span class="k">public</span> <span class="k">static</span> <span class="n">SubResource</span> <span class="n">AnotherSet</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">class</span> <span class="nc">SubResource</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="kt">string</span> <span class="n">AnotherResource</span> <span class="p">=&gt;</span> <span class="s">"Please, translate!"</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now you will have 2 resources discovered with following keys:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>MySampleProject.MyResources.SampleResource
MySampleProject.MyResources.AnotherSet.AnotherResource
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now you can access this like following:</p>

<pre><code class="language-razor">@using DbLocalizationProvider

&lt;div&gt;
    @Html.Translate(() =&gt; MyResources.AnotherSet.AnotherResource)
&lt;/div&gt;
</code></pre>

<p>This is why during resource scanning process, library “preserves” nested resource context (<code class="language-plaintext highlighter-rouge">AnotherSet.AnotherResource</code>) and not setting resource key as <code class="language-plaintext highlighter-rouge">SubResource.AnotherResource</code> - to match with used <code class="language-plaintext highlighter-rouge">LambdaExpression</code> to reach that resource via <code class="language-plaintext highlighter-rouge">HtmlHelper</code> or any other usage.</p>

<p>More about this will be in up coming post - “<em>Part 1: Model and Resource Discovery Process</em>”.</p>

<h3 id="localized-models">Localized Models</h3>

<p>Another more interesting way and usage is to define localizable view models.</p>

<p>Localizable view model means that <code class="language-plaintext highlighter-rouge">DbLocalizationProvider</code> library will search for <code class="language-plaintext highlighter-rouge">[LocalizedModel]</code> attributes and will discover all models and further discovery of the resources there.</p>

<p>Now you may define following view model:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">MySampleProject</span> <span class="p">{</span>

    <span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">MyViewModel</span>
    <span class="p">{</span>
        <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"This is default value"</span><span class="p">)]</span>
        <span class="k">public</span> <span class="kt">string</span> <span class="n">SampleProperty</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now you will have similar resource discovered as it was with <code class="language-plaintext highlighter-rouge">[LocalizedModel]</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>MySampleProject.MyViewModel.SampleProperty
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Default value for the resource will be <code class="language-plaintext highlighter-rouge">"This is default value"</code> (this is taken from <code class="language-plaintext highlighter-rouge">[Display]</code> attribute).</p>

<p><strong>NB!</strong> If there will be no <code class="language-plaintext highlighter-rouge">[Display]</code> attribute for the property - name of the property (<code class="language-plaintext highlighter-rouge">SampleProperty</code>) will be used as default resource value.</p>

<h3 id="model-data-annotations">Model Data Annotations</h3>

<p>Usually view models are decorated with various <code class="language-plaintext highlighter-rouge">DataAnnotation</code> attributes to get model validation into the Asp.Net Mvc request processing pipeline. Which is very fine and <code class="language-plaintext highlighter-rouge">DbLocalizationProvider</code> aware of these attributes once scanning for localized models.</p>

<p>So if you add bit more attributes to initial view model:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">MySampleProject</span> <span class="p">{</span>

    <span class="p">[</span><span class="n">LocalizedModel</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">MyViewModel</span>
    <span class="p">{</span>
        <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"This is default value"</span><span class="p">)]</span>
        <span class="p">[</span><span class="n">Required</span><span class="p">]</span>
        <span class="p">[</span><span class="nf">StringLength</span><span class="p">(</span><span class="m">5</span><span class="p">)]</span>
        <span class="k">public</span> <span class="kt">string</span> <span class="n">SampleProperty</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Following resources will be discovered:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>MySampleProject.MyViewModel.SampleProperty
MySampleProject.MyViewModel.SampleProperty-Required
MySampleProject.MyViewModel.SampleProperty-StringLength
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Which gives you a possibility to translation precise error messages shown when particular property has invalid value for this model.</p>

<p>So you can easily continue using Html helper extensions like:</p>

<pre><code class="language-razor">&lt;div&gt;
    @Html.LabelFor(m =&gt; m.SampleProperty)
    @Html.EditorFor(m =&gt; m.SampleProperty)
&lt;/div&gt;
</code></pre>

<p>More about this will be in up coming post - “<em>Part 1: Model and Resource Discovery Process</em>”.</p>

<p>Now if I take a look at one of my view model before and after adding <code class="language-plaintext highlighter-rouge">DbLocaliztionProvider</code> - seems like new version of the model is much more cleaner and readable.</p>

<p><img src="/assets/img/2016/03/2016-02-25_15-15-35.png" alt="" /></p>

<h2 id="import-language-xml-files">Import Language Xml Files</h2>

<p>This is a natural situation when adding <code class="language-plaintext highlighter-rouge">DbLocalizationProvider</code> to the project - there already will be Xml language files present.</p>

<p>Even after <code class="language-plaintext highlighter-rouge">DbLocalizationProvider</code> library is added - old Xml language files will continue to work. However - if you would like to get rid of language files completely - you will need to migrate them to the database.</p>

<p>Migration may happen in 2 ways:</p>

<ul>
  <li>via SQL script generated by migration tool</li>
  <li>sometimes direct access (via <code class="language-plaintext highlighter-rouge">SqlConnection</code> object) may not be applicable. That’s why it’s possible to extract all Xml language file resources and later import them into database via Administration UI (AdminUI).</li>
</ul>

<h3 id="migration-with-sql-script">Migration with SQL script</h3>

<p>Migration via SQL script is pretty simple. First of all you need to install <code class="language-plaintext highlighter-rouge">DbLocalizationProvider.MigrationTool</code> package. Then you can execute <code class="language-plaintext highlighter-rouge">.exe</code> file inside package <code class="language-plaintext highlighter-rouge">tools/</code> folder.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; DbLocalizationProvider.MigrationTool.exe -s="{path-to-project}" -e -i
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Explanation of switches used:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">-s</code> - specifies <strong>s</strong>ource directory for the project (your web root)</li>
  <li><code class="language-plaintext highlighter-rouge">-e</code> - asks migration tool to <strong>e</strong>xport all resources from language Xml files into SQL format file (resulting file <code class="language-plaintext highlighter-rouge">localization-resource-translations.sql</code> by default is located in the same folder specified by <code class="language-plaintext highlighter-rouge">-s</code>)</li>
  <li><code class="language-plaintext highlighter-rouge">-i</code> - asks migration tool to <strong>i</strong>mport resources from exported file into directly database (using connection string named <code class="language-plaintext highlighter-rouge">"EPiServerDB"</code>)</li>
</ul>

<p><img src="/assets/img/2016/03/2016-02-27_22-48-32.png" alt="" /></p>

<h3 id="migration-via-json-file">Migration via JSON file</h3>

<p>Using JSON format export file is similar as with SQL script file, you just need to provide switch to use JSON file (import from AdminUI is supported only with JSON format files).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; DbLocalizationProvider.MigrationTool.exe -s="{path-to-project}" -e --json
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Commands:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">-s</code> - specifies <strong>s</strong>ource directory for the project (your web root)</li>
  <li><code class="language-plaintext highlighter-rouge">-e</code> - asks migration tool to <strong>e</strong>xport all resources from language Xml files (resulting file <code class="language-plaintext highlighter-rouge">localization-resource-translations.json</code> by default is located in the same folder specified by <code class="language-plaintext highlighter-rouge">-s</code>)</li>
  <li><code class="language-plaintext highlighter-rouge">--json</code> - to use JSON format</li>
</ul>

<p><img src="/assets/img/2016/02/2016-02-27_22-54-11.png" alt="" /></p>

<p>Now you can use result JSON file and import it from AdminUI.</p>

<h2 id="manage-resources-in-adminui">Manage Resources in AdminUI</h2>

<p>There are 2 type of actors in localization module administration UI:</p>

<ul>
  <li><strong>Editors</strong> - users in this role can access resources, change translations and do some basic setup of the AdminUI (like, pick only languages and translations in interest). Following roles classifies as editors - <code class="language-plaintext highlighter-rouge">WebEditors</code>, <code class="language-plaintext highlighter-rouge">CmsEditors</code>, <code class="language-plaintext highlighter-rouge">LocalizationEditors</code>.</li>
  <li><strong>Administrators</strong> - users in this role has access to more features in AdminUI, like Import/Export, create new or delete manually resource, etc. Users in these roles classifies as administrators - <code class="language-plaintext highlighter-rouge">Administrators</code>, <code class="language-plaintext highlighter-rouge">CmsAdmins</code>, <code class="language-plaintext highlighter-rouge">WebAdmins</code>, <code class="language-plaintext highlighter-rouge">LocalizationAdmins</code>.</li>
</ul>

<h2 id="see-it-in-action">See it in Action!</h2>

<p>Few sample videos to see new provider in action.</p>

<p>Simple resource definition:</p>

<iframe src="https://player.vimeo.com/video/156990357" width="800" height="520" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>

<p>Simple View Model definition:</p>

<iframe src="https://player.vimeo.com/video/157056409" width="800" height="520" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>

<p>Newly added language branch awareness:</p>

<iframe src="https://player.vimeo.com/video/157062616" width="800" height="520" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>

<h2 id="where-do-i-get-it">Where do I get it?</h2>

<p>Nothing is more easy as installing <a href="http://nuget.episerver.com/en/OtherPages/Package/?packageId=DbLocalizationProvider">NuGet package</a> :)</p>

<h2 id="read-more">Read More</h2>
<p>More about new EPiServer Localization Provider in this blog post series (<em>upcoming</em>):</p>

<ul>
  <li><a href="https://tech-fellow.eu/2016/03/16/db-localization-provider-part-1-resources-and-models/">Part 1: Resources and Models</a></li>
  <li><a href="https://tech-fellow.eu/2016/04/21/db-localization-provider-part-2-configuration-and-extensions/">Part 2: Configuration and Extensions</a></li>
  <li><a href="https://tech-fellow.eu/2017/02/22/localization-provider-import-and-export-merge/">Part 3: Import and Export</a></li>
  <li><a href="https://tech-fellow.eu/2017/10/10/localizationprovider-tree-view-export-and-migrations/">Part 4: Resource Refactoring and Migrations</a></li>
</ul>

<p>Library is open sourced and and you can find it @ <a href="https://github.com/valdisiljuconoks/LocalizationProvider">GitHub</a>.</p>

<p>Happy localizing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Localization Provider" /><category term="Episerver" /><category term="Optimizely" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[Why on the Earth I would ever want to change my EPiServer localization system? EPiServer provides you with a way to organize localization resources using set of Xml files. Working on multi-lingual projects and seeing how support teams are struggling and bored with changing resource value - thought: there has to be space for improvement..]]></summary></entry><entry><title type="html">Create Your Library Configuration API for EPiServer</title><link href="https://tech-fellow.eu/2016/02/23/create-your-library-configuration-api-for-episerver/" rel="alternate" type="text/html" title="Create Your Library Configuration API for EPiServer" /><published>2016-02-23T10:30:00+02:00</published><updated>2016-02-23T10:30:00+02:00</updated><id>https://tech-fellow.eu/2016/02/23/create-your-library-configuration-api-for-episerver</id><content type="html" xml:base="https://tech-fellow.eu/2016/02/23/create-your-library-configuration-api-for-episerver/"><![CDATA[<p>Time comes when you need to extent EPiServer functionality by providing your own library with new or modified functionality.
I’m big fan of configuration via code. Which may give you possibility to configure some features with <code class="language-plaintext highlighter-rouge">LambdaExpression</code>, e.g. <code class="language-plaintext highlighter-rouge">() =&gt; true</code> to ensure that you are able to set feature’s state <code class="language-plaintext highlighter-rouge">on</code> or <code class="language-plaintext highlighter-rouge">off</code> during runtime. This opens up quite interesting scenarios that I’m going to cover soon enough in other blog post.</p>

<p>Anyway, what I’m looking for is to make sure that my library consumers can do something like this:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span> <span class="p">(</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">MyLibInit</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">ConfigurationContext</span><span class="p">.</span><span class="nf">Setup</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span>
                                  <span class="p">{</span>
                                      <span class="n">ctx</span><span class="p">.</span><span class="n">ConfigOption</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
                                  <span class="p">});</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>From the “end-user” perspective everything seems quite logic -&gt; following best practices for EPiServer development - startup initialization is moved to <code class="language-plaintext highlighter-rouge">InitializableModule</code>.</p>

<h2 id="module-call-order">Module Call Order</h2>

<p>Regardless that “end-user” code (<code class="language-plaintext highlighter-rouge">MyLibInit.cs</code>) seems OK, this makes it a bit challenging to set everything up correctly on library’s side. The issue here is with order of calls for <code class="language-plaintext highlighter-rouge">InitializableModule</code> initialization code. Following best practices for EPiServer development also on library’s side - we would need to setup our library via <code class="language-plaintext highlighter-rouge">InitializableModule</code> as well (<code class="language-plaintext highlighter-rouge">LibInit.cs</code>).</p>

<p>This is not guaranteed in EPiServer - which means that sometimes your “end-user” module may be called <em>before</em> library’s init module - this is perfect timing of the modules - library’s module can now read configuration values setup by library consumer code:</p>

<p><img src="/assets/img/2016/02/2016-02-22_23-35-50-2.png" alt="" /></p>

<p>However, sometimes EPiServer may call library init module <em>before</em> “end-user” module - which means that configuration settings will have no effect (as they are set after library is initialized):</p>

<p><img src="/assets/img/2016/02/2016-02-22_23-42-20.png" alt="" /></p>

<h2 id="create-mid-dependency-module">Create Mid-Dependency Module</h2>

<p>One thought that I gave chance to prove itself was to create intermediate fake dependency module - that library “end-user” module could depend upon and then create another module internally that would also be dependent on this fake module. And then add “actual” initialization module (<code class="language-plaintext highlighter-rouge">LibInit.cs</code>) as dependent module for this fake module. Visually it may look something like this:</p>

<p><img src="/assets/img/2016/02/2016-02-22_23-49-00-1.png" alt="" /></p>

<p>However, in this case (and I haven’t dig into more details) case was so that EPiServer made sure that <code class="language-plaintext highlighter-rouge">LibInit</code> is called before <code class="language-plaintext highlighter-rouge">MyLibInit</code>. I’m speculating here that EPiServer makes sure that “longest” dependency chain gets called first.</p>

<h2 id="solution">Solution</h2>

<p>Actually solution for this case of dependency juggling is <strong>really</strong> simple. Fortunately EPiServer exposes few events that you can hook onto and add your logic after all of the modules have done their job:</p>

<p><img src="/assets/img/2016/02/2016-02-22_23-57-58-1.png" alt="" /></p>

<p>Using event subscription - it’s guaranteed that your event handler will be called <em>after</em> all modules have done their job - including one that setup your configuration context.</p>

<p>In code it looks really simple:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span> <span class="p">(</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">LibInit</span> <span class="p">:</span> <span class="n">IInitializationModule</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="kt">bool</span> <span class="n">_eventHandlerAttached</span><span class="p">;</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">_eventHandlerAttached</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">return</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="n">context</span><span class="p">.</span><span class="n">InitComplete</span> <span class="p">+=</span> <span class="n">ContextOnInitComplete</span><span class="p">;</span>
        <span class="n">_eventHandlerAttached</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
    <span class="p">}</span>

   <span class="k">private</span> <span class="k">void</span> <span class="nf">ContextOnInitComplete</span><span class="p">(</span><span class="kt">object</span> <span class="n">sender</span><span class="p">,</span> <span class="n">EventArgs</span> <span class="n">eventArgs</span><span class="p">)</span>
   <span class="p">{</span>
        <span class="p">...</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="solution-with-icontainer-access">Solution with IContainer Access</h2>

<p>Solution seems to be simple enough to configure your own library behavior based on what “end-user” has configured.</p>

<p>Sometimes you may need to swap out some stuff from IoC container and replace with your own stuff (for instance, if “end-user” is willing to do so and had configured your library with that setting).</p>

<p><code class="language-plaintext highlighter-rouge">IContainer</code> is not accessible in <code class="language-plaintext highlighter-rouge">InitializableModule</code> interface. But EPiServer gives access to dependency container while executing collection of <code class="language-plaintext highlighter-rouge">IConfigurableModule</code>.</p>

<p>Which means that we just need to refactor our module to implement <code class="language-plaintext highlighter-rouge">IConfigurableModule</code> and then capture instance of <code class="language-plaintext highlighter-rouge">IContainer</code> and inject things we need later on:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span> <span class="p">(</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">LibInit</span> <span class="p">:</span> <span class="n">IConfigurableModule</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="n">IContainer</span> <span class="n">_container</span><span class="p">;</span>
    <span class="k">private</span> <span class="kt">bool</span> <span class="n">_eventHandlerAttached</span><span class="p">;</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">_eventHandlerAttached</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">return</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="n">context</span><span class="p">.</span><span class="n">InitComplete</span> <span class="p">+=</span> <span class="n">ContextOnInitComplete</span><span class="p">;</span>
        <span class="n">_eventHandlerAttached</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureContainer</span><span class="p">(</span><span class="n">ServiceConfigurationContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_container</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">Container</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="k">void</span> <span class="nf">ContextOnInitComplete</span><span class="p">(</span><span class="kt">object</span> <span class="n">sender</span><span class="p">,</span> <span class="n">EventArgs</span> <span class="n">eventArgs</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_container</span><span class="p">.</span><span class="nf">Configure</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span> <span class="n">ctx</span><span class="p">.</span><span class="n">For</span><span class="p">&lt;</span><span class="n">X</span><span class="p">&gt;().</span><span class="n">Use</span><span class="p">&lt;</span><span class="n">Y</span><span class="p">&gt;());</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Subscription to the <code class="language-plaintext highlighter-rouge">InitComplete</code> event makes it possible to do things in your library after your consumers have configured stuff via their initializable modules.</p>

<p>Happy coding!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[Time comes when you need to extent EPiServer functionality by providing your own library with new or modified functionality. I’m big fan of configuration via code. Which may give you possibility to configure some features with LambdaExpression, e.g. () =&gt; true to ensure that you are able to set feature’s state on or off during runtime. This opens up quite interesting scenarios that I’m going to cover soon enough in other blog post.]]></summary></entry><entry><title type="html">driven by Content Area</title><link href="https://tech-fellow.eu/2016/01/26/head-driven-by-content-area/" rel="alternate" type="text/html" title="driven by Content Area" /><published>2016-01-26T10:30:00+02:00</published><updated>2016-01-26T10:30:00+02:00</updated><id>https://tech-fellow.eu/2016/01/26/head-driven-by-content-area</id><content type="html" xml:base="https://tech-fellow.eu/2016/01/26/head-driven-by-content-area/"><![CDATA[<p>For some powerful sites and editors sometimes it’s wise to give them power to manipulate some stuff in <code class="language-plaintext highlighter-rouge">&lt;head&gt;</code> area. One of the simplest way to give editors this possibility is to create ContentArea where editors could create particular set of available blocks that would output themselves between <code class="language-plaintext highlighter-rouge">&lt;head&gt;</code> elements.</p>

<p>By default EPiServer will generate wrapping element around content area (<code class="language-plaintext highlighter-rouge">div</code> tag name is actually controllable as well, more info <a href="https://tech-fellow.eu/2015/06/11/content-area-under-the-hood-part-3/">here</a>):</p>

<pre><code class="language-razor">@Html.PropertyFor(m =&gt; m.PageHeaderArea)
</code></pre>

<p>Resulting in:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;div&gt;</span>                 <span class="c">&lt;!-- CA wrapper element --&gt;</span>
    <span class="nt">&lt;div</span> <span class="err">...</span><span class="nt">&gt;</span>         <span class="c">&lt;!-- Block element --&gt;</span>
        <span class="nt">&lt;</span><span class="err">...</span><span class="nt">&gt;</span>         <span class="c">&lt;!-- Actual content of the block --&gt;</span>
    <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>EPiServer gives you an option to skip wrapper element generation - resulting only in set of blocks added to the content area.</p>

<pre><code class="language-razor">@Html.PropertyFor(m =&gt; m.PageHeaderArea, new { HasContainer = false })
</code></pre>

<p>Resulting in:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;div</span> <span class="err">...</span><span class="nt">&gt;</span>         <span class="c">&lt;!-- Block element --&gt;</span>
    <span class="nt">&lt;</span><span class="err">...</span><span class="nt">&gt;</span>         <span class="c">&lt;!-- Actual content of the block --&gt;</span>
<span class="nt">&lt;/div&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>However, we still see that wrapping <code class="language-plaintext highlighter-rouge">&lt;div&gt;</code> element is not desired in <code class="language-plaintext highlighter-rouge">&lt;head&gt;</code> area.</p>

<p>Looking for the best place to add feature to skip even further - not to generate block wrapping element, but only content of the block itself.. Found that <a href="http://nuget.episerver.com/en/OtherPages/Package/?packageId=EPiBootstrapArea">Twitter Bootstrap aware ContentAreaRender</a> could be a perfect spot for new functionality.</p>

<p>So with latest version (v3.3.3) you can now write markup something like shown below.</p>

<p><strong>UPDATE!</strong> You need to use <code class="language-plaintext highlighter-rouge">HasEditContainer = false</code> to avoid rendering edit container for the <code class="language-plaintext highlighter-rouge">ContentArea</code>. Otherwise you may end up with invalid markup that <code class="language-plaintext highlighter-rouge">&lt;head&gt;</code> element contains <code class="language-plaintext highlighter-rouge">&lt;div&gt;</code> elements inside.</p>

<pre><code class="language-razor">@Html.PropertyFor(m =&gt; m.PageHeaderArea,
                  new
                  {
                      HasContainer = false,
                      HasItemContainer = false,
                      HasEditContainer = false
                  })
</code></pre>

<p>Resulting in:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;</span><span class="err">...</span><span class="nt">&gt;</span>         <span class="c">&lt;!-- Only actual content of the block --&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="use-case---meta-data-block">Use Case - Meta Data Block</h2>

<p>One of the use cases we had - to give editors possibility to add minifest files for the page by themselves.</p>

<p>So markup for the block is pretty straight forward:</p>

<pre><code class="language-razor">@model DynamicMenu.Models.Blocks.MetaDataBlock

&lt;link rel="@Model.RelationshipName" href="@Url.ContentUrl(Model.Link)"&gt;
</code></pre>

<p>ContentArea definition for the start page:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">StartPage</span> <span class="p">:</span> <span class="n">PageData</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">AllowedTypes</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">MetaDataBlock</span><span class="p">))]</span>
    <span class="k">public</span> <span class="k">virtual</span> <span class="n">ContentArea</span> <span class="n">HeaderContentArea</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then in <code class="language-plaintext highlighter-rouge">_SiteLayout.cshtml</code> (or any other layout page where you define <code class="language-plaintext highlighter-rouge">&lt;head&gt;</code>) you can write:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;html&gt;</span>
<span class="nt">&lt;head&gt;</span>
    @Html.PropertyFor(m =&gt; startPage.HeaderContentArea,
                      new {
                            HasContainer = false,
                            HasItemContainer = false,
                            HasEditContainer = false
                          })
    ...
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Resulting in:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;html&gt;</span>
<span class="nt">&lt;head&gt;</span>
    <span class="nt">&lt;link</span> <span class="na">rel=</span><span class="s">"manifest"</span> <span class="na">href=</span><span class="s">"http://someserver/somefile.json"</span><span class="nt">&gt;</span>
    ...
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Happy heading!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[For some powerful sites and editors sometimes it’s wise to give them power to manipulate some stuff in &lt;head&gt; area. One of the simplest way to give editors this possibility is to create ContentArea where editors could create particular set of available blocks that would output themselves between &lt;head&gt; elements.]]></summary></entry><entry><title type="html">Year in Review</title><link href="https://tech-fellow.eu/2015/12/30/yearl-in-review/" rel="alternate" type="text/html" title="Year in Review" /><published>2015-12-30T23:30:00+02:00</published><updated>2015-12-30T23:30:00+02:00</updated><id>https://tech-fellow.eu/2015/12/30/yearl-in-review</id><content type="html" xml:base="https://tech-fellow.eu/2015/12/30/yearl-in-review/"><![CDATA[<p>This is perfect timing for a busy people like us in IT industry to stop by and look back on the path that has been walked and some good things accomplished.</p>

<p>Below is a short summary of things that I hope you will find useful and beneficial in your own way. This is an experience had this year within my lovely industry, company I’m working in and with people around me.</p>

<h2 id="github-move">Github Move</h2>

<p>I was using <code class="language-plaintext highlighter-rouge">git</code> and GitHub particularly as open source project repository quite a while. Once you will step over the peek of the learning curve, command-line interface and <code class="language-plaintext highlighter-rouge">git</code> command will become your new comfort zone, you may become a true fan of distributed source control system. This is great especially in open source projects where a lot of people may be involved and development and implementation of the project’s new features may happen in parallel or in even more tracks at the same time.</p>

<p>I thought this is great for open source project and couldn’t image to use it everyday in enterprise scenarios - when your company’s main source code repo in under <code class="language-plaintext highlighter-rouge">git</code> control. This turned out to be truly amazing journey and enjoyed its every inch.</p>

<h2 id="opensource-libraries">OpenSource libraries</h2>

<p>By reviewing GitHub activity over last years - I can see the pattern that most productive and active period happens during winter months. Who loves hacking while beach or <a href="https://en.wikipedia.org/wiki/Aggressive_inline_skating">inline</a> is calling you out? Is it related to daylight, when it’s over already at 4:00 PM? Not sure, but anyway - I find my self hacking again something new together to help fellow developers during the evenings and nights when darkness already covered our street and you are folded into stillness.</p>

<p><img src="/assets/img/2015/12/2015-12-28_23-05-11.png" alt="" /></p>

<p>This is good way to give you an overview of stuff I’ve been working on lately (over a year already) in order for you to decide whether this is something valuable and useful for you and projects you are working on.</p>

<p>These modules, libraries and frameworks have seen daylight only thanks to my library’s consumers, company customers, project’s contributors and my personal life motivators.</p>

<p>I would like to <strong>thank you all!</strong></p>

<h3 id="featureswitch">FeatureSwitch</h3>

<p>Looking at usage, downloads, questions and shown interest - in my opinion this is one of the most successful projects I’ve been busy with.</p>

<p>I was set on the project where a lot of <code class="language-plaintext highlighter-rouge">if/else</code> statements were typed just to check if this piece of code, that brings some value or adds some functionality to the project, is accessible and executable by the user, batch job and any other consumer of that code fragment. At that point an idea was born about more automatic and easier way to check these features and enable or disable those depending on outer environment, triggers or some arbitrary piece of code that tells library if feature is accessible in this context. Over the years - FeatureSwitch library grew into separate modules and adapters for various purposes. Most common used is plugin controlling feature states from the <a href="http://nuget.episerver.com/en/OtherPages/Package/?packageId=FeatureSwitch.EPiServer">EPiServer</a> administration UI. Even if you are diagnosing your web site using <a href="http://getglimpse.com/">Glimpse</a> platform, you can now turn on/off your features directly from <a href="">Glimpse Tab</a>.</p>

<p>There is still a lot of featurs to implement on my roadmap, but I’m always open to your ideas.</p>

<p>More info: <a href="https://github.com/valdisiljuconoks/FeatureSwitch">here</a>.</p>

<h3 id="imageresizerpluginsepiserverblobreader">ImageResizer.Plugins.EPiServerBlobReader</h3>

<p>Optimizing images for your site and thinking about mobile users is important topic nowadays. One of the most popular library for working with images in web is <a href="http://imageresizing.net/">ImageResizer</a>.</p>

<p>You need to hack some pieces together to tell ImageResizer how to work with EPiServer Blob reader in order to serve images from that storage. Martin Pickering has done brilliant job and stick together <a href="http://world.episerver.com/Code/Martin-Pickering/ImageResizingNet-integration-for-CMS75/">required parts</a> for the EPiServer.</p>

<p>I was really sick and tired of making the same stuff all over again and again - copying code from episever.com and adding to different projects. It was enough and just decided to take a duct tape, and wrap it up into a <a href="http://nuget.episerver.com/en/OtherPages/Package/?packageId=ImageResizer.Plugins.EPiServerBlobReader">NuGet package</a>.</p>

<p>More info: <a href="https://github.com/valdisiljuconoks/ImageResizer.Plugins.EPiServerBlobReader">here</a>.</p>

<h3 id="twitter-bootstrap-aware-episerver-contentarea">Twitter Bootstrap aware EPiServer ContentArea</h3>

<p>Another smaller, but still interesting project is about ContentArea and <a href="http://getbootstrap.com/">Twitter Bootstrap</a>. I would dare to agree that Bootstrap may be the world’s most popular mobile-first and responsive front-end framework.</p>

<p><img src="/assets/img/2015/12/2015-12-30_22-13-41.png" alt="" /></p>

<p>EPiServer demo site (<a href="http://world.episerver.com/download/Demo-Sites/Alloy-Technologies/">AlloyTech</a>) at some point has support for Bootstrap grid system to control the width of the blocks and the content on the content area. The lacking feature was to control the fallback on different form factors (screen sizes).</p>

<p>I had some working proof of concept stuff in few projects. Eventually - what turned out is a <a href="https://nuget.episerver.com/en/OtherPages/Package/?packageId=EPiBootstrapArea">NuGet package</a> that gives you possibility to control display options for every content type on the ContentArea.</p>

<p><img src="/assets/img/2015/12/2015-12-28_23-55-34.png" alt="" /></p>

<p>More info: <a href="https://github.com/valdisiljuconoks/EPiBootstrapArea">here</a></p>

<h3 id="scheduled-jobs-overview">Scheduled Jobs Overview</h3>

<p>Once I noticed an pretty interesting question on EPiServer forums where somebody were asking - what about scheduled jobs sort order in Admin menu. Once they are sorted in one way, next time you check Admin UI - scheduled jobs may be sorted the other way. Hard to find job you are looking for if the list is long enough.</p>

<p>This may become a bit annoying when you are dealing with EPiServer project where scheduled job count may exceed Content Type count :)</p>

<p>In the same EPiServer project we had pretty important scheduling times for our jobs, list of jobs hardly fitted on single page and there were no easy way to double-check whether job is enabled, was the last run cycle successful and when is next scheduled execution time. These were regular complaints from DevOps.</p>

<p>Decided to create some plugin that may display all these values on single page, giving DevOps an executive overview of all scheduled jobs, their statuses and other important information.</p>

<p><img src="/assets/img/2015/12/4-1-.png" alt="" /></p>

<p>ScheduledJobsOverview project was created pretty early in my EPiServer career and was one of the first projects were I tried to maintain the code base for ordinary <a href="http://nuget.episerver.com/en/OtherPages/Package/?packageId=TechFellow.ScheduledJobOverview">NuGet package</a> and <a href="http://world.episerver.com/add-ons-page/">EPiServer AddOn</a> at the same time. That made sense for versions where editor (actually packing admin) may install modules themselves. Nowadays - adding a package within developer workflow makes perfect sense. So much hustle back in times when at the moment of deployment you need to deal with changed environment by somebody else.</p>

<p>Kudos goes to <a href="http://world.episerver.com/System/Users-and-profiles/Community-Profile-Card/?userid=effcb213-0e04-de11-b9c4-0018717a8c82">Mathias Kunto</a> for giving an idea on how to augment existing EPiServer Admin UI page and add your own stuff using WebForms Page adapters. Brilliant idea.</p>

<p>More info: <a href="https://github.com/valdisiljuconoks/TechFellow.ScheduledJobOverview">here</a></p>

<h3 id="aspnet-mvc-areas-for-episerver">Asp.Net Mvc Areas for EPiServer</h3>

<p>I’m a big fan of structuring and organizing source code. It was awesome to see that EPiServer reference architecture site for the Commerce part (<a href="https://github.com/episerver/Quicksilver">Quicksilver</a>) introduced so called feature folders. Where they organize code and other assets related to that particular area under single folder. This makes so much easier to reason about code, structure and architecture of the solution.
I was missing only one thing - views or content type renderer templates were located under root folder - where default view engine is looking for. This still felt not so clean and feature folders were implemented only partially.</p>

<p>One of the potential way how to organize code in your web projects - is to use Mvc areas as functionality discriminators.</p>

<p>After a long research and series of experiments (that included several <a href="https://tech-fellow.ghost.io/tag/look-inside/">blog posts</a> from the “insight into EPiServer” series) came to conclusion that Mvc area could be used as grouping element to bundle related functionality together and also as discriminator between various EPiServer sites. Mvc area as discriminator for EPiServer sites is an interesting and easy way how you may organize your project code, content types and other supporting code for particular site.</p>

<p>Eventually <a href="http://nuget.episerver.com/en/OtherPages/Package/?packageId=MvcAreasForEPiServer">NuGet package</a> was rolled out to be beneficial for other as well.</p>

<p>More info: <a href="https://github.com/valdisiljuconoks/MvcAreasForEPiServer">here</a></p>

<h3 id="initialization-modules">Initialization Modules</h3>

<p>Sounds familiar? Well, I was involved in project where EPiServer was not an option, we were building pure Asp.Net Mvc application. Our startup code had some dependencies and also we pulled in some 3rd party libraries that had their own initialization approach. We tried to keep this code simple and modular, but needed to fulfill execution order requirements.</p>

<p>That reminded me EPiServer initialization engine kicking off at the very beginning of the app life cycle. EPiServer served as great piece of inspiration while creating this library.</p>

<p>Package represents my attempt to resolve this requirement and come up with something that others may find useful in their projects as well.</p>

<p>More info: <a href="https://github.com/valdisiljuconoks/InitializableModule">here</a></p>

<h3 id="form-multipart-media-formatter-for-webapi">Form Multipart Media Formatter for WebApi</h3>

<p>And last but not the least..</p>

<p>Have you tried to upload file from your favorite front-end framework to Asp.Net WebApi? Sounds simple, but turned out not to be. Missing part in WebApi architecture was multipart form media binder that should be responsible for understanding incoming request and bind values properly and create <a href="https://msdn.microsoft.com/en-us/library/system.web.httppostedfile(v=vs.110).aspx">HttpPostedFile</a> collection or similar data structure that represents list of files uploaded with incoming request.</p>

<p>Fortunately guy from Ukraine (<a href="https://github.com/iLexDev">Alexander Kozlovskiy</a>) made this happen. My 2 cents were just to pack it as <a href="https://www.nuget.org/packages/MultipartDataMediaFormatter/">NuGet package</a> and use it.</p>

<h3 id="payback-for-being-an-open-sourcer">Payback for being an Open Sourcer</h3>

<p>The case here is interesting. The other day I saw an advertisement on Facebook promoting WebSummit conference and urged you to submit <a href="https://github.com/valdisiljuconoks">GitHub account link</a> to enter contest to find free tickets to next summit in <a href="https://websummit.net/">Lisbon in 2016</a>. I’m not a big fan of such activities as I never won anywhere. Well, I haven’t played hard either..</p>

<p>Anyway, receiving mail like this makes me smile:</p>

<p><img src="/assets/img/2015/12/2015-12-28_23-20-39.png" alt="" /></p>

<p>Read more about <a href="https://websummit.net/open-source-contributors">Open Source contributors</a> contest to get free tickets to next for the WebSummit.</p>

<h2 id="episerver-conference">EPiServer Conference</h2>

<p>Close to the end of the year, EPiServer held an amazing conference in Vegas. Interesting and challenging for me this conference was because it was first time when I had a chance to polish speaking skills in other continent. It was really a fast forward through EPiServer Commerce content in 80 minutes counting in workshop tasks and questions and answers. Anyway - feedback from the audience was quite positive which makes me think that next time I should focus more on some deep dive advanced topic. This is the subject <a href="http://simpleprogrammer.com/">John Sonmez</a> is talking in his book - you need to find your niche, your area you are passion about. Debugging..?! That’s something I’m in.</p>

<p><img src="/assets/img/2015/12/emvp-summit-2015-1-.jpg" alt="" />
<em>Photo: Allan Thraen / Marija Jemuovic Delibasic</em></p>

<h2 id="books-read">Books Read</h2>

<p>It’s pretty hard to imagine professional career without reading the books. Most probably there will be technical and non-technical books in your list. We have to keep balance and not be geeky all the time.</p>

<p>Just to keep list short, would like to share my latest discoveries (first was gifted by an great colleague of mine - <a href="https://twitter.com/ahaneng">Alexander Haneng</a>). Sorted by influence on my career, professional and personal life.</p>

<ul>
  <li><a href="http://www.amazon.com/How-Win-Friends-Influence-People/dp/0671027034">How to win friends and influence people</a> (by Dale Carnegie)</li>
  <li><a href="https://www.manning.com/books/soft-skills">Soft Skills: The Software Developer’s Life Manual</a> (by John Z. Sonmez)</li>
  <li><a href="https://leanpub.com/software-architecture-for-developers">Software Architecture for Developers</a> (by Simon Brown)</li>
  <li><a href="https://leanpub.com/antifragilesoftware">Antifragile Software</a> (by Russ Miles)</li>
</ul>

<p>These books accompanied me on the plane, in the train and while waiting in the queue. My black Kindle is always with me and becomes best buddy in these situations.</p>

<p>Dale Carnegie changed the way I’m dealing with people. I could quote the whole book here, but to be short, the most influential principle from the book that I’m taking with me everywhere:</p>

<blockquote>
  <p>Don’t criticize anyone.</p>
</blockquote>

<p><a href="http://simpleprogrammer.com/">John Sonmez</a> gives you an elegant overview of your profession questioning you all the time - who would you like to become? What’s your goal and how you are going to achieve it? Giving you descriptions of various topics that software developer may wonder about in his/her career. The most interesting, important and influential question you need to ask:</p>

<blockquote>
  <p>How you are going to sell yourself?</p>
</blockquote>

<h2 id="socializing">Socializing</h2>

<p>People skills is an interesting topic. How to deal and work together with them. All the time we are giving with an option to make friends, interact with others and be open.</p>

<p>Conferences is a great possibility to find confederates and friends. Make use of it and enjoy.</p>

<p>Another interesting way to “socialize” is be active in the public, in community you are belonging to. My case is great Microsoft and EPiServer community. Great developers and amazon people. Through these channels, being a <em>Most Valuable Professional</em> (<strong>MVP</strong>) both - in <a href="https://mvp.microsoft.com/en-us/mvp/Valdis%20Iljuconoks-4024626">Microsoft</a> and in <a href="http://world.episerver.com/Articles/Items/EMVP-Announcement/">EPiServer</a> - opens doors to interesting connections and activities.</p>

<p><img src="/assets/img/2015/12/2015-12-30_22-50-11.png" alt="" /></p>

<p>Helping to your community could be done in various ways. My way is to help developers, help them to solve problems, overcome difficulties and achieve greater goals. Most easiest way is to be involved on forums, mentor and help other fellows to solve issues they are facing while working on projects. Be aware that may lead to some “complaints” as well :)</p>

<p><img src="/assets/img/2015/12/2015-12-30_14-58-49.png" alt="" /></p>

<h2 id="crapmanship">#crapmanship</h2>

<p>These days it’s hard to stick to only single area of interest - whether it’s front-end, backend, or something in between. Modern software craftsmanship practitioner runs through all the layers, learns all required tools, observes and understands best practices and patterns. It’s just natural when you are becoming a <a href="https://en.wikipedia.org/wiki/Full-stack_developer">full-stack developer</a> or someone who knows what tool suits best in particular situation.</p>

<p>However recent years show that customers require more and more value to be delivered almost by the same time and money. Leaving only the last vertex of the software project’s <a href="https://en.wikipedia.org/wiki/Project_management_triangle">triangle</a> flexible - <strong>quality</strong>.</p>

<p>Usually “quality” of the first variable that is cut from software development project management equation. This brings up the question - what are we creating in the first place? Is it a craftsmanship or crapmanship we are practicing here?</p>

<p>During the year more and more I was pulled in topics when it comes to estimates. Either it was over energized discussions about <a href="https://twitter.com/search?q=%23noestimates">#noestimates</a> in some conference coffee breaks or just a fact you face in the industry.</p>

<p>Anyhow I can not find the source for this quote, but while reading its origin - it just burned in my brain cells:</p>

<blockquote>
  <p>If there is no probability to finish 30% ahead of the schedule - the schedule is goal, not an estimate.</p>
</blockquote>

<p>It’s a hash tag <code class="language-plaintext highlighter-rouge">#crapmanship</code> I’ll be using to indicate some “interesting” cases while drifting through professional career and stumble upon this topic.</p>

<h2 id="whats-next">What’s next?</h2>

<p>There is plenty of things I would like to do to in the community and help other fellows to be more productive, help customers and partners.</p>

<p>First project that is scheduled for release in early January is something about EPiServer localization. Hope that will make lot of things easier, more productive and less annoying. Stay tuned!</p>

<p>Following John Sonmez recommendations I’m still searching for my niche in this industry and still considering to really deep dive into .Net application debugging, and especially EPiServer projects debugging. I know that it’s not common topic among EPiServer developers as most of the hardcore part has been done by the platform, but still - find it interesting and challenging for me and hope helpful for others as well. So will see. Some blog posts are in draft state already.</p>

<p>EPiServer Commerce is on the radar. Really hope and dive into this platform and become comfortable to talk about really advanced stuff there and main goal is to help out community on EPiServer World forums.</p>

<p>So all in all, I’m confident that 2016 year will bring us more interesting and challenging tasks to complete, .. and goals to achieve.</p>

<p>As usual - happy coding and Happy New Year! :)</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Year Review" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization" /><category term="year review" /><summary type="html"><![CDATA[This is perfect timing for a busy people like us in IT industry to stop by and look back on the path that has been walked and some good things accomplished.]]></summary></entry><entry><title type="html">Update EPiServer Commerce SKU price in lightweight way - Service Api</title><link href="https://tech-fellow.eu/2015/10/17/update-episerver-commerce-sku-price-in-a-lightweight-way/" rel="alternate" type="text/html" title="Update EPiServer Commerce SKU price in lightweight way - Service Api" /><published>2015-10-17T11:30:00+03:00</published><updated>2015-10-17T11:30:00+03:00</updated><id>https://tech-fellow.eu/2015/10/17/update-episerver-commerce-sku-price-in-a-lightweight-way</id><content type="html" xml:base="https://tech-fellow.eu/2015/10/17/update-episerver-commerce-sku-price-in-a-lightweight-way/"><![CDATA[<p>Lately I’ve been playing around EPiServer Service API. I found these interfaces really simple and lightweight way to manipulate with your catalog’s content and characteristics of the items in the catalog.
This blog post will show you the way how you can update SKU prices via these services using REST client library called “<a href="https://github.com/paulcbetts/refit">Refit</a>”. There are tons of various style and type REST client frameworks for accessing and consuming REST services. I do not have any interest in promoting “Refit” here, but found it really convenient way to work with.</p>

<h2 id="getting-started">Getting Started</h2>

<p>You will need to install <code class="language-plaintext highlighter-rouge">EPiServer.ServiceApi.Commerce</code> package from EPiServer’s NuGet feed to add REST service endpoints to your web site’s project.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>PM &gt; Install-Package EPiServer.ServiceApi.Commerce
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This package will also pull down <code class="language-plaintext highlighter-rouge">EPiServer.ServiceApi</code> package that contains some core endpoints for checking version of the Api library or, for instance, issuing access tokens.</p>

<p>Important to note, that in current implementation Service APIs allows only <code class="language-plaintext highlighter-rouge">TLS/SSL</code> access to the endpoints. It means if you are developing locally on IIS Express, you may need to enable SSL settings for the project:</p>

<p><img src="/assets/img/2015/10/2015-10-17_01-17-09.png" alt="" /></p>

<p>If you are running in IIS, then you can issue self-signed certificate to enable SSL connection to the server.</p>

<p>If you still experience TLS/SSL connection handshake failure (client app can’t make connection to target server because of self-signed certificate is not trusted, even if you added it to trusted CA root) you can for development purposes add exception to <code class="language-plaintext highlighter-rouge">ServicePointManager</code> to trust all certificates:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="n">ServicePointManager</span><span class="p">.</span><span class="n">ServerCertificateValidationCallback</span> <span class="p">+=</span>
    <span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="n">cert</span><span class="p">,</span> <span class="n">chain</span><span class="p">,</span> <span class="n">sslPolicyErrors</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="k">true</span><span class="p">;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>NB!</strong> Don’t forget to remove this line for production use!</p>

<h2 id="verify-service-endpoints">Verify Service Endpoints</h2>

<p>After you have installed package and re-compiled, re-launched the solution and login in CMS, you should be able to navigate to <code class="language-plaintext highlighter-rouge">https://localhost:44300/episerverapi/version</code> and see similar response:</p>

<p><img src="/assets/img/2015/10/2015-10-17_01-13-08.png" alt="" /></p>

<p>Which means that Service Api were registered correctly and at least <code class="language-plaintext highlighter-rouge">/version</code> route is working and you can access Api’s version information.</p>

<h2 id="define-service-contract-interface">Define Service Contract Interface</h2>

<p>“Refit” library is using interface for generating client interceptor type that you can use to call REST endpoint.
For simplicity let’s start with very basic set of methods needed for now to verify working state of the Service API endpoints.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">AccessTokenRequest</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">AccessTokenRequest</span><span class="p">(</span><span class="kt">string</span> <span class="n">username</span><span class="p">,</span> <span class="kt">string</span> <span class="n">password</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">Username</span> <span class="p">=</span> <span class="n">username</span><span class="p">;</span>
        <span class="n">Password</span> <span class="p">=</span> <span class="n">password</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="kt">string</span> <span class="n">Username</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Password</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

    <span class="p">[</span><span class="nf">AliasAs</span><span class="p">(</span><span class="s">"grant_type"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">GrantType</span> <span class="p">=&gt;</span> <span class="s">"password"</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">AccessTokenResponse</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">JsonProperty</span><span class="p">(</span><span class="s">"access_token"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Token</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

    <span class="p">[</span><span class="nf">JsonProperty</span><span class="p">(</span><span class="s">"token_type"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Type</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

    <span class="p">[</span><span class="nf">JsonProperty</span><span class="p">(</span><span class="s">"expires_in"</span><span class="p">)]</span>
    <span class="k">public</span> <span class="kt">int</span> <span class="n">Expires</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">interface</span> <span class="nc">ICommerceServiceApi</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">Get</span><span class="p">(</span><span class="s">"/episerverapi/version"</span><span class="p">)]</span>
    <span class="n">Task</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;</span> <span class="nf">GetVersionAsync</span><span class="p">();</span>

    <span class="p">[</span><span class="nf">Post</span><span class="p">(</span><span class="s">"/episerverapi/token"</span><span class="p">)]</span>
    <span class="n">Task</span><span class="p">&lt;</span><span class="n">AccessTokenResponse</span><span class="p">&gt;</span> <span class="nf">GetTokenAsync</span><span class="p">(</span>
        <span class="p">[</span><span class="nf">Body</span><span class="p">(</span><span class="n">BodySerializationMethod</span><span class="p">.</span><span class="n">UrlEncoded</span><span class="p">)]</span> <span class="n">AccessTokenRequest</span> <span class="n">request</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">AliasAs</code> attribute is needed because we are changing name of the property and how it should be rendered in outgoing POST.
How exactly this interface will be used - we will get back to that!</p>

<h2 id="create-consumer-app">Create Consumer App</h2>

<p>There are no special requirements for the client application. You need to install “Refit” library to work with REST services.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>PM &gt; Install-Package Refit
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="authenticate-against-services">Authenticate Against Services</h2>

<p>You will need an Access Token in order to submit any data to service or in some cases - even talk to the service (Http method - <code class="language-plaintext highlighter-rouge">GET</code>).
User access tokens are issued via <code class="language-plaintext highlighter-rouge">/episerverapi/token</code> endpoint. Currently EPiServer Service Api supports OAuth authentication method called <a href="http://self-issued.info/docs/draft-ietf-oauth-v2-bearer.html">Bearer</a>.</p>

<p>If we take a look at Service API <a href="http://world.episerver.com/documentation/Items/EPiServer-Service-API/Configuration-and-overview/Setting-up-EPiServerServiceApi/">documentation</a>, we can see that it’s required to provide username and password to authenticate against it.
Using extensible and rich WebApi client model, we can create a client message handler that will intercept calls and inject Http Header with this <code class="language-plaintext highlighter-rouge">Bearer</code> authentication data if requested by service endpoints, but don’t worry - we will get there!</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
</pre></td><td class="rouge-code"><pre><span class="k">internal</span> <span class="k">class</span> <span class="nc">AuthenticatedHttpClientHandler</span> <span class="p">:</span> <span class="n">HttpClientHandler</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">Func</span><span class="p">&lt;</span><span class="n">Task</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;&gt;</span> <span class="n">getToken</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">AuthenticatedHttpClientHandler</span><span class="p">(</span><span class="n">Func</span><span class="p">&lt;</span><span class="n">Task</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;&gt;</span> <span class="n">getToken</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">this</span><span class="p">.</span><span class="n">getToken</span> <span class="p">=</span> <span class="n">getToken</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">protected</span> <span class="k">override</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">HttpResponseMessage</span><span class="p">&gt;</span> <span class="nf">SendAsync</span><span class="p">(</span>
                                               <span class="n">HttpRequestMessage</span> <span class="n">request</span><span class="p">,</span>
                                               <span class="n">CancellationToken</span> <span class="n">cancellationToken</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">auth</span> <span class="p">=</span> <span class="n">request</span><span class="p">.</span><span class="n">Headers</span><span class="p">.</span><span class="n">Authorization</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">auth</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="c1">// See if the request has an authorize header</span>
            <span class="kt">var</span> <span class="n">token</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">getToken</span><span class="p">().</span><span class="nf">ConfigureAwait</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>
            <span class="n">request</span><span class="p">.</span><span class="n">Headers</span><span class="p">.</span><span class="n">Authorization</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">AuthenticationHeaderValue</span><span class="p">(</span><span class="n">auth</span><span class="p">.</span><span class="n">Scheme</span><span class="p">,</span>
                                                                          <span class="n">token</span><span class="p">);</span>
        <span class="p">}</span>

        <span class="k">return</span> <span class="k">await</span> <span class="k">base</span><span class="p">.</span><span class="nf">SendAsync</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">cancellationToken</span><span class="p">).</span><span class="nf">ConfigureAwait</span><span class="p">(</span><span class="k">false</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now when client message handler is in place, we can create new instances of REST service client proxy class:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">serviceFacade</span> <span class="p">=</span> <span class="n">RestService</span><span class="p">.</span><span class="n">For</span><span class="p">&lt;</span><span class="n">ICommerceServiceApi</span><span class="p">&gt;(</span>
    <span class="k">new</span> <span class="nf">HttpClient</span><span class="p">(</span><span class="k">new</span> <span class="nf">AuthenticatedHttpClientHandler</span><span class="p">(</span><span class="n">GetTokenAsync</span><span class="p">))</span>
<span class="p">{</span>
    <span class="n">BaseAddress</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">Uri</span><span class="p">(</span><span class="s">"https://localhost:44300"</span><span class="p">)</span>
<span class="p">});</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>“Refit” library allows you explicitly create new client proxy class instance by specifying <code class="language-plaintext highlighter-rouge">HttpClient</code> class to use, which in turn allows you to specify client message handler - that is out newly created “<em>interceptor</em>”.</p>

<p>Method <code class="language-plaintext highlighter-rouge">GetToken</code> is responsible for generating and retrieving access token from the server:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;</span> <span class="nf">GetTokenAsync</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">client</span> <span class="p">=</span> <span class="n">RestService</span><span class="p">.</span><span class="n">For</span><span class="p">&lt;</span><span class="n">ICommerceServiceApi</span><span class="p">&gt;(</span><span class="s">"https://localhost:44300"</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">token</span> <span class="p">=</span> <span class="k">await</span> <span class="n">client</span><span class="p">.</span><span class="nf">GetTokenAsync</span><span class="p">(</span><span class="k">new</span> <span class="nf">AccessTokenRequest</span><span class="p">(</span><span class="s">"admin"</span><span class="p">,</span> <span class="s">"store"</span><span class="p">));</span>
    <span class="k">return</span> <span class="n">token</span><span class="p">.</span><span class="n">Token</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So it really depends on how you secure your user’s credentials - “admin” user is somebody that EPiServer Commerce added by default to the user storage, but it depends on your solution architecture and security requirements - how you store, retrieve and use usernames and corresponding passwords.</p>

<p>After we have supplied client message handler for intercepting requests and adding authentication header to the request, and also providing the way how tokens get generated - we can switch to actual endpoint usage and try to call EPiServer Commerce endpoint for retrieving SKU item prices.</p>

<h2 id="get-sku-price-data">Get SKU Price Data</h2>

<p>To retrieve prices, we need to update Service API service contract interface:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">interface</span> <span class="nc">ICommerceServiceApi</span>
<span class="p">{</span>
    <span class="p">...</span>

    <span class="p">[</span><span class="nf">Get</span><span class="p">(</span><span class="s">"/episerverapi/commerce/entries/{entryCode}/prices"</span><span class="p">)]</span>
    <span class="p">[</span><span class="nf">Headers</span><span class="p">(</span><span class="s">"Authorization: Bearer"</span><span class="p">)]</span>
    <span class="n">Task</span><span class="p">&lt;</span><span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">PriceValueModel</span><span class="p">&gt;&gt;</span> <span class="nf">GetPricesAsync</span><span class="p">(</span><span class="kt">string</span> <span class="n">entryCode</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>From service contract interface you can see that there is an attribute <code class="language-plaintext highlighter-rouge">[Headers("Authorization: Bearer")]</code> added to the <code class="language-plaintext highlighter-rouge">GetProductPricesAsync</code> method. This will kick in client message handler and new token for this request will be generated and associated with new request (method <code class="language-plaintext highlighter-rouge">GetToken()</code> will be called from client message handler).</p>

<p><code class="language-plaintext highlighter-rouge">PriceValueModel</code> is just yet another service contract model class, that describes what’s exactly is on the response for <code class="language-plaintext highlighter-rouge">GetPricesAsync</code> method.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">Serializable</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">PriceValueModel</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">long</span><span class="p">?</span> <span class="n">PriceValueId</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">CatalogEntryCode</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="n">Guid</span> <span class="n">ApplicationId</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">MarketId</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">PriceTypeId</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">PriceCode</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="n">DateTime</span> <span class="n">ValidFrom</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="n">DateTime</span><span class="p">?</span> <span class="n">ValidUntil</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">decimal</span> <span class="n">MinQuantity</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">decimal</span> <span class="n">UnitPrice</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">CurrencyCode</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>So, once we have established connection with REST service endpoint, now we can retrieve prices for our catalog entries.
Let’s assume that there are some catalog entries with known codes (<code class="language-plaintext highlighter-rouge">Awesome-Glasses--Black-L</code> and <code class="language-plaintext highlighter-rouge">Awesome-Glasses--Blue-L</code>).</p>

<p>Usually prices may come from some external ERP systems, most probably generated as physical file on some file share with some weird XML format. Anyway, if we abstract from concrete implementation on how prices may be retrieved, this is the code fragment how you can reach service and ask for prices for these 2 SKUs:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">serviceFacade</span> <span class="p">=</span> <span class="n">RestService</span><span class="p">.</span><span class="n">For</span><span class="p">&lt;</span><span class="n">ICommerceServiceApi</span><span class="p">&gt;(</span>
                        <span class="k">new</span> <span class="nf">HttpClient</span><span class="p">(</span><span class="k">new</span> <span class="nf">AuthenticatedHttpClientHandler</span><span class="p">(</span><span class="n">GetTokenAsync</span><span class="p">))</span>
                        <span class="p">{</span>
                            <span class="n">BaseAddress</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">Uri</span><span class="p">(</span><span class="s">"https://localhost:44300"</span><span class="p">)</span>
                        <span class="p">});</span>

<span class="kt">var</span> <span class="n">newPrices</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Dictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">decimal</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="p">{</span>
        <span class="s">"Awesome-Glasses--Black-L"</span><span class="p">,</span> <span class="m">555.55M</span>
    <span class="p">},</span>
    <span class="p">{</span>
        <span class="s">"Awesome-Glasses--Blue-L"</span><span class="p">,</span> <span class="m">222.22M</span>
    <span class="p">}</span>
<span class="p">};</span>

<span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">newPrice</span> <span class="k">in</span> <span class="n">newPrices</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">existingPriceResult</span> <span class="p">=</span> <span class="k">await</span> <span class="n">serviceFacade</span><span class="p">.</span><span class="nf">GetPricesAsync</span><span class="p">(</span><span class="n">newPrice</span><span class="p">.</span><span class="n">Key</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">existingPriceResult</span><span class="p">.</span><span class="nf">Any</span><span class="p">())</span>
    <span class="p">{</span>
        <span class="c1">// price value exists for this SKU</span>
    <span class="p">}</span>
    <span class="k">else</span>
    <span class="p">{</span>
        <span class="c1">// price does not exist for this SKU</span>
    <span class="p">}</span>

<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Note how elegant is authentication done when accessing REST service?! No, you may not even notice - because it’s unobtrusive and transparent for consumer.</p>

<h2 id="update-prices">Update Prices</h2>

<p>When we can test either SKU has price or hasn’t - we can decide either we need to <code class="language-plaintext highlighter-rouge">POST</code> (create new price for the SKU) or <code class="language-plaintext highlighter-rouge">PUT</code> - update existing price.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
</pre></td><td class="rouge-code"><pre><span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">newPrice</span> <span class="k">in</span> <span class="n">newPrices</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">existingPriceResult</span> <span class="p">=</span> <span class="k">await</span> <span class="n">serviceFacade</span><span class="p">.</span><span class="nf">GetPricesAsync</span><span class="p">(</span><span class="n">newPrice</span><span class="p">.</span><span class="n">Key</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">existingPriceResult</span><span class="p">.</span><span class="nf">Any</span><span class="p">())</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">existingPrice</span> <span class="p">=</span> <span class="n">existingPriceResult</span><span class="p">.</span><span class="nf">First</span><span class="p">();</span>
        <span class="n">existingPrice</span><span class="p">.</span><span class="n">UnitPrice</span> <span class="p">=</span> <span class="n">newPrice</span><span class="p">.</span><span class="n">Value</span><span class="p">;</span>
        <span class="k">await</span> <span class="n">serviceFacade</span><span class="p">.</span><span class="nf">UpdatePriceAsync</span><span class="p">(</span><span class="n">newPrice</span><span class="p">.</span><span class="n">Key</span><span class="p">,</span>
                                             <span class="n">existingPrice</span><span class="p">.</span><span class="n">PriceValueId</span><span class="p">.</span><span class="n">Value</span><span class="p">,</span>
                                             <span class="n">existingPrice</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="k">else</span>
    <span class="p">{</span>
        <span class="k">await</span> <span class="n">serviceFacade</span><span class="p">.</span><span class="nf">SetPriceAsync</span><span class="p">(</span><span class="n">newPrice</span><span class="p">.</span><span class="n">Key</span><span class="p">,</span>
                                          <span class="k">new</span> <span class="n">PriceValueModel</span>
                                          <span class="p">{</span>
                                              <span class="n">CatalogEntryCode</span> <span class="p">=</span> <span class="n">newPrice</span><span class="p">.</span><span class="n">Key</span><span class="p">,</span>
                                              <span class="n">MarketId</span> <span class="p">=</span> <span class="s">"DEFAULT"</span><span class="p">,</span>
                                              <span class="n">CurrencyCode</span> <span class="p">=</span> <span class="s">"USD"</span><span class="p">,</span>
                                              <span class="n">UnitPrice</span> <span class="p">=</span> <span class="n">newPrice</span><span class="p">.</span><span class="n">Value</span><span class="p">,</span>
                                              <span class="n">ValidFrom</span> <span class="p">=</span> <span class="n">DateTime</span><span class="p">.</span><span class="n">UtcNow</span><span class="p">,</span>
                                          <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Code fragment may contain some hard-coded values and placeholders. It’s left unimplemented intentionally :)</p>

<h2 id="summary">Summary</h2>

<p>Service Api is really easy and lightweight way to talk to your Commerce backend and do some stuff there via some scripting language, C# job that is responsible for importing some stuff or updating data in catalog on regular basis. <strong>However</strong> Service Api is not designed to be used externally and be exposed to public usage and, for instance, consumed from even your own site’s front-end part.</p>

<p>Also only <code class="language-plaintext highlighter-rouge">Bearer</code> authentication support we find as limitation for current Service Api service implementation.</p>

<p>Set of Service Api endpoints are really useful when dealing with backend integration cases and scenarios, when you as Commerce site supplier or owner can provide quick and wasy way for 3rd party system to integrate and “push” data into Commerce.</p>

<p>Happy updating!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term="Commerce" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><category term="commerce" /><summary type="html"><![CDATA[Lately I’ve been playing around EPiServer Service API. I found these interfaces really simple and lightweight way to manipulate with your catalog’s content and characteristics of the items in the catalog. This blog post will show you the way how you can update SKU prices via these services using REST client library called “Refit”. There are tons of various style and type REST client frameworks for accessing and consuming REST services. I do not have any interest in promoting “Refit” here, but found it really convenient way to work with.]]></summary></entry><entry><title type="html">Row support added to Bootstrap ContentArea</title><link href="https://tech-fellow.eu/2015/09/20/row-support-added-to-bootstrap-contentarea/" rel="alternate" type="text/html" title="Row support added to Bootstrap ContentArea" /><published>2015-09-20T22:30:00+03:00</published><updated>2015-09-20T22:30:00+03:00</updated><id>https://tech-fellow.eu/2015/09/20/row-support-added-to-bootstrap-contentarea</id><content type="html" xml:base="https://tech-fellow.eu/2015/09/20/row-support-added-to-bootstrap-contentarea/"><![CDATA[<p>With helpful support from Huilaaja (<a href="https://twitter.com/Huilaaja">@huilaaja</a>) <a href="http://getbootstrap.com/">Bootstrap</a> aware <code class="language-plaintext highlighter-rouge">ContentArea</code> renderer (or in other words - <a href="http://nuget.episerver.com/en/OtherPages/Package/?packageId=EPiBootstrapArea">EPiBootstrapArea</a>) got row markup support.
Originally row support documentation for ContentArea you can find in author’s <a href="http://blog.huilaaja.net/2015/09/14/episerver-content-area-renderer-with-row-support/">blog post</a>.
With author’s permission now row support is added to Bootstrap aware content area renderer package.</p>

<h2 id="enable-row-support">Enable Row Support</h2>

<p>For backward compatibility and general idea of Bootstrap content area renderer - row support is disabled by default. You need to enable it explicitly.
If you want to enable row markup support “globally” on every content area, you should configure renderer in following way:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span> <span class="p">(</span><span class="n">SwapRendererInitModule</span><span class="p">))]</span>
<span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">SwapBootstrapRendererInitModule</span> <span class="p">:</span> <span class="n">IConfigurableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureContainer</span><span class="p">(</span><span class="n">ServiceConfigurationContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">context</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="nf">Configure</span><span class="p">(</span><span class="n">container</span> <span class="p">=&gt;</span> <span class="n">container</span>
                                        <span class="p">.</span><span class="n">For</span><span class="p">&lt;</span><span class="n">ContentAreaRenderer</span><span class="p">&gt;()</span>
                                        <span class="p">.</span><span class="n">Use</span><span class="p">&lt;</span><span class="n">BootstrapAwareContentAreaRenderer</span><span class="p">&gt;()</span>
                                        <span class="p">.</span><span class="nf">SetProperty</span><span class="p">(</span><span class="n">i</span> <span class="p">=&gt;</span> <span class="n">i</span><span class="p">.</span><span class="n">RowSupportEnabled</span> <span class="p">=</span> <span class="k">true</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Or you can also enable or disable row markup support on individual <code class="language-plaintext highlighter-rouge">ContentArea</code> property level (request renderer to add row markup for property even it’s globally disabled):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="n">@Html</span><span class="p">.</span><span class="nf">PropertyFor</span><span class="p">(</span><span class="n">m</span> <span class="p">=&gt;</span> <span class="n">m</span><span class="p">.</span><span class="n">MainContentArea</span><span class="p">,</span> <span class="k">new</span> <span class="p">{</span> <span class="n">rowsupport</span> <span class="p">=</span> <span class="k">true</span> <span class="p">})</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="disable-row-support">Disable Row Support</h2>

<p>You can disable row markup support with following methods:</p>

<ul>
  <li>Set configuration property to <code class="language-plaintext highlighter-rouge">false</code>:</li>
</ul>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span> <span class="p">(</span><span class="n">SwapRendererInitModule</span><span class="p">))]</span>
<span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">SwapBootstrapRendererInitModule</span> <span class="p">:</span> <span class="n">IConfigurableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureContainer</span><span class="p">(</span><span class="n">ServiceConfigurationContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">context</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="nf">Configure</span><span class="p">(</span><span class="n">container</span> <span class="p">=&gt;</span> <span class="n">container</span>
                                        <span class="p">.</span><span class="n">For</span><span class="p">&lt;</span><span class="n">ContentAreaRenderer</span><span class="p">&gt;()</span>
                                        <span class="p">.</span><span class="n">Use</span><span class="p">&lt;</span><span class="n">BootstrapAwareContentAreaRenderer</span><span class="p">&gt;()</span>
                                        <span class="p">.</span><span class="nf">SetProperty</span><span class="p">(</span><span class="n">i</span> <span class="p">=&gt;</span> <span class="n">i</span><span class="p">.</span><span class="n">RowSupportEnabled</span> <span class="p">=</span> <span class="k">false</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>Do it on property level (even it’s enabled globally):</li>
</ul>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="n">@Html</span><span class="p">.</span><span class="nf">PropertyFor</span><span class="p">(</span><span class="n">m</span> <span class="p">=&gt;</span> <span class="n">m</span><span class="p">.</span><span class="n">MainContentArea</span><span class="p">,</span> <span class="k">new</span> <span class="p">{</span> <span class="n">rowsupport</span> <span class="p">=</span> <span class="k">false</span> <span class="p">})</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>Remove custom initializable module - row markup support is disabled by default.</li>
</ul>

<h2 id="row-support-drawback">Row Support Drawback</h2>

<p>Beware that adding row markup support either globally or locally for particular area you are avoiding original flexibility that was behind creation of this Bootstrap aware content area renderer. Flexibility of fall back to different width on various screen sizes.
For instance, consider following markup:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;div&gt;</span>
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"row row0"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"block editorialblock col-lg-4 col-md-6"</span><span class="nt">&gt;</span>
            ...
        <span class="nt">&lt;/div&gt;</span>
        <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"block editorialblock col-lg-4 col-md-6"</span><span class="nt">&gt;</span>
            ...
        <span class="nt">&lt;/div&gt;</span>
        <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"block editorialblock col-lg-4 col-md-6"</span><span class="nt">&gt;</span>
            ...
        <span class="nt">&lt;/div&gt;</span>
    <span class="nt">&lt;/div&gt;</span>
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"row row1"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"block editorialblock col-lg-6 col-md-12"</span><span class="nt">&gt;</span>
            ...
        <span class="nt">&lt;/div&gt;</span>
        <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"block editorialblock col-lg-6 col-md-12"</span><span class="nt">&gt;</span>
            ...
        <span class="nt">&lt;/div&gt;</span>
    <span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Visually on large screen it looks like this:</p>

<p><img src="/assets/img/2015/09/2015-09-20_22-46-00.png" alt="" /></p>

<p>From markup it’s totally perfect to wrap both first elements into additional row because each of them occupies only half of the screen. But issue here is with smaller screen sizes - let’s say <code class="language-plaintext highlighter-rouge">col-md-*</code>. It’s said that blocks [1-3] should occupy half of the screen size on smaller devices (medium screen size). Then - there is no reason to wrap all 3 blocks inside the same row as on large screens.</p>

<p><img src="/assets/img/2015/09/2015-09-20_22-57-09.png" alt="" /></p>

<p><strong>NB!</strong> This means that it’s not necessary wrap them into single row. Adding row support may end up with fancy and interesting effects. <strong>So be careful!</strong> Portion for block sizes to fill up row is taken from <strong>block’s large screen</strong> size (<code class="language-plaintext highlighter-rouge">col-lg-*</code>).</p>

<p>Happy rowing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term="Bootstrap" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><category term="bootstrap" /><summary type="html"><![CDATA[With helpful support from Huilaaja (@huilaaja) Bootstrap aware ContentArea renderer (or in other words - EPiBootstrapArea) got row markup support. Originally row support documentation for ContentArea you can find in author’s blog post. With author’s permission now row support is added to Bootstrap aware content area renderer package.]]></summary></entry><entry><title type="html">What’s new in FeatureSwitch?</title><link href="https://tech-fellow.eu/2015/09/15/whats-new-in-featureswitch/" rel="alternate" type="text/html" title="What’s new in FeatureSwitch?" /><published>2015-09-15T22:15:00+03:00</published><updated>2015-09-15T22:15:00+03:00</updated><id>https://tech-fellow.eu/2015/09/15/whats-new-in-featureswitch</id><content type="html" xml:base="https://tech-fellow.eu/2015/09/15/whats-new-in-featureswitch/"><![CDATA[<p>It’s been while since last FeatureSwitch library release. Just pushed out a bit of stuff held under the hood. Some of them are requested by my lovely consumers :)
Here are enlisted some of the latest version features in the library.</p>

<p>1) <em>EPiServer Site Strategy</em>. Now you can use EPiServer’s site strategy to enable or disable feature per particular EPiServer site. With example below feature <code class="language-plaintext highlighter-rouge">ThisFeatureIsOnlyForSite1</code> will only be enabled if request is made against site named “Site1”, otherwise - feature will be disabled.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">EPiServerSite</span><span class="p">(</span><span class="n">Key</span> <span class="p">=</span> <span class="s">"Site1"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ThisFeatureIsOnlyForSite1</span> <span class="p">:</span> <span class="n">BaseFeature</span> <span class="p">{}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>In some enterprise solutions you can actually use multiple sites if needed, separated by comma.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">EPiServerSite</span><span class="p">(</span><span class="n">Key</span> <span class="p">=</span> <span class="s">"Site1, Site2"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ThisFeatureIsOnlyForSite1</span> <span class="p">:</span> <span class="n">BaseFeature</span> <span class="p">{}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>2) <em>Authorized Strategy</em>. Now there is a strategy that you can enable for users in specific role. With code below seems like that feature is really important as it will be enabled only for users in “Administrators” group.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">AuthorizedFor</span><span class="p">(</span><span class="n">Key</span> <span class="p">=</span> <span class="s">"Administrators"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">AuthorizedFeature</span> <span class="p">:</span> <span class="n">BaseFeature</span> <span class="p">{}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And also you can “relax” feature a bit and make it available for “Administrators” and also for “CmsAdmins”.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">AuthorizedFor</span><span class="p">(</span><span class="n">Key</span> <span class="p">=</span> <span class="s">"Administrators, CmsAdmins"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">AuthorizedFeature</span> <span class="p">:</span> <span class="n">BaseFeature</span> <span class="p">{}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Feature will be disabled for users in any other role (also for users that are not in any role).</p>

<p>3) <em>Cloud Configuration Support</em>. As we are moving more and more to skies, thought it may be valuable to have some tiny cloud (Microsoft Azure) support in FeatureSwitch library. Now by installing <code class="language-plaintext highlighter-rouge">FeatureSwitch.Azure</code> package you can get access to features that store their state in cloud and is accessible via <code class="language-plaintext highlighter-rouge">CloudConfigurationManager</code>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">CloudConfiguration</span><span class="p">(</span><span class="n">Key</span> <span class="p">=</span> <span class="s">"CloudFeature"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ThisFeatureIsInTheSkies</span> <span class="p">:</span> <span class="n">BaseFeature</span> <span class="p">{}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Settings are easily available via Azure management portal.</p>

<p><img src="/assets/img/2015/09/cloud-feature-1.png" alt="" /></p>

<p>4) <em>EPiServer 6.0 support dropped</em>. Your open source code at the moment of writing already turns into liability you commit yourself to support and maintain. At some point you just feel that you need to let some things go. In this release of <code class="language-plaintext highlighter-rouge">FeatureSwitch</code> library EPiServer v6.0 support was thing that was dropped.
For developers it means that package <code class="language-plaintext highlighter-rouge">FeatureSwitch.EPiServer</code> from version <a href="http://nuget.episerver.com/en/OtherPages/Package/?packageId=FeatureSwitch.EPiServer&amp;packageVersion=2.4.0">2.4.0</a> is now requiring EPiServer v8.0 version.</p>

<p>If you have previously used <code class="language-plaintext highlighter-rouge">FeatureSwitch.EPiServer.Cms75</code> package (up to <a href="http://nuget.episerver.com/en/OtherPages/Package/?packageId=FeatureSwitch.EPiServer.Cms75&amp;packageVersion=2.3.2">v2.3.2</a>) to target specifically version 7.x of EPiServer, you can now either update the package or remove it and install <code class="language-plaintext highlighter-rouge">FeatureSwitch.EPiServer</code>. Updated version of the package is empty and is referencing <code class="language-plaintext highlighter-rouge">FeatureSwitch.EPiServer</code> package (this is required for backward compatibility and easier upgrade path for consumers of Cms75 package).</p>

<p>Anyway, as always feedback is much appreciated.</p>

<p>Happy featuring!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Open Source" /><category term="Feature Switch" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="feature switch" /><summary type="html"><![CDATA[It’s been while since last FeatureSwitch library release. Just pushed out a bit of stuff held under the hood. Some of them are requested by my lovely consumers :) Here are enlisted some of the latest version features in the library.]]></summary></entry><entry><title type="html">Creating EPiServer Site Menu out of Block Driven Content</title><link href="https://tech-fellow.eu/2015/09/07/create-episerver-site-menu-out-of-block-driven-content/" rel="alternate" type="text/html" title="Creating EPiServer Site Menu out of Block Driven Content" /><published>2015-09-07T09:30:00+03:00</published><updated>2015-09-07T09:30:00+03:00</updated><id>https://tech-fellow.eu/2015/09/07/create-episerver-site-menu-out-of-block-driven-content</id><content type="html" xml:base="https://tech-fellow.eu/2015/09/07/create-episerver-site-menu-out-of-block-driven-content/"><![CDATA[<p>For one of our great customers we needed to make site out of just only few pages and lots of blocks. It reminds sort of single page application, just there is no client-side behavior as original SPA projects have.
Anyway, in the middle of the project we came to task to make site menu. As we know it’s quite easy to build site menu out of the pages and subpages and children pages of these subpages. But this time, we had almost no page structure in CMS, but instead, we have lots of <code class="language-plaintext highlighter-rouge">ContentArea</code> items. So we decided to play around CA items and try to build site’s menu out of these items.</p>

<h2 id="site-structure">Site Structure</h2>

<p>This is a prototype of project we had for the customer.</p>

<p><img src="/assets/img/2015/09/2015-09-06_21-23-59.png" alt="" /></p>

<p>Almost everything was driven by blocks and there were just few pages types only.</p>

<h2 id="menu-structure">Menu Structure</h2>

<p>It of course depends on precise project’s requirements, but site menu may look something like this:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;ul&gt;</span>
    <span class="nt">&lt;li&gt;</span>Menu Item 1
        <span class="nt">&lt;ul&gt;</span>
            <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"..."</span><span class="nt">&gt;</span>Submenu item 1<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
            <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"..."</span><span class="nt">&gt;</span>Submenu item 2<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
            <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"..."</span><span class="nt">&gt;</span>Submenu item 3<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
        <span class="nt">&lt;/ul&gt;</span>
    <span class="nt">&lt;/li&gt;</span>
    <span class="nt">&lt;li&gt;</span>Menu Item 2
        ...
    <span class="nt">&lt;/li&gt;</span>
    ...
<span class="nt">&lt;/ul&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Visually it should look like this:</p>

<p><img src="/assets/img/2015/09/2015-09-06_21-38-19-1.png" alt="" /></p>

<p>You see that we will need to generate links directly to blocks on the page. For instance <code class="language-plaintext highlighter-rouge">Page2</code> should be not generated in menu at all.</p>

<h2 id="preparing-content-types-to-be-in-menu">Preparing content types to be in menu</h2>

<h3 id="adjusting-page-types">Adjusting Page Types</h3>

<p>We need add special “marker” interface to the pages which should be part of the menu and those content should be as menu items to which visitor can navigate to.
Adding this interface and marking necessary page types with it - menu generator will be able to find where exactly content of the page is located and then proceed with submenu item generation out of the blocks.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">interface</span> <span class="nc">IHaveContent</span>
<span class="p">{</span>
    <span class="n">ContentArea</span> <span class="n">MainContentArea</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">ArticlePageWithContent</span> <span class="p">:</span> <span class="n">PageBase</span><span class="p">,</span> <span class="n">IHaveContent</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">CultureSpecific</span><span class="p">]</span>
    <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"Content"</span><span class="p">,</span>
        <span class="n">GroupName</span> <span class="p">=</span> <span class="n">SystemTabNames</span><span class="p">.</span><span class="n">Content</span><span class="p">,</span>
        <span class="n">Order</span> <span class="p">=</span> <span class="m">10</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">virtual</span> <span class="n">ContentArea</span> <span class="n">MainContentArea</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="adjusting-block-types">Adjusting Block Types</h3>

<p>While it’s easy to make decision whether page should be part of the menu (based on its <code class="language-plaintext highlighter-rouge">DisplayInMenu</code> attribute that is easily available for the editors), we need to add something similar for the blocks that will be placed inside Content Area - to filter out blocks that we do not need while generating menu content.</p>

<p>For this reason we can create “marker” interface - that will help us to distinguish between and understand which blocks we need to filter away.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">interface</span> <span class="nc">IMenuItem</span>
<span class="p">{</span>
    <span class="kt">bool</span> <span class="n">ShowInMenu</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="kt">string</span> <span class="n">DisplayNameInMenu</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Later those block types that need to be part of the menu - can implement this interface, so menu generator can filter be these.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ContentType</span><span class="p">(</span><span class="n">DisplayName</span> <span class="p">=</span> <span class="s">"EditorialBlock"</span><span class="p">,</span> <span class="n">GUID</span> <span class="p">=</span> <span class="s">"..."</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">EditorialBlock</span> <span class="p">:</span> <span class="n">BlockDataBase</span><span class="p">,</span> <span class="n">IMenuItem</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">CultureSpecific</span><span class="p">]</span>
    <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"Show in menu"</span><span class="p">,</span>
        <span class="n">GroupName</span> <span class="p">=</span> <span class="n">SystemTabNames</span><span class="p">.</span><span class="n">Content</span><span class="p">,</span>
        <span class="n">Order</span> <span class="p">=</span> <span class="m">10</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">virtual</span> <span class="kt">bool</span> <span class="n">ShowInMenu</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

    <span class="p">[</span><span class="n">CultureSpecific</span><span class="p">]</span>
    <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">Name</span> <span class="p">=</span> <span class="s">"Display name in menu"</span><span class="p">,</span>
        <span class="n">GroupName</span> <span class="p">=</span> <span class="n">SystemTabNames</span><span class="p">.</span><span class="n">Content</span><span class="p">,</span>
        <span class="n">Order</span> <span class="p">=</span> <span class="m">20</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">virtual</span> <span class="kt">string</span> <span class="n">DisplayNameInMenu</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>However - this interface is to restricted to block types only. Menu item generation also applies (and works) for the page types that are partially rendered through <code class="language-plaintext highlighter-rouge">ContentArea</code>.</p>

<h2 id="generating-the-menu">Generating the Menu</h2>

<h3 id="menu-view-model">Menu View model</h3>

<p>Next we need to produce view-model for the menu to generate markup from. This is straight forward:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">MenuItem</span>
<span class="p">{</span>

    <span class="k">public</span> <span class="nf">MenuItem</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">Items</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">SubMenuItem</span><span class="p">&gt;();</span>
        <span class="n">DisplayName</span> <span class="p">=</span> <span class="n">name</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="kt">string</span> <span class="n">DisplayName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">SubMenuItem</span><span class="p">&gt;</span> <span class="n">Items</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">internal</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">SubMenuItem</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">SubMenuItem</span><span class="p">(</span><span class="kt">string</span> <span class="n">blockId</span><span class="p">,</span> <span class="kt">string</span> <span class="n">displayName</span><span class="p">,</span> <span class="kt">string</span> <span class="n">targetPageAddress</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">DisplayName</span> <span class="p">=</span> <span class="n">displayName</span><span class="p">;</span>
        <span class="n">MenuLink</span> <span class="p">=</span> <span class="n">targetPageAddress</span> <span class="p">+</span> <span class="s">"#"</span> <span class="p">+</span> <span class="n">blockId</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="kt">string</span> <span class="n">DisplayName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">MenuLink</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Don’t worry - we will get back to the bookmark field in just a second.</p>

<h3 id="menu-controller">Menu Controller</h3>

<p>This is personal preference, but we usually extract common rendering (like menu) into its own controller (or merge together with other “common” part of the site) and let Asp.Net Mvc to invoke it correctly.</p>

<p>In your <code class="language-plaintext highlighter-rouge">_SiteLayout.cshtml</code> file you may write something similar:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="p">...</span>
<span class="p">&lt;</span><span class="n">body</span><span class="p">&gt;</span>
    <span class="n">@Html</span><span class="p">.</span><span class="nf">Action</span><span class="p">(</span><span class="s">"Menu"</span><span class="p">,</span> <span class="s">"Common)
</span>    <span class="p">...</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Which in turn will invoke this action from <code class="language-plaintext highlighter-rouge">CommonController.cs</code>:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">CommonController</span> <span class="p">:</span> <span class="n">Controller</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">ChildActionOnly</span><span class="p">]</span>
    <span class="k">public</span> <span class="n">ActionResult</span> <span class="nf">Menu</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="p">...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This will be the place where we will put our menu generation code.</p>

<h3 id="get-list-of-pages-to-show-in-menu">Get list of pages to show in menu</h3>

<p>First of all we need to get list of pages as 1st level menu items:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">ChildActionOnly</span><span class="p">]</span>
<span class="k">public</span> <span class="n">ActionResult</span> <span class="nf">Menu</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">menuItems</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">MenuItem</span><span class="p">&gt;();</span>
    <span class="kt">var</span> <span class="n">filter</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">FilterContentForVisitor</span><span class="p">();</span>

    <span class="kt">var</span> <span class="n">pages</span> <span class="p">=</span> <span class="n">_loader</span><span class="p">.</span><span class="n">GetChildren</span><span class="p">&lt;</span><span class="n">IContent</span><span class="p">&gt;(</span><span class="n">ContentReference</span><span class="p">.</span><span class="n">StartPage</span><span class="p">).</span><span class="nf">ToList</span><span class="p">();</span>
    <span class="n">filter</span><span class="p">.</span><span class="nf">Filter</span><span class="p">(</span><span class="n">pages</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">filteredPages</span> <span class="p">=</span> <span class="n">pages</span><span class="p">.</span><span class="n">Cast</span><span class="p">&lt;</span><span class="n">PageData</span><span class="p">&gt;().</span><span class="nf">Where</span><span class="p">(</span><span class="n">p</span> <span class="p">=&gt;</span> <span class="n">p</span><span class="p">.</span><span class="n">VisibleInMenu</span><span class="p">);</span>

    <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">page</span> <span class="k">in</span> <span class="n">filteredPages</span><span class="p">.</span><span class="n">OfType</span><span class="p">&lt;</span><span class="n">IHaveContent</span><span class="p">&gt;())</span>
    <span class="p">{</span>
        <span class="p">....</span>
    <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then we need to access page’s content area and generate submenu items out of those blocks (code is long enough as it’s a bit defensive):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
</pre></td><td class="rouge-code"><pre><span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">page</span> <span class="k">in</span> <span class="n">filteredPages</span><span class="p">.</span><span class="n">OfType</span><span class="p">&lt;</span><span class="n">IHaveContent</span><span class="p">&gt;())</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">contentArea</span> <span class="p">=</span> <span class="n">page</span><span class="p">.</span><span class="n">MainContentArea</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">contentArea</span> <span class="p">==</span> <span class="k">null</span> <span class="p">||</span> <span class="n">contentArea</span><span class="p">.</span><span class="n">FilteredItems</span> <span class="p">==</span> <span class="k">null</span> <span class="p">||</span> <span class="p">!</span><span class="n">contentArea</span><span class="p">.</span><span class="n">FilteredItems</span><span class="p">.</span><span class="nf">Any</span><span class="p">())</span>
    <span class="p">{</span>
        <span class="k">continue</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="kt">var</span> <span class="n">pageData</span> <span class="p">=</span> <span class="n">page</span> <span class="k">as</span> <span class="n">PageData</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">pageData</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">continue</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="kt">var</span> <span class="n">menuItem</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">MenuItem</span><span class="p">(</span><span class="n">pageData</span><span class="p">.</span><span class="n">Name</span><span class="p">);</span>

    <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">block</span> <span class="k">in</span> <span class="n">contentArea</span><span class="p">.</span><span class="n">FilteredItems</span><span class="p">.</span><span class="nf">Select</span><span class="p">(</span><span class="n">b</span> <span class="p">=&gt;</span> <span class="n">_loader</span><span class="p">.</span><span class="n">Get</span><span class="p">&lt;</span><span class="n">IContent</span><span class="p">&gt;(</span><span class="n">b</span><span class="p">.</span><span class="n">ContentLink</span><span class="p">)).</span><span class="n">OfType</span><span class="p">&lt;</span><span class="n">IMenuItem</span><span class="p">&gt;())</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(!</span><span class="n">block</span><span class="p">.</span><span class="n">ShowInMenu</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">continue</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="kt">var</span> <span class="n">blockInstance</span> <span class="p">=</span> <span class="n">block</span> <span class="k">as</span> <span class="n">IContent</span><span class="p">;</span>

        <span class="k">if</span> <span class="p">(</span><span class="n">blockInstance</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">continue</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="kt">var</span> <span class="n">pageAddress</span> <span class="p">=</span> <span class="n">_resolver</span><span class="p">.</span><span class="nf">GetUrl</span><span class="p">(</span><span class="n">pageData</span><span class="p">.</span><span class="n">ContentLink</span><span class="p">);</span>

        <span class="kt">var</span> <span class="n">subMenuItem</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SubMenuItem</span><span class="p">(</span><span class="n">blockInstance</span><span class="p">.</span><span class="nf">GetContentBookmarkName</span><span class="p">(),</span>
                                          <span class="p">!</span><span class="kt">string</span><span class="p">.</span><span class="nf">IsNullOrEmpty</span><span class="p">(</span><span class="n">block</span><span class="p">.</span><span class="n">DisplayNameInMenu</span><span class="p">)</span>
                                              <span class="p">?</span> <span class="n">block</span><span class="p">.</span><span class="n">DisplayNameInMenu</span>
                                              <span class="p">:</span> <span class="n">blockInstance</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span>
                                          <span class="n">pageAddress</span><span class="p">);</span>

        <span class="n">menuItem</span><span class="p">.</span><span class="n">Items</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">subMenuItem</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="n">menuItems</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">menuItem</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Basically code fragment above will look for all blocks inside our known <code class="language-plaintext highlighter-rouge">ContentArea</code>, will filter out only those blocks that expressed willingness to be part of the menu, and out of these blocks new <code class="language-plaintext highlighter-rouge">SubMenuItem</code> object instances are added to the Menu’s <code class="language-plaintext highlighter-rouge">ViewModel</code>.</p>

<h3 id="generating-the-markup">Generating the Markup</h3>

<p>Next what we need is actual markup that will be used to render the menu. I’m not a web designer and this is the best what I could come up with :)</p>

<pre><code class="language-razor">@model List&lt;DynamicMenu.Controllers.MenuItem&gt;

&lt;div&gt;
    Menu:

    &lt;div&gt;
        &lt;ul&gt;
            @foreach(var menuItem in Model)
            {
                &lt;li&gt;
                    @menuItem.DisplayName
                    @if(menuItem.Items.Any())
                    {
                        &lt;ul&gt;
                            @foreach(var subMenuItem in menuItem.Items)
                            {
                                &lt;li&gt;&lt;a href="@subMenuItem.MenuLink"&gt;@subMenuItem.DisplayName&lt;/a&gt;&lt;/li&gt;
                            }
                        &lt;/ul&gt;
                    }
                &lt;/li&gt;
            }
        &lt;/ul&gt;
    &lt;/div&gt;
&lt;/div&gt;
</code></pre>

<h3 id="bookmarking-the-content">Bookmarking the content</h3>

<p>So far so good. We now have view-model that contains data about the menu, we got controller that fills in view-model, we have markup that is rendering the menu.
Next thing that we need to do is to make sure that visitors will be able to navigate to particular block on particular page.
For this to work we need to make sure that links in menu are generated with bookmarks.
Let’s start from beginning. First, we need to fill in view-model data with submenu items containing some sort of bookmark name (Html bookmark links starts with <code class="language-plaintext highlighter-rouge">#</code> sign followed by name of the bookmark).
For this, I introduced extensions method for the <code class="language-plaintext highlighter-rouge">IContent</code>:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">ContentExtensions</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="nf">GetContentBookmarkName</span><span class="p">(</span><span class="k">this</span> <span class="n">IContent</span> <span class="n">content</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">content</span><span class="p">.</span><span class="nf">GetOriginalType</span><span class="p">().</span><span class="n">Name</span><span class="p">.</span><span class="nf">ToLowerInvariant</span><span class="p">()</span>
               <span class="p">+</span> <span class="s">"_"</span>
               <span class="p">+</span> <span class="n">content</span><span class="p">.</span><span class="n">ContentLink</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This extension method generates bookmark name similar to <code class="language-plaintext highlighter-rouge">"{name of the block type}_{id of the block}"</code>, e.g. <code class="language-plaintext highlighter-rouge">"editorialblock_556"</code>. This combination should ensure uniquality of the bookmarks across the page.</p>

<p>So submenu item markup may look like this:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">"/targetpage#editorialblock_556"</span><span class="nt">&gt;</span>Block 1<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Next (most interesting part for me), we need to somehow make EPiServer to generate these unique bookmark names exactly at the DOM location where block starts to render its content.
I couldn’t find more ideal candidate for this ar <code class="language-plaintext highlighter-rouge">ContentAreaRenderer</code> (you can read more about what exactly is customizable in ContentArea rendering pipeline <a href="https://tech-fellow.eu/2015/06/11/content-area-under-the-hood-part-3/">in my post</a>).</p>

<p>So one of the possibility is to completely override <code class="language-plaintext highlighter-rouge">ContentAreaRenderer</code> and add <code class="language-plaintext highlighter-rouge">id</code> attribute for the block tag element.
Another way (as most of our projects use Bootstrap), I used <a href="http://nuget.episerver.com/en/OtherPages/Package/?packageId=EPiBootstrapArea">EPiBootstrapArea</a> library and extended <code class="language-plaintext highlighter-rouge">ContentAreaRenderer</code> used there:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span> <span class="p">(</span><span class="n">SwapRendererInitModule</span><span class="p">))]</span>
<span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">SwapBootstrapRendererInitModule</span> <span class="p">:</span> <span class="n">IConfigurableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureContainer</span><span class="p">(</span><span class="n">ServiceConfigurationContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">context</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="nf">Configure</span><span class="p">(</span><span class="n">container</span> <span class="p">=&gt;</span> <span class="n">container</span>
                                        <span class="p">.</span><span class="n">For</span><span class="p">&lt;</span><span class="n">ContentAreaRenderer</span><span class="p">&gt;()</span>
                                        <span class="p">.</span><span class="n">Use</span><span class="p">&lt;</span><span class="n">AnotherBootstrapAwareContentAreaRenderer</span><span class="p">&gt;());</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span> <span class="p">{}</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">AnotherBootstrapAwareContentAreaRenderer</span> <span class="p">:</span> <span class="n">BootstrapAwareContentAreaRenderer</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">AnotherBootstrapAwareContentAreaRenderer</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="nf">SetElementStartTagRenderCallback</span><span class="p">(</span><span class="n">GenerateIdAtBlockElement</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="k">void</span> <span class="nf">GenerateIdAtBlockElement</span><span class="p">(</span><span class="n">HtmlNode</span> <span class="n">blockElement</span><span class="p">,</span> <span class="n">ContentAreaItem</span> <span class="n">contentAreaItem</span><span class="p">,</span> <span class="n">IContent</span> <span class="n">content</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">blockElement</span><span class="p">.</span><span class="n">Attributes</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="s">"id"</span><span class="p">,</span> <span class="n">content</span><span class="p">.</span><span class="nf">GetContentBookmarkName</span><span class="p">());</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Method <code class="language-plaintext highlighter-rouge">SetElementStartTagRenderCallback</code> gives me possibility to hook inside <code class="language-plaintext highlighter-rouge">ContentAreaItem</code> rendering process and do some magic with element DOM object (<code class="language-plaintext highlighter-rouge">HtmlNode</code> is coming from <a href="https://www.nuget.org/packages/HtmlAgilityPack">HtmlAgilityPack</a> library).</p>

<p>So eventually what we will get is <code class="language-plaintext highlighter-rouge">ContentAreaItem</code> starting with following markup:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"..."</span> <span class="na">id=</span><span class="s">"editorialblock_556"</span> <span class="err">...</span><span class="nt">&gt;</span>
    ...
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Which means that we now can connect menu item link with block on the page through this auto-generated bookmark name.</p>

<h2 id="summary">Summary</h2>

<p>To generate site menu out of content driven mostly by blocks you will need:</p>

<ul>
  <li>to prepare page and block types to take part in menu generation process (use some “marker” interfaces)</li>
  <li>find pages that will be added to the menu</li>
  <li>filter out content (list of <code class="language-plaintext highlighter-rouge">IContent</code> from which particular page consists of)</li>
  <li>also use another “marker” interface to extract data out of content required for the menu (like, menu item display name)</li>
  <li>make sure that you generate links in the menu with bookmark that will be later generated into <code class="language-plaintext highlighter-rouge">ContentAreaItem</code> starting tag element</li>
  <li>adjust <code class="language-plaintext highlighter-rouge">ContentAreaRenderer</code> to include block’s bookmark name as <code class="language-plaintext highlighter-rouge">id</code> attribute of the block’s start tag element;</li>
</ul>

<p>Happy site menu’ing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[For one of our great customers we needed to make site out of just only few pages and lots of blocks. It reminds sort of single page application, just there is no client-side behavior as original SPA projects have. Anyway, in the middle of the project we came to task to make site menu. As we know it’s quite easy to build site menu out of the pages and subpages and children pages of these subpages. But this time, we had almost no page structure in CMS, but instead, we have lots of ContentArea items. So we decided to play around CA items and try to build site’s menu out of these items.]]></summary></entry><entry><title type="html">Asp.Net Mvc Areas - Packed as NuGet</title><link href="https://tech-fellow.eu/2015/08/15/asp-net-mvc-areas-packed-as-nuget/" rel="alternate" type="text/html" title="Asp.Net Mvc Areas - Packed as NuGet" /><published>2015-08-15T09:30:00+03:00</published><updated>2015-08-15T09:30:00+03:00</updated><id>https://tech-fellow.eu/2015/08/15/asp-net-mvc-areas-packed-as-nuget</id><content type="html" xml:base="https://tech-fellow.eu/2015/08/15/asp-net-mvc-areas-packed-as-nuget/"><![CDATA[<p>If you would want to add Asp.Net Areas support to your EPiServer site, you would need to copy some files from my <a href="https://tech-fellow.eu/2015/01/21/full-support-for-asp-net-mvc-areas-in-episerver-7-5/">previous blog post</a>. Copying files from someone’s blog posts seems to be good idea, but it’s a bit problematic in case of updates or changes. If so, then we share common vision that by installing NuGet package, your project gets up-to-date support for Asp.Net Mvc Areas.</p>

<p><img src="/assets/img/2015/08/nuget-2.png" alt="" /></p>

<p>For that reason I packed up Asp.Net Mvc Areas support into NuGet package, for you guys. You may just need to install it and configure a bit if needed, to get things up and running.</p>

<h2 id="getting-started">Getting Started</h2>

<p>1) Install NuGet package:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>PM&gt; Install-Package MvcAreasForEPiServer
</pre></td></tr></tbody></table></code></pre></div></div>

<p>2) Register Mvc Areas. You have plenty of places to register this code fragment (<code class="language-plaintext highlighter-rouge">Application_Start</code>, <code class="language-plaintext highlighter-rouge">Global.RegisterRoutes</code>, <code class="language-plaintext highlighter-rouge">InitializableModule</code>, etc).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="n">AreaConfiguration</span><span class="p">.</span><span class="nf">RegisterAllAreas</span><span class="p">();</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>By default configuration setting to detect Mvc Area by controller (<code class="language-plaintext highlighter-rouge">EnableAreaDetectionByController</code>) will be enabled.</p>

<h2 id="configuration">Configuration</h2>

<p>If you want to disable Mvc Area detection by controller, you can choose configuration settings to customize this behavior during areas registration procedure.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">EPiServer</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ConfigureAreasSupportModule</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">AreaConfiguration</span><span class="p">.</span><span class="nf">RegisterAllAreas</span><span class="p">(</span><span class="n">config</span> <span class="p">=&gt;</span>
        <span class="p">{</span>
            <span class="n">config</span><span class="p">.</span><span class="n">EnableAreaDetectionByController</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
            <span class="n">config</span><span class="p">.</span><span class="n">EnableAreaDetectionBySite</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
        <span class="p">});</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>There are two configuration settings:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">EnableAreaDetectionByController</code>: this setting will make sure that Mvc Area is detected while executing controller for particular content type in that area;</li>
  <li><code class="language-plaintext highlighter-rouge">EnableAreaDetectionBySite</code>: this setting will make sure that Mvc Area is detected when accessing EPiServer site that is also defined as Mvc Area;</li>
</ul>

<p>More info about <strong>general insights</strong> of Mvc Area support for EPiServer sites: <a href="http://tech-fellow.eu/2015/01/22/full-support-asp-net-mvc-areas-episerver-7-5/">here</a>
More info about using Mvc Areas as EPiServer’s <strong>site discriminators</strong>: <a href="https://tech-fellow.eu/2015/08/10/asp-net-mvc-areas-in-episerver-part-2/">here</a></p>

<p>Happy slicing and dicing into areas!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[If you would want to add Asp.Net Areas support to your EPiServer site, you would need to copy some files from my previous blog post. Copying files from someone’s blog posts seems to be good idea, but it’s a bit problematic in case of updates or changes. If so, then we share common vision that by installing NuGet package, your project gets up-to-date support for Asp.Net Mvc Areas.]]></summary></entry><entry><title type="html">Asp.Net Mvc Areas in EPiServer - Part 2</title><link href="https://tech-fellow.eu/2015/08/10/asp-net-mvc-areas-in-episerver-part-2/" rel="alternate" type="text/html" title="Asp.Net Mvc Areas in EPiServer - Part 2" /><published>2015-08-10T14:30:00+03:00</published><updated>2015-08-10T14:30:00+03:00</updated><id>https://tech-fellow.eu/2015/08/10/asp-net-mvc-areas-in-episerver-part-2</id><content type="html" xml:base="https://tech-fellow.eu/2015/08/10/asp-net-mvc-areas-in-episerver-part-2/"><![CDATA[<p>Asp.Net Mvc Areas is a great way to organize and structure your EPiServer site. Once you have multi-tenant site where the same EPiServer installation with the same set of libraries, styles, script set and other assets is handling more than single site - Asp.Net Mvc Areas become really handy to group particular site’s specific assets and other stuff together under single folder. This also gives developers more obvious and more clear picture of the project setup.</p>

<p>However we all know that there is no <em>native</em> support for Asp.Net Mvc Areas inside EPiServer. I’ve been <a href="https://tech-fellow.eu/2015/01/21/full-support-for-asp-net-mvc-areas-in-episerver-7-5/">trying to add</a> some basic support for EPiServer installations to utilize Asp.Net Mvc Areas for developers to organize their stuff.
Anyway there is room for improvement. This blog post is about how to customize Asp.Net Mvc Areas usage in EPiServer projects even more or utilize Mvc Areas as EPiServer’s sites.</p>

<h2 id="mvc-area-as-site-discriminators">Mvc Area as Site Discriminators</h2>

<p>In order for us to be on the same context, let me enlist requirements for areas and its usage when serving multi-tenant sites:</p>

<ul>
  <li>There are two sites in the solution - <code class="language-plaintext highlighter-rouge">site1</code> and <code class="language-plaintext highlighter-rouge">site2</code>;</li>
</ul>

<p><img src="/assets/img/2015/08/ar-0.png" alt="" /></p>

<ul>
  <li>Every site should be implemented as Mvc Area;</li>
  <li>All site related assets should be located inside that area;</li>
  <li>Should be possible to have content type only defined and used in particular site/area;</li>
  <li>Should be possible to have <code class="language-plaintext highlighter-rouge">common content type</code> defined in root scope (not in particular site/area);</li>
  <li>Should be possible to have different template for the same common content type for each site. So basically as an editor I should be able to create 2 instances of <code class="language-plaintext highlighter-rouge">common block</code> and use each of the instance in each site;</li>
  <li>Should be possible to define rendering template for common block for each site. So basically when visitors are accessing <code class="language-plaintext highlighter-rouge">site1</code> - render template from <code class="language-plaintext highlighter-rouge">site1</code> should be used, and similarly when accessing <code class="language-plaintext highlighter-rouge">site2</code> - render template from <code class="language-plaintext highlighter-rouge">site2</code> should be used;</li>
  <li>Should be possible to choose correct layout page while previewing (when editors press “Edit” in content area context menu for particular block) the block instance. It means - if I’m in <code class="language-plaintext highlighter-rouge">site1</code> and press “Edit” on one of the blocks in content area, EPiServer should pick up correct preview template that may be defined in each site;</li>
</ul>

<p><img src="/assets/img/2015/08/ar-0-11.png" alt="" /></p>

<p>So following control-flow is needed:</p>

<ul>
  <li>if request is made for area specific controller - we set context to that area;</li>
  <li>if request is made against controller defined in “root” scope”, but there is matching Mvc Area for current EPiServer site, we need to set context to that particular area while executing template rendering;</li>
  <li>otherwise request flows through ordinary Asp.Net processing pipeline conventions;</li>
</ul>

<p>Hope that requirements for our tiny “multiple-sites-organized-by-areas” project is now more clear. Let’s start implementing necessary moving parts.</p>

<h2 id="implementing-requirements">Implementing Requirements</h2>

<h3 id="site-specific-content-type">Site Specific Content Type</h3>

<p>There are no special requirements for the content type defined inside Mvc Area with renderer, or without it - only with template.
This is already supported out of the box using code snippets from <a href="https://tech-fellow.eu/2015/01/21/full-support-for-asp-net-mvc-areas-in-episerver-7-5/">my earlier attempt</a> to add support for Mvc Areas inside EPiServer projects.</p>

<p><img src="/assets/img/2015/08/ar-0-1.png" alt="" /></p>

<h3 id="content-type-with-site-specific-template">Content Type with Site Specific Template</h3>

<p>Using following code snippets from <a href="https://tech-fellow.eu/2015/01/21/full-support-for-asp-net-mvc-areas-in-episerver-7-5/">my earlier attempts</a> to add Asp.Net Mvc Areas to EPiServer projects, you can easily define content type in “root” scope or any other project or namespace and have only single template in your particular area - either for <code class="language-plaintext highlighter-rouge">site1</code> or <code class="language-plaintext highlighter-rouge">site2</code>.</p>

<p><img src="/assets/img/2015/08/ar-1.png" alt="" /></p>

<h3 id="generic-content-with-templates-for-each-site">Generic Content with Templates for each Site</h3>

<p>More common case is when you have <code class="language-plaintext highlighter-rouge">GenericContentType</code> defined somewhere in “root” scope or any other project/namespace, and you have multiple sites set up as Mvc Areas. You define content type once and would like to have different template for every site.</p>

<p>In this case, when there is no renderer (controller) for the content type, proper context for template selection is already done by hosting page.
So in other words if such content is hosted inside the page that resides in particular Mvc Area, instructions to look for templates inside that area (<code class="language-plaintext highlighter-rouge">RouteData.DataTokens["area"]</code>) is already set by the page or <a href="https://github.com/valdisiljuconoks/EPiServer.MvcAreas/blob/master/EPiServer.MvcAreas/DetectAreaAttribute.cs">action filter specifically</a>.</p>

<p><img src="/assets/img/2015/08/ar-2.png" alt="" /></p>

<h3 id="generic-content-with-renderer-and-templates-for-each-site">Generic Content with Renderer and Templates for each Site</h3>

<p>Another case is when you have common renderer (content type controller) and templates for each site. Visually it looks something like this:</p>

<p><img src="/assets/img/2015/08/ar-3.png" alt="" /></p>

<p>For this particular case thing that we need to do - is to ensure that after content type renderer (controller) has been executed, we need to set context to specific site as Mvc Area in order to Asp.Net view engine collection to find proper views in located in area.
This could be done easily with few lines of code:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="c1">// if there is an area with the same name of the site - switch to that area</span>
<span class="k">if</span> <span class="p">(</span><span class="n">AreaTable</span><span class="p">.</span><span class="n">Areas</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="n">SiteDefinition</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">Name</span><span class="p">))</span>
<span class="p">{</span>
    <span class="n">RouteData</span><span class="p">.</span><span class="n">DataTokens</span><span class="p">[</span><span class="s">"area"</span><span class="p">]</span> <span class="p">=</span> <span class="n">SiteDefinition</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">Name</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So it means that following content type action:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">override</span> <span class="n">ActionResult</span> <span class="nf">Index</span><span class="p">(</span><span class="n">GenericBlockWithCtrl</span> <span class="n">currentBlock</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// if there is an area with the same name of the site - switch to that area</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">AreaTable</span><span class="p">.</span><span class="n">Areas</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="n">SiteDefinition</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">Name</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="n">RouteData</span><span class="p">.</span><span class="n">DataTokens</span><span class="p">[</span><span class="s">"area"</span><span class="p">]</span> <span class="p">=</span> <span class="n">SiteDefinition</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">Name</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="nf">PartialView</span><span class="p">(</span><span class="s">"_GenericBlockWithCtrl"</span><span class="p">,</span> <span class="n">currentBlock</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>will make sure that once action has been executed we instruct view engine collection that current context is in specific area. But do this only if we are currently accessing valid and known EPiServer site.</p>

<p>This also could be refactored into a action filter for more convenient usage:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">GenericBlockWithCtrlController</span> <span class="p">:</span> <span class="n">BlockController</span><span class="p">&lt;</span><span class="n">GenericBlockWithCtrl</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">SwitchToArea</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">override</span> <span class="n">ActionResult</span> <span class="nf">Index</span><span class="p">(</span><span class="n">GenericBlockWithCtrl</span> <span class="n">currentBlock</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="nf">PartialView</span><span class="p">(</span><span class="s">"_GenericBlockWithCtrl"</span><span class="p">,</span> <span class="n">currentBlock</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">SwitchToAreaAttribute</span> <span class="p">:</span> <span class="n">ActionFilterAttribute</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnActionExecuting</span><span class="p">(</span><span class="n">ActionExecutingContext</span> <span class="n">filterContext</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">base</span><span class="p">.</span><span class="nf">OnActionExecuting</span><span class="p">(</span><span class="n">filterContext</span><span class="p">);</span>

        <span class="c1">// if there is an area with the same name of the site - switch to that area</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">AreaTable</span><span class="p">.</span><span class="n">Areas</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="n">SiteDefinition</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">Name</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="n">filterContext</span><span class="p">.</span><span class="n">RouteData</span><span class="p">.</span><span class="n">DataTokens</span><span class="p">[</span><span class="s">"area"</span><span class="p">]</span> <span class="p">=</span> <span class="n">SiteDefinition</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">Name</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="handling-preview-controller">Handling Preview Controller</h2>

<p>Preview controller is not exactly what it says. EPiServer uses <code class="language-plaintext highlighter-rouge">Preview</code> category for its content templates to control who will be responsible for rendering the content when editor will edit the block content.</p>

<p><img src="/assets/img/2015/08/ar-4.png" alt="" /></p>

<p>Preview controller is defined as single instance inside “root” scope. So in order for this guy to detect proper EPiServer site and switch to that Mvc Area - we need to add our newly created filter attribute:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">TemplateDescriptor</span><span class="p">(</span>
    <span class="n">Inherited</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
    <span class="n">TemplateTypeCategory</span> <span class="p">=</span> <span class="n">TemplateTypeCategories</span><span class="p">.</span><span class="n">MvcController</span><span class="p">,</span> <span class="c1">//Required as cont</span>
    <span class="n">Tags</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span> <span class="p">{</span><span class="n">RenderingTags</span><span class="p">.</span><span class="n">Preview</span><span class="p">,</span> <span class="n">RenderingTags</span><span class="p">.</span><span class="n">Edit</span><span class="p">},</span>
    <span class="n">AvailableWithoutTag</span> <span class="p">=</span> <span class="k">false</span><span class="p">)]</span>
<span class="p">[</span><span class="n">VisitorGroupImpersonation</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">PreviewController</span> <span class="p">:</span> <span class="n">ActionControllerBase</span><span class="p">,</span> <span class="n">IRenderTemplate</span><span class="p">&lt;</span><span class="n">BlockData</span><span class="p">&gt;,</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">PreviewController</span><span class="p">(...)</span>
    <span class="p">{</span>
        <span class="p">....</span>
    <span class="p">}</span>

    <span class="p">[</span><span class="n">SwitchToArea</span><span class="p">]</span>
    <span class="k">public</span> <span class="n">ActionResult</span> <span class="nf">Index</span><span class="p">(</span><span class="n">IContent</span> <span class="n">currentContent</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="p">....</span>
        <span class="k">return</span> <span class="nf">View</span><span class="p">(</span><span class="n">model</span><span class="p">);</span>
    <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Also if you want to have multiple preview layout pages - let say different preview layout page for each site (that will definitely set editor in proper look &amp; feel when editing particular site’s block) you need to add view templates for preview controller inside your areas:</p>

<p><img src="/assets/img/2015/08/ar-5.png" alt="" /></p>

<p>The way how I prefer to setup layout page for views inside area is by using <code class="language-plaintext highlighter-rouge">_viewstart.cshtml</code> page:</p>

<pre><code class="language-razor">@{
    Layout = "Shared/Layouts/_SiteLayout.cshtml";
}
</code></pre>

<h2 id="summary">Summary</h2>

<p>Asp.Net Mvc Areas is an ideal way to organized and structure your site by features - you get all your feature related stuff under single folder structure that makes it really easy to find and understand the project.
However - you can also organize EPiServer’s project structure in such way that EPiServer site appears as separate Asp.Net Mvc Area - that also gives you a way to organize and structure your sites and projects. Latter needs a bit adjustments to make it work properly.</p>

<p>Source code for Asp.Net Mvc Areas and added support for EPiServer sites can be found in <a href="https://github.com/valdisiljuconoks/EPiServer.MvcAreas">GitHub</a> as well!</p>

<p>Happy coding in one of your areas!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[Asp.Net Mvc Areas is a great way to organize and structure your EPiServer site. Once you have multi-tenant site where the same EPiServer installation with the same set of libraries, styles, script set and other assets is handling more than single site - Asp.Net Mvc Areas become really handy to group particular site’s specific assets and other stuff together under single folder. This also gives developers more obvious and more clear picture of the project setup.]]></summary></entry><entry><title type="html">Content Area - Under the Hood, Part 3</title><link href="https://tech-fellow.eu/2015/06/11/content-area-under-the-hood-part-3/" rel="alternate" type="text/html" title="Content Area - Under the Hood, Part 3" /><published>2015-06-11T09:15:00+03:00</published><updated>2015-06-11T09:15:00+03:00</updated><id>https://tech-fellow.eu/2015/06/11/content-area-under-the-hood-part-3</id><content type="html" xml:base="https://tech-fellow.eu/2015/06/11/content-area-under-the-hood-part-3/"><![CDATA[<p>This is last blog post in series under the hood of Content Area. In this blog post we will take a look at how and what exactly could be customizable while content area is being rendered. Where and how developer can hook in, what can be overridden and controlled.</p>

<p>Parts in this series:</p>

<p>– <a href="https://tech-fellow.eu/2015/04/26/content-area-under-the-hood-part-1/">Part 1: Registration and Discovery</a>
– <a href="https://tech-fellow.eu/2015/05/30/content-area-under-the-hood-part-2/">Part 2: Template Selection</a>
– <strong>Part 3: Extensibility</strong></p>

<h2 id="overview">Overview</h2>

<p>Following parts and pieces can be customizable, changeable or replaced by other code completely:</p>

<ul>
  <li><em>Change renderer</em> - It’s possible to change they guy who is responsible for whole process in the first place. You can swap content area renderer completely and replace with your own code. You would need to inherit from built-in <code class="language-plaintext highlighter-rouge">ContentAreaRenderer</code>, swap it out in IoC container and do your stuff;</li>
  <li><em>Change display template</em> - Change view (<code class="language-plaintext highlighter-rouge">ContentArea.ascx</code>) for the content area type;</li>
  <li><em>Customize rendering</em> - It’s possible to add and specify various settings while rendering then content area (<code class="language-plaintext highlighter-rouge">Html.PropertyFor(..., new { }</code>);</li>
  <li><em>Handle events</em> - As  we got to know in <a href="https://tech-fellow.eu/2015/05/30/content-area-under-the-hood-part-2/">Part 2</a> <code class="language-plaintext highlighter-rouge">TemplateResolver</code> fires few events. We are able to hook on those events and customize templates selected as we need.</li>
</ul>

<h2 id="replace-renderer">Replace Renderer</h2>

<p>If something does not work as expected, you need some customization that is not achievable by other methods, want to add some extra stuff on top of existing content area renderer? It’s possible to inherit from built-in <code class="language-plaintext highlighter-rouge">ContentAreaRenderer</code>, replace methods with your own and register new implementation in IoC container.</p>

<h3 id="inherit-from-built-in-renderer">Inherit from Built-in Renderer</h3>

<p>Inheritance is simple:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">MyOwnContentAreaRenderer</span> <span class="p">:</span> <span class="n">ContentAreaRenderer</span>
<span class="p">{</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>These are all methods that make sense to override and change behavior (most probably there is no point to override method that checks if currently CMS context is set to <code class="language-plaintext highlighter-rouge">Edit</code> mode):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</pre></td><td class="rouge-code"><pre><span class="k">void</span> <span class="nf">Render</span><span class="p">(</span><span class="n">HtmlHelper</span> <span class="n">htmlHelper</span><span class="p">,</span> <span class="n">ContentArea</span> <span class="n">contentArea</span><span class="p">)</span>

<span class="k">void</span> <span class="nf">RenderContentAreaItems</span><span class="p">(</span>
            <span class="n">HtmlHelper</span> <span class="n">htmlHelper</span><span class="p">,</span>
            <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">ContentAreaItem</span><span class="p">&gt;</span> <span class="n">contentAreaItems</span><span class="p">)</span>

<span class="k">void</span> <span class="nf">RenderContentAreaItem</span><span class="p">(</span>
            <span class="n">HtmlHelper</span> <span class="n">htmlHelper</span><span class="p">,</span>
            <span class="n">ContentAreaItem</span> <span class="n">contentAreaItem</span><span class="p">,</span>
            <span class="kt">string</span> <span class="n">templateTag</span><span class="p">,</span>
            <span class="kt">string</span> <span class="n">htmlTag</span><span class="p">,</span>
            <span class="kt">string</span> <span class="n">cssClass</span><span class="p">)</span>

<span class="k">void</span> <span class="nf">BeforeRenderContentAreaItemStartTag</span><span class="p">(</span>
            <span class="n">TagBuilder</span> <span class="n">tagBuilder</span><span class="p">,</span>
            <span class="n">ContentAreaItem</span> <span class="n">contentAreaItem</span><span class="p">)</span>

<span class="n">TemplateModel</span> <span class="nf">ResolveTemplate</span><span class="p">(</span>
            <span class="n">HtmlHelper</span> <span class="n">htmlHelper</span><span class="p">,</span>
            <span class="n">IContent</span> <span class="n">content</span><span class="p">,</span>
            <span class="kt">string</span> <span class="n">templateTag</span><span class="p">)</span>

<span class="kt">string</span> <span class="nf">GetContentAreaTemplateTag</span><span class="p">(</span><span class="n">HtmlHelper</span> <span class="n">htmlHelper</span><span class="p">)</span>

<span class="kt">string</span> <span class="nf">GetContentAreaItemTemplateTag</span><span class="p">(</span>
            <span class="n">HtmlHelper</span> <span class="n">htmlHelper</span><span class="p">,</span>
            <span class="n">ContentAreaItem</span> <span class="n">contentAreaItem</span><span class="p">)</span>

<span class="kt">string</span> <span class="nf">GetContentAreaHtmlTag</span><span class="p">(</span>
            <span class="n">HtmlHelper</span> <span class="n">htmlHelper</span><span class="p">,</span>
            <span class="n">ContentArea</span> <span class="n">contentArea</span><span class="p">)</span>

<span class="kt">string</span> <span class="nf">GetContentAreaItemHtmlTag</span><span class="p">(</span>
            <span class="n">HtmlHelper</span> <span class="n">htmlHelper</span><span class="p">,</span>
            <span class="n">ContentAreaItem</span> <span class="n">contentAreaItem</span><span class="p">)</span>

<span class="kt">string</span> <span class="nf">GetContentAreaItemCssClass</span><span class="p">(</span>
            <span class="n">HtmlHelper</span> <span class="n">htmlHelper</span><span class="p">,</span>
            <span class="n">ContentAreaItem</span> <span class="n">contentAreaItem</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Let’s go through the call sequence of each of these methods.</p>

<p><img src="/assets/img/2015/06/p3-1.png" alt="" /></p>

<p>Eventual impact of each method in resulting markup is shown in diagram below:</p>

<p><img src="/assets/img/2015/06/p3-2.png" alt="" /></p>

<p>If you are looking for an easy way to customize resulting markup of <code class="language-plaintext highlighter-rouge">ContentArea</code>, without overriding almost everything in <code class="language-plaintext highlighter-rouge">ContentAreaRenderer</code>, head to “<em>Customize Rendering</em>” section.</p>

<p>Few observations:</p>

<ul>
  <li>Why CSS <code class="language-plaintext highlighter-rouge">class=""</code> for content area itself can’t be controlled via <code class="language-plaintext highlighter-rouge">virtual</code> method in the same way as other customization for <code class="language-plaintext highlighter-rouge">Html</code> tags and <code class="language-plaintext highlighter-rouge">Css class</code> for area item?</li>
  <li>Why there is no <code class="language-plaintext highlighter-rouge">AfterRenderContentAreaItemEndTag</code> method? Where you could hook in and add some necessary stuff <em>after</em> content area item has closed its tag element?</li>
</ul>

<h3 id="swap-default-renderer">Swap Default Renderer</h3>
<p>So once you are ready with your own content area renderer you will need to set it in action. In order to swap out built-in renderer and replace it with your own, all you need to do is to replace one in IoC container:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">ServiceContainerInitialization</span><span class="p">))]</span>
<span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">SwapRendererInitModule</span> <span class="p">:</span> <span class="n">IConfigurableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureContainer</span><span class="p">(</span><span class="n">ServiceConfigurationContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">context</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="nf">Configure</span><span class="p">(</span><span class="n">container</span> <span class="p">=&gt;</span>
            <span class="n">container</span><span class="p">.</span><span class="n">For</span><span class="p">&lt;</span><span class="n">ContentAreaRenderer</span><span class="p">&gt;()</span>
                     <span class="p">.</span><span class="n">Use</span><span class="p">&lt;</span><span class="n">MyOwnContentAreaRenderer</span><span class="p">&gt;());</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now everything and anywhere where <code class="language-plaintext highlighter-rouge">ContentArea</code> property is rendered - you will get full access and control of workflow and can customize it according to site’s requirements.</p>

<h2 id="change-display-template">Change Display Template</h2>

<p>If you want to become real hacker and apply your logic to every single content area and also do some black magic with markup and the way how content areas are rendered, you may need to swap out existing built-in template for <code class="language-plaintext highlighter-rouge">ContentArea</code> by just creating “more specific” display template in your <code class="language-plaintext highlighter-rouge">Shared/DisplayTemplates</code> folder (or anywhere where Asp.Net can find it):</p>

<p><img src="/assets/img/2015/06/p3-3-1.png" alt="" /></p>

<p>I’ve seen projects where this was implemented. Fun times to try to find it out.. Custom display template for EPiServer built-in type was the last idea that came to mind.</p>

<h2 id="customize-rendering">Customize Rendering</h2>
<p>There are also some extension points on how you can customize content area resulting markup.</p>

<p>Basically you can pass in few known to EPiServer keys in <code class="language-plaintext highlighter-rouge">ViewData</code> when executing <code class="language-plaintext highlighter-rouge">@Html.PropertyFor()</code>. For instance:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="p">...</span>
<span class="n">@Html</span><span class="p">.</span><span class="nf">PropertyFor</span><span class="p">(</span><span class="n">m</span> <span class="p">=&gt;</span> <span class="n">m</span><span class="p">.</span><span class="n">ContentArea</span><span class="p">,</span> <span class="k">new</span> <span class="p">{</span> <span class="n">tag</span> <span class="p">=</span> <span class="s">"some-tag"</span> <span class="p">})</span>
<span class="p">...</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Following are known keys to EPiServer you can pass in:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">Tag</code> - I think one of the most important <code class="language-plaintext highlighter-rouge">ViewData</code> key while rendering content area. This key regulates what templates may be selected for the content area and potentially for its items. For more info on template selection - please read <a href="https://tech-fellow.eu/2015/05/30/content-area-under-the-hood-part-2/">Part 2</a>;</li>
  <li><code class="language-plaintext highlighter-rouge">HasContainer</code> - key indicates whether to generate wrapping element for the content area at all;</li>
  <li><code class="language-plaintext highlighter-rouge">CustomTag</code> - wrapping element name for the content area (defaults to “<code class="language-plaintext highlighter-rouge">div</code>”) if <code class="language-plaintext highlighter-rouge">hascontainer = true</code>. Small observation - a bit confusing and could be mismatched with <code class="language-plaintext highlighter-rouge">tag</code>;</li>
  <li><code class="language-plaintext highlighter-rouge">CssClass</code> - CSS class(-es) to add to content area wrapping element</li>
  <li><code class="language-plaintext highlighter-rouge">ChildrenCustomTagName</code> - element name for every content area item (defaults to “<code class="language-plaintext highlighter-rouge">div</code>”). Small observation - naming for area element name and child element name should be consistent. Let’s say: either <code class="language-plaintext highlighter-rouge">customtagname</code> for content area itself or <code class="language-plaintext highlighter-rouge">childerencustomtag</code> for item;</li>
  <li><code class="language-plaintext highlighter-rouge">ChildrenCssClass</code> - CSS class(-es) name to add to every content area item</li>
</ul>

<p>So this are list of keys you can pass in:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="n">@Html</span><span class="p">.</span><span class="nf">PropertyFor</span><span class="p">(</span><span class="n">m</span> <span class="p">=&gt;</span> <span class="n">m</span><span class="p">.</span><span class="n">ContentArea</span><span class="p">,</span> <span class="k">new</span> <span class="p">{</span>
    <span class="n">Tag</span> <span class="p">=</span> <span class="s">"some-tag"</span><span class="p">,</span>
    <span class="n">HasContainer</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
    <span class="n">CustomTag</span> <span class="p">=</span> <span class="s">"ul"</span><span class="p">,</span>
    <span class="n">CssClass</span> <span class="p">=</span> <span class="s">"this-is-a-list-class"</span><span class="p">,</span>
    <span class="n">ChildrenCustomTagName</span> <span class="p">=</span> <span class="s">"li"</span><span class="p">,</span>
    <span class="n">ChildrenCssClass</span> <span class="p">=</span> <span class="s">"this-is-list-item-class"</span>
<span class="p">})</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>In the results you will get something like this assuming that there are few items added to the content area:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"this-is-a-list-class"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"this-is-list-item-class"</span><span class="nt">&gt;</span>...<span class="nt">&lt;/li&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"this-is-list-item-class"</span><span class="nt">&gt;</span>...<span class="nt">&lt;/li&gt;</span>
  <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"this-is-list-item-class"</span><span class="nt">&gt;</span>...<span class="nt">&lt;/li&gt;</span>
<span class="nt">&lt;/ul&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Which gives you pretty much flexibility to render content area as you want and need. This reminds me of <a href="http://world.episerver.com/blogs/Per-Magne-Skuseth/">Per Magne’s</a> approach to build <a href="http://world.episerver.com/blogs/Per-Magne-Skuseth/Dates/2013/8/Developing-a-drag-and-droppable-menu-MVC/">menu driven by content area</a>.</p>

<h2 id="handle-resolving-events">Handle Resolving Events</h2>

<p>There 2 type of events that could be handled during content area rendering:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">TemplateResolving</code> - from the name of the event it’s clear that this event is raised <em>before</em> template is resolved;</li>
  <li><code class="language-plaintext highlighter-rouge">TemplateResolved</code> - however this event on the other hand is raised after EPiServer has finished template resolving process;</li>
</ul>

<p>Both of these events are exposed from EPiServer API in order for us developers to hook in, handle and customize selection of the template.</p>

<p>Event handling for the template selection is pretty straight forward:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">CustomizedRenderingInitialization</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">context</span><span class="p">.</span><span class="n">Locate</span><span class="p">.</span><span class="nf">TemplateResolver</span><span class="p">().</span><span class="n">TemplateResolving</span> <span class="p">+=</span>
            <span class="n">TemplateCoordinator</span><span class="p">.</span><span class="n">OnTemplateResolving</span><span class="p">;</span>

        <span class="n">context</span><span class="p">.</span><span class="n">Locate</span><span class="p">.</span><span class="nf">TemplateResolver</span><span class="p">().</span><span class="n">TemplateResolved</span> <span class="p">+=</span>
            <span class="n">TemplateCoordinator</span><span class="p">.</span><span class="n">OnTemplateResolved</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">ServiceLocator</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">TemplateResolver</span><span class="p">&gt;().</span><span class="n">TemplateResolving</span> <span class="p">-=</span>
            <span class="n">TemplateCoordinator</span><span class="p">.</span><span class="n">OnTemplateResolving</span><span class="p">;</span>

        <span class="n">ServiceLocator</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">TemplateResolver</span><span class="p">&gt;().</span><span class="n">TemplateResolved</span> <span class="p">-=</span>
            <span class="n">TemplateCoordinator</span><span class="p">.</span><span class="n">OnTemplateResolved</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">TemplateCoordinator</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">OnTemplateResolved</span><span class="p">(</span><span class="kt">object</span> <span class="n">sender</span><span class="p">,</span> <span class="n">TemplateResolverEventArgs</span> <span class="n">args</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// handle event - you may change selected template by:</span>
        <span class="c1">// args.SelectedTemplate = ....;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">OnTemplateResolving</span><span class="p">(</span><span class="kt">object</span> <span class="n">sender</span><span class="p">,</span> <span class="n">TemplateResolverEventArgs</span> <span class="n">args</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// handle event - you may change selected template by:</span>
        <span class="c1">// args.SelectedTemplate = ....;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This code fragment is taken from our old friend AlloyTech sample site. However I haven’t dig into on why during <code class="language-plaintext highlighter-rouge">Initialize</code> service locator is access as <code class="language-plaintext highlighter-rouge">context.Locate</code>, but in <code class="language-plaintext highlighter-rouge">Uninitialize</code> we are referring to service locator as <code class="language-plaintext highlighter-rouge">ServiceLocator.Current</code>. I’m sure there is a reason behind this.</p>

<p>For more info about template model selection and it’s internals - please read <a href="https://tech-fellow.eu/2015/05/30/content-area-under-the-hood-part-2/">Part 2</a> of these series.</p>

<h2 id="summary">Summary</h2>

<p>Overall <code class="language-plaintext highlighter-rouge">ContentArea</code> was one of the most interesting improvement over EPiServer’s 6.x <code class="language-plaintext highlighter-rouge">ComposerBlock</code> concept. It’s really powerful and you may achieve high flexibility and utilize it’s potential in various scenarios.
However - I guess that <code class="language-plaintext highlighter-rouge">ContentArea</code> needs a bit more love when it comes to discovery of magic behind the scene - that was main goal for these series to spread knowledge I gain while research EPiServer libraries.
The most challenging and interesting for me was <a href="https://tech-fellow.eu/2015/05/30/content-area-under-the-hood-part-2/">Part 2</a> where I recapped how template model is working and how models are selected based on environmental settings. This part I find most unclear for developers (Usually questions are - “I do have a view for the block and I do have a controller for the block. Why my controller is not invoked, but instead view is rendered directly?”).</p>

<p>Hope that these series will give you some more insightful look at what’s going on when EPiServer scans your template models, when you execute <code class="language-plaintext highlighter-rouge">@Html.PropertyFor(m =&gt; m.ContentArea)</code>, which template model will be chosen and how to customize other stuff for the content area rendering pipeline.</p>

<p>Happy coding!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><category term="under the hood" /><summary type="html"><![CDATA[This is last blog post in series under the hood of Content Area. In this blog post we will take a look at how and what exactly could be customizable while content area is being rendered. Where and how developer can hook in, what can be overridden and controlled.]]></summary></entry><entry><title type="html">Content Area - Under the Hood, Part 2</title><link href="https://tech-fellow.eu/2015/05/30/content-area-under-the-hood-part-2/" rel="alternate" type="text/html" title="Content Area - Under the Hood, Part 2" /><published>2015-05-30T09:15:00+03:00</published><updated>2015-05-30T09:15:00+03:00</updated><id>https://tech-fellow.eu/2015/05/30/content-area-under-the-hood-part-2</id><content type="html" xml:base="https://tech-fellow.eu/2015/05/30/content-area-under-the-hood-part-2/"><![CDATA[<p>This is second post in series of EPiServer Content Area feature. This time we will take a look at how render templates are selected. In the <a href="https://tech-fellow.eu/2015/04/26/content-area-under-the-hood-part-1/">first part</a> we looked closer on how templates get discovered and registered in Template Model Repository.
Selection of the template is one of the most important fragment of whole rendering pipeline for the content area. This part of the process may turn out to be one of the most non-understandable and kind of black box component (reviewing questions on the EPiServer World forum). But it’s crucial to understand what’s really going on under the hood. And this blog post is all about that.</p>

<p><img src="/assets/img/2015/05/p2-1.png" alt="" /></p>

<p>Parts in this series:</p>

<p>– <a href="https://tech-fellow.eu/2015/04/26/content-area-under-the-hood-part-1/">Part 1: Registration and Discovery</a>
– <strong>Part 2: Template Selection</strong>
– <a href="https://tech-fellow.eu/2015/06/11/content-area-under-the-hood-part-3/">Part 3: Extensibility</a></p>

<h2 id="template-resolver">Template Resolver</h2>

<p>As we looked of template registration step of the rendering process of content area in previous post, selection of the template to use for the rendering starts in ContentAreaRenderer:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nf">ResolveTemplate</span><span class="p">(</span><span class="n">htmlHelper</span><span class="p">,</span> <span class="n">content</span><span class="p">,</span> <span class="n">templateTag</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Which delegates control further down to <code class="language-plaintext highlighter-rouge">ITemplateResolver</code> (actually <code class="language-plaintext highlighter-rouge">TemplateResolverImplementation</code>):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="nf">Resolve</span><span class="p">(</span><span class="n">htmlHelper</span><span class="p">.</span><span class="n">ViewContext</span><span class="p">.</span><span class="n">HttpContext</span><span class="p">,</span>
        <span class="p">..,</span>
        <span class="p">...,</span>
        <span class="n">TemplateTypeCategories</span><span class="p">.</span><span class="n">MvcPartial</span><span class="p">,</span>
        <span class="n">templateTag</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Enumeration <code class="language-plaintext highlighter-rouge">TemplateTypeCategories.MvcPartial</code> actually points to two other enumeration members: <code class="language-plaintext highlighter-rouge">MvcPartialView</code> and <code class="language-plaintext highlighter-rouge">MvcPartialController</code>, so EPiServer is looking for template models within either partial view or partial controller categories.</p>

<h2 id="handling-events-during-template-resolve">Handling Events during Template Resolve</h2>

<p><code class="language-plaintext highlighter-rouge">Resolve</code> method is wrapped around 2 events which are implemented in order for the website code to be able to control a bit how and which template is selected:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">TemplateResolving</code>: this event is raised at the beginning of the template selection. If you subscribe to this event, you have a control of which template should be selected before even EPiServer will try to resolve. If you modify event arguments and assign <code class="language-plaintext highlighter-rouge">SelectedTemplate</code> property, you basically telling EPiServer that it should skip further selection process and use your template. EPiServer will continue template model selection process if <code class="language-plaintext highlighter-rouge">SelectedTemplate</code> is null after raising the event (basically if there is no event handler or somebody set it to <code class="language-plaintext highlighter-rouge">null</code> for some reason).</li>
</ul>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">CustomizedRenderingInitializationModule</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">context</span><span class="p">.</span><span class="n">Locate</span><span class="p">.</span><span class="nf">TemplateResolver</span><span class="p">()</span>
            <span class="p">.</span><span class="n">TemplateResolving</span> <span class="p">+=</span> <span class="n">TemplateCoordinator</span><span class="p">.</span><span class="n">OnTemplateResolving</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">ServiceLocator</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">TemplateResolver</span><span class="p">&gt;()</span>
            <span class="p">.</span><span class="n">TemplateResolving</span> <span class="p">-=</span> <span class="n">TemplateCoordinator</span><span class="p">.</span><span class="n">OnTemplateResolving</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">TemplateCoordinator</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">OnTemplateResolving</span><span class="p">(</span><span class="kt">object</span> <span class="n">sender</span><span class="p">,</span> <span class="n">TemplateResolverEventArgs</span> <span class="n">args</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">repo</span> <span class="p">=</span> <span class="n">ServiceLocator</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">TemplateModelRepository</span><span class="p">&gt;();</span>
        <span class="n">args</span><span class="p">.</span><span class="n">SelectedTemplate</span> <span class="p">=</span> <span class="n">repo</span><span class="p">.</span><span class="nf">List</span><span class="p">(</span><span class="n">args</span><span class="p">.</span><span class="n">ContentType</span><span class="p">.</span><span class="n">ModelType</span><span class="p">).</span><span class="nf">First</span><span class="p">();</span>  <span class="c1">// put actual code here ...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><em>NB!</em> Implementation of event handler for selected template is not ready for production use. Don’t copy the code as it may mess around with your templates. Fragment is provided just as code sample :)</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">TemplateResolved</code>: this is another event raised after selection of the template has ended and EPiServer has done its job. This is the place to override selected template and instruct EPiServer to use other template if it’s necessary.</li>
</ul>

<p><img src="/assets/img/2015/05/p2-2.png" alt="" /></p>

<h2 id="template-model">Template Model</h2>
<p>Each discovered and registered template model has following data model that is stored in template model repository. Almost all properties are playing important role in template selection. We will touch role of those properties in sections below.</p>

<table><thead><th>Field Name</th><th>Description</th><thead><tbody><tr><td>Name</td><td>Name of the template model. Gets type name from the content type it's rendering.</td></tr><tr><td>Default</td><td>Flag specifying is this template default.</td></tr><tr><td>Inherit</td><td>Flag indicating whether this model allows inheritance to other child content types.</td></tr><tr><td>TemplateType</td><td>Actual type (class) that may handle the execution of rendering of the template. Not necessarily that each template must have template type.</td></tr><tr><td>TemplateTypeCategory</td><td>What type of template is this? In our case we are interested in `MvcPartialView` and `MvcPartialController`.</td></tr><tr><td>Path</td><td>If path was resolved or set explicitly for the template, it's stored here.</td></tr><tr><td>AvailableWithoutTags</td><td>Flag indicating whether template can also be used without tags. Frequently used together with tagged templates.</td></tr><tr><td>Tags</td><td>List of tags associated with this template model (see "Tagging Templates" section).</td></tr></tbody><table>

## Tagging the Templates
Before proceeding further with template selection it's worth to revisit tagging mechanism for template models.
Main idea behind the tagging was that you may have a single block type, but you would need to customize look &amp; feel of the block in some cases by switching templates. This is easily achievable if you specify `tag` while rendering content area. I've seen quite frequent usage of tags when you may have some shared block and it should look “green with 2 buttons” on one page, and “yellow without buttons” on the other page.
There are two ways how you can get tags attached to the template model:

- by using `TemplateDescriptor` attribute:

```csharp
[TemplateDescriptor(
    Default = true,
    TemplateTypeCategory = TemplateTypeCategories.MvcPartialController,
    Tags = new[] { "SampleTag" },
    ModelType = typeof(SampleBlock),
    AvailableWithoutTag = false)]
public class MyUltraBlockController : ...
{ }
```

- or by manually registering required template with associated tags:

```csharp
[ServiceConfiguration(typeof(IViewTemplateModelRegistrator))]
public class TemplateCoordinator : IViewTemplateModelRegistrator
{
    public void Register(TemplateModelCollection registrator)
    {
        registrator.Add(typeof(SampleBlock),
                                     new TemplateModel
                                     {
                                         Tags = new[] { "full-width" },
                                         AvailableWithoutTag = false,
                                         Default = true,
                                         Name = "SampleBlockFullWidth",
                                     });

```

Then you can render content area with specified `Tag` added to the area:

```razor
@Html.PropertyFor(m =&gt; m.MainContentArea, new { Tag = "SampleTag" })
```

I'm thinking of tags something like setting the context for the rendering cycle. Using tags you may get totally different look and / or feel of the same content type - just by choosing different templates to be used while rendering the content.
Tags also are playing important role in template selection process.


## Template Selection Process

After `TemplateResolving` event was raised and no template was selected, EPiServer will continue selection process. Doing two things:

- it will try to fetch template based on the `tag` that was used while rendering the content area (if any were used).
- if no template was found based on tags, EPiServer will continue on default logic for selecting the template for the content type.

The overall process looks like as illustrated in diagram below. We will dig into each of the steps in more details.

![](/assets/img/2015/05/p2-3.png)


Flowchart `Yes` paths are straight forward - if at some point template is selected/found - EPiServer will just use that one without further selection.
Interesting paths and steps are `try to get by tag` and `select template with preferred model`.

### Choosing Template Models by Tag

So what really happens under `TryGetTemplateByTag` method?

![](/assets/img/2015/05/p2-4.png)

There are two important input parameters to this method:

- list of supported templates: supported templates are templates that are registered for particular content type (`ModelType` while registering template model in repository via attribute or view registrator)

- list of all active display channels for current request

Display channels is feature to make it possible to adopt content rendering to specific cases during handling of the request. More info about display channels - [EPiServer SDK Documentation](http://world.episerver.com/documentation/Items/Developers-Guide/EPiServer-CMS/8/Rendering/Display-channels/Display-channels/).

This is the logic of the template selection by `tag`:
**a)** from the list of supported templates ones those have matching `Tag` with any current active channels are selected. If there is no template models marked with `Tag` as any current active channels EPiServer continues with list of supported templates;
**b)** then out of filtered template models by active channel, EPiServer is taking only those template models that have the same `tag` that is used in current content area rendering.
**c)** after the list of possible candidate templates is built, the single model is selected from the list (see "Selecting the Model" section below). Here templates available only within tag are filtered (`AvailableWithoutTags` property of the template model should be set to `false`);


For example if you have following template models registered for particular content type:

<table><thead><th>Id</th><th>Tags</th><th>AvailableWithoutTags</th><th>Default</th><thead><tbody><tr><td>T1</td><td>"SampleTag", "mobile"</td><td>`false`</td><td>`true`</td></tr><tr><td>T2</td><td>"mobile"</td><td>`true`</td><td>`true`</td></tr><tr><td>T3</td><td>"SampleTag"</td><td>`false`</td><td>`true`</td></tr><tr><td>T4</td><td>"SampleTag", "AnotherTag", mobile"</td><td>`true`</td><td>`true`</td></tr><tr><td>T5</td><td>[ ]</td><td>`true`</td><td>`true`</td></tr><tr><td>T6</td><td>"SampleTag", "mobile"</td><td>`false`</td><td>`false`</td></tr></tbody><table>

Assuming that you have `mobile` as active channel during the render and your content area is rendered with `SampleTag` as `Tag`:

```
@Html.PropertyFor(m =&gt; m.MainContentArea, new { Tag = "SampleTag" })
```

Choice of templates are following:
**a)** `T1`, `T2`, `T4` and `T6` will be chosen (have matching `Tag` - "mobile");
**b)** `T1`, `T4` and `T6` will be chosen (they have matching `tag` that was used to render content area - "SampleTag");
**c)** `T1` and `T6` are passed further to selection of the model (as they have `AvailableWithoutTag` set to `false`);


### Choosing Template Models with Preferred Model

If template model choice by `Tag` failed (either there was no `tag` used during rendering of the content area or there were no matching templates by tag), EPiServer tries to choose template models from list of supported templates.


![](/assets/img/2015/05/p2-5.png)


Logic behind choosing template models with preferred model is following:
**a)** all template models that have `Tag` the same as any of current active channels are also added to the list of supported templates;
**b)** if there is no template that match any current active display channel and `ContentType` has defined default Mvc view or default Mvc controller - one is chosen (default template has to be `MvcPartialView` or `MvcPartialController`). Default Mvc view or controller you can define here:


![](/assets/img/2015/05/p2-6.png)


**c)** if there is no templates matched active display channel, or content type has no default Mvc view or controller defined, EPiServer continues with selecting the model out of supported template list (see "Selecting the Model" section below). Here also templates that are available without tags are considered and taken into account (`AvailableWithoutTags` property of the template model is set to `true`);


### Selecting the Model

After EPiServer has built a list of templates, selection of the one and only model is made.

Selection of the template is fairly easy task for the EPiServer. Logic behind of selection is as following:
**a)** list of chosen templates is sorted by `Category` key. Which means looking at `TemplatesTypeCategories` enumeration - partial controllers will be on top followed by partial views;
**b)** Template marked as default (`Default = true`) and not inherited (`IsInherited() = false`) is selected;
**c)** If there is no such template (default and not inherited), just default template is selected instead;
**d)** if there is no default template defined - first template from the ordered list of chosen templates is selected.

For example, if we continue with our sample template model list, `T1` and `T6` were passed to selection logic:

<table><thead><th>Id</th><th>Tags</th><th>AvailableWithoutTags</th><th>Default</th><thead><tbody><tr><td>T1</td><td>"SampleTag", "mobile"</td><td>`false`</td><td>`true`</td></tr><tr><td>T6</td><td>"SampleTag", "mobile"</td><td>`false`</td><td>`false`</td></tr></tbody><table>

So assuming that none of them are inherited, the final selected model will be `T1` (as it's default template for this content type - `Default = true`).

## What happens after template is selected?

After EPiServer has selected the template model to use for rendering the content area item, there still happens small black magic here and there. Control flows further to `IContentRenderer`.


![](/assets/img/2015/05/p2-7.png)


Content renderer first decides what type of template model it is - partial view or controller. If template is partial view - view is rendered, if partial controller - child action for the controller is invoked via Asp.Net Mvc standard request handling pipeline (`TemplateType` points to actual controller type to create).

Interesting part is how EPiServer handles rendering of the template if it's of category partial view. EPiServer heavily relies on `ViewEngineCollection` to find particular template on the disk and execute it (by consuming `ViewEngineCollection.FindPartialView` method via its own cached view engine collection).

Actually there is simple logic underneath:
**a)** First, EPiServer anyway will try to find view with name "`Model.Name`" + "`.`" + "`Tag`";
**b)** If this fails, EPiServer will try to find view with the name of the template (`TemplateModel.Name`);
**c)** If that fails, EPiServer will try to find a view by `TemplateModel.Path` property value (if set any).

So we can illustrate this process with new diagram:


![](/assets/img/2015/05/p2-8.png)


*NB!* However there is a small catch with step *a)*.
Assume that you have following template model registered:

```csharp
viewTemplateModelRegistrator.Add(typeof(SampleBlock),
     new TemplateModel
     {
         Tags = new[] { "mobile" },
         AvailableWithoutTag = false,
         Default = true,
         Name = "SampleBlockMobile",
         Path = "~/Views/Shared/Blocks/_SampleBlockMobile.cshtml"
     });
```

Assume that content area was rendered with custom tag:

```razor
@Html.PropertyFor(m =&gt; m.MainContentArea, new { Tag = "supertag" })
```

Assume that we do have an active display channel named "mobile" while rendering the content area. So form all choice and selection logic described above, template is matched and recognized as good enough.
As there are a lot of moving parts during template selection, this may get a bit tricky. Let’s assume that you have following file in your partial views location:

```
"~/Views/Shared/Blocks/_SampleBlockMobile.supertag.cshtml"
```

I'll leave it as your homework to decide whether "_SampleBlockMobile.cshtml" or "_SampleBlockMobile.supertag.cshtml" will be selected as the one and only template :)

## Whole Process

So in total eventually the whole process of template selection looks like this:


![](/assets/img/2015/05/p2-9.png)


## Verdict

Content type template model [discovery and registration](http://tech-fellow.eu/2015/04/26/content-area-under-the-hood-part-1/) is pretty easy task for EPiServer. However choice, filtering the templates and selecting the one may turn out to be tricky component to deal with during EPiServer site implementation.

If you get unsure if template got registered, review properties of the template model inside template model repository, browse the content of the repository or want to understand more, I really recommend [Developers Tools from EPiServer](https://github.com/episerver/DeveloperTools). Under section `Templates` there is a section with all discovered and registered templates for any content type. It’s fantastic tool!


## Next Part

In next blog post we will cover various extensibility points added to the pipeline where you can hook in and add your stuff.

Happy rendering!

[*eof*]
</table></thead></thead></table></table></thead></thead></table></table></thead></thead></table>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><category term="under the hood" /><summary type="html"><![CDATA[This is second post in series of EPiServer Content Area feature. This time we will take a look at how render templates are selected. In the first part we looked closer on how templates get discovered and registered in Template Model Repository. Selection of the template is one of the most important fragment of whole rendering pipeline for the content area. This part of the process may turn out to be one of the most non-understandable and kind of black box component (reviewing questions on the EPiServer World forum). But it’s crucial to understand what’s really going on under the hood. And this blog post is all about that.]]></summary></entry><entry><title type="html">Content Area - Under the Hood, Part 1</title><link href="https://tech-fellow.eu/2015/04/26/content-area-under-the-hood-part-1/" rel="alternate" type="text/html" title="Content Area - Under the Hood, Part 1" /><published>2015-04-26T09:35:00+03:00</published><updated>2015-04-26T09:35:00+03:00</updated><id>https://tech-fellow.eu/2015/04/26/content-area-under-the-hood-part-1</id><content type="html" xml:base="https://tech-fellow.eu/2015/04/26/content-area-under-the-hood-part-1/"><![CDATA[<p>Lately I was visiting and revisiting content area, code and functionality around this feature in EPiServer and decided to revisit it once again and take a closer look at what’s really inside. So the blog post is not about what content area is, but how it works, how responsible party for rendering and templating is selected when EPiServer needs to render this one of the most powerful content editing feature.</p>

<p>This is a multi-part blog post series about what happens under <code class="language-plaintext highlighter-rouge">ContentArea</code> property in EPiServer.</p>

<p>Parts in this series:
– <strong>Part 1: Registration and Discovery</strong>
– <a href="https://tech-fellow.eu/2015/05/30/content-area-under-the-hood-part-2/">Part 2: Template Selection</a>
– <a href="https://tech-fellow.eu/2015/06/11/content-area-under-the-hood-part-3/">Part 3: Extensibility</a></p>

<h2 id="overview">Overview</h2>
<p>Everything starts with property definition on content data:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ContentType</span><span class="p">(</span><span class="n">GUID</span> <span class="p">=</span> <span class="s">"265F52C3-5E88-4AFE-90F8-9A42819D9EAF"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">StartPage</span> <span class="p">:</span> <span class="n">PageData</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">Display</span><span class="p">(</span><span class="n">GroupName</span> <span class="p">=</span> <span class="n">SystemTabNames</span><span class="p">.</span><span class="n">Content</span><span class="p">,</span> <span class="n">Order</span> <span class="p">=</span> <span class="m">10</span><span class="p">,</span> <span class="n">Name</span> <span class="p">=</span> <span class="err">“</span><span class="n">Content</span> <span class="n">area</span><span class="err">”</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">virtual</span> <span class="n">ContentArea</span> <span class="n">MainContentArea</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>From the technical perspective <code class="language-plaintext highlighter-rouge">ContentArea</code> property is still just an ordinary page property, in this case it’s just yet another <code class="language-plaintext highlighter-rouge">XhtmlString</code> type of property.
Interesting part about content area is that all the content and some of the settings for items EPiServer is storing as semi html data. For instance this area:</p>

<p><img src="/assets/img/2015/05/content-area-100.png" alt="" /></p>

<p>Is stored as html data:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre>data-contentguid="e51f496b-ebe..."
data-contentlink="6"
data-contentname="sample block 1"&gt;{}
data-contentguid="5dd9a357-761...."
data-contentlink="7"
data-contentname="with controller"
data-epi-content-display-option="full"&gt;{}
data-contentguid="08399f13-9339-46...."
data-contentlink="10"
data-contentname="with iview"
data-epi-content-display-option="full"&gt;{}
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Interesting part starts with what exactly EPiServer is doing when it’s given a command to render a content area inside content template:</p>

<pre><code class="language-razor">@Html.PropertyFor(m =&gt; m.MainContentArea)
</code></pre>

<h2 id="rendering-pipeline">Rendering Pipeline</h2>
<p>Let’s take a look at what happens under the hood when EPiServer encounters <code class="language-plaintext highlighter-rouge">PropertyFor(ContentArea)</code>. Method basically goes through few discovery steps to pick up template to be used for content area rendering. If nothing has been modified and there are no deviations from built-in functionality – eventually method will call <code class="language-plaintext highlighter-rouge">DisplayFor</code> (from Asp.Net Mvc).</p>

<p>Below is short overview of pipeline what happens during content area rendering:</p>

<p><img src="/assets/img/2015/05/content-area-200.png" alt="" /></p>

<p>Asp.Net Mvc <code class="language-plaintext highlighter-rouge">DisplayFor</code> finally hits <code class="language-plaintext highlighter-rouge">ContentArea.ascx</code> file which calls <code class="language-plaintext highlighter-rouge">Html.RenderContentArea()</code>. <code class="language-plaintext highlighter-rouge">ContentArea.ascx</code> file is located in <code class="language-plaintext highlighter-rouge">EPiServer.Cms.Shell.UI.zip</code> file which is part of CMS package and is located in protected modules directory.</p>

<p>There are 2 essential steps to let Asp.Net Mvc hit <code class="language-plaintext highlighter-rouge">ContentArea.ascx</code>:
a) Special view engine is registered together with EPiServer site that has access to this <code class="language-plaintext highlighter-rouge">.zip</code> file and knows about content of the file;
b) View engine is registered by <code class="language-plaintext highlighter-rouge">UIInititialization</code> module;</p>

<p>File <code class="language-plaintext highlighter-rouge">ContentArea.ascx</code> does not contain much code – immediately passes control over to <code class="language-plaintext highlighter-rouge">ContentAreaRenderer</code> the guy who is responsible for rest of the process.
<code class="language-plaintext highlighter-rouge">ContentAreaRender</code> is responsible also for selecting (actually not the selection itself, but at least calling code that will do the stuff) which rendering template will be used for particular content area item. All registered templates are stored in <code class="language-plaintext highlighter-rouge">TemplateModelRepository</code> and you can get direct access to these templates via this class. We will take a look at who and how is filling up template model repository a bit later in section about scanning and discovery of the renderers.</p>

<h2 id="types-of-template-renderers">Types of Template Renderers</h2>
<p>There are few types of template renderers available to render content of area item.</p>

<p><img src="/assets/img/2015/05/content-area-300.png" alt="" /></p>

<p>Available render templates:
a) <em>markup view</em> – just an ordinary markup view
b) <em>IView</em> – something that implements <code class="language-plaintext highlighter-rouge">IView</code> interface directly
c) <em>partial content controller</em> – type derived from <code class="language-plaintext highlighter-rouge">PartialContentController</code></p>

<h3 id="aspnet-mvc-view-as-render-template">Asp.Net Mvc View as Render Template</h3>
<p>The easiest and fastest way to get content out to page is “register” ordinary Asp.Net Mvc view as rendering template. EPiServer will call view directly passing in content type it is rendering. Registration is set into quotes because it’s not always explicit manual registration. There is also automatic discovery process in place, but we will take a look at that a bit later.
Model of the view must be the same as content type it’s handling a rendering for:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="n">@model</span> <span class="n">SampleProject</span><span class="p">.</span><span class="n">Models</span><span class="p">.</span><span class="n">Cms</span><span class="p">.</span><span class="n">Blocks</span><span class="p">.</span><span class="n">SampleBlock</span>
<span class="err">…</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="iview-as-render-template">IView as Render Template</h3>
<p>Sometimes it’s not enough with just dumb view template, maybe some code should be executed before actual rendering of the markup, some calculations or anything.
For this reason there is a possibility to register something that implements <code class="language-plaintext highlighter-rouge">IView</code> interface as render template for the content.
So the render template itself is pretty straight forward (assuming that there is a block of type <code class="language-plaintext highlighter-rouge">SampleBlockWithIView</code>):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">SampleBlockWithIViewRenderer</span> <span class="p">:</span> <span class="n">IView</span><span class="p">,</span>
                                            <span class="n">IRenderTemplate</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Render</span><span class="p">(</span><span class="n">ViewContext</span> <span class="n">viewContext</span><span class="p">,</span> <span class="n">TextWriter</span> <span class="n">writer</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="err">…</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><em>NB!</em> There are issues for passed in <code class="language-plaintext highlighter-rouge">ViewContext</code> – about what exactly you <a href="http://world.episerver.com/Modules/Forum/Pages/Thread.aspx?id=114901">will receive</a>. But that’s minor issue for now.</p>

<p>How to get registered? Wait till discovery and registration section on this blog post.</p>

<h3 id="blockcontroller-as-render-template">BlockController as Render Template</h3>
<p>The most Mvc-ish way to handle rendering of the block is to create a controller that is inheriting from <code class="language-plaintext highlighter-rouge">BlockController</code></p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">SampleBlockWithCtrlController</span> <span class="p">:</span> <span class="n">BlockController</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">override</span> <span class="n">ActionResult</span> <span class="nf">Index</span><span class="p">(</span><span class="n">SampleBlockWithCtrl</span> <span class="n">currentBlock</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="err">…</span>
        <span class="k">return</span> <span class="nf">PartialView</span><span class="p">(</span><span class="err">…</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><em>NB!</em> However EPiServer is complaining that this implementation of block render template is <a href="http://world.episerver.com/blogs/Jonas-Bergqvist/Dates/2013/6/Hidden-template-functionality-in-the-MVC-implementation/">very slow</a> and is desired to be avoided.</p>

<h2 id="template-scanning-and-discovery-process">Template Scanning and Discovery Process</h2>
<p>All discovered templates and renders are stored in template model repository. This section will describe how exactly templates are discovered and then stored in this repository.</p>

<p><img src="/assets/img/2015/05/content-area-400.png" alt="" /></p>

<p>Template model repository is main data source for template selector when <code class="language-plaintext highlighter-rouge">ContentAreaRenderer</code> needs to find what template to use when rendering the content.</p>

<p><img src="/assets/img/2015/05/content-area-500.png" alt="" /></p>

<p>There are two main responsible parties for filling up the repository:
a) <code class="language-plaintext highlighter-rouge">RenderTemplateScanner</code>
b) <code class="language-plaintext highlighter-rouge">ViewRegistrator</code></p>

<h3 id="rendertemplate-scanning-process">RenderTemplate Scanning Process</h3>
<p><code class="language-plaintext highlighter-rouge">RenderTemplateScanner</code> gets kicked in discovery process by <code class="language-plaintext highlighter-rouge">ModelSyncInitialization</code> initialization module at the very beginning of the request processing pipeline.</p>

<p>There are few main responsibilities for <code class="language-plaintext highlighter-rouge">RenderTemplateScanner</code> process:
a) It looks for everybody that implements marker interface <code class="language-plaintext highlighter-rouge">IRenderTemplate</code> and registers it. It means that all <code class="language-plaintext highlighter-rouge">PageController</code>s and <code class="language-plaintext highlighter-rouge">BlockController</code>s are being registered by this guy;
b) It also looks for <code class="language-plaintext highlighter-rouge">TemplateDescriptorAttribute</code>s and registers mentioned template model explicitly in the repository;</p>

<p>For instance in this sample code from AlloyTech sample site – will tell EPiServer to register this as render template with various settings (read more in <a href="https://tech-fellow.eu/2015/05/28/content-area-under-the-hood-part-2/">Part 2</a>: about template selection).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">TemplateDescriptor</span><span class="p">(</span><span class="n">Inherited</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
                    <span class="n">TemplateTypeCategory</span> <span class="p">=</span> <span class="n">TemplateTypeCategories</span><span class="p">.</span><span class="n">MvcController</span><span class="p">,</span>
                    <span class="n">Tags</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span> <span class="p">{</span> <span class="n">RenderingTags</span><span class="p">.</span><span class="n">Preview</span><span class="p">,</span> <span class="n">RenderingTags</span><span class="p">.</span><span class="n">Edit</span> <span class="p">},</span>
                    <span class="n">AvailableWithoutTag</span> <span class="p">=</span> <span class="k">false</span><span class="p">)]</span>
<span class="p">[</span><span class="n">VisitorGroupImpersonation</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">PreviewController</span> <span class="p">:</span> <span class="n">ActionControllerBase</span><span class="p">,</span> <span class="n">IRenderTemplate</span>
<span class="p">{</span>
    <span class="err">…</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="aspnet-mvc-view-scanning-process">Asp.Net Mvc View Scanning Process</h3>
<p>Second part of the template model discovery process is view registration. It may create template models in the repository (for not previously registered model types) or it may update already existing ones with an newly discovered information about available template(-s).</p>

<p><em>NB!</em> Interesting part about Mvc view template discovery is that it gets kicked in only on first request by <code class="language-plaintext highlighter-rouge">ContentRoute</code>. I can just speculate that this delay is needed to let Mvc and other moving parts to finish it’s registration and initialization and to discover Mvc views in EPiServer’s initialization module could be pretty early in the pipeline.</p>

<p>So what does <code class="language-plaintext highlighter-rouge">ViewRegistrator</code> do? It’s responsible for 2 processes:
a) Manual template model registration (see “Manual Registration” below);
b) Convention based template model registration (see “Conventions Based Registration” below);</p>

<h3 id="manual-registration">Manual Registration</h3>

<p>There is possibility to skip all automatic or semi-automatic discovery processes and do manual template model registration. This is supported by <code class="language-plaintext highlighter-rouge">ViewRegistrator</code> which looks for types implementing <code class="language-plaintext highlighter-rouge">IViewTemplateModelRegistrator</code> interface and calls <code class="language-plaintext highlighter-rouge">Register</code> method.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ServiceConfiguration</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">IViewTemplateModelRegistrator</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">TemplateCoordinator</span> <span class="p">:</span> <span class="n">IViewTemplateModelRegistrator</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Register</span><span class="p">(</span><span class="n">TemplateModelCollection</span> <span class="n">viewTemplateModelRegistrator</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="err">…</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then it’s really up to the developer how and which templates are registered.
Here developer can provide every single detail to the template model needed to be registered.
For instance this registration can’t be discovered with any automatic registration and therefore done manually:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">Register</span><span class="p">(</span><span class="n">TemplateModelCollection</span> <span class="n">registrator</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">registrator</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">SampleBlock</span><span class="p">),</span>
                    <span class="k">new</span> <span class="n">TemplateModel</span>
                    <span class="p">{</span>
                        <span class="n">Tags</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span> <span class="p">{</span> <span class="s">"full-width"</span> <span class="p">},</span>
                        <span class="n">AvailableWithoutTag</span> <span class="p">=</span> <span class="k">false</span><span class="p">,</span>
                        <span class="n">Default</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
                        <span class="n">Name</span> <span class="p">=</span> <span class="s">"SampleBlockFullWidth"</span><span class="p">,</span>
                        <span class="n">Path</span> <span class="p">=</span> <span class="s">"~/Views/Shared/Blocks/_SampleBlockFullWidth.cshtml"</span>
                    <span class="p">});</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>It’s also possible to register any template type (actual code that will handle rendering) within template model. For instance you can manually register <code class="language-plaintext highlighter-rouge">IView</code> template as template type:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ServiceConfiguration</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">IViewTemplateModelRegistrator</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">TemplateCoordinator</span> <span class="p">:</span> <span class="n">IViewTemplateModelRegistrator</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Register</span><span class="p">(</span><span class="n">TemplateModelCollection</span> <span class="n">registrator</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">registrator</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span>
            <span class="k">typeof</span><span class="p">(</span><span class="n">SampleBlockWithIView</span><span class="p">),</span>
            <span class="k">new</span> <span class="n">TemplateModel</span>
            <span class="p">{</span>
                <span class="n">Default</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
                <span class="n">AvailableWithoutTag</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span>
                <span class="n">TemplateTypeCategory</span> <span class="p">=</span> <span class="n">TemplateTypeCategories</span><span class="p">.</span><span class="n">MvcPartialView</span><span class="p">,</span>
                <span class="n">Name</span> <span class="p">=</span> <span class="s">"SampleBlockWithIViewRenderer"</span><span class="p">,</span>
                <span class="n">TemplateType</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="n">SampleBlockWithIViewRenderer</span><span class="p">)</span>
            <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Explicit registration gives you more control over how and what template renderer to register comparing to automatic discovery.</p>

<h3 id="conventions-based-registration">Conventions Based Registration</h3>

<p>Another part of <code class="language-plaintext highlighter-rouge">ViewRegistrator</code> is to discover templates based on default naming conventions.
So for instance when you will have a partial view with the same name as model type that is inside your partial view locations (probably registered by custom <code class="language-plaintext highlighter-rouge">ViewEngine</code>) it’s registered as template render for this model type.</p>

<p><img src="/assets/img/2015/05/content-area-600.png" alt="" /></p>

<h2 id="next-part">Next Part</h2>

<p>In next blog post we will cover how templates are being selected based on various settings inside registered <code class="language-plaintext highlighter-rouge">TemplateModel</code>.</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><category term="under the hood" /><summary type="html"><![CDATA[Lately I was visiting and revisiting content area, code and functionality around this feature in EPiServer and decided to revisit it once again and take a closer look at what’s really inside. So the blog post is not about what content area is, but how it works, how responsible party for rendering and templating is selected when EPiServer needs to render this one of the most powerful content editing feature.]]></summary></entry><entry><title type="html">Switch Content Language Everywhere in EPiServer</title><link href="https://tech-fellow.eu/2015/04/09/switch-content-language-everywhere-in-episerver/" rel="alternate" type="text/html" title="Switch Content Language Everywhere in EPiServer" /><published>2015-04-09T13:30:00+03:00</published><updated>2015-04-09T13:30:00+03:00</updated><id>https://tech-fellow.eu/2015/04/09/switch-content-language-everywhere-in-episerver</id><content type="html" xml:base="https://tech-fellow.eu/2015/04/09/switch-content-language-everywhere-in-episerver/"><![CDATA[<p>Nowadays lot of sites are localized or globalized (depending from which point of view you are looking at). Usually it means that developer has to provide some sort of language switcher for the end-user to pick another content language. This blog post is about small trick that I’m using when need to provide switcher on web sites driven by EPiServer.</p>

<p>I’ll not dig into details on how to get started with globalization and how localization engine and services are working (you can find lot of information in <a href="http://world.episerver.com/documentation/Items/Developers-Guide/EPiServer-Framework/7/Localization/">SDK</a>).</p>

<h2 id="common-features">Common Features</h2>

<p>It really depends on each site’s requirements, but here are some common cases that regular site may have:</p>

<ul>
  <li>provide content in different language;</li>
  <li>give possibility for end-user to switch language;</li>
  <li>enlist all available languages defined in the site;</li>
  <li>if current page does not exist in target language (one that end-user is going to switch to) – redirect user to start page;</li>
  <li>if current page exists in target language – redirect user to new page version in requested content language;</li>
  <li>preserve all query parameters from the current page (not to loose contextual information while switching);</li>
  <li>optional: persist selected language somewhere (sometimes auto-select content language is needed when user accessing site next time);</li>
</ul>

<h2 id="enlisting-available-languages">Enlisting Available Languages</h2>

<p>This is really easy. Type that will give you everything is <code class="language-plaintext highlighter-rouge">LanguageBranchRepository</code>:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="n">IList</span><span class="p">&lt;</span><span class="n">LanguageBranch</span><span class="p">&gt;</span> <span class="n">languages</span> <span class="p">=</span>
          <span class="n">ServiceLocator</span><span class="p">.</span><span class="n">Current</span>
                <span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">LanguageBranchRepository</span><span class="p">&gt;()</span>
                <span class="p">.</span><span class="nf">ListEnabled</span><span class="p">();</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If you need to check whether current language while looping is the same as current page, this is also easy:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="nf">@foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">lang</span> <span class="k">in</span> <span class="n">languages</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="kt">string</span><span class="p">.</span><span class="nf">Equals</span><span class="p">(</span><span class="n">Model</span><span class="p">.</span><span class="n">CurrentPage</span><span class="p">.</span><span class="n">Language</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span> <span class="n">lang</span><span class="p">.</span><span class="n">LanguageID</span><span class="p">,</span>
                      <span class="n">StringComparison</span><span class="p">.</span><span class="n">CurrentCultureIgnoreCase</span><span class="p">))</span>
    <span class="p">{</span> <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="generating-target-page-address">Generating Target Page Address</h2>

<p>Next thing we need is to generate target page address in particular content language that will be used in language switcher. There could be cases when end-user is on page that does not exist in other languages, regardless of that site most probably needs to provider language switcher anyway. Target address in this case may be start page. It’s simple condition in code (assuming that Model in the view is view-model with access to current page from EPiServer).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">contentLoader</span> <span class="p">=</span> <span class="n">ServiceLocator</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">IContentLoader</span><span class="p">&gt;();</span>

<span class="nf">@foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">lang</span> <span class="k">in</span> <span class="n">languages</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">languageSelector</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">LanguageSelector</span><span class="p">(</span><span class="n">lang</span><span class="p">.</span><span class="n">LanguageID</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">alternatePage</span> <span class="p">=</span>
             <span class="n">contentLoader</span><span class="p">.</span><span class="n">Get</span><span class="p">&lt;</span><span class="n">PageData</span><span class="p">&gt;(</span><span class="n">Model</span><span class="p">.</span><span class="n">CurrentPage</span><span class="p">.</span><span class="n">ContentLink</span><span class="p">,</span> <span class="n">languageSelector</span><span class="p">)</span>
             <span class="p">??</span> <span class="n">contentLoader</span><span class="p">.</span><span class="n">Get</span><span class="p">&lt;</span><span class="n">PageData</span><span class="p">&gt;(</span><span class="n">ContentReference</span><span class="p">.</span><span class="n">StartPage</span><span class="p">,</span> <span class="n">languageSelector</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Once we got target page content reference, we can generate url for that page:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="p">...</span>
<span class="kt">var</span> <span class="n">resolver</span> <span class="p">=</span> <span class="n">ServiceLocator</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">UrlResolver</span><span class="p">&gt;();</span>

<span class="nf">@foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">lang</span> <span class="k">in</span> <span class="n">languages</span><span class="p">)</span>
<span class="p">{</span>
    <span class="p">...</span>
    <span class="kt">var</span> <span class="n">alternatePageAddress</span> <span class="p">=</span> <span class="n">resolver</span><span class="p">.</span><span class="nf">GetUrl</span><span class="p">(</span><span class="n">alternatePage</span><span class="p">.</span><span class="n">ContentLink</span><span class="p">,</span>
                                               <span class="n">languageSelector</span><span class="p">.</span><span class="n">LanguageBranch</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="preserving-query-parameters">Preserving Query Parameters</h3>

<p>Very simple solution to preserve any query parameter if applicable.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="nf">@foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">lang</span> <span class="k">in</span> <span class="n">languages</span><span class="p">)</span>
<span class="p">{</span>
    <span class="p">...</span>
    <span class="kt">var</span> <span class="n">parameters</span> <span class="p">=</span> <span class="n">Request</span><span class="p">.</span><span class="n">Url</span> <span class="p">!=</span> <span class="k">null</span> <span class="p">?</span> <span class="n">Request</span><span class="p">.</span><span class="n">Url</span><span class="p">.</span><span class="n">Query</span> <span class="p">:</span> <span class="kt">string</span><span class="p">.</span><span class="n">Empty</span><span class="p">;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now we can generate target page address:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="p">&lt;</span><span class="n">a</span> <span class="n">href</span><span class="p">=</span><span class="s">"@(alternatePageAddress + "</span><span class="n">switchlanguage</span><span class="s">" + parameters)"</span><span class="p">&gt;</span><span class="n">@lang</span><span class="p">.</span><span class="n">Name</span><span class="p">&lt;/</span><span class="n">a</span><span class="p">&gt;</span>

<span class="c1">// this will give us link for 'href':</span>
<span class="c1">//  "/{language-code}/target-page/switchlanguage?parameter1=value1&amp;.."</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="switchlanguage-action-handler">`SwitchLanguage’ Action Handler</h2>

<p>Using generated link we should switch language wherever end-user is in the site, on any page with any query parameters already added to the url. It means that we can safely provider language switcher link everywhere on the site.
Action <code class="language-plaintext highlighter-rouge">SwitchLanguage</code> is special action that will be invoked by Asp.Net Mvc together with EPiServer when action look-up will fail.</p>

<p>You may ask why da heck do I need to create new action for handling content language and how this differs from ordinary target link to target language? One of the reason why I like special handler is that I do have freedom of what exactly happens when user explicitly chooses to change content language and not just visiting page in particular language.</p>

<p>So who is handling this <code class="language-plaintext highlighter-rouge">SwitchLanguage</code> action?</p>

<p>I wasn’t aware that there is a small extensibility point in Asp.Net Mvc – called `Handle Unknown Action’. Unknown action handler is implemented in base Mvc controller and overwritten in EPiServer base action controller.
You will need to register this unknown action handler and tell EPiServer to register this in it’s internal list of handlers:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ServiceConfiguration</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">IUnknownActionHandler</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">LanguageSwitcherHandler</span> <span class="p">:</span> <span class="n">IUnknownActionHandler</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">ActionName</span>
    <span class="p">{</span>
        <span class="k">get</span>
        <span class="p">{</span>
            <span class="k">return</span> <span class="s">"changelanguage"</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">ActionResult</span> <span class="nf">HandleAction</span><span class="p">(</span><span class="n">Controller</span> <span class="n">controller</span><span class="p">)</span>
    <span class="p">{</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This will tell EPiServer: whenever you will receive a message from Asp.Net Mvc that action was not dispatched (because there is no method implemented that may handle requested action from request) please invoke this action handler if action name matches <code class="language-plaintext highlighter-rouge">ActionName</code> property value.</p>

<p>As request has been already made to target page in target content language you can easily extract language out of <code class="language-plaintext highlighter-rouge">RouteData</code>:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">LanguageSwitcherHandler</span> <span class="p">:</span> <span class="n">IUnknownActionHandler</span>
<span class="p">{</span>
    <span class="p">...</span>

    <span class="k">public</span> <span class="n">ActionResult</span> <span class="nf">HandleAction</span><span class="p">(</span><span class="n">Controller</span> <span class="n">controller</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">language</span> <span class="p">=</span> <span class="n">controller</span><span class="p">.</span><span class="n">RouteData</span><span class="p">.</span><span class="n">Values</span><span class="p">[</span><span class="s">"language"</span><span class="p">].</span><span class="nf">ToString</span><span class="p">();</span>
    <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>What you do with this language is really up to you and site’s requirements. Usually it may be preserved in cookie, session, cloud storage or whatever other persistent media for later usage.</p>

<h2 id="what-to-do-next-when-language-is-switched">What to do next when language is switched?</h2>

<p>Next what you may need to do is to actually process originally requested page or action.
I know that this is not ideal solution, but one of the easiest way was to generate new url without <code class="language-plaintext highlighter-rouge">“/switchlanguage”</code> action and send back redirect action result to client, to force browser to request new page once again within new browser state (assuming that maybe you may persist new selected language in browser’s cookies).</p>

<p><strong>NB!</strong> Sounds like not an ideal solution for production site?! :) Most probably. The proper way you may need to do is actually something like Server.Execute() did in old good days.</p>

<h2 id="summary">Summary</h2>

<p>So using unknown action handlers it’s possible:</p>

<ul>
  <li>give possibility for end-user to switch language wherever he or she is in the site;</li>
  <li>developer precise moment and handler that will be invoked when end-user will switch content language, and not just requesting page in particular content language;</li>
  <li>query parameters are preserved if any;</li>
</ul>

<p>Happy coding!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term="Commerce" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><category term="commerce" /><summary type="html"><![CDATA[Nowadays lot of sites are localized or globalized (depending from which point of view you are looking at). Usually it means that developer has to provide some sort of language switcher for the end-user to pick another content language. This blog post is about small trick that I’m using when need to provide switcher on web sites driven by EPiServer.]]></summary></entry><entry><title type="html">Bootstrap aware Content Area for EPiServer 8.0</title><link href="https://tech-fellow.eu/2015/04/02/bootstrap-aware-content-area-for-episerver-8-0/" rel="alternate" type="text/html" title="Bootstrap aware Content Area for EPiServer 8.0" /><published>2015-04-02T22:30:00+03:00</published><updated>2015-04-02T22:30:00+03:00</updated><id>https://tech-fellow.eu/2015/04/02/bootstrap-aware-content-area-for-episerver-8-0</id><content type="html" xml:base="https://tech-fellow.eu/2015/04/02/bootstrap-aware-content-area-for-episerver-8-0/"><![CDATA[<p>I got pull request from <a href="https://github.com/mathiasnohall">Mathias Nohall</a> on GitHub asking for adding support for EPiServer v8.0. This is what we call open-sourcing :). I was thinking this is good moment to introduce some breaking changes in EPiBootstrapArea plugin and give you fresh package compatible with v8.0 of EPiServer and also cleaned-up from some left-overs (mainly pointed out by <a href="https://github.com/valdisiljuconoks/EPiBootstrapArea/pull/3">Mark’s pull request</a>).</p>

<h2 id="changes">Changes</h2>

<p>Here is list of changes that has been applied for this release:</p>

<ul>
  <li>New referenced EPiServer NuGet package is version 8.3;</li>
  <li>DDS stored DisplayModeFallback is now more optional;</li>
  <li>Primary list of DisplayModeFallbacks are retrieved from <code class="language-plaintext highlighter-rouge">EPiBootstrapArea.Providers.DisplayModeFallbackDefaultProvider</code> provider;</li>
  <li>It’s possible to provide additional display modes from the code or from the DDS storage;</li>
</ul>

<h2 id="supply-additional-display-modes">Supply Additional Display Modes</h2>

<p>It’s not an exception that your project may require additional or totally another set of display modes. If this is your case and you need to provide additional display modes, all you need to do is swap default provider and override <code class="language-plaintext highlighter-rouge">GetAll()</code> method.</p>

<p>Swap default provider:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">EPiServer</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">RegisterDisplayModesModule</span> <span class="p">:</span> <span class="n">IConfigurableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureContainer</span><span class="p">(</span><span class="n">ServiceConfigurationContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">context</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="nf">Configure</span><span class="p">(</span><span class="n">ConfigureContainer</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">ConfigureContainer</span><span class="p">(</span><span class="n">ConfigurationExpression</span> <span class="n">container</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">container</span><span class="p">.</span><span class="n">For</span><span class="p">&lt;</span><span class="n">IDisplayModeFallbackProvider</span><span class="p">&gt;()</span>
                 <span class="p">.</span><span class="n">Use</span><span class="p">&lt;</span><span class="n">DisplayModeFallbackCustomProvider</span><span class="p">&gt;();</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Preload</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">parameters</span><span class="p">)</span>
    <span class="p">{</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Implement your own set or add additional display modes:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">DisplayModeFallbackCustomProvider</span> <span class="p">:</span> <span class="n">DisplayModeFallbackDefaultProvider</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">override</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">DisplayModeFallback</span><span class="p">&gt;</span> <span class="nf">GetAll</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">original</span> <span class="p">=</span> <span class="k">base</span><span class="p">.</span><span class="nf">GetAll</span><span class="p">();</span>

        <span class="n">original</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">new</span> <span class="n">DisplayModeFallback</span>
        <span class="p">{</span>
            <span class="n">Name</span> <span class="p">=</span> <span class="s">"This is from code (1/12)"</span><span class="p">,</span>
            <span class="n">Tag</span> <span class="p">=</span> <span class="s">"one-12th-from-code"</span><span class="p">,</span>
            <span class="n">LargeScreenWidth</span> <span class="p">=</span> <span class="m">12</span><span class="p">,</span>
            <span class="n">MediumScreenWidth</span> <span class="p">=</span> <span class="m">12</span><span class="p">,</span>
            <span class="n">SmallScreenWidth</span> <span class="p">=</span> <span class="m">12</span><span class="p">,</span>
            <span class="n">ExtraSmallScreenWidth</span> <span class="p">=</span> <span class="m">12</span>
        <span class="p">});</span>

        <span class="k">return</span> <span class="n">original</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="adding-support-for-dds-driven-storage">Adding Support for DDS Driven Storage</h2>

<p>In order to get back DDS driven storage for display modes – you need to swap built-in provider with another build-in <code class="language-plaintext highlighter-rouge">EPiBootstrapArea.Providers.DisplayModeDdsFallbackProvider</code>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">EPiServer</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">RegisterDisplayModesModule</span> <span class="p">:</span> <span class="n">IConfigurableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureContainer</span><span class="p">(</span><span class="n">ServiceConfigurationContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">context</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="nf">Configure</span><span class="p">(</span><span class="n">ConfigureContainer</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">ConfigureContainer</span><span class="p">(</span><span class="n">ConfigurationExpression</span> <span class="n">container</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">container</span><span class="p">.</span><span class="n">For</span><span class="p">&lt;</span><span class="n">IDisplayModeFallbackProvider</span><span class="p">&gt;()</span>
                 <span class="p">.</span><span class="n">Use</span><span class="p">&lt;</span><span class="n">DisplayModeDdsFallbackProvider</span><span class="p">&gt;();</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Preload</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">parameters</span><span class="p">)</span>
    <span class="p">{</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Provider <code class="language-plaintext highlighter-rouge">DisplayModeDdsFallbackProvider</code> will only add modes that are not previously registered in DDS by comparing <code class="language-plaintext highlighter-rouge">Tag</code> properties for display modes.</p>

<p>If you need additional DisplayModes than default ones provided by the package – you can do that easily in overridden class:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">EPiServer</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">RegisterDisplayModesModule</span> <span class="p">:</span> <span class="n">IConfigurableModule</span>
<span class="p">{</span>
     <span class="k">private</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">ConfigureContainer</span><span class="p">(</span><span class="n">ConfigurationExpression</span> <span class="n">container</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">container</span><span class="p">.</span><span class="n">For</span><span class="p">&lt;</span><span class="n">IDisplayModeFallbackProvider</span><span class="p">&gt;()</span>
                 <span class="p">.</span><span class="n">Use</span><span class="p">&lt;</span><span class="n">DisplayModeCustomDdsFallbackProvider</span><span class="p">&gt;();</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">DisplayModeCustomDdsFallbackProvider</span> <span class="p">:</span> <span class="n">DisplayModeDdsFallbackProvider</span>
<span class="p">{</span>
    <span class="k">protected</span> <span class="k">override</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">DisplayModeFallback</span><span class="p">&gt;</span> <span class="nf">GetInitialData</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">original</span> <span class="p">=</span> <span class="k">base</span><span class="p">.</span><span class="nf">GetInitialData</span><span class="p">();</span>

        <span class="n">original</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">new</span> <span class="n">DisplayModeFallback</span>
        <span class="p">{</span>
            <span class="n">Name</span> <span class="p">=</span> <span class="s">"From code (1 / 12)"</span><span class="p">,</span>
            <span class="n">Tag</span> <span class="p">=</span> <span class="s">"from-code"</span><span class="p">,</span>
            <span class="n">LargeScreenWidth</span> <span class="p">=</span> <span class="m">12</span><span class="p">,</span>
            <span class="n">MediumScreenWidth</span> <span class="p">=</span> <span class="m">12</span><span class="p">,</span>
            <span class="n">SmallScreenWidth</span> <span class="p">=</span> <span class="m">12</span><span class="p">,</span>
            <span class="n">ExtraSmallScreenWidth</span> <span class="p">=</span> <span class="m">12</span>
        <span class="p">});</span>

        <span class="k">return</span> <span class="n">original</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This should additionally add another display mode available for editor’s disposal.</p>

<p><img src="/assets/img/2015/05/display-mode-from-code.png" alt="" /></p>

<p>Thanks and happy coding!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term="Bootstrap" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><category term="bootstrap" /><summary type="html"><![CDATA[I got pull request from Mathias Nohall on GitHub asking for adding support for EPiServer v8.0. This is what we call open-sourcing :). I was thinking this is good moment to introduce some breaking changes in EPiBootstrapArea plugin and give you fresh package compatible with v8.0 of EPiServer and also cleaned-up from some left-overs (mainly pointed out by Mark’s pull request).]]></summary></entry><entry><title type="html">Add localization to your angular.js stuff from EPiServer providers</title><link href="https://tech-fellow.eu/2015/03/16/add-localization-to-your-angular-js-stuff-from-episerver-providers/" rel="alternate" type="text/html" title="Add localization to your angular.js stuff from EPiServer providers" /><published>2015-03-16T20:05:00+02:00</published><updated>2015-03-16T20:05:00+02:00</updated><id>https://tech-fellow.eu/2015/03/16/add-localization-to-your-angular-js-stuff-from-episerver-providers</id><content type="html" xml:base="https://tech-fellow.eu/2015/03/16/add-localization-to-your-angular-js-stuff-from-episerver-providers/"><![CDATA[<p>Sneaking inside default EPiServer’s sample sites (like AlloyTech) we can notice that Xml based localization provider is being used. It’s nice approach to keep all localization resources in single place, well-structured using XPath query to fetch a value and group into multiple languages.
 We can argue here about various drawbacks for this provider (like, stringly typed access – actually there is a small poly fill for this <a href="https://openwaves.codeplex.com/SourceControl/latest#OpenWaves.EPiServer.Localization/trunk/src/">OpenWaves.EPiServer.Localization</a>, lack of possibility to make new authoring of localization resources by editors – also we can find some attempts to fix this – <a href="https://github.com/PNergard/CMS75XmlResourcesTool">CMS75XmlResourcesTool</a>) but this is not the point of the blog post.</p>

<p>In this blog post we are going through steps how to move server-side EPiServer Xml based resource provider content over to client-side and localize angular.js controllers, services or bindings – basically how to let angular.js to know that there is localization enabled and it’s located on the server and it’s in Xml format understandable by EPiServer providers.</p>

<h2 id="adding-localization-service-to-angularjs-application">Adding Localization Service to Angular.js Application</h2>

<p>First of all we would need to add localization support to angular.js side. For this we can pick <a href="https://github.com/doshprompt/angular-localization">angular-localization on github.com package</a> (execute this in your directory where front-end stuff is located):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>bower install angular-localization
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Next we need to add it to our application. Simple:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="o">&lt;</span><span class="nx">script</span> <span class="nx">src</span><span class="o">=</span><span class="dl">"</span><span class="s2">{front-end}/angular/angular.js</span><span class="dl">"</span><span class="o">&gt;&lt;</span><span class="sr">/script</span><span class="err">&gt;
</span><span class="o">&lt;</span><span class="nx">script</span> <span class="nx">src</span><span class="o">=</span><span class="dl">"</span><span class="s2">{front-end}/angular-localization/angular-localization.js</span><span class="dl">"</span><span class="o">&gt;&lt;</span><span class="sr">/script</span><span class="err">&gt;
</span>
<span class="nx">angular</span><span class="p">.</span><span class="nf">module</span><span class="p">(</span><span class="dl">'</span><span class="s1">myApp</span><span class="dl">'</span><span class="p">,</span> <span class="p">[</span><span class="dl">'</span><span class="s1">ngLocalize</span><span class="dl">'</span><span class="p">])</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>That’s it. Next we need to connect it to the server-side.</p>

<h2 id="connect-localization-service-to-webapi">Connect localization service to WebApi</h2>

<p>By default angular-localization will try to fetch localization resource file (Json format) based on decision how you request resource keys. If you request <code class="language-plaintext highlighter-rouge">locale.getString('shared.sampleKey')</code> plugin will assume that there must be file named <code class="language-plaintext highlighter-rouge">shared.lang.json</code> in your resource directory under culture subdirectory.</p>

<p>For instance you should then have a <code class="language-plaintext highlighter-rouge">.lang.json</code> file located in <code class="language-plaintext highlighter-rouge">languages/en-US/shared.lang.json</code> with following content:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="p">{</span><span class="w">
    </span><span class="err">sampleKey:</span><span class="w"> </span><span class="s2">"sample value"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>If you request localization resource value by following key (shared.sampleKey):</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="nx">angular</span><span class="p">.</span><span class="nf">module</span><span class="p">(</span><span class="dl">'</span><span class="s1">myApp</span><span class="dl">'</span><span class="p">)</span>
       <span class="p">.</span><span class="nf">controller</span><span class="p">(</span><span class="dl">'</span><span class="s1">myController</span><span class="dl">'</span><span class="p">,</span> <span class="p">[</span><span class="dl">'</span><span class="s1">$scope</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">locale</span><span class="dl">'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">$scope</span><span class="p">,</span> <span class="nx">locale</span><span class="p">)</span> <span class="p">{</span>

           <span class="kd">function</span> <span class="nf">init</span><span class="p">()</span> <span class="p">{</span>
                <span class="kd">var</span> <span class="nx">message</span> <span class="o">=</span> <span class="nx">locale</span><span class="p">.</span><span class="nf">getString</span><span class="p">(</span><span class="dl">'</span><span class="s1">shared.sampleKey</span><span class="dl">'</span><span class="p">);</span>
           <span class="p">}</span>

        <span class="p">}]);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Localization service will try to fetch <code class="language-plaintext highlighter-rouge">shared.lang.json</code> file (because shared in the name of the bundle for the service – bundle = set of resources located in the file with bundle name) from resource directory based on default localization service settings.</p>

<p><strong>NB!</strong> Actually you need to use locale.ready() to workaround asynchronous call to fetch the resources:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="nx">angular</span><span class="p">.</span><span class="nf">module</span><span class="p">(</span><span class="dl">'</span><span class="s1">myApp</span><span class="dl">'</span><span class="p">)</span>
       <span class="p">.</span><span class="nf">controller</span><span class="p">(</span><span class="dl">'</span><span class="s1">myController</span><span class="dl">'</span><span class="p">,</span> <span class="p">[</span><span class="dl">'</span><span class="s1">$scope</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">locale</span><span class="dl">'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">$scope</span><span class="p">,</span> <span class="nx">locale</span><span class="p">)</span> <span class="p">{</span>

           <span class="kd">function</span> <span class="nf">init</span><span class="p">()</span> <span class="p">{</span>
                <span class="nx">locale</span><span class="p">.</span><span class="nf">ready</span><span class="p">(</span><span class="dl">'</span><span class="s1">shared</span><span class="dl">'</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
                    <span class="nx">message</span> <span class="o">=</span> <span class="nx">locale</span><span class="p">.</span><span class="nf">getString</span><span class="p">(</span><span class="dl">'</span><span class="s1">shared.sampleKey</span><span class="dl">'</span><span class="p">);</span>
                <span class="p">});</span>
           <span class="p">}</span>

       <span class="p">}]);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Instead what we want to do is to redirect angular-localization service to get Json content directly from our <code class="language-plaintext highlighter-rouge">WebApi</code> controller.</p>

<p>Configuring localization service</p>

<p>First of all we need to configure localization service to connect to our not yet existing controller to fetch resources.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="nx">angular</span><span class="p">.</span><span class="nf">module</span><span class="p">(</span><span class="dl">'</span><span class="s1">myApp</span><span class="dl">'</span><span class="p">,</span> <span class="p">[</span><span class="dl">'</span><span class="s1">ngLocalze</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">ngLocalize.Config</span><span class="dl">'</span><span class="p">])</span>
       <span class="p">.</span><span class="nf">value</span><span class="p">(</span><span class="dl">'</span><span class="s1">localeConf</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span>
            <span class="na">basePath</span><span class="p">:</span> <span class="dl">'</span><span class="s1">/api/localization/get-translation</span><span class="dl">'</span><span class="p">,</span>
            <span class="na">fileExtension</span><span class="p">:</span> <span class="dl">''</span>
       <span class="p">})</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>After these tweaks angular-localization service will try to reach for similar url: <code class="language-plaintext highlighter-rouge">/api/localization/get-translation/{language-code}/{name-of-bundle}</code> to fetch localization resources.</p>

<p>Next we need to create Api controller itself. Actually not a big deal:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">RoutePrefix</span><span class="p">(</span><span class="s">"api/localization"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">LocalizationApiController</span> <span class="p">:</span> <span class="n">BaseApiController</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">Route</span><span class="p">(</span><span class="s">"get-translation/{language}/{bundle}"</span><span class="p">)]</span>
    <span class="p">[</span><span class="n">HttpGet</span><span class="p">]</span>
    <span class="k">public</span> <span class="n">Dictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;</span> <span class="nf">GetTranslation</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">language</span> <span class="p">=</span> <span class="n">RequestContext</span><span class="p">.</span><span class="n">RouteData</span><span class="p">.</span><span class="n">Values</span><span class="p">[</span><span class="s">"language"</span><span class="p">];</span>
        <span class="kt">var</span> <span class="n">bundle</span> <span class="p">=</span> <span class="n">RequestContext</span><span class="p">.</span><span class="n">RouteData</span><span class="p">.</span><span class="n">Values</span><span class="p">[</span><span class="s">"bundle"</span><span class="p">];</span>

        <span class="kt">var</span> <span class="n">results</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Dictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;();</span>

        <span class="k">return</span> <span class="n">results</span><span class="p">;</span>
    <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This small controller will make sure that if request is coming to the controller to fetch Json data (expected as key/value format) – it’s is returned as this is automatically done by Json serializer if we are returning <code class="language-plaintext highlighter-rouge">Dictionary&lt;k,v&gt;</code>.</p>

<p>Next thing is completely up to you (as you have both – requested language and bundle name) I’ll describe our approach to fetch resource translations only for that particular bundle.</p>

<p>Use strongly-typed interface to Xml resources</p>

<p>If we install <code class="language-plaintext highlighter-rouge">OpenWaves.EPiServer.Localization</code> plugin – it makes sure that content from Xml file gets converted into object graph that could be traversed and walked around.</p>

<p>Let’s say we have Xml file with following resource keys:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;languages&gt;</span>
  <span class="nt">&lt;language</span> <span class="na">name=</span><span class="s">"English"</span> <span class="na">id=</span><span class="s">"en"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;Shared&gt;</span>
      <span class="nt">&lt;SampleKey&gt;</span>This is sample value<span class="nt">&lt;/SampleKey&gt;</span>
    <span class="nt">&lt;/Shared&gt;</span>
  <span class="nt">&lt;/language&gt;</span>
<span class="nt">&lt;/languages&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">OpenWaves.EPiServer.Localization</code> will generate <code class="language-plaintext highlighter-rouge">TranslationKeys.Shared</code> property that will contain collection of resources keys defined below that element.
 Using this approach we can traverse keys and generate json formatted reply in our controller:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">Route</span><span class="p">(</span><span class="s">"get-translation/{language}/{bundle}"</span><span class="p">)]</span>
<span class="p">[</span><span class="n">HttpGet</span><span class="p">]</span>
<span class="k">public</span> <span class="n">Dictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;</span> <span class="nf">GetTranslation</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">results</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Dictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;();</span>
    <span class="kt">var</span> <span class="n">language</span> <span class="p">=</span> <span class="n">RequestContext</span><span class="p">.</span><span class="n">RouteData</span><span class="p">.</span><span class="n">Values</span><span class="p">[</span><span class="s">"language"</span><span class="p">];</span>

    <span class="nf">TraverseTranslations</span><span class="p">(</span><span class="n">TranslationKeys</span><span class="p">.</span><span class="n">Shared</span><span class="p">,</span> <span class="n">results</span><span class="p">,</span> <span class="k">new</span> <span class="nf">CultureInfo</span><span class="p">(</span><span class="n">language</span><span class="p">));</span>
    <span class="k">return</span> <span class="n">results</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">private</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">TraverseTranslations</span><span class="p">(</span><span class="n">ITranslationEntry</span> <span class="n">rootEntry</span><span class="p">,</span>
                                         <span class="n">IDictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;</span> <span class="n">results</span><span class="p">,</span>
                                         <span class="n">CultureInfo</span> <span class="n">culture</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">collection</span> <span class="p">=</span> <span class="n">rootEntry</span> <span class="k">as</span> <span class="n">TranslationKeyCollection</span><span class="p">;</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">collection</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">collection</span><span class="p">.</span><span class="n">Entries</span><span class="p">.</span><span class="nf">ForEach</span><span class="p">(</span><span class="n">x</span> <span class="p">=&gt;</span> <span class="nf">TraverseTranslations</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">results</span><span class="p">,</span> <span class="n">culture</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="kt">var</span> <span class="n">key</span> <span class="p">=</span> <span class="n">rootEntry</span> <span class="k">as</span> <span class="n">TranslationKey</span><span class="p">;</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">key</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">results</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">key</span><span class="p">.</span><span class="n">Path</span><span class="p">,</span> <span class="n">key</span><span class="p">.</span><span class="nf">GetStringByCulture</span><span class="p">(</span><span class="n">culture</span><span class="p">));</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>NB!</strong> Recommend not to use <code class="language-plaintext highlighter-rouge">{bundle}</code> route data to fetch resources – this may open some vulnerability for your site’s “power users”. Instead use hard-coded route path to fetch resources for specific bundle / area:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">Route</span><span class="p">(</span><span class="s">"get-translation/{language}/shared"</span><span class="p">)]</span>
<span class="p">[</span><span class="n">HttpGet</span><span class="p">]</span>
<span class="k">public</span> <span class="n">Dictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;</span> <span class="nf">GetTranslation</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">results</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Dictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;();</span>
    <span class="kt">var</span> <span class="n">language</span> <span class="p">=</span> <span class="n">RequestContext</span><span class="p">.</span><span class="n">RouteData</span><span class="p">.</span><span class="n">Values</span><span class="p">[</span><span class="s">"language"</span><span class="p">];</span>

    <span class="nf">TraverseTranslations</span><span class="p">(</span><span class="n">TranslationKeys</span><span class="p">.</span><span class="n">Shared</span><span class="p">,</span> <span class="n">results</span><span class="p">,</span> <span class="k">new</span> <span class="nf">CultureInfo</span><span class="p">(</span><span class="n">language</span><span class="p">));</span>
    <span class="k">return</span> <span class="n">results</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Fixing resource key names</p>

<p>By default using <code class="language-plaintext highlighter-rouge">OpenWaves.EPiServer.Localization</code> plugin key.Path will be <code class="language-plaintext highlighter-rouge">XPath</code> syntax – this will not play nicely with angular-localization service.
Let’s say we have following Xml file:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;languages&gt;</span>
  <span class="nt">&lt;language</span> <span class="na">name=</span><span class="s">"English"</span> <span class="na">id=</span><span class="s">"en"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;Shared&gt;</span>
      <span class="nt">&lt;SampleKey&gt;</span>
        <span class="nt">&lt;AnotherSampleKey&gt;</span>
          <span class="nt">&lt;ThirdKey&gt;</span>This is the value<span class="nt">&lt;/ThirdKey&gt;</span>
        <span class="nt">&lt;/AnotherSampleKey&gt;</span>
      <span class="nt">&lt;/SampleKey&gt;</span>
    <span class="nt">&lt;/Shared&gt;</span>
  <span class="nt">&lt;/language&gt;</span>
<span class="nt">&lt;/languages&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Asking for resources through our newly created controller we will get back flatten Json:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="p">{</span><span class="w">
    </span><span class="nl">"/Shared/SampleKey/AnotherSampleKey/ThirdKey"</span><span class="p">:</span><span class="w"> </span><span class="s2">"This is the value"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>We need to apply few fixes in order to get service running:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">Route</span><span class="p">(</span><span class="s">"get-translation/{language}/shared"</span><span class="p">)]</span>
<span class="p">[</span><span class="n">HttpGet</span><span class="p">]</span>
<span class="k">public</span> <span class="n">Dictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;</span> <span class="nf">GetTranslation</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">results</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Dictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;();</span>
    <span class="kt">var</span> <span class="n">language</span> <span class="p">=</span> <span class="n">RequestContext</span><span class="p">.</span><span class="n">RouteData</span><span class="p">.</span><span class="n">Values</span><span class="p">[</span><span class="s">"language"</span><span class="p">];</span>

    <span class="nf">TraverseTranslations</span><span class="p">(</span><span class="n">TranslationKeys</span><span class="p">.</span><span class="n">Shared</span><span class="p">,</span>
                         <span class="n">results</span><span class="p">,</span>
                         <span class="k">new</span> <span class="nf">CultureInfo</span><span class="p">(</span><span class="n">language</span><span class="p">),</span>
                         <span class="n">TranslationKeys</span><span class="p">.</span><span class="n">Shared</span><span class="p">.</span><span class="n">Name</span><span class="p">);</span>

    <span class="k">return</span> <span class="n">results</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">private</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">TraverseTranslations</span><span class="p">(</span><span class="n">ITranslationEntry</span> <span class="n">rootEntry</span><span class="p">,</span>
                                         <span class="n">IDictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;</span> <span class="n">results</span><span class="p">,</span>
                                         <span class="n">CultureInfo</span> <span class="n">culture</span><span class="p">,</span>
                                         <span class="kt">string</span> <span class="n">groupName</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">collection</span> <span class="p">=</span> <span class="n">rootEntry</span> <span class="k">as</span> <span class="n">TranslationKeyCollection</span><span class="p">;</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">collection</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">collection</span><span class="p">.</span><span class="n">Entries</span><span class="p">.</span><span class="nf">ForEach</span><span class="p">(</span><span class="n">x</span> <span class="p">=&gt;</span> <span class="nf">TraverseTranslations</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">results</span><span class="p">,</span> <span class="n">culture</span><span class="p">,</span> <span class="n">rootEntry</span><span class="p">.</span><span class="n">Name</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="kt">var</span> <span class="n">key</span> <span class="p">=</span> <span class="n">rootEntry</span> <span class="k">as</span> <span class="n">TranslationKey</span><span class="p">;</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">key</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">path</span> <span class="p">=</span> <span class="n">key</span><span class="p">.</span><span class="n">Path</span><span class="p">.</span><span class="nf">Replace</span><span class="p">(</span><span class="s">"/"</span> <span class="p">+</span> <span class="n">groupName</span> <span class="p">+</span> <span class="s">"/"</span><span class="p">,</span> <span class="s">""</span><span class="p">).</span><span class="nf">Replace</span><span class="p">(</span><span class="s">"/"</span><span class="p">,</span> <span class="s">"-"</span><span class="p">);</span>
        <span class="n">results</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">key</span><span class="p">.</span><span class="nf">GetStringByCulture</span><span class="p">(</span><span class="n">culture</span><span class="p">));</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This small patch will make json look like following:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>{
    "SampleKey-AnotherSampleKey-ThirdKey": "This is the value"
}
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now we can safely use new service using a bit different naming conventions for resource keys:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="nx">angular</span><span class="p">.</span><span class="nf">module</span><span class="p">(</span><span class="dl">'</span><span class="s1">myApp</span><span class="dl">'</span><span class="p">)</span>
       <span class="p">.</span><span class="nf">controller</span><span class="p">(</span><span class="dl">'</span><span class="s1">myController</span><span class="dl">'</span><span class="p">,</span> <span class="p">[</span><span class="dl">'</span><span class="s1">$scope</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">locale</span><span class="dl">'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">$scope</span><span class="p">,</span> <span class="nx">locale</span><span class="p">)</span> <span class="p">{</span>

           <span class="kd">function</span> <span class="nf">init</span><span class="p">()</span> <span class="p">{</span>
                <span class="nx">locale</span><span class="p">.</span><span class="nf">ready</span><span class="p">(</span><span class="dl">'</span><span class="s1">shared</span><span class="dl">'</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
                    <span class="nx">message</span> <span class="o">=</span> <span class="nx">locale</span><span class="p">.</span><span class="nf">getString</span><span class="p">(</span><span class="dl">'</span><span class="s1">shared.SampleKey-AnotherSampleKey-ThirdKey</span><span class="dl">'</span><span class="p">);</span>
                <span class="p">});</span>
           <span class="p">}</span>

       <span class="p">}]);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="summary">Summary</h2>

<p>In order to localize angular.js stuff on client-side based on server-side Xml resource providers you need to:</p>

<p>a) Add localization service to angular application;
b) Configure service to fetch resources from WebApi route;
c) Add WebApi controller that will listen on that route;
d) optional: add OpenWaves localization plugin to enable strongly-typed access to resources;
e) Based on requested bundle and culture generate set of translation keys back in reply as Dictionary&lt;k,v&gt; entries get them serialized automatically into json key/value format;</p>

<p>Good luck localizing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term="Add-On" /><category term=".NET" /><category term="C#" /><category term="Localization Provider" /><category term="Episerver" /><category term="Optimizely" /><category term="add-on" /><category term=".net" /><category term="c#" /><category term="open source" /><category term="localization" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[Sneaking inside default EPiServer’s sample sites (like AlloyTech) we can notice that Xml based localization provider is being used. It’s nice approach to keep all localization resources in single place, well-structured using XPath query to fetch a value and group into multiple languages. We can argue here about various drawbacks for this provider (like, stringly typed access – actually there is a small poly fill for this OpenWaves.EPiServer.Localization, lack of possibility to make new authoring of localization resources by editors – also we can find some attempts to fix this – CMS75XmlResourcesTool) but this is not the point of the blog post.]]></summary></entry><entry><title type="html">Full support for Asp.Net Mvc areas in EPiServer 7.5</title><link href="https://tech-fellow.eu/2015/01/22/full-support-for-asp-net-mvc-areas-in-episerver-7-5/" rel="alternate" type="text/html" title="Full support for Asp.Net Mvc areas in EPiServer 7.5" /><published>2015-01-22T01:30:00+02:00</published><updated>2015-01-22T01:30:00+02:00</updated><id>https://tech-fellow.eu/2015/01/22/full-support-for-asp-net-mvc-areas-in-episerver-7-5</id><content type="html" xml:base="https://tech-fellow.eu/2015/01/22/full-support-for-asp-net-mvc-areas-in-episerver-7-5/"><![CDATA[<p>This is a blog post about how to add Asp.Net Mvc areas back in town and add full support in EPiServer v7.5. I’ll not spend time to explain what Mvc area is, most probably if you are reading this, you already are looking for a way to add it or adjust it to your needs in your EPiServer project.
 I know that there has been some attempts to add <a href="http://world.episerver.com/Blogs/Tuan--Truong/Dates/2014/2/Upgrade-to-EPiServer-Commerce-75--Part-2-MVC-Areas-Support-For-EPiServer-7--above/">Mvc areas for EPiServer 7.5</a>. Either you have to modify your view engine or add new one. Latter I don’t like at all. <a href="http://world.episerver.com/Blogs/Tuan--Truong/Dates/2014/2/Upgrade-to-EPiServer-Commerce-75--Part-2-MVC-Areas-Support-For-EPiServer-7--above/#comment3613">Someone tries</a> to inherit from some base controller class in each area and then somehow trick Mvc engine to tell in which area we currently are.</p>

<p>But there is a small challenge for any of methods mentioned and used above. For EPiServer blocks (or partial views in Mvc terms) there are two types of view template registration available:</p>

<p><strong>a)</strong> Partial rendering registration: This is something that you can find in AlloyTech sample site under <code class="language-plaintext highlighter-rouge">TemplateCoordinator</code> and is used in cases when conventions based registration (b) is not possible – manually telling EPiServer which view template to use for what content type.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ServiceConfiguration</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">IViewTemplateModelRegistrator</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">TemplateCoordinator</span> <span class="p">:</span> <span class="n">IViewTemplateModelRegistrator</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Register</span><span class="p">(</span><span class="n">TemplateModelCollection</span> <span class="n">viewTemplateModelRegistrator</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">viewTemplateModelRegistrator</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">JumbotronBlock</span><span class="p">),</span> <span class="k">new</span> <span class="n">TemplateModel</span>
        <span class="p">{</span>
            <span class="n">Tags</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span> <span class="p">{</span> <span class="n">Global</span><span class="p">.</span><span class="n">ContentAreaTags</span><span class="p">.</span><span class="n">FullWidth</span> <span class="p">},</span>
            <span class="n">AvailableWithoutTag</span> <span class="p">=</span> <span class="k">false</span><span class="p">,</span>
            <span class="n">Path</span> <span class="p">=</span> <span class="nf">BlockPath</span><span class="p">(</span><span class="s">"JumbotronBlockWide.cshtml"</span><span class="p">)</span>
        <span class="p">});</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>b)</strong> Conventions based registration: This is the case when EPiServer is asking underlying Mvc view engine collection to find matching partial view for particular content type. So basically what it means is when you will have block of name <code class="language-plaintext highlighter-rouge">EditorialBlock</code> and you do have a partial view <code class="language-plaintext highlighter-rouge">EditorialBlock.cshtml</code> (or any other engine powered view template) in some of partial view locations EPiServer will match them and will render that partial view directly when asked to render the block.</p>

<p><img src="/assets/img/2015/01/epiareas-conventions.png" alt="" /></p>

<p>So latter does not really work well in either view engine customization case or route’s data token adjustment case.
 As usual I’m looking for some sort of automation out of the box that does not need to be adjusted every time we add new area, change or delete existing ones.</p>

<h2 id="adding-mvc-area-via-visual-studio">Adding Mvc Area via Visual Studio</h2>

<p>So as we are using built-in Mvc areas scaffolding support in Visual Studio we are ending up with automatically generated area registration code:</p>

<p><img src="/assets/img/2015/01/epiareas-add.png" alt="" /></p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">SampleAreaAreaRegistration</span> <span class="p">:</span> <span class="n">AreaRegistration</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">override</span> <span class="kt">string</span> <span class="n">AreaName</span>
    <span class="p">{</span>
        <span class="k">get</span>
        <span class="p">{</span>
            <span class="k">return</span> <span class="s">"SampleArea"</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">RegisterArea</span><span class="p">(</span><span class="n">AreaRegistrationContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">context</span><span class="p">.</span><span class="nf">MapRoute</span><span class="p">(</span>
            <span class="s">"SampleArea_default"</span><span class="p">,</span>
            <span class="s">"SampleArea/{controller}/{action}/{id}"</span><span class="p">,</span>
            <span class="k">new</span> <span class="p">{</span> <span class="n">action</span> <span class="p">=</span> <span class="s">"Index"</span><span class="p">,</span> <span class="n">id</span> <span class="p">=</span> <span class="n">UrlParameter</span><span class="p">.</span><span class="n">Optional</span> <span class="p">}</span>
        <span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is something we can use for further automation.</p>

<h2 id="keep-track-of-registered-areas">Keep Track of Registered Areas</h2>

<p>By taking a deeper look at what happens under the hood when you are registering an area, we can see that there is actually nothing we can use later for enumerating through all registered areas.
So I had to wrap around this code and added my method for registering areas:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">AreaConfiguration</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">RegisterAllAreas</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">AreaRegistration</span><span class="p">.</span><span class="nf">RegisterAllAreas</span><span class="p">();</span>

        <span class="kt">var</span> <span class="n">types</span> <span class="p">=</span> <span class="n">Assembly</span><span class="p">.</span><span class="nf">GetExecutingAssembly</span><span class="p">().</span><span class="nf">GetExportedTypes</span><span class="p">();</span>
        <span class="kt">var</span> <span class="n">areas</span> <span class="p">=</span> <span class="n">types</span><span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">t</span> <span class="p">=&gt;</span> <span class="nf">IsTypeOf</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="k">typeof</span><span class="p">(</span><span class="n">AreaRegistration</span><span class="p">)));</span>

        <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">area</span> <span class="k">in</span> <span class="n">areas</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="kt">var</span> <span class="n">areaRegistration</span> <span class="p">=</span> <span class="n">AreaTable</span><span class="p">.</span><span class="nf">AddArea</span><span class="p">(</span><span class="n">area</span><span class="p">);</span>

            <span class="p">...</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="k">static</span> <span class="kt">bool</span> <span class="nf">IsTypeOf</span><span class="p">(</span><span class="n">Type</span> <span class="n">type</span><span class="p">,</span> <span class="n">Type</span> <span class="n">parentType</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">parentType</span><span class="p">.</span><span class="nf">IsAssignableFrom</span><span class="p">(</span><span class="n">type</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">AreaTable</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">static</span> <span class="k">readonly</span> <span class="n">AreaCollection</span> <span class="n">_instance</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">AreaCollection</span><span class="p">();</span>

    <span class="k">public</span> <span class="k">static</span> <span class="n">AreaCollection</span> <span class="n">Areas</span>
    <span class="p">{</span>
        <span class="k">get</span>
        <span class="p">{</span>
            <span class="k">return</span> <span class="n">_instance</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">internal</span> <span class="k">static</span> <span class="n">AreaRegistration</span> <span class="nf">AddArea</span><span class="p">(</span><span class="n">Type</span> <span class="n">area</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">area</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="s">"area"</span><span class="p">);</span>
        <span class="p">}</span>

        <span class="kt">var</span> <span class="n">areaRegistration</span> <span class="p">=</span> <span class="p">(</span><span class="n">AreaRegistration</span><span class="p">)</span><span class="n">Activator</span><span class="p">.</span><span class="nf">CreateInstance</span><span class="p">(</span><span class="n">area</span><span class="p">);</span>
        <span class="n">Areas</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">new</span> <span class="nf">Area</span><span class="p">(</span><span class="n">areaRegistration</span><span class="p">.</span><span class="n">AreaName</span><span class="p">));</span>

        <span class="k">return</span> <span class="n">areaRegistration</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>From the consumer point of view nothing really changes. You just need to change from</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">EPiServerApplication</span> <span class="p">:</span> <span class="n">EPiServer</span><span class="p">.</span><span class="n">Global</span>
<span class="p">{</span>
    <span class="k">protected</span> <span class="k">void</span> <span class="nf">Application_Start</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">AreaRegistration</span><span class="p">.</span><span class="nf">RegisterAllAreas</span><span class="p">();</span>
        <span class="p">...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>to</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">EPiServerApplication</span> <span class="p">:</span> <span class="n">EPiServer</span><span class="p">.</span><span class="n">Global</span>
<span class="p">{</span>
    <span class="k">protected</span> <span class="k">void</span> <span class="nf">Application_Start</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">AreaConfiguration</span><span class="p">.</span><span class="nf">RegisterAllAreas</span><span class="p">();</span>
        <span class="p">...</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now this new method will give us tracking of registered areas which we will need later when registering conventions based partial views.</p>

<h2 id="hook-in-to-register-partial-views">Hook-in to Register Partial Views</h2>

<p>While browsing around disassembled <code class="language-plaintext highlighter-rouge">EPiServer Framework</code> dark cellars I stumbled upon class <code class="language-plaintext highlighter-rouge">EPiServer.Web.Routing.ContentRoute</code>. Eventually this class turned out to responsible for firing view discovery and registration process. Happens this only in the first request and while content is being routed (I can imagine why this is needed..)</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">override</span> <span class="n">RouteData</span> <span class="nf">GetRouteData</span><span class="p">(</span><span class="n">HttpContextBase</span> <span class="n">httpContext</span><span class="p">)</span>
<span class="p">{</span>
    <span class="p">...</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">ContentRoute</span><span class="p">.</span><span class="n">_isFirstRequest</span><span class="p">)</span>
        <span class="k">this</span><span class="p">.</span><span class="nf">FirstIncomingRequest</span><span class="p">(</span><span class="n">httpContext</span><span class="p">);</span>

<span class="k">protected</span> <span class="k">virtual</span> <span class="k">void</span> <span class="nf">FirstIncomingRequest</span><span class="p">(</span><span class="n">HttpContextBase</span> <span class="n">httpContext</span><span class="p">)</span>
<span class="p">{</span>
    <span class="p">...</span>
    <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">_viewRegistrator</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
        <span class="k">this</span><span class="p">.</span><span class="n">_viewRegistrator</span><span class="p">.</span><span class="nf">RegisterViews</span><span class="p">(</span><span class="n">httpContext</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So we have to hook inside this class to do our step for registering view templates located in registered areas. I noticed that EPiServer is “raising an event” for this case when content is going to be routed:
<code class="language-plaintext highlighter-rouge">this.OnRoutingContent(routingEventArgs)</code>;</p>

<p>Unfortunately this seems like an event but it’s not. EPiServer provides a delegate here that consumer can set in order to get invoked by the framework (hope they will fix this in future versions).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="c1">/// &lt;summary&gt;</span>
<span class="c1">/// Raised when outgoing virtual path has been created.</span>
<span class="c1">///</span>
<span class="c1">/// &lt;/summary&gt;</span>
<span class="k">public</span> <span class="k">static</span> <span class="n">EventHandler</span><span class="p">&lt;</span><span class="n">RoutingEventArgs</span><span class="p">&gt;</span> <span class="n">RoutingContent</span><span class="p">;</span>
<span class="c1">/// &lt;summary&gt;</span>
<span class="c1">/// Raised when an incoming request have been routed to a content instance.</span>
<span class="c1">///</span>
<span class="c1">/// &lt;/summary&gt;</span>
<span class="k">public</span> <span class="k">static</span> <span class="n">EventHandler</span><span class="p">&lt;</span><span class="n">RoutingEventArgs</span><span class="p">&gt;</span> <span class="n">RoutedContent</span><span class="p">;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So I ended up with following class that hooks-in, after first request has been issued and content is going to be routed (built-in view template registration has been already executed and most of block templates have been already discovered and registered) we can step in and finish registration process by walking around partial views locations in registered areas and trying to match against templates registered by run-time in <code class="language-plaintext highlighter-rouge">ContentTypeModelRepository</code>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">AddMvcAreasSupportModule</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">ContentRoute</span><span class="p">.</span><span class="n">RoutingContent</span> <span class="p">+=</span> <span class="n">OnRoutingContent</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Preload</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">parameters</span><span class="p">)</span>
    <span class="p">{</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="k">void</span> <span class="nf">OnRoutingContent</span><span class="p">(</span><span class="kt">object</span> <span class="n">sender</span><span class="p">,</span> <span class="n">RoutingEventArgs</span> <span class="n">e</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">PartialViewsInAreasRegistrar</span><span class="p">.</span><span class="nf">Register</span><span class="p">(</span><span class="k">new</span> <span class="nf">HttpContextWrapper</span><span class="p">(</span><span class="n">HttpContext</span><span class="p">.</span><span class="n">Current</span><span class="p">));</span>
        <span class="n">ContentRoute</span><span class="p">.</span><span class="n">RoutingContent</span> <span class="p">-=</span> <span class="n">OnRoutingContent</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Registering partial view templates located in areas</p>

<p>Once we got chance to walk through, discover and register view templates for out blocks located in areas we need some built-in stuff from EPiServer. Therefore created small static factory method to get instance of registrar class:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">PartialViewsInAreasRegistrar</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">static</span> <span class="k">volatile</span> <span class="kt">bool</span> <span class="n">_isInitialized</span><span class="p">;</span>
    <span class="k">private</span> <span class="k">static</span> <span class="k">readonly</span> <span class="kt">object</span> <span class="n">_lockObj</span> <span class="p">=</span> <span class="k">new</span> <span class="kt">object</span><span class="p">();</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IContentTypeModelScanner</span> <span class="n">_contentTypeModelScanner</span><span class="p">;</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">TemplateModelRepository</span> <span class="n">_templateModelRepository</span><span class="p">;</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">CachingViewEnginesWrapper</span> <span class="n">_viewEngineWrapper</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">PartialViewsInAreasRegistrar</span><span class="p">(</span>
        <span class="n">IContentTypeModelScanner</span> <span class="n">contentTypeModelScanner</span><span class="p">,</span>
        <span class="n">TemplateModelRepository</span> <span class="n">templateModelRepository</span><span class="p">,</span>
        <span class="n">CachingViewEnginesWrapper</span> <span class="n">viewEngineWrapper</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_contentTypeModelScanner</span> <span class="p">=</span> <span class="n">contentTypeModelScanner</span><span class="p">;</span>
        <span class="n">_templateModelRepository</span> <span class="p">=</span> <span class="n">templateModelRepository</span><span class="p">;</span>
        <span class="n">_viewEngineWrapper</span> <span class="p">=</span> <span class="n">viewEngineWrapper</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">Register</span><span class="p">(</span><span class="n">HttpContextBase</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">lock</span> <span class="p">(</span><span class="n">_lockObj</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">_isInitialized</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="k">return</span><span class="p">;</span>
            <span class="p">}</span>

            <span class="kt">var</span> <span class="n">reg</span> <span class="p">=</span> <span class="n">ServiceLocator</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">PartialViewsInAreasRegistrar</span><span class="p">&gt;();</span>
            <span class="n">reg</span><span class="p">.</span><span class="nf">RegisterPartials</span><span class="p">(</span><span class="n">context</span><span class="p">);</span>

            <span class="n">_isInitialized</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And next these are methods that take all the heavy-lifting and walkthrough, discover and register view templates if any:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">RegisterPartials</span><span class="p">(</span><span class="n">HttpContextBase</span> <span class="n">context</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">controllerContext</span> <span class="p">=</span> <span class="k">new</span> <span class="n">ControllerContext</span>
    <span class="p">{</span>
        <span class="n">RequestContext</span> <span class="p">=</span> <span class="k">new</span> <span class="n">RequestContext</span>
        <span class="p">{</span>
            <span class="n">RouteData</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">RouteData</span><span class="p">(),</span>
            <span class="n">HttpContext</span> <span class="p">=</span> <span class="n">context</span>
        <span class="p">},</span>
        <span class="n">HttpContext</span> <span class="p">=</span> <span class="n">context</span>
    <span class="p">};</span>

    <span class="n">controllerContext</span><span class="p">.</span><span class="n">RouteData</span><span class="p">.</span><span class="n">Values</span><span class="p">[</span><span class="s">"controller"</span><span class="p">]</span> <span class="p">=</span> <span class="s">"[Unknown]"</span><span class="p">;</span>

    <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">area</span> <span class="k">in</span> <span class="n">AreaTable</span><span class="p">.</span><span class="n">Areas</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">controllerContext</span><span class="p">.</span><span class="n">RouteData</span><span class="p">.</span><span class="n">DataTokens</span><span class="p">[</span><span class="s">"area"</span><span class="p">]</span> <span class="p">=</span> <span class="n">area</span><span class="p">.</span><span class="n">Name</span><span class="p">;</span>
        <span class="nf">FindPartialViewInArea</span><span class="p">(</span><span class="n">controllerContext</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">private</span> <span class="k">void</span> <span class="nf">FindPartialViewInArea</span><span class="p">(</span><span class="n">ControllerContext</span> <span class="n">controllerContext</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">type</span> <span class="k">in</span> <span class="n">_contentTypeModelScanner</span><span class="p">.</span><span class="n">ContentTypes</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">contentType</span> <span class="p">=</span> <span class="n">type</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span>
            <span class="n">_templateModelRepository</span><span class="p">.</span><span class="nf">List</span><span class="p">(</span><span class="n">contentType</span><span class="p">)</span>
                                    <span class="p">.</span><span class="nf">Any</span><span class="p">(</span><span class="n">p</span> <span class="p">=&gt;</span> <span class="n">p</span><span class="p">.</span><span class="n">TemplateTypeCategory</span><span class="p">.</span><span class="nf">IsCategory</span><span class="p">(</span><span class="n">TemplateTypeCategories</span><span class="p">.</span><span class="n">MvcPartialView</span><span class="p">)</span> <span class="p">&amp;&amp;</span> <span class="kt">string</span><span class="p">.</span><span class="nf">IsNullOrEmpty</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">Path</span><span class="p">)))</span>
        <span class="p">{</span>
            <span class="k">continue</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="c1">// NOTE: this line in Release Mode was scanning only first area.</span>
        <span class="c1">// If there were more than one area and requested block would be located</span>
        <span class="c1">// in 2nd or any other area, EPiServer would add this template to noHit</span>
        <span class="c1">// cache and would assume that view does not exist at all.</span>

        <span class="c1">//  Replaced with view search directly via ViewEngines collection.</span>
        <span class="c1">// If this hits performance - we would need to search for another solution here.</span>

        <span class="c1">// var partialView = _viewEngineWrapper.FindPartialView(controllerContext, contentType.Name);</span>

        <span class="kt">var</span> <span class="n">partialView</span> <span class="p">=</span> <span class="n">ViewEngines</span><span class="p">.</span><span class="n">Engines</span><span class="p">.</span><span class="nf">FindPartialView</span><span class="p">(</span><span class="n">controllerContext</span><span class="p">,</span> <span class="n">contentType</span><span class="p">.</span><span class="n">Name</span><span class="p">);</span>

        <span class="k">if</span> <span class="p">(</span><span class="n">partialView</span><span class="p">.</span><span class="n">View</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">continue</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="kt">var</span> <span class="n">templateModel</span> <span class="p">=</span> <span class="k">new</span> <span class="n">TemplateModel</span>
        <span class="p">{</span>
            <span class="n">Name</span> <span class="p">=</span> <span class="n">contentType</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span>
            <span class="n">TemplateTypeCategory</span> <span class="p">=</span> <span class="n">TemplateTypeCategories</span><span class="p">.</span><span class="n">MvcPartialView</span>
        <span class="p">};</span>

        <span class="c1">// This is UPDATED code fragment !</span>
        <span class="kt">var</span> <span class="n">view</span> <span class="p">=</span> <span class="n">partialView</span><span class="p">.</span><span class="n">View</span> <span class="k">as</span> <span class="n">BuildManagerCompiledView</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">view</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">templateModel</span><span class="p">.</span><span class="n">Path</span> <span class="p">=</span> <span class="n">view</span><span class="p">.</span><span class="n">ViewPath</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="n">_templateModelRepository</span><span class="p">.</span><span class="nf">RegisterTemplate</span><span class="p">(</span><span class="n">contentType</span><span class="p">,</span> <span class="n">templateModel</span><span class="p">);</span>
        <span class="n">partialView</span><span class="p">.</span><span class="n">ViewEngine</span><span class="p">.</span><span class="nf">ReleaseView</span><span class="p">(</span><span class="n">controllerContext</span><span class="p">,</span> <span class="n">partialView</span><span class="p">.</span><span class="n">View</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Code fragment does few things:</p>

<p><strong>a)</strong> First of all it creates artificial controller context, setting everything we have so far (including name of the controller).<br />
<strong>b)</strong> Then iterates through our registered areas (remember I told that we will need list of areas at some point, well this is 1st usage) and asks to try to find partials that matches in this particular area.<br />
The only thing Asp.Net needs in order to start looking for a template in areas folders is to set <code class="language-plaintext highlighter-rouge">DataToken</code> for route data:
<code class="language-plaintext highlighter-rouge">controllerContext.RouteData.DataTokens["area"] = area.Name</code>;<br />
<strong>c)</strong> Then we iterate through all template models registered by runtime and we are looking for types that does not have <code class="language-plaintext highlighter-rouge">MvcPartialView</code> renderer without set path. By EPiServer conventions <code class="language-plaintext highlighter-rouge">MvcPartialView</code> is template model category used by blocks to render themselves. And if the path is not set for these renderers that means these are automatically conventions-based registered templates.<br />
<strong>d)</strong> If content type does not have registered template with category <code class="language-plaintext highlighter-rouge">MvcPartialView</code> with empty path – we need to ask for underlying view engine collection to find partial view: <code class="language-plaintext highlighter-rouge">FindPartialView()</code>. We set area name in <code class="language-plaintext highlighter-rouge">DataToken</code> collection for the <code class="language-plaintext highlighter-rouge">RouteData</code> so Mvc will try to look in that particular area’s partial view locations.<br /></p>

<p><strong>UPDATE!</strong> (Added description for case – when you need to preview block located in area using Preview controller and view template located in root):</p>

<p>e) We try to cast to <code class="language-plaintext highlighter-rouge">BuildManagerCompiledView</code> to get view path to be used in template model information. If we succeed we can write down discovered template path for our template model.</p>

<h2 id="return-view-from-controllers-action">Return View from Controller’s Action</h2>

<p>EPiServer does not have issues invoking controller’s action for particular content type even if controller is located in Mvc area. Problem for Asp.Net Mvc is to find proper view to render <code class="language-plaintext highlighter-rouge">ActionResult</code>. In this case we need to tell Mvc that we are currently in appropriate area. Someone suggests to do it in base controller for that area. But I know how it usually happens. We all are working in Google’s Copy-Paste department :) You may forget to change area name in that base controller. We need to find a more automated way to set this <code class="language-plaintext highlighter-rouge">DataToken</code>.
 We can use Mvc’s action filters to intercept call to controller’s action and setup stuff we need before executing action.
In our registrar registration (I know – sounds weird) module need to add another filter:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">AddMvcAreasSupportModule</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">GlobalFilters</span><span class="p">.</span><span class="n">Filters</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">ServiceLocator</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">DetectAreaAttribute</span><span class="p">&gt;());</span>
        <span class="n">ContentRoute</span><span class="p">.</span><span class="n">RoutingContent</span> <span class="p">=</span> <span class="n">OnRoutingContent</span><span class="p">;</span>
        <span class="p">...</span>
    <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>New filter <code class="language-plaintext highlighter-rouge">DetectAreaAttribute</code> (also weird that filter name ends with Attribute, it’s because it could be added directly to controller as well).
 Before we continue with filter we need to make small adjustment to our area registration process. For a sake of performance I decided to keep track of known controllers in area registered in <code class="language-plaintext highlighter-rouge">AreaTable</code> collection. New version of area registration process is following:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">AreaConfiguration</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">RegisterAllAreas</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">AreaRegistration</span><span class="p">.</span><span class="nf">RegisterAllAreas</span><span class="p">();</span>

        <span class="kt">var</span> <span class="n">types</span> <span class="p">=</span> <span class="n">Assembly</span><span class="p">.</span><span class="nf">GetExecutingAssembly</span><span class="p">().</span><span class="nf">GetExportedTypes</span><span class="p">();</span>
        <span class="kt">var</span> <span class="n">areas</span> <span class="p">=</span> <span class="n">types</span><span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">t</span> <span class="p">=&gt;</span> <span class="nf">IsTypeOf</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="k">typeof</span><span class="p">(</span><span class="n">AreaRegistration</span><span class="p">)));</span>

        <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">area</span> <span class="k">in</span> <span class="n">areas</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="kt">var</span> <span class="n">areaRegistration</span> <span class="p">=</span> <span class="n">AreaTable</span><span class="p">.</span><span class="nf">AddArea</span><span class="p">(</span><span class="n">area</span><span class="p">);</span>

            <span class="kt">var</span> <span class="n">ns</span> <span class="p">=</span> <span class="n">area</span><span class="p">.</span><span class="n">Namespace</span><span class="p">;</span>
            <span class="k">if</span> <span class="p">(</span><span class="kt">string</span><span class="p">.</span><span class="nf">IsNullOrEmpty</span><span class="p">(</span><span class="n">ns</span><span class="p">))</span>
            <span class="p">{</span>
                <span class="k">continue</span><span class="p">;</span>
            <span class="p">}</span>

            <span class="kt">var</span> <span class="n">allTypesInArea</span> <span class="p">=</span> <span class="n">types</span><span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">t</span> <span class="p">=&gt;</span> <span class="n">t</span><span class="p">.</span><span class="n">Namespace</span> <span class="p">!=</span> <span class="k">null</span>
                                                  <span class="p">&amp;&amp;</span> <span class="n">t</span><span class="p">.</span><span class="n">Namespace</span><span class="p">.</span><span class="nf">StartsWith</span><span class="p">(</span><span class="n">ns</span><span class="p">)</span> <span class="p">&amp;&amp;</span> <span class="nf">IsTypeOf</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="k">typeof</span><span class="p">(</span><span class="n">Controller</span><span class="p">)));</span>

            <span class="n">allTypesInArea</span><span class="p">.</span><span class="nf">ToList</span><span class="p">().</span><span class="nf">ForEach</span><span class="p">(</span><span class="n">t</span> <span class="p">=&gt;</span> <span class="n">AreaTable</span><span class="p">.</span><span class="nf">RegisterController</span><span class="p">(</span><span class="n">t</span><span class="p">.</span><span class="n">FullName</span><span class="p">,</span> <span class="n">areaRegistration</span><span class="p">.</span><span class="n">AreaName</span><span class="p">));</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="k">static</span> <span class="kt">bool</span> <span class="nf">IsTypeOf</span><span class="p">(</span><span class="n">Type</span> <span class="n">type</span><span class="p">,</span> <span class="n">Type</span> <span class="n">parentType</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">parentType</span><span class="p">.</span><span class="nf">IsAssignableFrom</span><span class="p">(</span><span class="n">type</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">AreaTable</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">static</span> <span class="k">readonly</span> <span class="n">AreaCollection</span> <span class="n">_instance</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">AreaCollection</span><span class="p">();</span>
    <span class="k">private</span> <span class="k">static</span> <span class="k">readonly</span> <span class="n">Dictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;</span> <span class="n">_controllersMap</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Dictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;();</span>

    <span class="k">internal</span> <span class="k">static</span> <span class="n">AreaRegistration</span> <span class="nf">AddArea</span><span class="p">(</span><span class="n">Type</span> <span class="n">area</span><span class="p">)...</span>

    <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="nf">GetAreaForController</span><span class="p">(</span><span class="kt">string</span> <span class="n">controllerName</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">string</span> <span class="k">value</span><span class="p">;</span>
        <span class="k">return</span> <span class="n">_controllersMap</span><span class="p">.</span><span class="nf">TryGetValue</span><span class="p">(</span><span class="n">controllerName</span><span class="p">,</span> <span class="k">out</span> <span class="k">value</span><span class="p">)</span> <span class="p">?</span> <span class="k">value</span> <span class="p">:</span> <span class="k">null</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">internal</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">RegisterController</span><span class="p">(</span><span class="kt">string</span> <span class="n">controllerName</span><span class="p">,</span> <span class="kt">string</span> <span class="n">areaName</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(!</span><span class="n">_controllersMap</span><span class="p">.</span><span class="nf">ContainsKey</span><span class="p">(</span><span class="n">controllerName</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="n">_controllersMap</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">controllerName</span><span class="p">,</span> <span class="n">areaName</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We wrote down all controllers’ <code class="language-plaintext highlighter-rouge">FullName</code> and area name in which they are located. This gives us a dictionary of controller and particular area. We will use this collection while trying to understand which area we are in while executing controller’s action. Normally this would be carried out by matched Mvc route already.
Filter code is pretty straight forward:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">DetectAreaAttribute</span> <span class="p">:</span> <span class="n">ActionFilterAttribute</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnActionExecuting</span><span class="p">(</span><span class="n">ActionExecutingContext</span> <span class="n">filterContext</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">areaName</span> <span class="p">=</span> <span class="n">AreaTable</span><span class="p">.</span><span class="nf">GetAreaForController</span><span class="p">(</span><span class="n">filterContext</span><span class="p">.</span><span class="n">Controller</span><span class="p">.</span><span class="nf">GetType</span><span class="p">().</span><span class="n">FullName</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">areaName</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">filterContext</span><span class="p">.</span><span class="n">RouteData</span><span class="p">.</span><span class="n">DataTokens</span><span class="p">[</span><span class="s">"area"</span><span class="p">]</span> <span class="p">=</span> <span class="n">areaName</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Once we set <code class="language-plaintext highlighter-rouge">filterContext.RouteData.DataTokens["area"] = areaName</code>; Mvc is sure where to look for what. If <code class="language-plaintext highlighter-rouge">DataToken</code> is not set then Mvc view engines will follow default conventions and most probably will look for templates somewhere under ~/Views/… folder.</p>

<p>Now project and template structure may look and be organized like this:</p>

<p><img src="/assets/img/2015/01/epiareas-fin.png" alt="" /></p>

<h2 id="duplicate-block-names">Duplicate Block Names</h2>

<p>I’m sure that this is not the best style to organize your blocks, but if you have a case when two blocks are defined with the same name (but with different namespaces and GUIDs for sure) and each of them is located in different area – this code will not handle that properly. If you have such cases, please drop me a note – I’m looking for a way to decorate block definition with some sort of area name where template is located. But again, I’m strongly don’t recommend to introduce another misunderstanding in your project and avoid such cases. Most easiest way to get rid of this is to rename one of the blocks to other name and template respectively.</p>

<h2 id="wrapping-it-up">Wrapping it up</h2>

<p>In general this was interesting journey for me inside template registration process and how properly one should be implemented to hook in existing discovery and registration process.
I shuffled together a <a href="https://github.com/valdisiljuconoks/EPiServer.MvcAreas/tree/master">sample project on github.com</a> where you can take a look at complete source code. It’s not production quality library yet. If you are interested in getting one with few configuration options you may expect as a consumer – drop me a note, we will definitely figure out something.</p>

<p>Happy coding!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[This is a blog post about how to add Asp.Net Mvc areas back in town and add full support in EPiServer v7.5. I’ll not spend time to explain what Mvc area is, most probably if you are reading this, you already are looking for a way to add it or adjust it to your needs in your EPiServer project. I know that there has been some attempts to add Mvc areas for EPiServer 7.5. Either you have to modify your view engine or add new one. Latter I don’t like at all. Someone tries to inherit from some base controller class in each area and then somehow trick Mvc engine to tell in which area we currently are.]]></summary></entry><entry><title type="html">FeatureSwitch meets Glimpse</title><link href="https://tech-fellow.eu/2015/01/02/featureswitch-meets-glimpse/" rel="alternate" type="text/html" title="FeatureSwitch meets Glimpse" /><published>2015-01-02T22:55:00+02:00</published><updated>2015-01-02T22:55:00+02:00</updated><id>https://tech-fellow.eu/2015/01/02/featureswitch-meets-glimpse</id><content type="html" xml:base="https://tech-fellow.eu/2015/01/02/featureswitch-meets-glimpse/"><![CDATA[<p><code class="language-plaintext highlighter-rouge">FeatureSwitch</code> library got yet another plugin in its family. Glimpse is an amazing framework for troubleshooting and tracing your web application, even in production environment. If by coincidence you are a consumer of this framework and also use <code class="language-plaintext highlighter-rouge">FeatureSwitch</code> library, then now they run together. You can access your features through Glimpse control panel.</p>

<h2 id="installation">Installation</h2>
<p>You need to install a package from <a href="https://www.nuget.org/packages/FeatureSwitch.Glimpse/">nuget.org</a> feed:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>&gt; Install-Package FeatureSwitch.Glimpse
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Using <code class="language-plaintext highlighter-rouge">FeatureSwitch.Glimpse</code> package you can get an overview of your features and its state through <code class="language-plaintext highlighter-rouge">FeatureSwitch</code> tab.</p>

<p><img src="/assets/img/2015/01/glimpse-1-1.png" alt="" /></p>

<p>There is also an Glimpse’s resource which provides you an access to <code class="language-plaintext highlighter-rouge">FeatureSwitch</code> control panel. You can enable/disable particular feature.</p>

<p><img src="/assets/img/2015/01/glimpse-2.png" alt="" /></p>

<p>If check-box for the feature is disabled in Glimpse control panel it means that there are only read-only strategies configured for feature.</p>

<h2 id="fix-for-incorrect-feature-state">Fix for incorrect feature state</h2>

<p>There could be a case when incorrect feature state is shown in Glimpse’s resource <code class="language-plaintext highlighter-rouge">FeatureSwitch</code> Config. If you your feature has strategy based on <code class="language-plaintext highlighter-rouge">HttpSession</code> then there is a high chance that state for the feature will be incorrect. This is due to the fact that Glimpse <code class="language-plaintext highlighter-rouge">HttpHandler</code> is not session state enabled. While executing Glimpse resource Session is set to null which means that <code class="language-plaintext highlighter-rouge">FeatureSwitch</code> context detects this feature as disabled.
 If you need correct state this is easy to fix. Find following line in web.config file:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;system.webServer&gt;</span>
  <span class="nt">&lt;handlers&gt;</span>
    <span class="nt">&lt;add</span> <span class="na">name=</span><span class="s">"Glimpse"</span> <span class="na">path=</span><span class="s">"glimpse.axd"</span> <span class="na">verb=</span><span class="s">"GET"</span> <span class="na">type=</span><span class="s">"Glimpse.AspNet.HttpHandler, Glimpse.AspNet"</span> <span class="na">preCondition=</span><span class="s">"integratedMode"</span> <span class="nt">/&gt;</span>
  <span class="nt">&lt;/handlers&gt;</span>
<span class="nt">&lt;/system.webServer&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This controls what is invoked when accessing Glimpse. You need to change Glimpse’s default <code class="language-plaintext highlighter-rouge">HttpHandler</code> to <code class="language-plaintext highlighter-rouge">FeatureSwitch</code> custom one:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;system.webServer&gt;</span>
  <span class="nt">&lt;handlers&gt;</span>
    <span class="nt">&lt;add</span> <span class="na">name=</span><span class="s">"Glimpse"</span> <span class="na">path=</span><span class="s">"glimpse.axd"</span> <span class="na">verb=</span><span class="s">"GET"</span> <span class="na">type=</span><span class="s">"FeatureSwitch.Glimpse.SessionHttpHandler, FeatureSwitch.Glimpse"</span> <span class="na">preCondition=</span><span class="s">"integratedMode"</span> <span class="nt">/&gt;</span>
  <span class="nt">&lt;/handlers&gt;</span>
<span class="nt">&lt;/system.webServer&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now correct state should show up in <code class="language-plaintext highlighter-rouge">FeatureSwitch</code> control panel as <code class="language-plaintext highlighter-rouge">HttpSession</code> is now available for Glimpse’s resources.</p>

<p>Happy coding!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Feature Switch" /><category term=".net" /><category term="c#" /><category term="feature switch" /><summary type="html"><![CDATA[FeatureSwitch library got yet another plugin in its family. Glimpse is an amazing framework for troubleshooting and tracing your web application, even in production environment. If by coincidence you are a consumer of this framework and also use FeatureSwitch library, then now they run together. You can access your features through Glimpse control panel.]]></summary></entry><entry><title type="html">EPiServer DDS Strategy for FeatureSwitch</title><link href="https://tech-fellow.eu/2014/12/24/episerver-dds-strategy-for-featureswitch/" rel="alternate" type="text/html" title="EPiServer DDS Strategy for FeatureSwitch" /><published>2014-12-24T11:30:00+02:00</published><updated>2014-12-24T11:30:00+02:00</updated><id>https://tech-fellow.eu/2014/12/24/episerver-dds-strategy-for-featureswitch</id><content type="html" xml:base="https://tech-fellow.eu/2014/12/24/episerver-dds-strategy-for-featureswitch/"><![CDATA[<p>Thanks to <a href="http://world.episerver.com/blogs/paul-smith/">Paul Smith</a> for adding some more <a href="https://github.com/valdisiljuconoks/FeatureSwitch">EPiServer integration for FeatureSwitch</a> library. Now <code class="language-plaintext highlighter-rouge">FeatureSwitch</code> EPiServer integration library is equipped with DDS storage strategy. This was pretty easy to implement:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">EPiServerDatabaseStrategyImpl</span> <span class="p">:</span> <span class="n">BaseStrategyImpl</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">override</span> <span class="kt">bool</span> <span class="nf">Read</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">store</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="n">FeatureState</span><span class="p">).</span><span class="nf">GetStore</span><span class="p">();</span>
        <span class="kt">var</span> <span class="n">definition</span> <span class="p">=</span> <span class="n">store</span><span class="p">.</span><span class="n">Items</span><span class="p">&lt;</span><span class="n">featurestate</span><span class="p">&gt;().</span><span class="nf">FirstOrDefault</span><span class="p">(</span><span class="n">d</span> <span class="p">=&gt;</span> <span class="n">d</span><span class="p">.</span><span class="n">Name</span> <span class="p">==</span> <span class="n">Context</span><span class="p">.</span><span class="n">Key</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">definition</span> <span class="p">!=</span> <span class="k">null</span> <span class="p">&amp;&amp;</span> <span class="n">definition</span><span class="p">.</span><span class="n">Enabled</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Write</span><span class="p">(</span><span class="kt">bool</span> <span class="n">state</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">store</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="n">FeatureState</span><span class="p">).</span><span class="nf">GetStore</span><span class="p">();</span>
        <span class="kt">var</span> <span class="n">definition</span> <span class="p">=</span> <span class="n">store</span><span class="p">.</span><span class="n">Items</span><span class="p">&lt;</span><span class="n">featurestate</span><span class="p">&gt;().</span><span class="nf">FirstOrDefault</span><span class="p">(</span><span class="n">d</span> <span class="p">=&gt;</span> <span class="n">d</span><span class="p">.</span><span class="n">Name</span> <span class="p">==</span> <span class="n">Context</span><span class="p">.</span><span class="n">Key</span><span class="p">)</span> <span class="p">??</span> <span class="k">new</span> <span class="n">FeatureState</span> <span class="p">{</span> <span class="n">Name</span> <span class="p">=</span> <span class="n">Context</span><span class="p">.</span><span class="n">Key</span> <span class="p">};</span>

        <span class="n">definition</span><span class="p">.</span><span class="n">Enabled</span> <span class="p">=</span> <span class="n">state</span><span class="p">;</span>
        <span class="n">store</span><span class="p">.</span><span class="nf">Save</span><span class="p">(</span><span class="n">definition</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>DDS storage strategy gives you more control over how feature state is saved and also makes it easier to alter it (for instance using <a href="https://github.com/Geta/DdsAdmin">Geta’s DDS Admin</a> plugin).</p>

<p><img src="/assets/img/2014/12/dds-strategy.png" alt="" /></p>

<p>Here goes some more information about how to add new custom strategies and other stuff.</p>

<h2 id="adding-new-strategies">Adding New Strategies</h2>

<p>Currently <code class="language-plaintext highlighter-rouge">FeatureSwitch</code> comes with some <a href="https://github.com/valdisiljuconoks/FeatureSwitch/wiki#strategies">built-in strategies</a>. However it’s natural that there is a need to extend <code class="language-plaintext highlighter-rouge">FeatureSwitch</code> and add new strategies. This is really easy to implement.
<code class="language-plaintext highlighter-rouge">FeatureSwitch</code> recognizes two types of strategies:</p>

<ul>
  <li><em>Initializable</em>: these strategies take part only during <code class="language-plaintext highlighter-rouge">FeatureSwitch</code> initialization routine and are called while feature set context is built-up. To create initializable strategy you need to implement <code class="language-plaintext highlighter-rouge">FeatureSwitch.Strategies.IStrategy</code> interface.</li>
  <li><em>Read-only</em>: read-only strategies are strategies that are able to read form the underlying storage initial value of the feature but not able to store or save it back. There will be disabled checkbox for features that are marked with these strategies in Asp.Net control panel. To create initializable strategy you need to implement <code class="language-plaintext highlighter-rouge">FeatureSwitch.Strategies.IStrategyStorageReader</code> interface.</li>
  <li><em>Writeable</em>: these strategies are able to update underlying storage and save new state of the feature. Features marked with these strategies will have enabled checkbox in Asp.Net control panel. To create initializable strategy you need to implement <code class="language-plaintext highlighter-rouge">FeatureSwitch.Strategies.IStrategyStorageWriter</code> interface.</li>
</ul>

<p>In order to implement your new initializable strategy it’s enough to implement IStrategy interface.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">EmptyStrategyImpl</span> <span class="p">:</span> <span class="n">IStrategy</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">ConfigurationContext</span> <span class="n">configurationContext</span><span class="p">)</span>
    <span class="p">{</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We will get back to <code class="language-plaintext highlighter-rouge">ConfigurationContext</code> a bit later. So as you can see this strategy is called when feature set context is built by passing configuration context to the Initialize method.
In order to implement your new read-only strategy it’s enough to implement <code class="language-plaintext highlighter-rouge">IStrategyStorageReader</code> interface.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">SampleReaderImpl</span> <span class="p">:</span> <span class="n">IStrategyStorageReader</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">ConfigurationContext</span> <span class="n">configurationContext</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">throw</span> <span class="k">new</span> <span class="n">System</span><span class="p">.</span><span class="nf">NotImplementedException</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="kt">bool</span> <span class="nf">Read</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="k">throw</span> <span class="k">new</span> <span class="n">System</span><span class="p">.</span><span class="nf">NotImplementedException</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As you can see there is no feature identification mentioned in <code class="language-plaintext highlighter-rouge">Read</code> method. Identification key of the feature (one that is used in attribute definition).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">AppSettings</span><span class="p">(</span><span class="n">Key</span> <span class="p">=</span> <span class="s">"MySampleFeatureKey"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">MySampleFeature</span> <span class="p">:</span> <span class="n">BaseFeature</span>
<span class="p">{</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You can access feature key via <code class="language-plaintext highlighter-rouge">ConfigurationContext.Key</code> (that is passed in <code class="language-plaintext highlighter-rouge">Initialize</code> method).</p>

<p>To get rid of <code class="language-plaintext highlighter-rouge">Initialize</code> method and not bothering yourself to store configurationContext somewhere, you can inherit from <code class="language-plaintext highlighter-rouge">FeatureSwitch.Strategies.Implementations.BaseStrategyReaderImpl</code>. It will take care of this.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">SampleReaderImpl</span> <span class="p">:</span> <span class="n">BaseStrategyReaderImpl</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">override</span> <span class="kt">bool</span> <span class="nf">Read</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="k">throw</span> <span class="k">new</span> <span class="n">System</span><span class="p">.</span><span class="nf">NotImplementedException</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="adding-new-writable-strategies">Adding New Writable Strategies</h2>

<p>To create writable strategy you need to either implement <code class="language-plaintext highlighter-rouge">IStrategyStorageWriter</code>:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">SampleWriterImpl</span> <span class="p">:</span> <span class="n">IStrategyStorageWriter</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">ConfigurationContext</span> <span class="n">configurationContext</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">throw</span> <span class="k">new</span> <span class="n">System</span><span class="p">.</span><span class="nf">NotImplementedException</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="kt">bool</span> <span class="nf">Read</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="k">throw</span> <span class="k">new</span> <span class="n">System</span><span class="p">.</span><span class="nf">NotImplementedException</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Write</span><span class="p">(</span><span class="kt">bool</span> <span class="n">state</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">throw</span> <span class="k">new</span> <span class="n">System</span><span class="p">.</span><span class="nf">NotImplementedException</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Or you can inherit from <code class="language-plaintext highlighter-rouge">FeatureSwitch.Strategies.BaseStrategyImpl</code> to reduce code a bit:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">SampleWriterImpl</span> <span class="p">:</span> <span class="n">BaseStrategyImpl</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">override</span> <span class="kt">bool</span> <span class="nf">Read</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="k">throw</span> <span class="k">new</span> <span class="n">System</span><span class="p">.</span><span class="nf">NotImplementedException</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">Write</span><span class="p">(</span><span class="kt">bool</span> <span class="n">state</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">throw</span> <span class="k">new</span> <span class="n">System</span><span class="p">.</span><span class="nf">NotImplementedException</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="dependency-injection-support">Dependency Injection Support</h2>

<p>Strategies are constructed using dependency injection services which means that strategies with constructor injections are supported out-of-box. So strategies like these will be constructed as long as necessary dependencies will be available in IoC (inversion of control) container.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">readonly</span> <span class="n">ISampleInjectedInterface</span> <span class="n">_sample</span><span class="p">;</span>

<span class="k">public</span> <span class="nf">StrategyWithParameterReader</span><span class="p">(</span><span class="n">ISampleInjectedInterface</span> <span class="n">sample</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">_sample</span> <span class="p">=</span> <span class="n">sample</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="enable-your-custom-strategy">Enable Your Custom Strategy</h2>

<p>When new strategy has been implemented it’s important that you enable it.
To enable new strategy you need to:</p>

<ul>
  <li>Create associated attribute that will be used to map your new strategy to particular feature marking that this feature is backed up by your strategy</li>
  <li>Register this mapping in <code class="language-plaintext highlighter-rouge">FeatureSwitch</code> context.</li>
</ul>

<p>To create mapping attribute – you need just new class inheriting from <code class="language-plaintext highlighter-rouge">FeatureStrategyAttribute</code>:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">MyNewStrategy</span> <span class="p">:</span> <span class="n">FeatureStrategyAttribute</span>
<span class="p">{</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And you need to register new strategy implementation with particular attribute (if you are in <a href="https://github.com/valdisiljuconoks/FeatureSwitch/wiki/EPiServer-Integration">EPiServer context</a> – you can use EPiServer’s <code class="language-plaintext highlighter-rouge">InitializableModule</code>, or if you are on your own – you can use <a href="https://github.com/valdisiljuconoks/InitializableModule">my custom made initializable module infrastructure</a> to register this mapping):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">FeatureSetBuilder</span><span class="p">(</span><span class="k">new</span> <span class="nf">StructureMapDependencyContainer</span><span class="p">());</span>
<span class="n">builder</span><span class="p">.</span><span class="nf">Build</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span>
<span class="p">{</span>
    <span class="n">ctx</span><span class="p">.</span><span class="n">ForStrategy</span><span class="p">&lt;</span><span class="n">mynewstrategy</span><span class="p">&gt;().</span><span class="n">Use</span><span class="p">&lt;</span><span class="n">mynewstrategyimpl</span><span class="p">&gt;();</span>
<span class="p">});</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And now you can use your new strategy on feature:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">MyNewStrategy</span><span class="p">(</span><span class="n">Key</span> <span class="p">=</span> <span class="s">"MySampleFeatureKey"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">MySampleFeature</span> <span class="p">:</span> <span class="n">BaseFeature</span>
<span class="p">{</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h1 id="configuration-context-of-the-strategy">Configuration Context of the Strategy</h1>

<p><code class="language-plaintext highlighter-rouge">ConfigurationContext</code> is something that is needed for the strategy to initialize properly and get some info about feature “attached” to. <code class="language-plaintext highlighter-rouge">ConfigurationContext</code> is passed when strategy is initialized during feature set context build process and passed to <code class="language-plaintext highlighter-rouge">Initialize</code> method:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">interface</span> <span class="nc">IStrategy</span>
<span class="p">{</span>
    <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">ConfigurationContext</span> <span class="n">configurationContext</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Currently there is no built-in support for customizing configuration context (providing ways to extend and hook into configuration context creation process), but this is something I’m looking into in future releases of <code class="language-plaintext highlighter-rouge">FeatureSwitch</code> library.</p>

<p>Happy coding!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Feature Switch" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="feature switch" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[Thanks to Paul Smith for adding some more EPiServer integration for FeatureSwitch library. Now FeatureSwitch EPiServer integration library is equipped with DDS storage strategy. This was pretty easy to implement:]]></summary></entry><entry><title type="html">Add Community to your site created via VS Extensions</title><link href="https://tech-fellow.eu/2014/10/08/add-community-to-your-site-created-via-vs-extensions/" rel="alternate" type="text/html" title="Add Community to your site created via VS Extensions" /><published>2014-10-08T10:10:00+03:00</published><updated>2014-10-08T10:10:00+03:00</updated><id>https://tech-fellow.eu/2014/10/08/add-community-to-your-site-created-via-vs-extensions</id><content type="html" xml:base="https://tech-fellow.eu/2014/10/08/add-community-to-your-site-created-via-vs-extensions/"><![CDATA[<h2 id="set-the-playground">Set the playground</h2>

<p>After you have successfully followed <a href="http://tedgustaf.com/blog/2014/4/installing-episerver-cms-75/">Ted’s tutorial</a> on how to create a site using almost nothing else than Visual Studio. Next thing what is in your work queue is to add EPiServer Community functionality on top of this.</p>

<h2 id="add-community-via-deployment-center">Add Community via Deployment Center</h2>

<p>One of the way is old-school – via Deployment Center.
First of all you may even be able not to see your site there (regardless that you have added it to IIS).</p>

<p>While surfing of EPiServer source code using surfboard with <a href="http://www.red-gate.com/products/dotnet-development/reflector/">Reflector</a> sticker on back, I noticed that EPiServer install library that is responsible for enlisting applicable sites in the site tree is checking that there shouldn’t be <code class="language-plaintext highlighter-rouge">EPiServer.Community.dll</code> file in target app’s <code class="language-plaintext highlighter-rouge">bin</code> folder and <code class="language-plaintext highlighter-rouge">EPiServer.dll</code> <em>has</em> to be with 7.5 version and major and minor ones respectively.</p>

<p>Which means that in order to enlist your newly created site in EPiServer installation wizard’s site tree – you have to copy over <code class="language-plaintext highlighter-rouge">EPiServer.dll</code> file from some other application (preferably from app installed via Deployment Center).</p>

<p>After you copied over older version of <code class="language-plaintext highlighter-rouge">EPiServer.dll</code> file you may receive following error message while installing Community for your site:</p>

<p><img src="/assets/img/2014/10/community-err-1-.png" alt="" /></p>

<p>To be honest, error message looks weird and does tell exactly <strong>nothing</strong>.</p>

<p>Again, browsing installation source code I discovered that this particular error may occur for the sites created via Visual Studio plugin that has this element in web.config file:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;configuration&gt;</span>
  <span class="nt">&lt;episerver&gt;</span>
    <span class="nt">&lt;workflowSettings</span> <span class="na">disable=</span><span class="s">"true"</span> <span class="nt">/&gt;</span>
    ...
</pre></td></tr></tbody></table></code></pre></div></div>

<p>What is needed for the installation scripts is old style episerver.config file that is mentioned as a source for the <code class="language-plaintext highlighter-rouge">episerver</code> element.</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;episerver</span> <span class="na">configSource=</span><span class="s">"episerver.config"</span> <span class="nt">/&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So you just have to extract this element into its own file (usually <code class="language-plaintext highlighter-rouge">episerver.config</code>). And don’t forget to add a namespace for this element (it’s used in installation scripts as well):</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;episerver</span> <span class="na">xmlns=</span><span class="s">"http://EPiServer.Configuration.EPiServerSection"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;applicationSettings</span> <span class="na">globalErrorHandling=</span><span class="s">"RemoteOnly"</span> <span class="err">...</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="launch-the-site">Launch the site</h2>

<p>Now you can continue installation of the Community via Deployment Center (this will make sure that database structures and procedures and other stuff is added).
 Before you launch the site I noticed that after installation of the Community module <code class="language-plaintext highlighter-rouge">connectionStrings</code> element from inline listing of the connections was converted to:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;connectionStrings</span> <span class="na">configSource=</span><span class="s">"connectionStrings.config"</span> <span class="nt">/&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>File named <code class="language-plaintext highlighter-rouge">connectionStrings.config</code> does not exist of course. So be careful – you may need to revert back your connection strings.</p>

<p>After you launched the site you may immediately receive an error (or sometimes when you are accessing AdminUI) that <code class="language-plaintext highlighter-rouge">EPiServer.Shell.UI.dll</code> version <code class="language-plaintext highlighter-rouge">7.8.0.0</code> does not exist or could not be found.</p>

<p>All you need to do is to add assembly redirect under <code class="language-plaintext highlighter-rouge">runtime</code> element:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;runtime&gt;</span>
<span class="nt">&lt;assemblyBinding</span> <span class="na">xmlns=</span><span class="s">"urn:schemas-microsoft-com:asm.v1"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;dependentAssembly&gt;</span>
    <span class="nt">&lt;assemblyIdentity</span> <span class="na">name=</span><span class="s">"EPiServer.Shell.UI"</span> <span class="na">publicKeyToken=</span><span class="s">"8fe83dea738b45b7"</span> <span class="na">culture=</span><span class="s">"neutral"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;bindingRedirect</span> <span class="na">oldVersion=</span><span class="s">"0.0.0.0-7.8.0.0"</span> <span class="na">newVersion=</span><span class="s">"7.8.0.0"</span> <span class="nt">/&gt;</span>
  <span class="nt">&lt;/dependentAssembly&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="access-adminui-optional">Access AdminUI (optional)</h2>

<p>After you have successfully installed Community on top of your site created via Visual Studio plugin accessing AdminUI you may receive an error blaming that there is no <code class="language-plaintext highlighter-rouge">LocalSqlServer</code> connection string:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre>Configuration Error

Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.

Parser Error Message: The connection name ‘LocalSqlServer’ was not found in the applications configuration or the connection string is empty.

Source File: C:/Windows/Microsoft.NET/Framework64/v4.0.30319/Config/machine.config Line: 252
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Things you need to do is pretty simple – just add <code class="language-plaintext highlighter-rouge">clear</code> element in the <code class="language-plaintext highlighter-rouge">profiles/providers</code> section to clear out any other foreign providers and live just with EPiServer ones.</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;system.web&gt;</span>
  <span class="nt">&lt;profile&gt;</span>
    <span class="nt">&lt;providers&gt;</span>
      <span class="nt">&lt;clear/&gt;</span>
      ...
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Happy communiting!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[Set the playground]]></summary></entry><entry><title type="html">Chasing for NullReferenceException in EPiServer Relate+</title><link href="https://tech-fellow.eu/2014/09/03/chasing-for-nullreferenceexception-in-episerver-relate/" rel="alternate" type="text/html" title="Chasing for NullReferenceException in EPiServer Relate+" /><published>2014-09-03T17:55:00+03:00</published><updated>2014-09-03T17:55:00+03:00</updated><id>https://tech-fellow.eu/2014/09/03/chasing-for-nullreferenceexception-in-episerver-relate</id><content type="html" xml:base="https://tech-fellow.eu/2014/09/03/chasing-for-nullreferenceexception-in-episerver-relate/"><![CDATA[<p>This is a blog post telling a short story about one of the developer’s nightmare beast hunting case – <code class="language-plaintext highlighter-rouge">System.NullReferenceException</code>.</p>

<h2 id="hunting-game-starts">Hunting Game Starts</h2>

<p>Once up on a time I received an interesting issue regarding user authentication in one of the projects.
Issue description was telling that it was not possible for the users to login to the site. We were using EPiServer Relate+ in that particular area of the application.
At least I had something for the exceptional case on production server. Following message was observed in local Windows Event store:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre>Exception information:
 Exception type: NullReferenceException
 Exception message: Object reference not set to an instance of an object.
 at EPiServer.Common.Security.Data.SecurityFactory.&lt;&gt;c__DisplayClass5d.b__5c()
 at EPiServer.Data.Providers.SqlDatabaseHandler.&lt;&gt;c__DisplayClass4.b__3()
 at EPiServer.Data.Providers.SqlDatabaseHandler.&lt;&gt;c__DisplayClass7`1.b__6()
 at EPiServer.Data.Providers.SqlTransientErrorsRetryPolicy.Execute[TResult](Func`1 method)
 at EPiServer.Common.Security.SecurityHandler.UpdateUser(IUser user)
 at EPiServer.Common.Web.Authorization.Integrator.SynchronizeUser(MembershipUser membershipUser, String password, Boolean enableCreateNew)
 at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
 at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean&amp; completedSynchronously)
</pre></td></tr></tbody></table></code></pre></div></div>

<p>At least</p>

<p><img src="/assets/img/2014/09/something.png" alt="" /></p>

<h2 id="lets-do-some-hardcore">Let’s do some hardcore</h2>

<p>One of the best friends of yours is <a href="http://msdn.microsoft.com/en-us/library/windows/hardware/ff551063(v=vs.85).aspx">WinDbg</a> on production environment when it comes to debugging and hunting down something.
Let’s fire that guy up on the server (actually you just need to make <code class="language-plaintext highlighter-rouge">xcopy</code> over to server at least for single <code class="language-plaintext highlighter-rouge">.exe</code> file – but it may depend if you need some additional symbols or extensions to use).
 First of all you need to tell that you are actually a .Net developer:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre> .loadby sos clr
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As from Windows Event log we can see that this is a <code class="language-plaintext highlighter-rouge">NullReferenceException</code> we can set explicitly a breakpoint for WinDbg instructing it that we need a notification only this guy gets thrown and don’t bother me with any other first chance junk you will come across:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre> !soe -Create System.NullReferenceException
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now we are free to reproduce a test scenario when users are not able to login in application. And “voilà” – we get back to WinDbg with breakpoint hit.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
</pre></td><td class="rouge-code"><pre>0:033&gt; !clrstack
 OS Thread Id: 0x6d4 (33)
 Child SP IP Call Site
 0000006da87ada10 00007ff95ee78162 EPiServer.Common.Security.Data.SecurityFactory+&lt;&gt;c__DisplayClass5d.b__5c()
 0000006da87adb40 00007ff95c1c1aff *** ERROR: Module load completed but symbols could not be loaded for C:/Windows/Microsoft.NET/Framework64/v4.0.30319/Temporary ASP.NET Files/root/ab1314ba/3ae9e6be/assembly/dl3/49a2918e/d9a3f7fc_f08fcf01/EPiServer.Data.dll
 EPiServer.Data.Providers.SqlDatabaseHandler+&lt;&gt;c__DisplayClass4.b__3()
 0000006da87adb70 00007ff95c1c1790 EPiServer.Data.Providers.SqlDatabaseHandler+&lt;&gt;c__DisplayClass7`1[[System.Boolean, mscorlib]].b__6()
 0000006da87adbd0 00007ff95b9a2622 EPiServer.Data.Providers.SqlTransientErrorsRetryPolicy.Execute[[System.Boolean, mscorlib]](System.Func`1)
 0000006da87adcf0 00007ff95ee76cff EPiServer.Common.Security.SecurityHandler.UpdateUser(EPiServer.Common.Security.IUser)
 0000006da87adda0 00007ff95ee5e56c *** ERROR: Module load completed but symbols could not be loaded for C:/Windows/Microsoft.NET/Framework64/v4.0.30319/Temporary ASP.NET Files/root/ab1314ba/3ae9e6be/assembly/dl3/ad46c74b/15e1f2fc_f08fcf01/EPiServer.Common.Web.Authorization.dll
 EPiServer.Common.Web.Authorization.Integrator.SynchronizeUser(System.Web.Security.MembershipUser, System.String, Boolean)
 0000006da87adf10 00007ff9b258b680 *** WARNING: Unable to verify checksum for C:/Windows/assembly/NativeImages_v4.0.30319_64/System.Web/2e2a972f876941b5d11da10ae390fdf0/System.Web.ni.dll
 *** ERROR: Module load completed but symbols could not be loaded for C:/Windows/assembly/NativeImages_v4.0.30319_64/System.Web/2e2a972f876941b5d11da10ae390fdf0/System.Web.ni.dll
 System.Web.HttpApplication+SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
 0000006da87adf70 00007ff9b256bee5 System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef)
 0000006da87ae010 00007ff9b258954a System.Web.HttpApplication+PipelineStepManager.ResumeSteps(System.Exception)
 0000006da87ae160 00007ff9b256c0f3 System.Web.HttpApplication.BeginProcessRequestNotification(System.Web.HttpContext, System.AsyncCallback)
 0000006da87ae1b0 00007ff9b256613e System.Web.HttpRuntime.ProcessRequestNotificationPrivate(System.Web.Hosting.IIS7WorkerRequest, System.Web.HttpContext)
 0000006da87ae250 00007ff9b256efb1 System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)
 0000006da87ae460 00007ff9b256e9e2 System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)
 0000006da87ae4b0 00007ff9b2cc28d1 DomainNeutralILStubClass.IL_STUB_ReversePInvoke(Int64, Int64, Int64, Int32)
 0000006da87aecc8 00007ff9b9e3736e [InlinedCallFrame: 0000006da87aecc8] System.Web.Hosting.UnsafeIISMethods.MgdIndicateCompletion(IntPtr, System.Web.RequestNotificationStatus ByRef)
 0000006da87aecc8 00007ff9b261838b [InlinedCallFrame: 0000006da87aecc8] System.Web.Hosting.UnsafeIISMethods.MgdIndicateCompletion(IntPtr, System.Web.RequestNotificationStatus ByRef)
 0000006da87aeca0 00007ff9b261838b DomainNeutralILStubClass.IL_STUB_PInvoke(IntPtr, System.Web.RequestNotificationStatus ByRef)
 0000006da87aed70 00007ff9b256f19f System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)
 0000006da87aef80 00007ff9b256e9e2 System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)
 0000006da87aefd0 00007ff9b2cc28d1 DomainNeutralILStubClass.IL_STUB_ReversePInvoke(Int64, Int64, Int64, Int32)
 0000006da87af1d8 00007ff9b9e375c3 [ContextTransitionFrame: 0000006da87af1d8]
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Well, this doesn’t give much more info about what’s really is happening on the server. Stacktrace is almost the same except that now we do have much more noise.
 One of the downside of this exception is that it occurs in EPiServer module where we do have limited access to source code and debug symbols.
 So, if you are lucky and you have a <code class="language-plaintext highlighter-rouge">RedGate Reflector Pro</code> version, that incredible tool has VS plugin that allows you “<code class="language-plaintext highlighter-rouge">Enable Debugging</code>” for even 3rd party libs to which you don’t have a source code available. RedGate Reflector disassemble <code class="language-plaintext highlighter-rouge">.dll</code> file and then generates <code class="language-plaintext highlighter-rouge">.pdb</code> file out also. This enables you to copy generated debug symbol files to target application site and inspect where excatly this happens in source code.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre>0:033&gt; !clrstack
 OS Thread Id: 0x6d4 (33)
 Child SP IP Call Site
 0000006da87ada10 00007ff95ee78162 EPiServer.Common.Security.Data.SecurityFactory+&lt;&gt;c__DisplayClass5d.b__5c() [C:/Users/valdis/AppData/Local/Red Gate/.NET Reflector 8/Cache/0/EPiServer.Common.Security.pdb.source/EPiServer/Common/Security/Data/SecurityFactory.cs @ 1020]
 0000006da87adb40 00007ff95c1c1aff *** ERROR: Module load completed but symbols could not be loaded for C:/Windows/Microsoft.NET/Framework64/v4.0.30319/Temporary ASP.NET Files/root/ab1314ba/3ae9e6be/assembly/dl3/49a2918e/d9a3f7fc_f08fcf01/EPiServer.Data.dll
 EPiServer.Data.Providers.SqlDatabaseHandler+&lt;&gt;c__DisplayClass4.b__3()
 0000006da87adb70 00007ff95c1c1790 EPiServer.Data.Providers.SqlDatabaseHandler+&lt;&gt;c__DisplayClass7`1[[System.Boolean, mscorlib]].b__6()
 0000006da87adbd0 00007ff95b9a2622 EPiServer.Data.Providers.SqlTransientErrorsRetryPolicy.Execute[[System.Boolean, mscorlib]](System.Func`1)
 0000006da87adcf0 00007ff95ee76cff EPiServer.Common.Security.SecurityHandler.UpdateUser(EPiServer.Common.Security.IUser) [C:/Users/valdis/AppData/Local/Red Gate/.NET Reflector 8/Cache/0/EPiServer.Common.Security.pdb.source/EPiServer/Common/Security/SecurityHandler.cs @ 1223]
….
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Finally we can spot a source of our exception. The given source line number actually as it turned out wasn’t really precise – it pointed to following region in our <code class="language-plaintext highlighter-rouge">UpdateUser</code> method where <code class="language-plaintext highlighter-rouge">OpenIDCollection</code> is constructed:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="rouge-code"><pre><span class="k">protected</span> <span class="k">internal</span> <span class="k">virtual</span> <span class="k">void</span> <span class="nf">UpdateUser</span><span class="p">(</span><span class="n">User</span> <span class="n">user</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">User</span> <span class="n">tmpUser</span> <span class="p">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">GetUser</span><span class="p">(</span><span class="n">user</span><span class="p">.</span><span class="n">ID</span><span class="p">,</span> <span class="k">true</span><span class="p">);</span>
    <span class="p">...</span>

    <span class="n">databaseHandler</span><span class="p">.</span><span class="nf">ExecuteTransaction</span><span class="p">((</span><span class="n">Action</span><span class="p">)</span> <span class="p">(()</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="err">…</span>
        <span class="n">OpenIDCollection</span> <span class="n">local_3</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">OpenIDCollection</span><span class="p">();</span>

        <span class="k">if</span><span class="p">(</span><span class="n">tmpUser</span><span class="p">.</span><span class="n">OpenIDs</span><span class="p">.</span><span class="n">Count</span> <span class="p">&gt;</span> <span class="m">0</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="err">…</span>
        <span class="p">}</span>

        <span class="err">…</span>
    <span class="p">}));</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Browsing constructor of the custom collection – we can be sure there is actually nothing that could be <code class="language-plaintext highlighter-rouge">null</code> and/or throw an <code class="language-plaintext highlighter-rouge">Exception</code>.</p>

<h2 id="inspecting-method-parameters">Inspecting method parameters</h2>

<p>Well, next thing that we could do is to browse a bit around executing environment of the method.
As <code class="language-plaintext highlighter-rouge">UpdateUser</code> uses lambda expressions it starts to get a bit more trickier and more fun.
To get a parameters for given stacktrace we can use <code class="language-plaintext highlighter-rouge">-p</code> switch for <code class="language-plaintext highlighter-rouge">clrstack</code> command:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="rouge-code"><pre>0:033&gt; !clrstack -p
 OS Thread Id: 0x6d4 (33)
 Child SP IP Call Site
 0000006da87ada10 00007ff95ee78162 EPiServer.Common.Security.Data.SecurityFactory+&lt;&gt;c__DisplayClass5d.b__5c() [C:/Users/valdis/AppData/Local/Red Gate/.NET Reflector 8/Cache/0/EPiServer.Common.Security.pdb.source/EPiServer/Common/Security/Data/SecurityFactory.cs @ 1020]
 PARAMETERS:
 this (0x0000006da87adb40) = 0x0000006c59f138f0

0000006da87adb40 00007ff95c1c1aff EPiServer.Data.Providers.SqlDatabaseHandler+&lt;&gt;c__DisplayClass4.b__3()
 PARAMETERS:
 this =

0000006da87adb70 00007ff95c1c1790 EPiServer.Data.Providers.SqlDatabaseHandler+&lt;&gt;c__DisplayClass7`1[[System.Boolean, mscorlib]].b__6()
 PARAMETERS:
 this =

0000006da87adbd0 00007ff95b9a2622 EPiServer.Data.Providers.SqlTransientErrorsRetryPolicy.Execute[[System.Boolean, mscorlib]](System.Func`1)
 PARAMETERS:
 this (0x0000006da87adcf0) = 0x0000006c59df9c68
 method (0x0000006da87adcf8) = 0x0000006c59f1d5a0
…
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We can dump lambda expression generated method parameter object and see what’s inside there:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre>0:033&gt; !do 0x0000006c59f138f0
 Name: EPiServer.Common.Security.Data.SecurityFactory+&lt;&gt;c__DisplayClass5d
 MethodTable: 00007ff95ef12578
 EEClass: 00007ff95ef07f00
 Size: 56(0x38) bytes
 File: C:/Windows/Microsoft.NET/Framework64/v4.0.30319/Temporary ASP.NET Files/root/ab1314ba/3ae9e6be/assembly/dl3/3230184a/15e1f2fc_f08fcf01/EPiServer.Common.Security.dll
 Fields:
 MT Field Offset Type VT Attr Value Name
 00007ff95b4d7048 400010e 8 …mon.Security.User 0 instance 0000000000000000 tmpUser
 00007ff95bdd1958 400010f 10 …ativeAccessRights 0 instance 0000006c59f1ba38 accessRights
 00007ff95b65dfd8 4000110 18 ….IDatabaseHandler 0 instance 0000006c59df9bd0 databaseHandler
 00007ff95bdbd158 4000111 20 …a.SecurityFactory 0 instance 0000006b547918a0 &lt;&gt;4__this
 00007ff95b4d7048 4000112 28 …mon.Security.User 0 instance 0000006c59f10308 user
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This gets more interesting. We can see that <code class="language-plaintext highlighter-rouge">tmpUser</code> actually is <code class="language-plaintext highlighter-rouge">null</code> – <code class="language-plaintext highlighter-rouge">Value = 0000000000000000</code>.
If we take a closer look at body of the method we can see that <code class="language-plaintext highlighter-rouge">tmpUser</code> is used later on to understand what kind of changes have been made to the user in order to calculate necessary updates to be sent to database.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre>User tmpUser = this.GetUser(user.ID, true);
...

if(tmpUser.OpenIDs.Count &gt; 0)
{
    ...
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We can verify once again the passed in user object to the method (dump <code class="language-plaintext highlighter-rouge">user</code> from the lambda expression parameter object):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre>0:033&gt; !do 0000006c59f10308
 Name: EPiServer.Common.Security.User
 MethodTable: 00007ff95b4d7048
 EEClass: 00007ff95b49fc30
 Size: 272(0x110) bytes
 File: C:/Windows/Microsoft.NET/Framework64/v4.0.30319/Temporary ASP.NET Files/root/ab1314ba/3ae9e6be/assembly/dl3/3230184a/15e1f2fc_f08fcf01/EPiServer.Common.Security.dll
 Fields:
 MT Field Offset Type VT Attr Value Name
 00007ff9b8e737c8 4000001 18 System.Int32 1 instance 95887 m_id
 00007ff9b8e87978 4000002 20 System.Guid 1 instance 0000006c59f10328 m_uniqueId
 00007ff9b8e711b8 4000003 8 System.Object 0 instance 0000006a5ade9d88 _syncObj
 00007ff9b8e6f370 4000004 1c System.Boolean 1 instance 0 m_ownedObjectsLoaded
 00007ff9b8e711b8 4000005 10 System.Object 0 instance 0000006a5ade9b88 m_master
 00007ff95b483748 4000006 30 ….IFrameworkEntity 0 instance 0000006a5ade9b88 m_entity
 ...
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We can see that <code class="language-plaintext highlighter-rouge">user</code> variable seems like to be valid. It has it’s own ID, Master object, etc.</p>

<h2 id="inspecting-last-chain--database">Inspecting last chain – database</h2>

<p>Well, if we take a look at <code class="language-plaintext highlighter-rouge">GetUser(int, bool)</code> method that’s filling up <code class="language-plaintext highlighter-rouge">tmpUser</code> variable we can see that one of the way that this method returns <code class="language-plaintext highlighter-rouge">null</code> value is if it fails to read SP result or there is no results at all.
So it’s quite interesting what would stored procedure return and why <code class="language-plaintext highlighter-rouge">GetUser</code> returns null in the first place?</p>

<p>Sneak peek into stored procedure and executing query we can get confirmation that there is no such user with <code class="language-plaintext highlighter-rouge">ID</code> (<code class="language-plaintext highlighter-rouge">95887</code>) given by <code class="language-plaintext highlighter-rouge">user</code> variable that was passed in as method parameter for our lambda expression.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>select * from tblEPiServerCommonUser where intID = 95887

(0 row(s) affected)
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now it get’s really confusing.
Let’s get back to facts that we know already:</p>

<ul>
  <li>When user is logging in we got an exception</li>
  <li>New users are not saved in the database</li>
  <li>Synchronization process happens for the Relate+ user anyway</li>
</ul>

<p>Our project specifics were that during initial process when we need to create new user, it gets synced once again after domain has raised an event and handler received roles from external system.
During this second round <code class="language-plaintext highlighter-rouge">UpdateUser</code> somehow fails with <code class="language-plaintext highlighter-rouge">NullReferenceException</code>.
Digging more into SQL queries and its results finally I noticed following line:</p>

<p><img src="/assets/img/2015/06/null-ref-excp-1.png" alt="" /></p>

<p>This was the key to the solution. By executing manually failing command we got response from the SQL Server:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre>exec spEPiServerCommunityBlogAddBlog @strHeader=N’MyPage Blog for User ”…”’,@strBody=N”,@intAuthorID=…,@blnPingEnabled=0,@strLanguageID=NULL,@intStatus=1

Msg 515, Level 16, State 2, Procedure spEPiServerCommunityBlogAddBlog, Line 11
 Cannot insert the value NULL into column ‘intPreviousStatus’, table ‘dbEPiServer.dbo.tblEPiServerCommunityBlog'; column does not allow nulls. INSERT fails.
 The statement has been terminated.
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As it’s turned out – you have to double check what’s going in your database after you ran EPiServer Relate+ database upgrade scripts. Not complete database schema was upgraded correctly!</p>

<p>Have fun!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term="Debugging" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><category term="debugging" /><summary type="html"><![CDATA[This is a blog post telling a short story about one of the developer’s nightmare beast hunting case – System.NullReferenceException.]]></summary></entry><entry><title type="html">Initializable modules without EPiServer</title><link href="https://tech-fellow.eu/2014/08/18/initializable-modules-without-episerver/" rel="alternate" type="text/html" title="Initializable modules without EPiServer" /><published>2014-08-18T14:15:00+03:00</published><updated>2014-08-18T14:15:00+03:00</updated><id>https://tech-fellow.eu/2014/08/18/initializable-modules-without-episerver</id><content type="html" xml:base="https://tech-fellow.eu/2014/08/18/initializable-modules-without-episerver/"><![CDATA[<p><a href="http://world.episerver.com/Documentation/Items/Developers-Guide/EPiServer-CMS/75/Initialization/Creating-an-initialization-module/">EPiServer initialization modules</a> is a great feature to provide plugin facilities for the hosting application. I find initialization modules pretty handful in cases when you need to initialize some library, configure some stuff or do whatever needed at application start-up.
 However there are times when you have to develop site without wonderful backup platform that takes all boring boilerplate code away and provides with much awesome stuff and features.
 Let’s switch to ordinary Asp.Net Mvc application initialization code:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">assembly</span><span class="p">:</span> <span class="nf">OwinStartupAttribute</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">WebApplication1</span><span class="p">.</span><span class="n">Startup</span><span class="p">))]</span>
<span class="k">namespace</span> <span class="nn">WebApplication1</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">partial</span> <span class="k">class</span> <span class="nc">Startup</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="k">void</span> <span class="nf">Configuration</span><span class="p">(</span><span class="n">IAppBuilder</span> <span class="n">app</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="nf">ConfigureAuth</span><span class="p">(</span><span class="n">app</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>In order to add new steps for initialization you may need to add new method invocation under or above <code class="language-plaintext highlighter-rouge">ConfigureAuth(app)</code> method:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">Configuration</span><span class="p">(</span><span class="n">IAppBuilder</span> <span class="n">app</span><span class="p">)</span>
<span class="p">{</span>
    <span class="nf">ConfigureAuth</span><span class="p">(</span><span class="n">app</span><span class="p">);</span>
    <span class="c1">// OtherSetupMethod();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then you may need to create new <code class="language-plaintext highlighter-rouge">Startup</code> class partial fragment that is located under <code class="language-plaintext highlighter-rouge">App_Start</code> folder just to follow used conventions in default project template. Tiny place for a small library :)</p>

<h2 id="initialization-modules">Initialization Modules</h2>

<p>So I took inspiration EPiServer gave and created a small initialization module library that does exactly what it says – you are able to create a initialization modules which will be called during application start-up or at any your preferred time during app life cycle.</p>

<p>So by using <a href="https://github.com/valdisiljuconoks/InitializableModule">InitializationModule library</a> you are able to rewrite user authentication setup in default Asp.Net Mvc template with following code.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">assembly</span><span class="p">:</span> <span class="nf">OwinStartupAttribute</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">WebApplication1</span><span class="p">.</span><span class="n">Startup</span><span class="p">))]</span>
<span class="k">namespace</span> <span class="nn">WebApplication1</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">partial</span> <span class="k">class</span> <span class="nc">Startup</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="k">void</span> <span class="nf">Configuration</span><span class="p">(</span><span class="n">IAppBuilder</span> <span class="n">app</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="kt">var</span> <span class="n">process</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ModuleExecutionProcess</span><span class="p">(</span><span class="n">app</span><span class="p">);</span>
            <span class="kt">var</span> <span class="n">context</span> <span class="p">=</span> <span class="n">process</span><span class="p">.</span><span class="nf">Execute</span><span class="p">();</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You can now rewrite authentication setup code using initialization modules:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">WebApplication1</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">partial</span> <span class="k">class</span> <span class="nc">Startup</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
    <span class="p">{</span>
        <span class="k">private</span> <span class="k">readonly</span> <span class="n">IAppBuilder</span> <span class="n">_app</span><span class="p">;</span>

        <span class="k">public</span> <span class="nf">Startup</span><span class="p">(</span><span class="n">IAppBuilder</span> <span class="n">app</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">this</span><span class="p">.</span><span class="n">_app</span> <span class="p">=</span> <span class="n">app</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">()</span>
        <span class="p">{</span>
            <span class="c1">// Configure the db context, user manager and signin manager to use a single instance per request</span>
            <span class="n">_app</span><span class="p">.</span><span class="nf">CreatePerOwinContext</span><span class="p">(</span><span class="n">ApplicationDbContext</span><span class="p">.</span><span class="n">Create</span><span class="p">);</span>
            <span class="n">_app</span><span class="p">.</span><span class="nf">CreatePerOwinContext</span><span class="p">(</span><span class="n">ApplicationUserManager</span><span class="p">.</span><span class="n">Create</span><span class="p">);</span>
            <span class="n">_app</span><span class="p">.</span><span class="nf">CreatePerOwinContext</span><span class="p">(</span><span class="n">ApplicationSignInManager</span><span class="p">.</span><span class="n">Create</span><span class="p">);</span>

            <span class="c1">// …</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Taking a look at <code class="language-plaintext highlighter-rouge">Global.asacx.cs</code> file content it seems very good candidate for a initialization modules:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">MvcApplication</span> <span class="p">:</span> <span class="n">System</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">HttpApplication</span>
<span class="p">{</span>
    <span class="k">protected</span> <span class="k">void</span> <span class="nf">Application_Start</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">AreaRegistration</span><span class="p">.</span><span class="nf">RegisterAllAreas</span><span class="p">();</span>
        <span class="n">GlobalConfiguration</span><span class="p">.</span><span class="nf">Configure</span><span class="p">(</span><span class="n">WebApiConfig</span><span class="p">.</span><span class="n">Register</span><span class="p">);</span>
        <span class="n">FilterConfig</span><span class="p">.</span><span class="nf">RegisterGlobalFilters</span><span class="p">(</span><span class="n">GlobalFilters</span><span class="p">.</span><span class="n">Filters</span><span class="p">);</span>
        <span class="n">RouteConfig</span><span class="p">.</span><span class="nf">RegisterRoutes</span><span class="p">(</span><span class="n">RouteTable</span><span class="p">.</span><span class="n">Routes</span><span class="p">);</span>
        <span class="n">BundleConfig</span><span class="p">.</span><span class="nf">RegisterBundles</span><span class="p">(</span><span class="n">BundleTable</span><span class="p">.</span><span class="n">Bundles</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="dependencies-between-modules">Dependencies between modules</h2>

<p>Initialization modules provides built-in support for specifying cross-module dependencies. Let’s say we do have following modules:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">Module1</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">()</span>
    <span class="p">{</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">Module1</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">Module2</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">()</span>
    <span class="p">{</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">Module2</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">Module3</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">()</span>
    <span class="p">{</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">Module2</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">Module4</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">()</span>
    <span class="p">{</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">Module4</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">Module5</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">()</span>
    <span class="p">{</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Using <code class="language-plaintext highlighter-rouge">ModuleDependency</code> attribute you can specify that one module is dependent on others’ module execution result, e.g., <code class="language-plaintext highlighter-rouge">Module3</code> will not be executed before <code class="language-plaintext highlighter-rouge">Module2</code>, <code class="language-plaintext highlighter-rouge">Module5</code> before <code class="language-plaintext highlighter-rouge">Module4</code>, etc.</p>

<p>Graphically this looks like this:</p>

<p><img src="/assets/img/2014/08/depend.PNG" alt="" /></p>

<p>Engine takes care of proper execution order for the dependent modules. However – it’s defined which module will be executed first – module <code class="language-plaintext highlighter-rouge">Module3</code> or module <code class="language-plaintext highlighter-rouge">Module4</code>. If you need to define a specific execution order for the modules on “the same level” – probably they are not on the same level – somebody has dependency on other.</p>

<h2 id="module-resolution">Module resolution</h2>

<p>Initialization modules sometimes may depend not only on other modules but they may require something from outer world as well - it’s an ordinary case in enterprise applications – some dependencies injected.</p>

<p>It’s possible to provide module resolution function to <a href="https://github.com/valdisiljuconoks/InitializableModule">InitializationModule library</a> in order to specify how modules are resolved in <a href="http://blog.ploeh.dk/2010/09/29/TheRegisterResolveReleasepattern/">RRR</a> cycle.</p>

<p>Let’s say in this particular case we are using <code class="language-plaintext highlighter-rouge">StructureMap DI</code> container (particular implementation of container does not play any role in this case as library does not care about implementation - power of <code class="language-plaintext highlighter-rouge">System.Func</code>).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">process</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ModuleExecutionProcess</span><span class="p">(</span><span class="n">ObjectFactory</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">context</span> <span class="p">=</span> <span class="n">process</span><span class="p">.</span><span class="nf">Execute</span><span class="p">();</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>In this case every discovered module will be resolved using specified function (<code class="language-plaintext highlighter-rouge">Func</code>).
It may seem a bit of <a href="http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/">Service locator anti-pattern</a>. But it’s a bit better than creating a <a href="http://blog.ploeh.dk/2014/05/19/conforming-container/">conforming container</a> for every DI framework out there.</p>

<p><a href="https://github.com/valdisiljuconoks/InitializableModule">InitializationModule library</a> is available in <a href="https://www.nuget.org/packages/TechFellow.InitializableModule/">nuget.org feed</a> and source code is  pushed to <a href="https://github.com/valdisiljuconoks/InitializableModule">GitHub</a>.</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[EPiServer initialization modules is a great feature to provide plugin facilities for the hosting application. I find initialization modules pretty handful in cases when you need to initialize some library, configure some stuff or do whatever needed at application start-up. However there are times when you have to develop site without wonderful backup platform that takes all boring boilerplate code away and provides with much awesome stuff and features. Let’s switch to ordinary Asp.Net Mvc application initialization code:]]></summary></entry><entry><title type="html">Lambda expression and small “around” method to reduce DRY</title><link href="https://tech-fellow.eu/2014/08/16/lambda-expression-and-small-around-method-to-reduce-dry/" rel="alternate" type="text/html" title="Lambda expression and small “around” method to reduce DRY" /><published>2014-08-16T12:30:00+03:00</published><updated>2014-08-16T12:30:00+03:00</updated><id>https://tech-fellow.eu/2014/08/16/lambda-expression-and-small-around-method-to-reduce-dry</id><content type="html" xml:base="https://tech-fellow.eu/2014/08/16/lambda-expression-and-small-around-method-to-reduce-dry/"><![CDATA[<p>When you are acting as façade or in any other “forward-like” role sometimes error handling may come pretty boring stuff to deal with.
For instance if you are acting as front-end client proxy class for some <code class="language-plaintext highlighter-rouge">REST Api</code> behind the scenes, code below may look familiar – that you have to replicate yourself all the time and catch for instance in this case IO error and response content format error (if they return invalid formatted <code class="language-plaintext highlighter-rouge">Json</code> object).</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
</pre></td><td class="rouge-code"><pre><span class="k">protected</span> <span class="k">void</span> <span class="nf">Operation1</span><span class="p">()</span>
<span class="p">{</span>
    <span class="k">try</span>
    <span class="p">{</span>
        <span class="c1">// some black magic happens here..</span>
    <span class="p">}</span>
    <span class="k">catch</span> <span class="p">(</span><span class="n">HttpRequestException</span> <span class="n">e</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// handle IO issue</span>
        <span class="k">return</span> <span class="err">…</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">catch</span> <span class="p">(</span><span class="n">JsonReaderException</span> <span class="n">e</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// handle response content issue</span>
        <span class="k">return</span> <span class="err">…</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">protected</span> <span class="k">void</span> <span class="nf">FancyOperation2</span><span class="p">()</span>
<span class="p">{</span>
    <span class="k">try</span>
    <span class="p">{</span>
        <span class="c1">// some black magic happens here..</span>
    <span class="p">}</span>
    <span class="k">catch</span> <span class="p">(</span><span class="n">HttpRequestException</span> <span class="n">e</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// handle IO issue</span>
        <span class="k">return</span> <span class="err">…</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">catch</span> <span class="p">(</span><span class="n">JsonReaderException</span> <span class="n">e</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// handle response content issue</span>
        <span class="k">return</span> <span class="err">…</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We are know that repetition is anything about to remember it better, but for me as design practitioner and <code class="language-plaintext highlighter-rouge">DRY</code> principle defender this seems to be too much. There is definitely a space to improve and reduce some of the duplicates.
The most simplest solution is to utilize Lambda expressions and refactor these methods to use “around” method (for me it drives small similarities with <a href="http://stackoverflow.com/questions/267862/what-makes-lisp-macros-so-special">Lisp macros</a>).
So what we could do better in this case is to create new method that receives Action and does all boring stuff like handling the error cases:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="k">protected</span> <span class="k">void</span> <span class="nf">Try</span><span class="p">(</span><span class="n">Action</span> <span class="n">action</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">try</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="nf">action</span><span class="p">();</span>
    <span class="p">}</span>
    <span class="k">catch</span> <span class="p">(</span><span class="n">HttpRequestException</span> <span class="n">e</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// handle IO issue</span>
        <span class="k">return</span> <span class="err">…</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">catch</span> <span class="p">(</span><span class="n">JsonReaderException</span> <span class="n">e</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// handle response content issue</span>
        <span class="k">return</span> <span class="err">…</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So <code class="language-plaintext highlighter-rouge">Operation1</code> and <code class="language-plaintext highlighter-rouge">FancyOperation2</code> now looks much better and cleaner.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre> <span class="k">protected</span> <span class="k">void</span> <span class="nf">Operation1</span><span class="p">()</span>
<span class="p">{</span>
    <span class="nf">Try</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
        <span class="c1">// some black magic happens here..</span>
    <span class="p">});</span>
<span class="p">}</span>

<span class="k">protected</span> <span class="k">void</span> <span class="nf">FancyOperation2</span><span class="p">()</span>
<span class="p">{</span>
    <span class="nf">Try</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
        <span class="c1">// some black magic happens here..</span>
    <span class="p">});</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>I guess it’s a bit better now.</p>

<p>Happy Coding!
[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Lisp" /><category term=".net" /><category term="c#" /><category term="lisp" /><summary type="html"><![CDATA[When you are acting as façade or in any other “forward-like” role sometimes error handling may come pretty boring stuff to deal with. For instance if you are acting as front-end client proxy class for some REST Api behind the scenes, code below may look familiar – that you have to replicate yourself all the time and catch for instance in this case IO error and response content format error (if they return invalid formatted Json object).]]></summary></entry><entry><title type="html">Format Your Exception Message Properly</title><link href="https://tech-fellow.eu/2014/08/13/format-your-exception-message-properly/" rel="alternate" type="text/html" title="Format Your Exception Message Properly" /><published>2014-08-13T00:45:00+03:00</published><updated>2014-08-13T00:45:00+03:00</updated><id>https://tech-fellow.eu/2014/08/13/format-your-exception-message-properly</id><content type="html" xml:base="https://tech-fellow.eu/2014/08/13/format-your-exception-message-properly/"><![CDATA[<h2 id="not-so-nice-failure">Not so Nice Failure</h2>
<p>I was hacking around <a href="http://particular.net/service-platform">NServiceBus</a> (NSB) application and came across pretty unpleasant failure from <code class="language-plaintext highlighter-rouge">NSB</code>. So in short we were using <code class="language-plaintext highlighter-rouge">Unicast</code> bus that basically means that producer-side of the message has to have a configuration set to which <code class="language-plaintext highlighter-rouge">NSB</code> endpoint particular message should be sent. In this case we were using <a href="http://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-how-to-use-queues/#what-is">Microsoft Azure Storage Queues</a> as physical transport level.
In case when you don’t have a particular configuration to instruct <code class="language-plaintext highlighter-rouge">NSB</code> where the message has to be delivered you may encounter following exceptional message:</p>

<p><img src="/assets/img/2014/08/nsb-exc.png" alt="" /></p>

<p>Which does not tell much about root cause of the exception.
Stack trace looks even more obscure:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
</pre></td><td class="rouge-code"><pre>at NServiceBus.Azure.Transports.WindowsAzureStorageQueues.AzureMessageQueueSender.Send(TransportMessage message, Address address) in y:/BuildAgent/work/ba77a0c29cee2af1/src/NServiceBus.Azure.Transports.WindowsAzureStorageQueues/AzureMessageQueueSender.cs:line 37
 at NServiceBus.Unicast.Behaviors.DispatchMessageToTransportBehavior.Invoke(SendPhysicalMessageContext context, Action next) in y:/BuildAgent/work/31f8c64a6e8a2d7c/src/NServiceBus.Core/Unicast/Behaviors/DispatchMessageToTransportBehavior.cs:line 77
 at NServiceBus.Pipeline.BehaviorChain`1.InvokeNext(T context) in y:/BuildAgent/work/31f8c64a6e8a2d7c/src/NServiceBus.Core/Pipeline/BehaviorChain.cs:line 51 at NServiceBus.Pipeline.BehaviorChain`1.Invoke(T context) in y:/BuildAgent/work/31f8c64a6e8a2d7c/src/NServiceBus.Core/Pipeline/BehaviorChain.cs:line 36
 at NServiceBus.Pipeline.PipelineExecutor.Execute[T](BehaviorChain`1 pipelineAction, T context) in y:/BuildAgent/work/31f8c64a6e8a2d7c/src/NServiceBus.Core/Pipeline/PipelineExecutor.cs:line 139
 at NServiceBus.Pipeline.PipelineExecutor.InvokeSendPipeline(SendOptions sendOptions, TransportMessage physicalMessage) in y:/BuildAgent/work/31f8c64a6e8a2d7c/src/NServiceBus.Core/Pipeline/PipelineExecutor.cs:line 97
 at NServiceBus.Unicast.Behaviors.CreatePhysicalMessageBehavior.Invoke(SendLogicalMessagesContext context, Action next) in y:/BuildAgent/work/31f8c64a6e8a2d7c/src/NServiceBus.Core/Unicast/Behaviors/CreatePhysicalMessageBehavior.cs:line 57
 at NServiceBus.Pipeline.BehaviorChain`1.InvokeNext(T context) in y:/BuildAgent/work/31f8c64a6e8a2d7c/src/NServiceBus.Core/Pipeline/BehaviorChain.cs:line 51 at NServiceBus.Pipeline.BehaviorChain`1.Invoke(T context) in y:/BuildAgent/work/31f8c64a6e8a2d7c/src/NServiceBus.Core/Pipeline/BehaviorChain.cs:line 36
 at NServiceBus.Pipeline.PipelineExecutor.Execute[T](BehaviorChain`1 pipelineAction, T context) in y:/BuildAgent/work/31f8c64a6e8a2d7c/src/NServiceBus.Core/Pipeline/PipelineExecutor.cs:line 139
 at NServiceBus.Pipeline.PipelineExecutor.InvokeSendPipeline(SendOptions sendOptions, IEnumerable`1 messages) in y:/BuildAgent/work/31f8c64a6e8a2d7c/src/NServiceBus.Core/Pipeline/PipelineExecutor.cs:line 78
 at NServiceBus.Unicast.UnicastBus.InvokeSendPipeline(SendOptions sendOptions, List`1 messages) in y:/BuildAgent/work/31f8c64a6e8a2d7c/src/NServiceBus.Core/Unicast/UnicastBus.cs:line 749
 at NServiceBus.Unicast.UnicastBus.SendMessages(SendOptions sendOptions, List`1 messages) in y:/BuildAgent/work/31f8c64a6e8a2d7c/src/NServiceBus.Core/Unicast/UnicastBus.cs:line 725
 at NServiceBus.Unicast.UnicastBus.Send(Object[] messages) in y:/BuildAgent/work/31f8c64a6e8a2d7c/src/NServiceBus.Core/Unicast/UnicastBus.cs:line 571
 at NServiceBus.Unicast.UnicastBus.Send(Object message) in y:/BuildAgent/work/31f8c64a6e8a2d7c/src/NServiceBus.Core/Unicast/UnicastBus.cs:line 555
….
at lambda_method(Closure , ControllerBase , Object[] )
 at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
 at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
 at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
 at System.Web.Mvc.Async.AsyncControllerActionInvoker.ActionInvocation.InvokeSynchronousActionMethod()
 at System.Web.Mvc.Async.AsyncControllerActionInvoker.b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState)
 at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult)
 at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
 at System.Web.Mvc.Async.AsyncResultWrapper.End[TResult](IAsyncResult asyncResult, Object tag)
 at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult)
 at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.b__3f()
 at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.&lt;&gt;c__DisplayClass48.b__41()
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="traceable-failure-sample">Traceable Failure Sample</h2>

<p>This reminds me how important actually is to capture failure case and provide meaningful exception message to the consumer (in this case DevOps guy who is monitoring the system or Dev who is developing the site) in order to relief search of exception origin.</p>

<p>Once I was refactoring default <code class="language-plaintext highlighter-rouge">Asp.Net Mvc</code> 5 sample file with built-in authentication.</p>

<p>You may have seen <code class="language-plaintext highlighter-rouge">AccountController</code> with multiple constructors. One of them is accepting instance of <code class="language-plaintext highlighter-rouge">UserManager</code> another constructor is parameter-less providing instance of <code class="language-plaintext highlighter-rouge">UserManager</code> class by constructing it manually:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="nf">AccountController</span><span class="p">()</span> <span class="p">:</span>
    <span class="k">this</span><span class="p">(</span><span class="k">new</span> <span class="nf">UserManager</span><span class="p">(</span><span class="k">new</span> <span class="nf">UserStore</span><span class="p">(</span><span class="k">new</span> <span class="nf">ApplicationDbContext</span><span class="p">())))</span>
<span class="p">{</span>
<span class="p">}</span>

<span class="k">public</span> <span class="nf">AccountController</span><span class="p">(</span><span class="n">UserManager</span> <span class="n">userManager</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">UserManager</span> <span class="p">=</span> <span class="n">userManager</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>I thought it should be good actually to utilize <code class="language-plaintext highlighter-rouge">Inversion of Control</code> capabilities and inject proper instance of ‘UserManager’ class when requested by dependency resolver. So I got rid of this extra constructor, but forgot to configure IoC container properly.
In a return what I got was a nicely formatted exception message that IoC (in this case <a href="http://docs.structuremap.net/">StructureMap</a>) is not able to resolve requested service type and here goes why:</p>

<p><img src="/assets/img/2014/08/sm-exc.png" alt="" /></p>

<p>Highlighted lines even shows which constructor was picked up by resolver and what kind of argument instance was used (<code class="language-plaintext highlighter-rouge">* Default of …</code> means that <code class="language-plaintext highlighter-rouge">IoC</code> library tries to resolve requested type further down in container).</p>

<p>Reading this particular exception message I can fully understand where is the case and can start to investigate why IoC was not able to resolve requested type.</p>

<p>Forgot to instruct how to get instance of <code class="language-plaintext highlighter-rouge">UserManager</code> class:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="n">For</span><span class="p">&lt;</span><span class="n">UserManager</span><span class="p">&gt;()</span>
    <span class="p">.</span><span class="nf">Use</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span> <span class="k">new</span> <span class="nf">UserManager</span><span class="p">(</span><span class="k">new</span> <span class="nf">UserStore</span><span class="p">(</span><span class="n">ctx</span><span class="p">.</span><span class="nf">GetInstance</span><span class="p">())));</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Prepare to fail.</p>

<p><img src="http://www.cs.cmu.edu/~fgandon/miscellaneous/japan/Image2.gif" alt="" /></p>
<blockquote>
  <p>Nana korobi, ya oki
— Japanese proverb</p>
</blockquote>

<p>Happy coding!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term=".net" /><category term="c#" /><summary type="html"><![CDATA[Not so Nice Failure I was hacking around NServiceBus (NSB) application and came across pretty unpleasant failure from NSB. So in short we were using Unicast bus that basically means that producer-side of the message has to have a configuration set to which NSB endpoint particular message should be sent. In this case we were using Microsoft Azure Storage Queues as physical transport level. In case when you don’t have a particular configuration to instruct NSB where the message has to be delivered you may encounter following exceptional message:]]></summary></entry><entry><title type="html">Eliminate Wrapping Element for EPiServer Content Area Item</title><link href="https://tech-fellow.eu/2014/06/23/eliminate-wrapping-element-for-episerver-content-area-item/" rel="alternate" type="text/html" title="Eliminate Wrapping Element for EPiServer Content Area Item" /><published>2014-06-23T19:10:00+03:00</published><updated>2014-06-23T19:10:00+03:00</updated><id>https://tech-fellow.eu/2014/06/23/eliminate-wrapping-element-for-episerver-content-area-item</id><content type="html" xml:base="https://tech-fellow.eu/2014/06/23/eliminate-wrapping-element-for-episerver-content-area-item/"><![CDATA[<p>This blog posts describes some new features added to latest <a href="https://github.com/valdisiljuconoks/EPiBootstrapArea">EPiBootstrapArea</a> plugin library.</p>

<h2 id="register-new-display-mode-from-code">Register New Display Mode from Code</h2>
<p>Using <code class="language-plaintext highlighter-rouge">EPiBootstrapArea</code> plugin it’s possible to rely on some of the automatically generated display modes. Those are covering almost all portions of the area (starting from whole width ending with one-quarter). However not always default fallback modes suited well for various projects.</p>

<p>In latest <code class="language-plaintext highlighter-rouge">1.2</code> version you may register new display mode by code in EPiServer init module using <a href="https://github.com/valdisiljuconoks/EPiBootstrapArea/blob/master/Registrar.cs">Registrar</a>.</p>

<p>Following code registers new display mode named “The real half” that takes <em>really</em> just a half of the area on all device screen sizes.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
</pre></td><td class="rouge-code"><pre><span class="k">using</span> <span class="nn">EPiBootstrapArea</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">EPiServer.Framework</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">EPiServer.Framework.Initialization</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">InitializationModule</span> <span class="p">=</span> <span class="n">EPiServer</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">InitializationModule</span><span class="p">;</span>

<span class="k">namespace</span> <span class="nn">EPiServer.Templates.Alloy.Business.Initialization</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">InitializationModule</span><span class="p">))]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">CustomDisplayModes</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">Registrar</span><span class="p">.</span><span class="nf">Register</span><span class="p">(</span><span class="k">new</span> <span class="n">DisplayModeFallback</span>
            <span class="p">{</span>
                <span class="n">Name</span> <span class="p">=</span> <span class="err">“</span><span class="n">The</span> <span class="n">real</span> <span class="n">half</span><span class="err">”</span><span class="p">,</span>
                <span class="n">LargeScreenWidth</span> <span class="p">=</span> <span class="m">6</span><span class="p">,</span>
                <span class="n">MediumScreenWidth</span> <span class="p">=</span> <span class="m">6</span><span class="p">,</span>
                <span class="n">SmallScreenWidth</span> <span class="p">=</span> <span class="m">6</span><span class="p">,</span>
                <span class="n">ExtraSmallScreenWidth</span> <span class="p">=</span> <span class="m">6</span><span class="p">,</span>
                <span class="n">Tag</span> <span class="p">=</span> <span class="err">“</span><span class="n">sample</span><span class="p">-</span><span class="n">tag</span><span class="err">”</span>
            <span class="p">});</span>
        <span class="p">}</span>

        <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
        <span class="p">{</span>
        <span class="p">}</span>

        <span class="k">public</span> <span class="k">void</span> <span class="nf">Preload</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">parameters</span><span class="p">)</span>
        <span class="p">{</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Order of initialization modules doesn’t matter as eventually both default mode registration process and custom modes registered through <a href="https://github.com/valdisiljuconoks/EPiBootstrapArea/blob/master/Registrar.cs">Registrar</a> uses display mode <code class="language-plaintext highlighter-rouge">Comparer</code> to distinguish identity of the mode (it compares all property values). If you will register the same mode twice or more times it will be just skipped.</p>

<p>Unfortunately currently you can’t remove display mode from the code. You have to do it either directly in database or you can use <a href="https://github.com/Geta/DdsAdmin">tool</a> to manipulate data in <code class="language-plaintext highlighter-rouge">Dynamic Data Store (DDS)</code>.</p>

<h2 id="content-area-item-wrapping-element">Content Area Item Wrapping Element</h2>

<p>Another feature that came in was to provide ability not to render wrapping <code class="language-plaintext highlighter-rouge">div</code> element if block content is empty. For instance request was based on some sort of block that enlists items. There could be cases when list is empty (for instance no news items returned). In that case block should not render any markup at all. As you may know EPiServer adds wrapping element around block while it’s rendering (good insight of what happens when content is rendered could be found in <a href="http://joelabrahamsson.com/how-episervers-html-helper-propertyfor-works/">article by Joel</a>).
So eventually I ended up with following “consumer-side” code:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ContentType</span><span class="p">(</span><span class="n">DisplayName</span> <span class="p">=</span> <span class="err">“</span><span class="n">ReallyEmptyBlock</span><span class="err">”</span><span class="p">,</span> <span class="n">GUID</span> <span class="p">=</span> <span class="err">“…”</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ReallyEmptyBlock</span> <span class="p">:</span> <span class="n">BlockData</span><span class="p">,</span> <span class="n">IControlVisibility</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">bool</span> <span class="n">HideIfEmpty</span>
    <span class="p">{</span>
        <span class="k">get</span>
        <span class="p">{</span>
            <span class="k">return</span> <span class="k">true</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Essentially you will need to implement <code class="language-plaintext highlighter-rouge">IControlVisibility</code> interface that will take care of wrapping element around block content. If block eventually returns something that satisfies <code class="language-plaintext highlighter-rouge">string.IsNullOrEmpty</code> method (in other words returns completely nothing) no markup will be rendered on content area either.</p>

<h3 id="behind-the-scene">Behind the Scene</h3>

<p>In order to make this happen I had to override <code class="language-plaintext highlighter-rouge">RenderContentAreaItem</code> method for content area render.
The tricky part about this one is that base render method is pretty closed when it comes to customization of its behavior and other aspects. If you take a look at where exactly rendered markup is output you can see that it takes current renderer from <code class="language-plaintext highlighter-rouge">HtmlHelper</code> ():</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">EPiServer.Web.Mvc.Html</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">IContentDataExtensions</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">RenderContentData</span><span class="p">(</span><span class="k">this</span> <span class="n">HtmlHelper</span> <span class="n">html</span><span class="p">,</span> <span class="err">…</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">html</span><span class="p">.</span><span class="n">ViewContext</span><span class="p">.</span><span class="n">Writer</span><span class="p">.</span><span class="nf">Write</span><span class="p">(</span><span class="err">…</span><span class="p">)</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This one reminds me of <a href="http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/">ServiceLocator anti-pattern</a> defined and heavily defended by Mark Seeman. It means that you as child class actor can’t really control final output destination of markup rendered. It would be so much easier if <code class="language-plaintext highlighter-rouge">RenderContetAreaItem</code> would expect to receive <code class="language-plaintext highlighter-rouge">TextWriter</code> as one of the parameters for the method.
Anyway base <code class="language-plaintext highlighter-rouge">EPiServer</code> Api comes AS-IS. The only way how we can trick renderer is to swap <code class="language-plaintext highlighter-rouge">TextWriter</code> and inject temporary writer at the moment when content of the block is rendered and then inspect and analyze it. If content is empty then just don’t add anything to the original writer and eventually we need to remember to swap it back (in order to continue proper rendering of other items on the content area).</p>

<p>Code fragment that takes care of this is shown below. In this case I’m just using <a href="http://htmlagilitypack.codeplex.com/">HtmlAgilityPack</a> to inspect content of wrapping element correctly. I know that this needs additional dependency to another package, but you know we are all living in chaos of NuGet dependencies.. :)</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
</pre></td><td class="rouge-code"><pre><span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">RenderContentAreaItem</span><span class="p">(</span>
                        <span class="n">HtmlHelper</span> <span class="n">htmlHelper</span><span class="p">,</span>
                        <span class="n">ContentAreaItem</span> <span class="n">contentAreaItem</span><span class="p">,</span>
                        <span class="kt">string</span> <span class="n">templateTag</span><span class="p">,</span>
                        <span class="kt">string</span> <span class="n">htmlTag</span><span class="p">,</span>
                        <span class="kt">string</span> <span class="n">cssClass</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">originalWriter</span> <span class="p">=</span> <span class="n">htmlHelper</span><span class="p">.</span><span class="n">ViewContext</span><span class="p">.</span><span class="n">Writer</span><span class="p">;</span>
    <span class="kt">var</span> <span class="n">tempWriter</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">StringWriter</span><span class="p">();</span>

    <span class="n">htmlHelper</span><span class="p">.</span><span class="n">ViewContext</span><span class="p">.</span><span class="n">Writer</span> <span class="p">=</span> <span class="n">tempWriter</span><span class="p">;</span>
    <span class="kt">var</span> <span class="n">content</span> <span class="p">=</span> <span class="n">contentAreaItem</span><span class="p">.</span><span class="nf">GetContent</span><span class="p">(</span><span class="n">ContentRepository</span><span class="p">);</span>

    <span class="k">try</span>
    <span class="p">{</span>
        <span class="k">base</span><span class="p">.</span><span class="nf">RenderContentAreaItem</span><span class="p">(</span><span class="n">htmlHelper</span><span class="p">,</span> <span class="n">contentAreaItem</span><span class="p">,</span> <span class="n">templateTag</span><span class="p">,</span> <span class="n">htmlTag</span><span class="p">,</span> <span class="n">cssClass</span><span class="p">);</span>

        <span class="kt">var</span> <span class="n">contentItemContent</span> <span class="p">=</span> <span class="n">tempWriter</span><span class="p">.</span><span class="nf">ToString</span><span class="p">();</span>
        <span class="kt">var</span> <span class="n">shouldRender</span> <span class="p">=</span> <span class="nf">IsInEditMode</span><span class="p">(</span><span class="n">htmlHelper</span><span class="p">);</span>

        <span class="k">if</span> <span class="p">(!</span><span class="n">shouldRender</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="kt">var</span> <span class="n">doc</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">HtmlDocument</span><span class="p">();</span>
            <span class="n">doc</span><span class="p">.</span><span class="nf">Load</span><span class="p">(</span><span class="k">new</span> <span class="nf">StringReader</span><span class="p">(</span><span class="n">contentItemContent</span><span class="p">));</span>
            <span class="kt">var</span> <span class="n">blockContentNode</span> <span class="p">=</span> <span class="n">doc</span><span class="p">.</span><span class="n">DocumentNode</span><span class="p">.</span><span class="n">ChildNodes</span><span class="p">.</span><span class="nf">FirstOrDefault</span><span class="p">();</span>

            <span class="k">if</span> <span class="p">(</span><span class="n">blockContentNode</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="n">shouldRender</span> <span class="p">=</span> <span class="p">!</span><span class="kt">string</span><span class="p">.</span><span class="nf">IsNullOrEmpty</span><span class="p">(</span><span class="n">blockContentNode</span><span class="p">.</span><span class="n">InnerHtml</span><span class="p">);</span>
                <span class="k">if</span> <span class="p">(!</span><span class="n">shouldRender</span><span class="p">)</span>
                <span class="p">{</span>
                    <span class="c1">// ReSharper disable once SuspiciousTypeConversion.Global</span>
                    <span class="kt">var</span> <span class="n">visibilityControlledContent</span> <span class="p">=</span> <span class="n">content</span> <span class="k">as</span> <span class="n">IControlVisibility</span><span class="p">;</span>
                    <span class="n">shouldRender</span> <span class="p">=</span> <span class="p">(</span><span class="n">visibilityControlledContent</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
                                    <span class="p">||</span> <span class="p">(!</span><span class="n">visibilityControlledContent</span><span class="p">.</span><span class="n">HideIfEmpty</span><span class="p">);</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span>

        <span class="k">if</span> <span class="p">(</span><span class="n">shouldRender</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">originalWriter</span><span class="p">.</span><span class="nf">Write</span><span class="p">(</span><span class="n">contentItemContent</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">finally</span>
    <span class="p">{</span>
        <span class="c1">// restore original writer to proceed further with rendering pipeline</span>
        <span class="n">htmlHelper</span><span class="p">.</span><span class="n">ViewContext</span><span class="p">.</span><span class="n">Writer</span> <span class="p">=</span> <span class="n">originalWriter</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You can grab it on <a href="http://nuget.episerver.com/en/OtherPages/Package/?packageId=EPiBootstrapArea">EPiServer NuGet</a>.</p>

<p>Happy coding!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[This blog posts describes some new features added to latest EPiBootstrapArea plugin library.]]></summary></entry><entry><title type="html">Pragmatic problem solving – Answer to the EPiServer forum question</title><link href="https://tech-fellow.eu/2014/04/04/pragmatic-problem-solving-answer-to-the-episerver-forum-question/" rel="alternate" type="text/html" title="Pragmatic problem solving – Answer to the EPiServer forum question" /><published>2014-04-04T00:25:00+03:00</published><updated>2014-04-04T00:25:00+03:00</updated><id>https://tech-fellow.eu/2014/04/04/pragmatic-problem-solving-answer-to-the-episerver-forum-question</id><content type="html" xml:base="https://tech-fellow.eu/2014/04/04/pragmatic-problem-solving-answer-to-the-episerver-forum-question/"><![CDATA[<p>At some point I was questioned about how I’m learning and finding the answers.
Generally for the learning process a huge inspiration came from “Pragmatic Thinking and Learning: Refactor Your Wetware” by Andy Hunt.</p>

<p><img src="/assets/img/2014/04/ahptl.jpg" alt="" /></p>

<blockquote>
  <p>Software development happens in your head. Not in an editor, IDE, or design tool. You’re well educated on how to work with software and hardware, but what about wetware—our own brains? Learning new skills and new technology is critical to your career, and it’s all in your head.</p>
</blockquote>

<h2 id="walk-through-learning-and-research">Walk-through learning and research</h2>
<p>I want you to walk with me through my learning and research process and activities while answering to one of interesting questions on <a href="http://stackoverflow.com/questions/18640042/structuremap-exception-code-202-when-opening-visitor-group-tab-within-episerver">stackoverflow.com</a>.
Question essentially is pretty interesting in its own nature. It was asked at the beginning of 2013 September. Question was still hanging around up till 2014 April with no answer to it. Either it was too hard (which I don’t believe was the case) or it just flushed away together with other stuff that is screaming for our attention (read – spam).
Anyway: discovery process for the answer was thrilled enough to pick it up for adding more details to it.</p>

<h2 id="original-question">Original question</h2>
<p>Original question was about <code class="language-plaintext highlighter-rouge">VisitorGroups</code> and custom criteria for them.
xlevel asked on SO: <em>”I’ve created a visitor group and I’m trying to inject a class into it.I have the class all wired up and running fine in the site where I am injecting it into a block.”</em></p>

<p>Author also provided some hints on idea he had behind the error: <em>”I suspect the issue is that the Modules area have their own <code class="language-plaintext highlighter-rouge">StructureMap Container</code>. Is this the case? And if so, how is the best way to make sure your mappings are carried through?”</em></p>

<h2 id="finding-the-answer">Finding the answer</h2>
<h3 id="verification">Verification</h3>
<p>My first rule on find the answer is to verify existing theorems. So I should verify idea that author gave in order to understand is this the real situation or just a wild guess. Theory is:  dependency container <strong>is not shared</strong> between <em>ordinary</em> CMS parts (blocks, pages, etc) and <em>module</em> – like VisitorGroup section in CMS.</p>

<p>First thing that I needed to find is a way how EPiServer is creating a controller for visitor groups because original exception is located somewhere deep in dark corridors of EPiServer Framework platform code:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="err">…</span>
<span class="p">[</span><span class="n">ActivationException</span><span class="p">:</span> <span class="n">Activation</span> <span class="n">error</span> <span class="n">occurred</span> <span class="k">while</span> <span class="n">trying</span> <span class="n">to</span> <span class="k">get</span> <span class="n">instance</span> <span class="n">of</span> <span class="n">type</span> <span class="n">VisitorGroupsController</span><span class="p">,</span> <span class="n">key</span> <span class="err">“”</span><span class="p">]</span>
<span class="n">EPiServer</span><span class="p">.</span><span class="n">ServiceLocation</span><span class="p">.</span><span class="n">ServiceLocatorImplBase</span><span class="p">.</span><span class="nf">GetInstance</span><span class="p">(</span><span class="n">Type</span> <span class="n">serviceType</span><span class="p">,</span> <span class="n">String</span> <span class="n">key</span><span class="p">)</span> <span class="p">+</span><span class="m">156</span>
 <span class="n">EPiServer</span><span class="p">.</span><span class="n">Shell</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">Mvc</span><span class="p">.</span><span class="n">ModuleControllerFactory</span><span class="p">.</span><span class="nf">CreateController</span><span class="p">(</span><span class="n">RequestContext</span> <span class="n">requestContext</span><span class="p">,</span> <span class="n">String</span> <span class="n">controllerName</span><span class="p">)</span> <span class="p">+</span><span class="m">351</span>
 <span class="n">EPiServer</span><span class="p">.</span><span class="n">Shell</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">Mvc</span><span class="p">.</span><span class="n">ModuleMvcHandler</span><span class="p">.</span><span class="nf">ProcessRequestInit</span><span class="p">(</span><span class="n">HttpContextBase</span> <span class="n">httpContext</span><span class="p">)</span> <span class="p">+</span><span class="m">105</span>
 <span class="n">EPiServer</span><span class="p">.</span><span class="n">Shell</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">Mvc</span><span class="p">.</span><span class="n">ModuleMvcHandler</span><span class="p">.</span><span class="nf">BeginProcessRequest</span><span class="p">(</span><span class="n">HttpContextBase</span> <span class="n">httpContext</span><span class="p">,</span> <span class="n">AsyncCallback</span> <span class="n">callback</span><span class="p">,</span> <span class="n">Object</span> <span class="n">state</span><span class="p">)</span> <span class="p">+</span><span class="m">17</span>
 <span class="n">System</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">CallHandlerExecutionStep</span><span class="p">.</span><span class="n">System</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">HttpApplication</span><span class="p">.</span><span class="n">IExecutionStep</span><span class="p">.</span><span class="nf">Execute</span><span class="p">()</span> <span class="p">+</span><span class="m">12272575</span>
 <span class="n">System</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">HttpApplication</span><span class="p">.</span><span class="nf">ExecuteStep</span><span class="p">(</span><span class="n">IExecutionStep</span> <span class="n">step</span><span class="p">,</span> <span class="n">Boolean</span><span class="p">&amp;</span> <span class="n">completedSynchronously</span><span class="p">)</span> <span class="p">+</span><span class="m">288</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>From exception stacktrace it’s obvious that we need to trace down how <code class="language-plaintext highlighter-rouge">VisitorGroupsController</code> is constructed via <code class="language-plaintext highlighter-rouge">ModuleControllerFactory</code>.
Let’s sneak peek in EPiServer source code for evidence:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="n">IController</span> <span class="nf">CreateController</span><span class="p">(</span><span class="n">RequestContext</span> <span class="n">requestContext</span><span class="p">,</span> <span class="kt">string</span> <span class="n">controllerName</span><span class="p">)</span>
<span class="p">{</span>
    <span class="err">…</span>
    <span class="n">IController</span> <span class="n">controller</span> <span class="p">=</span> <span class="k">this</span><span class="p">.</span><span class="n">_serviceLocator</span><span class="p">.</span><span class="nf">GetInstance</span><span class="p">(</span><span class="n">serviceType</span><span class="p">)</span> <span class="k">as</span> <span class="n">IController</span><span class="p">;</span>
    <span class="err">…</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Service locator is given as dependency while constructing a type (constructor dependency injection):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="nf">ModuleControllerFactory</span><span class="p">(</span><span class="n">IServiceLocator</span> <span class="n">serviceLocator</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">this</span><span class="p">.</span><span class="n">_serviceLocator</span> <span class="p">=</span> <span class="n">serviceLocator</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Next I need to check how exactly <code class="language-plaintext highlighter-rouge">ModuleControllerFactory</code> is constructed (most probably via some automatic type creation – but just to verify).
Using cool Visual Studio features you are able to find any reference to this type. I found one in <code class="language-plaintext highlighter-rouge">ShellInitialization</code> module that is responsible for various type initialization routine and setup. during app startup. And found our type in interest:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureContainer</span><span class="p">(</span><span class="n">ServiceConfigurationContext</span> <span class="n">context</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">context</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="nf">Configure</span><span class="p">((</span><span class="n">Action</span><span class="p">)</span> <span class="p">(</span><span class="n">ce</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">ce</span><span class="p">.</span><span class="n">For</span><span class="p">&lt;</span><span class="n">ModuleTable</span><span class="p">&gt;().</span><span class="nf">Singleton</span><span class="p">();</span>
        <span class="n">ce</span><span class="p">.</span><span class="n">For</span><span class="p">&lt;</span><span class="n">IModuleControllerFactory</span><span class="p">&gt;().</span><span class="n">Use</span><span class="p">&lt;</span><span class="n">ModuleControllerFactory</span><span class="p">&gt;();</span>
        <span class="err">…</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As <code class="language-plaintext highlighter-rouge">Shell</code> is initialized via <code class="language-plaintext highlighter-rouge">InitializableModule</code> infrastructure and IoC container is configured in the same way as other modules are (even custom) this rejects idea that dependency container is not shared across various parts of the EPiServer CMS platform.</p>

<h3 id="lets-look-at-origin">Let’s look at origin</h3>
<p>Next thing in search and finding answer is to return to origin of the issue – in this case back to exception that is thrown and guy who is causing the exception.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>StructureMap Exception Code: 202
 No Default Instance defined for PluginFamily EPiServer.ServiceLocation.ServiceAccessor`1[[EPiServer.Templates.Alloy.Business.Initialization.IMemberFactory, EPiServer.Templates.Alloy.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], EPiServer.Framework, Version=7.5.1003.0, Culture=neutral, PublicKeyToken=8fe83dea738b45b7
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is <em>really</em> something wrong with IoC container and registered types there.
Let’s return to our guy who is causing the error:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">VisitorGroupCriterion</span><span class="p">(</span><span class="n">Category</span> <span class="p">=</span> <span class="err">“</span><span class="n">Custom</span> <span class="n">Criterion</span><span class="err">”</span><span class="p">,</span>
<span class="n">DisplayName</span> <span class="p">=</span> <span class="err">“</span><span class="n">IsMemberCriterion</span><span class="err">”</span><span class="p">,</span>
<span class="n">Description</span> <span class="p">=</span> <span class="err">“</span><span class="n">IsMemberCriterion</span><span class="err">”</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">IsMemberCriterion</span> <span class="p">:</span> <span class="n">CriterionBase</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="n">Injected</span> <span class="n">MemberFactory</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

    <span class="k">public</span> <span class="k">override</span> <span class="kt">bool</span> <span class="nf">IsMatch</span><span class="p">(</span><span class="n">IPrincipal</span> <span class="n">principal</span><span class="p">,</span> <span class="n">HttpContextBase</span> <span class="n">httpContext</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">MemberFactory</span><span class="p">.</span><span class="n">Service</span><span class="p">.</span><span class="nf">Match</span><span class="p">(</span><span class="n">httpContext</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>One of the trick would be to refactor injection from <code class="language-plaintext highlighter-rouge">Injected</code> to constructor injection:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="nf">IsMemberCriterion</span><span class="p">(</span><span class="n">IMemberFactory</span> <span class="n">factory</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">_factory</span> <span class="p">=</span> <span class="n">factory</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is cool except that EPiServer VisitorGroup controller does not like this while constructing UI section and trying to create criterion instances:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="rouge-code"><pre> <span class="p">[</span><span class="n">MissingMethodException</span><span class="p">]:</span> <span class="n">No</span> <span class="n">parameterless</span> <span class="n">constructor</span> <span class="n">defined</span> <span class="k">for</span> <span class="k">this</span> <span class="kt">object</span><span class="p">.</span>
 <span class="n">at</span> <span class="n">System</span><span class="p">.</span><span class="n">RuntimeTypeHandle</span><span class="p">.</span><span class="nf">CreateInstance</span><span class="p">(</span><span class="n">RuntimeType</span> <span class="n">type</span><span class="p">,</span> <span class="n">Boolean</span> <span class="n">publicOnly</span><span class="p">,</span> <span class="n">Boolean</span> <span class="n">noCheck</span><span class="p">,</span> <span class="n">Boolean</span><span class="p">&amp;</span> <span class="n">canBeCached</span><span class="p">,</span> <span class="n">RuntimeMethodHandleInternal</span><span class="p">&amp;</span> <span class="n">ctor</span><span class="p">,</span> <span class="n">Boolean</span><span class="p">&amp;</span> <span class="n">bNeedSecurityCheck</span><span class="p">)</span>
 <span class="n">at</span> <span class="n">System</span><span class="p">.</span><span class="n">RuntimeType</span><span class="p">.</span><span class="nf">CreateInstanceSlow</span><span class="p">(</span><span class="n">Boolean</span> <span class="n">publicOnly</span><span class="p">,</span> <span class="n">Boolean</span> <span class="n">skipCheckThis</span><span class="p">,</span> <span class="n">Boolean</span> <span class="n">fillCache</span><span class="p">,</span> <span class="n">StackCrawlMark</span><span class="p">&amp;</span> <span class="n">stackMark</span><span class="p">)</span>
 <span class="n">at</span> <span class="n">System</span><span class="p">.</span><span class="n">RuntimeType</span><span class="p">.</span><span class="nf">CreateInstanceDefaultCtor</span><span class="p">(</span><span class="n">Boolean</span> <span class="n">publicOnly</span><span class="p">,</span> <span class="n">Boolean</span> <span class="n">skipCheckThis</span><span class="p">,</span> <span class="n">Boolean</span> <span class="n">fillCache</span><span class="p">,</span> <span class="n">StackCrawlMark</span><span class="p">&amp;</span> <span class="n">stackMark</span><span class="p">)</span>
 <span class="n">at</span> <span class="n">System</span><span class="p">.</span><span class="n">Activator</span><span class="p">.</span><span class="nf">CreateInstance</span><span class="p">(</span><span class="n">Type</span> <span class="n">type</span><span class="p">,</span> <span class="n">Boolean</span> <span class="n">nonPublic</span><span class="p">)</span>
 <span class="n">at</span> <span class="n">System</span><span class="p">.</span><span class="n">Activator</span><span class="p">.</span><span class="nf">CreateInstance</span><span class="p">(</span><span class="n">Type</span> <span class="n">type</span><span class="p">)</span>
 <span class="n">at</span> <span class="n">EPiServer</span><span class="p">.</span><span class="n">Cms</span><span class="p">.</span><span class="n">Shell</span><span class="p">.</span><span class="n">UI</span><span class="p">.</span><span class="n">Controllers</span><span class="p">.</span><span class="n">VisitorGroupsController</span><span class="p">.</span><span class="nf">CriteriaUI</span><span class="p">(</span><span class="n">String</span> <span class="n">typeName</span><span class="p">)</span>
 <span class="n">at</span> <span class="nf">lambda_method</span><span class="p">(</span><span class="n">Closure</span> <span class="p">,</span> <span class="n">ControllerBase</span> <span class="p">,</span> <span class="n">Object</span><span class="p">[]</span> <span class="p">)</span>
 <span class="n">at</span> <span class="n">System</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">Mvc</span><span class="p">.</span><span class="n">ReflectedActionDescriptor</span><span class="p">.</span><span class="nf">Execute</span><span class="p">(</span><span class="n">ControllerContext</span> <span class="n">controllerContext</span><span class="p">,</span> <span class="n">IDictionary</span><span class="err">`</span><span class="m">2</span> <span class="n">parameters</span><span class="p">)</span>
 <span class="n">at</span> <span class="n">System</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">Mvc</span><span class="p">.</span><span class="n">ControllerActionInvoker</span><span class="p">.</span><span class="nf">InvokeActionMethod</span><span class="p">(</span><span class="n">ControllerContext</span> <span class="n">controllerContext</span><span class="p">,</span> <span class="n">ActionDescriptor</span> <span class="n">actionDescriptor</span><span class="p">,</span> <span class="n">IDictionary</span><span class="err">`</span><span class="m">2</span> <span class="n">parameters</span><span class="p">)</span>
 <span class="n">at</span> <span class="n">System</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">Mvc</span><span class="p">.</span><span class="n">ControllerActionInvoker</span><span class="p">.&lt;&gt;</span><span class="n">c__DisplayClass13</span><span class="p">.</span><span class="nf">b__10</span><span class="p">()</span>
 <span class="n">at</span> <span class="n">System</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">Mvc</span><span class="p">.</span><span class="n">ControllerActionInvoker</span><span class="p">.</span><span class="nf">InvokeActionMethodFilter</span><span class="p">(</span><span class="n">IActionFilter</span> <span class="n">filter</span><span class="p">,</span> <span class="n">ActionExecutingContext</span> <span class="n">preContext</span><span class="p">,</span> <span class="n">Func</span><span class="err">`</span><span class="m">1</span> <span class="n">continuation</span><span class="p">)</span>
 <span class="n">at</span> <span class="n">System</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">Mvc</span><span class="p">.</span><span class="n">ControllerActionInvoker</span><span class="p">.</span><span class="nf">InvokeActionMethodFilter</span><span class="p">(</span><span class="n">IActionFilter</span> <span class="n">filter</span><span class="p">,</span> <span class="n">ActionExecutingContext</span> <span class="n">preContext</span><span class="p">,</span> <span class="n">Func</span><span class="err">`</span><span class="m">1</span> <span class="n">continuation</span><span class="p">)</span>
 <span class="n">at</span> <span class="n">System</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">Mvc</span><span class="p">.</span><span class="n">ControllerActionInvoker</span><span class="p">.</span><span class="nf">InvokeActionMethodWithFilters</span><span class="p">(</span><span class="n">ControllerContext</span> <span class="n">controllerContext</span><span class="p">,</span> <span class="n">IList</span><span class="err">`</span><span class="m">1</span> <span class="n">filters</span><span class="p">,</span> <span class="n">ActionDescriptor</span> <span class="n">actionDescriptor</span><span class="p">,</span> <span class="n">IDictionary</span><span class="err">`</span><span class="m">2</span> <span class="n">parameters</span><span class="p">)</span>
 <span class="n">at</span> <span class="n">System</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">Mvc</span><span class="p">.</span><span class="n">ControllerActionInvoker</span><span class="p">.</span><span class="nf">InvokeAction</span><span class="p">(</span><span class="n">ControllerContext</span> <span class="n">controllerContext</span><span class="p">,</span> <span class="n">String</span> <span class="n">actionName</span><span class="p">)</span>
 <span class="n">at</span> <span class="n">System</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">Mvc</span><span class="p">.</span><span class="n">Controller</span><span class="p">.</span><span class="nf">ExecuteCore</span><span class="p">()</span>
 <span class="n">at</span> <span class="n">System</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">Mvc</span><span class="p">.</span><span class="n">ControllerBase</span><span class="p">.</span><span class="nf">Execute</span><span class="p">(</span><span class="n">RequestContext</span> <span class="n">requestContext</span><span class="p">)</span>
 <span class="n">at</span> <span class="n">EPiServer</span><span class="p">.</span><span class="n">Shell</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">Mvc</span><span class="p">.</span><span class="n">ModuleMvcHandler</span><span class="p">.</span><span class="nf">ProcessController</span><span class="p">(</span><span class="n">IController</span> <span class="n">controller</span><span class="p">)</span>
 <span class="n">at</span> <span class="n">EPiServer</span><span class="p">.</span><span class="n">Shell</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">Mvc</span><span class="p">.</span><span class="n">ModuleMvcHandler</span><span class="p">.</span><span class="nf">BeginProcessRequest</span><span class="p">(</span><span class="n">HttpContextBase</span> <span class="n">httpContext</span><span class="p">,</span> <span class="n">AsyncCallback</span> <span class="n">callback</span><span class="p">,</span> <span class="n">Object</span> <span class="n">state</span><span class="p">)</span>
 <span class="n">at</span> <span class="n">System</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">HttpApplication</span><span class="p">.</span><span class="n">CallHandlerExecutionStep</span><span class="p">.</span><span class="n">System</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">HttpApplication</span><span class="p">.</span><span class="n">IExecutionStep</span><span class="p">.</span><span class="nf">Execute</span><span class="p">()</span>
 <span class="n">at</span> <span class="n">System</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">HttpApplication</span><span class="p">.</span><span class="nf">ExecuteStep</span><span class="p">(</span><span class="n">IExecutionStep</span> <span class="n">step</span><span class="p">,</span> <span class="n">Boolean</span><span class="p">&amp;</span> <span class="n">completedSynchronously</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>There is another workaround to this problem – let’s define parameter-less constructor and get instance of required type manually:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">IsMemberCriterion</span> <span class="p">:</span> <span class="n">CriterionBase</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IMemberFactory</span> <span class="n">_factory</span><span class="p">;</span>

<span class="k">public</span> <span class="nf">IsMemberCriterion</span><span class="p">()</span> <span class="p">:</span> <span class="k">this</span><span class="p">(</span><span class="n">ServiceLocator</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">IMemberFactory</span><span class="p">&gt;())</span>
<span class="p">{</span>
<span class="p">}</span>

<span class="k">public</span> <span class="nf">IsMemberCriterion</span><span class="p">(</span><span class="n">IMemberFactory</span> <span class="n">factory</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">_factory</span> <span class="p">=</span> <span class="n">factory</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This works and now everybody is happy: <code class="language-plaintext highlighter-rouge">IMemberFactory</code> is injected from IoC container, controller is able to create new criterion instance. Maybe everybody is satisfied except me – for me this really seems more like workaround and not proper solution. So let’s keep digging..</p>

<h3 id="finding-the-solution">Finding the Solution</h3>
<p>According to pragmatic learning theory – you have to be present in surroundings of the issue and imagine where the problem could be originating from.
What didn’t left me was an idea that original problem is in the definition line of <code class="language-plaintext highlighter-rouge">Injected</code>. I’ve seen a lot of these style of injection in EPiServer source code and also in our own code.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="n">Injected</span> <span class="n">MemberFactory</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Looking at source code of <code class="language-plaintext highlighter-rouge">Injected</code> we can see that somebody will have to provide <code class="language-plaintext highlighter-rouge">ServiceAccessor</code> type while constructing instance of injected property. <code class="language-plaintext highlighter-rouge">ServiceAccessor</code> is just an ordinary .Net delegate.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">delegate</span> <span class="n">TService</span> <span class="nf">ServiceAccessor</span><span class="p">();</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Next thing what we can do is to try find how <code class="language-plaintext highlighter-rouge">ServiceAccessor</code> is used across EPiServer libraries and other various modules. Again using some cool Visual Studio features like <code class="language-plaintext highlighter-rouge">Find All References</code> you can easily spot usages of the type. For the <code class="language-plaintext highlighter-rouge">ServiceAccessor</code> there are zillions of various usages but one interesting usage just popup. It was located in EPiServer.Framework assembly:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="p">...</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">FrameworkInitialization</span> <span class="p">:</span> <span class="n">IConfigurableModule</span><span class="p">,</span> <span class="p">...</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureContainer</span><span class="p">(</span><span class="n">ServiceConfigurationContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">context</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="nf">Configure</span><span class="p">(</span><span class="n">ce</span> <span class="p">=&gt;</span>
            <span class="n">ce</span><span class="p">.</span><span class="n">For</span><span class="p">&lt;</span><span class="n">ServiceAccessor</span><span class="p">&lt;</span><span class="n">HttpContextBase</span><span class="p">&gt;&gt;()</span>
              <span class="p">.</span><span class="nf">Use</span><span class="p">((</span><span class="n">ServiceAccessor</span><span class="p">&lt;</span><span class="n">HttpContextBase</span><span class="p">&gt;)(()</span> <span class="p">=&gt;</span> <span class="p">...)));</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This fragment <code class="language-plaintext highlighter-rouge">ce.For&lt;ServiceAccessor&lt;HttpContextBase&gt;&gt;</code> definitely approves that somebody is really registering service accessors for various types.
The next usage of <code class="language-plaintext highlighter-rouge">ServiceAccessor</code> finally gave me more insight of what’s really going on under the hood. That was <code class="language-plaintext highlighter-rouge">ServiceContainerInitialization</code> module.</p>

<p>I landed on small internal class:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">ServiceAccessorFactory</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>That is responsible for providing factory style methods for creating new <code class="language-plaintext highlighter-rouge">ServiceAccessor</code>s.
Few steps up on usage and calling chain I ended in method <code class="language-plaintext highlighter-rouge">public void Process(Type type, Registry registry)</code> that takes care of service registration into the IoC container.
Method is asking for a list of types that are decorated with something that is implementing <code class="language-plaintext highlighter-rouge">IServiceConfiguration</code> interface.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="k">foreach</span> <span class="p">(</span><span class="n">IServiceConfiguration</span> <span class="n">attribute</span> <span class="k">in</span> <span class="n">type</span><span class="p">.</span><span class="nf">GetCustomAttributes</span><span class="p">(</span><span class="k">typeof</span> <span class="p">(</span><span class="n">IServiceConfiguration</span><span class="p">),</span> <span class="k">true</span><span class="p">))</span>
<span class="p">{</span>
    <span class="err">…</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="formulating-the-answer">Formulating the answer</h3>
<p>Next step in research process naturally is structuring my findings and formulating the answer to the original question.
And here goes what I understood: <em>”If you decorate something with attribute that is implementing <code class="language-plaintext highlighter-rouge">IServiceConfiguration</code> then somebody else takes care of that and registers service accessor in IoC container for this class according to specified life-cycle and creation settings.”</em>.</p>

<p>So in order to get your custom class as target for <code class="language-plaintext highlighter-rouge">Injected</code> you have to tell EPiServer how that <code class="language-plaintext highlighter-rouge">Type</code> should be constructed, for how long it should live and maybe other infrastructure level information in order to instantiate that accordingly. The final solution to the problem is following code snippet:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre> [ServiceConfiguration(Lifecycle = ServiceInstanceScope.Unique, ServiceType = typeof(IMemberFactory))]
 public class MemberFactory : IMemberFactory
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As it turned out the solution was pretty simple and easy but the way to get to the solution wasn’t so straight..</p>

<p>Happy coding!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[At some point I was questioned about how I’m learning and finding the answers. Generally for the learning process a huge inspiration came from “Pragmatic Thinking and Learning: Refactor Your Wetware” by Andy Hunt.]]></summary></entry><entry><title type="html">FeatureSwitch library 1.0 – Released!</title><link href="https://tech-fellow.eu/2014/03/28/featureswitch-library-1-0-released/" rel="alternate" type="text/html" title="FeatureSwitch library 1.0 – Released!" /><published>2014-03-28T23:40:00+02:00</published><updated>2014-03-28T23:40:00+02:00</updated><id>https://tech-fellow.eu/2014/03/28/featureswitch-library-1-0-released</id><content type="html" xml:base="https://tech-fellow.eu/2014/03/28/featureswitch-library-1-0-released/"><![CDATA[<p>Have you ever wrote the code like following to verify that either you have to disable or enable some functionality base on set of conditions (usually different sources):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">if</span><span class="p">(</span><span class="n">ConfigurationManager</span><span class="p">.</span><span class="n">AppSettings</span><span class="p">[</span><span class="s">"MyKey"</span><span class="p">]</span> <span class="p">==</span> <span class="s">"true"</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// feature is enabled - do something</span>
    <span class="p">...;</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="c1">// feature is disabled - do something</span>
    <span class="p">...;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>or something like this:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">if</span><span class="p">(</span><span class="n">HttpContext</span><span class="p">.</span><span class="n">Current</span> <span class="p">!=</span> <span class="k">null</span>
   <span class="p">&amp;&amp;</span> <span class="n">HttpContext</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">Session</span> <span class="p">!=</span> <span class="k">null</span>
   <span class="p">&amp;&amp;</span> <span class="n">HttpContext</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">Session</span><span class="p">[</span><span class="s">"MyKey"</span><span class="p">]</span> <span class="p">==</span> <span class="s">"true"</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="p">...;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">FeatureSwitch</code> library should reduce amount of time and code needed to implement feature toggle in unified way. <code class="language-plaintext highlighter-rouge">FeatureSwitch</code> library is easily adoptable and extendable.</p>

<h2 id="overview">Overview</h2>

<p><code class="language-plaintext highlighter-rouge">FeatureSwitch</code> library is based on two basic aspects <a href="https://github.com/valdisiljuconoks/FeatureSwitch/wiki#features">features</a> and <a href="https://github.com/valdisiljuconoks/FeatureSwitch/wiki#strategies">strategies</a>. In combination they provide enough input data for feature set builder to construct feature context to be used later to check whether particular feature is enabled or disabled.
There are few integration and helper libraries as well around <code class="language-plaintext highlighter-rouge">FeatureSwitch</code> core lib:</p>

<ul>
  <li><a href="https://github.com/valdisiljuconoks/FeatureSwitch/wiki/Asp.Net-MVC-Integration">Mvc Control Panel</a> – <code class="language-plaintext highlighter-rouge">FeatureSwitch</code> control panel where you can visually see state of the each feature and change it</li>
  <li><a href="https://github.com/valdisiljuconoks/FeatureSwitch/wiki/Web-Optimization-Helpers">Web Optimization</a> – Helpers for styles and scripts conditional bundling and minification</li>
  <li><a href="https://github.com/valdisiljuconoks/FeatureSwitch/wiki/EPiServer-Integration">EPiServer integration</a> – Module to integrate into EPiServer CMS platform for easier access to UI Control Panel</li>
</ul>

<h2 id="where-do-i-get-packages">Where do I get packages?</h2>

<p>All packages are available on NuGet feeds:</p>

<ul>
  <li><a href="https://www.nuget.org/packages/FeatureSwitch/">Core library</a></li>
  <li><a href="https://www.nuget.org/packages/FeatureSwitch.AspNet.Mvc/">Asp.Net Mvc Integration</a></li>
  <li><a href="https://www.nuget.org/packages/FeatureSwitch.AspNet.Mvc5/">Asp.Net Mvc 5 Integration / Owin</a></li>
  <li><a href="https://www.nuget.org/packages/FeatureSwitch.Web.Optimization/">Web Optimization pack</a></li>
  <li><a href="http://nuget.episerver.com/en/OtherPages/Package/?packageId=FeatureSwitch.EPiServer">EPiServer integration</a></li>
</ul>

<h2 id="features">Features</h2>

<p>Feature is main aspect of <code class="language-plaintext highlighter-rouge">FeatureSwitch</code> library it’s your logical feature representation – either it’s enabled or disabled. You will need to define your features to work with <code class="language-plaintext highlighter-rouge">FeatureSwitch</code> library.</p>

<p>To define your feature you have to create class that inherits from <code class="language-plaintext highlighter-rouge">FeatureSwitch.BaseFeature</code> class:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">MySampleFeature</span> <span class="p">:</span> <span class="n">FeatureSwitch</span><span class="p">.</span><span class="n">BaseFeature</span>
<span class="p">{</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Keep in mind that you will need to add at least one strategy for the feature in order to enable it.</p>

<p>By default every feature is <strong>disabled</strong>!</p>

<h2 id="setup-featureset-builder">Setup (FeatureSet builder)</h2>

<p>To get started with <code class="language-plaintext highlighter-rouge">FeatureSwitch</code> you need to kick-off <a href="https://github.com/valdisiljuconoks/FeatureSwitch/blob/master/FeatureSwitch/FeatureSetBuilder.cs"><code class="language-plaintext highlighter-rouge">FeatureSetBuilder</code></a> by calling <code class="language-plaintext highlighter-rouge">Build()</code> instance method:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">FeatureSetBuilder</span><span class="p">();</span>
<span class="n">builder</span><span class="p">.</span><span class="nf">Build</span><span class="p">();</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>By calling <code class="language-plaintext highlighter-rouge">Build()</code> method you are triggering auto-discovery of features in current application domain loaded assemblies. Auto-discovery will look for classes inheriting from <code class="language-plaintext highlighter-rouge">FeatureSwitch.BaseFeature</code> class. Those are assumed to be features.</p>

<h2 id="check-if-feature-is-enabled">Check if feature is enabled?</h2>

<p>After features have been discovered and set has been built you are able to check whether feature is enabled or not:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">isEnabled</span> <span class="p">=</span> <span class="n">FeatureContext</span><span class="p">.</span><span class="nf">IsEnabled</span><span class="p">();</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You can also use some of the <code class="language-plaintext highlighter-rouge">IsEnabled</code> overloads for other usages.</p>

<h2 id="strategies">Strategies</h2>

<p>Whereas strategies are aspect in the library that is controlling either feature is enabled or disabled in the current circumstances. Strategy is an attribute you decorate your feature with:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="n">FeatureSwitch</span><span class="p">.</span><span class="n">Strategies</span><span class="p">.</span><span class="nf">AppSettings</span><span class="p">(</span><span class="n">Key</span> <span class="p">=</span> <span class="s">"MySampleFeatureKey"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">MySampleFeature</span> <span class="p">:</span> <span class="n">BaseFeature</span>
<span class="p">{</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Currently FeatureSwitch release contains following built-in strategies:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">AlwaysFalse</code> – by using this strategy your feature will be always disabled</li>
  <li><code class="language-plaintext highlighter-rouge">AlwaysTrue</code> – this strategy will always make your feature shine</li>
  <li><code class="language-plaintext highlighter-rouge">AppSettings</code> – key under <code class="language-plaintext highlighter-rouge">&lt;appSettings&gt;</code> element either in <code class="language-plaintext highlighter-rouge">web.config</code> or <code class="language-plaintext highlighter-rouge">app.config</code> will control this feature state</li>
  <li><code class="language-plaintext highlighter-rouge">HttpSession</code> – if you need more permanent storage for your feature’s state you can make use of Http session</li>
  <li><code class="language-plaintext highlighter-rouge">QueryString</code> – if you will provide magic key in query string, feature may enable or disable.</li>
</ul>

<h3 id="multiple-strategies">Multiple Strategies</h3>

<p>Single feature can support more that one strategy. For instance:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">AppSettings</span><span class="p">(</span><span class="n">Key</span> <span class="p">=</span> <span class="s">"StyleOptimizationDisabled"</span><span class="p">)]</span>
<span class="p">[</span><span class="nf">QueryString</span><span class="p">(</span><span class="n">Key</span> <span class="p">=</span> <span class="s">"DisableStyleOptimization"</span><span class="p">,</span> <span class="n">Order</span> <span class="p">=</span> <span class="m">1</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">StyleOptimizationDisabled</span> <span class="p">:</span> <span class="n">BaseFeature</span>
<span class="p">{</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This feature is controlled by <code class="language-plaintext highlighter-rouge">StyleOptimizationDisabled</code> element key in <code class="language-plaintext highlighter-rouge">web.config</code> file and then also by the query string passed in during request. It means that feature is disabled by <code class="language-plaintext highlighter-rouge">AppSettings</code> strategy but could be enabled by <code class="language-plaintext highlighter-rouge">QueryString</code> strategy (providing proper query string parameter <code class="language-plaintext highlighter-rouge">?DisableStyleOptimization=true</code>) – feature is eventually enabled.</p>

<p>In order to attach multiple strategies to single feature you need to define order for the strategy using <code class="language-plaintext highlighter-rouge">Order</code> property. <code class="language-plaintext highlighter-rouge">FetureSetBuilder</code> will fail if it founds multiple strategies with undefined or equal order.</p>

<p>When feature is asked for enabled state all strategies in ascending order are used to query for feature enabled state. If any of those return <code class="language-plaintext highlighter-rouge">true</code> feature is enabled.</p>

<h3 id="writable-strategies">Writable Strategies</h3>

<p>Sometimes it’s required to store feature enabled state in more permanent storage (session, cache, etc). For this reason you can use any of <code class="language-plaintext highlighter-rouge">FeatureSwitch.Strategies.BaseStrategyImpl</code> implementations.</p>

<p>Currently available writable strategies:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">HttpSession</code> – using this strategy you can enable or disable feature and it will remain in this state as long as session is alive</li>
</ul>

<h2 id="advanced-featureswitch-context-constructions">Advanced FeatureSwitch Context Constructions</h2>

<p>At moment of current release of FeatureSwitch library we do have dependency on <a href="https://www.nuget.org/packages/structuremap/">StructureMap</a> in order to keep track of strategies and dependencies and also to support <a href="http://en.wikipedia.org/wiki/Dependency_injection">constructor injection</a> for custom strategies if needed (this is subject for refactoring).</p>

<p>Using dependency injection you are able to instruct <code class="language-plaintext highlighter-rouge">FeatureSetBuilder</code> how to construct context and which strategies to use and how to initialize them.</p>

<h2 id="disable-auto-discovery">Disable Auto-Discovery</h2>

<p>Sometimes it’s required to disable auto-discovery and use only predefined list of features.
This can be accomplished using <code class="language-plaintext highlighter-rouge">action</code> parameter of <code class="language-plaintext highlighter-rouge">Build()</code> method:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">FeatureSetBuilder</span><span class="p">();</span>
<span class="n">builder</span><span class="p">.</span><span class="nf">Build</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span> <span class="n">ctx</span><span class="p">.</span><span class="n">AddFeature</span><span class="p">&lt;</span><span class="n">MySampleFeature</span><span class="p">&gt;());</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This will add only <code class="language-plaintext highlighter-rouge">MySampleFeature</code> to the context and will not perform auto-discovery of features.</p>

<h2 id="strategy-swap">Strategy Swap</h2>

<p>Let’s assume that for any reason you are required to change / swap built-in strategy with some other implementation. This can be used by using configuration expression while building feature set (<code class="language-plaintext highlighter-rouge">MySampleFeature</code> is configured to use <code class="language-plaintext highlighter-rouge">AppSettings</code> strategy):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">FeatureSetBuilder</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">container</span> <span class="p">=</span> <span class="n">builder</span><span class="p">.</span><span class="nf">Build</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span>
<span class="p">{</span>
    <span class="n">ctx</span><span class="p">.</span><span class="nf">AddFeature</span><span class="p">();</span>
    <span class="n">ctx</span>
      <span class="p">.</span><span class="n">ForStrategy</span><span class="p">&lt;</span><span class="n">AppSettings</span><span class="p">&gt;()</span>
      <span class="p">.</span><span class="n">Use</span><span class="p">&lt;</span><span class="n">SomeFancyStrategyImplementation</span><span class="p">&gt;();</span>
<span class="p">});</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="custom-strategy-with-dependency-injection">Custom Strategy With Dependency Injection</h2>

<p>Let’s assume that we have a fancy strategy that is depended on even more fancier service to work properly:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">StrategyWithConstructorParameterReader</span> <span class="p">:</span> <span class="n">BaseStrategyImpl</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">StrategyWithConstructorParameterReader</span><span class="p">(</span><span class="n">ISampleInjectedInterface</span> <span class="n">sample</span><span class="p">)</span>
    <span class="p">{</span>
<span class="p">...</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So to properly configure dependency composition root we need to configure <code class="language-plaintext highlighter-rouge">FeatureSetBuilder</code> to inject <code class="language-plaintext highlighter-rouge">ISampleInjectedInterface</code> properly.</p>

<p>To do so you can use <code class="language-plaintext highlighter-rouge">dependencyConfiguration</code> parameter of <code class="language-plaintext highlighter-rouge">Build()</code> method:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="n">builder</span><span class="p">.</span><span class="nf">Build</span><span class="p">(</span><span class="n">dependencyConfiguration</span><span class="p">:</span> <span class="n">ex</span> <span class="p">=&gt;</span> <span class="n">ex</span><span class="p">.</span><span class="n">For</span><span class="p">&lt;</span><span class="n">ISampleInjectedInterface</span><span class="p">&gt;().</span><span class="n">Use</span><span class="p">&lt;</span><span class="n">SampleInjectedInterface</span><span class="p">&gt;());</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="more-information">More Information</h2>

<p>More information on <a href="https://github.com/valdisiljuconoks/FeatureSwitch/wiki/Extending-FeatureSwitch-library">extending</a> FeatureSwitch library.</p>

<p>Happy switching the features!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Feature Switch" /><category term=".net" /><category term="c#" /><category term="feature switch" /><summary type="html"><![CDATA[Have you ever wrote the code like following to verify that either you have to disable or enable some functionality base on set of conditions (usually different sources):]]></summary></entry><entry><title type="html">Tiny C# clean-up improves understanding of the code</title><link href="https://tech-fellow.eu/2014/03/28/tiny-c-clean-up-improves-understanding-of-the-code/" rel="alternate" type="text/html" title="Tiny C# clean-up improves understanding of the code" /><published>2014-03-28T23:40:00+02:00</published><updated>2014-03-28T23:40:00+02:00</updated><id>https://tech-fellow.eu/2014/03/28/tiny-c-clean-up-improves-understanding-of-the-code</id><content type="html" xml:base="https://tech-fellow.eu/2014/03/28/tiny-c-clean-up-improves-understanding-of-the-code/"><![CDATA[<p>I’m starting to collect small fragments from everyday life to understand and increase understanding and readability of code I’m coming across.
First piece in this category is gone which I came across while contributing to one of the open source modules.</p>

<p>Original fragment:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="rouge-code"><pre><span class="p">{</span>
    <span class="n">IEnumerable</span> <span class="n">btypes</span> <span class="p">=</span> <span class="nf">GetBlockTypes</span><span class="p">();</span>
    <span class="n">List</span> <span class="n">blockproperties</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">List</span><span class="p">();</span>
    <span class="kt">int</span> <span class="n">x</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span>

    <span class="k">foreach</span> <span class="p">(</span><span class="n">BlockType</span> <span class="n">type</span> <span class="k">in</span> <span class="n">btypes</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">x</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span>

        <span class="k">foreach</span> <span class="p">(</span><span class="n">PropertyDefinition</span> <span class="n">def</span> <span class="k">in</span> <span class="n">type</span><span class="p">.</span><span class="n">PropertyDefinitions</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">x</span><span class="p">++;</span>
            <span class="n">blockproperties</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">new</span> <span class="n">TypePropertyResultItem</span> <span class="p">{</span>
                <span class="n">TypeName</span> <span class="p">=</span> <span class="n">x</span> <span class="p">==</span> <span class="m">1</span> <span class="p">?</span> <span class="n">type</span><span class="p">.</span><span class="n">Name</span> <span class="p">:</span> <span class="s">""</span><span class="p">,</span>
                <span class="n">PropertyName</span> <span class="p">=</span> <span class="n">def</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span>
                <span class="n">Description</span> <span class="p">=</span> <span class="n">def</span><span class="p">.</span><span class="nf">TranslateDescription</span><span class="p">(),</span>
                <span class="n">DisplayName</span> <span class="p">=</span> <span class="n">def</span><span class="p">.</span><span class="nf">TranslateDisplayName</span><span class="p">()</span>
            <span class="p">});</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="n">blockproperties</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Modified code fragment:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="rouge-code"><pre><span class="p">{</span>
    <span class="kt">var</span> <span class="n">types</span> <span class="p">=</span> <span class="nf">GetBlockTypes</span><span class="p">();</span>
    <span class="kt">var</span> <span class="n">blockproperties</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">List</span><span class="p">();</span>

    <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">type</span> <span class="k">in</span> <span class="n">types</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">blockproperties</span><span class="p">.</span><span class="nf">AddRange</span><span class="p">(</span><span class="n">type</span><span class="p">.</span><span class="n">PropertyDefinitions</span><span class="p">.</span><span class="nf">Select</span><span class="p">((</span><span class="n">def</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span> <span class="p">=&gt;</span>
            <span class="k">new</span> <span class="n">TypePropertyResultItem</span>
            <span class="p">{</span>
                <span class="n">TypeName</span> <span class="p">=</span> <span class="n">i</span> <span class="p">==</span> <span class="m">0</span> <span class="p">?</span> <span class="n">type</span><span class="p">.</span><span class="n">Name</span> <span class="p">:</span> <span class="kt">string</span><span class="p">.</span><span class="n">Empty</span><span class="p">,</span>
                <span class="n">PropertyName</span> <span class="p">=</span> <span class="n">def</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span>
                <span class="n">Description</span> <span class="p">=</span> <span class="n">def</span><span class="p">.</span><span class="nf">TranslateDescription</span><span class="p">(),</span>
                <span class="n">DisplayName</span> <span class="p">=</span> <span class="n">def</span><span class="p">.</span><span class="nf">TranslateDisplayName</span><span class="p">()</span>
            <span class="p">}));</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="n">blockproperties</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Happy reading not your code! :)</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term=".net" /><category term="c#" /><summary type="html"><![CDATA[I’m starting to collect small fragments from everyday life to understand and increase understanding and readability of code I’m coming across. First piece in this category is gone which I came across while contributing to one of the open source modules.]]></summary></entry><entry><title type="html">Update to EPiServer Responsive Tables</title><link href="https://tech-fellow.eu/2014/03/16/updated-episerver-responsive-tables/" rel="alternate" type="text/html" title="Update to EPiServer Responsive Tables" /><published>2014-03-16T18:10:00+02:00</published><updated>2014-03-16T18:10:00+02:00</updated><id>https://tech-fellow.eu/2014/03/16/updated-episerver-responsive-tables</id><content type="html" xml:base="https://tech-fellow.eu/2014/03/16/updated-episerver-responsive-tables/"><![CDATA[<p>Initially <a href="https://tech-fellow.ghost.io/2014/03/06/responsive-episerver-tables/">responsive tables plugin</a> was based on pure CSS implementation transposing table from table view into a block stacking cells vertically. Solution based on CSS rules is good enough to reduce markup and style tables based on style sheets. However this approach seems to be not really reliable. For me as back-end developer CSS seems to be one of the most fragile thing on the web – any browser, any device and any device + screen size combination may render your stat-of-art web page unpredictably. The same case came to responsive tables when it comes to render stacked table based on CSS rules on some smaller devices and different browsers.</p>

<p>Therefore we decided to switch from CSS styles to transposed table in hard way – generating new markup for existing table transposing every table cell. Plugin relies on proper table layout and semantic markup. Our solution is heavily based on <a href="http://johnpolacek.github.io/stacktable.js/">stacktable.js by John Polacek</a>.</p>

<h2 id="make-table-responsive">Make table responsive</h2>
<p>As an editor you need to make sure following things are done for your responsive table.</p>

<p>1) Mark your table as <code class="language-plaintext highlighter-rouge">responsive</code>.</p>

<p><img src="/assets/img/2014/03/3.png" alt="" /></p>

<p>2) Define table header (<code class="language-plaintext highlighter-rouge">thead</code>).</p>

<p><img src="/assets/img/2014/03/2.png" alt="" /></p>

<p>3) Define table header cells for appropriate columns.</p>

<p><img src="/assets/img/2014/03/6.PNG" alt="" /></p>

<p>As a developer you need to:</p>

<p>1) Include <code class="language-plaintext highlighter-rouge">responsive-table.js</code> (<a href="https://github.com/Geta/responsive-table/blob/master/responsive-table.js">found here</a>).
2) Include <code class="language-plaintext highlighter-rouge">responsive-table.css</code> (<a href="https://github.com/Geta/responsive-table/blob/master/responsive-table.css">found here</a>).</p>

<p>And any table that is attributed with <code class="language-plaintext highlighter-rouge">responsive</code> class transpose:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nf">$</span><span class="p">(</span><span class="err">‘</span><span class="nx">table</span><span class="p">.</span><span class="nx">responsive</span><span class="err">’</span><span class="p">).</span><span class="nf">stacktable</span><span class="p">();</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="update">Update</h2>
<p>New version of responsive tables now support also a table captions (originally supported by EPiServer tinyMCE editor, but left out from original plugin by John Polacek).</p>

<p><img src="/assets/img/2014/03/7.png" alt="" /></p>

<p><img src="/assets/img/2014/03/8.PNG" alt="" /></p>

<p><img src="/assets/img/2014/03/9.PNG" alt="" /></p>

<h2 id="source-code">Source code</h2>
<p>Source code could be found @ Geta AS <a href="https://github.com/Geta/responsive-table">GitHub</a>.</p>

<p>Happy coding!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[Initially responsive tables plugin was based on pure CSS implementation transposing table from table view into a block stacking cells vertically. Solution based on CSS rules is good enough to reduce markup and style tables based on style sheets. However this approach seems to be not really reliable. For me as back-end developer CSS seems to be one of the most fragile thing on the web – any browser, any device and any device + screen size combination may render your stat-of-art web page unpredictably. The same case came to responsive tables when it comes to render stacked table based on CSS rules on some smaller devices and different browsers.]]></summary></entry><entry><title type="html">ImageResizer.Plugin.EPiServerBlobReader</title><link href="https://tech-fellow.eu/2014/03/16/imageresizer-plugin-episerverblobreader/" rel="alternate" type="text/html" title="ImageResizer.Plugin.EPiServerBlobReader" /><published>2014-03-16T09:15:00+02:00</published><updated>2014-03-16T09:15:00+02:00</updated><id>https://tech-fellow.eu/2014/03/16/imageresizer-plugin-episerverblobreader</id><content type="html" xml:base="https://tech-fellow.eu/2014/03/16/imageresizer-plugin-episerverblobreader/"><![CDATA[<p><code class="language-plaintext highlighter-rouge">ImageResizer</code> is one of top choice library when it comes to optimizing media assets in web context. EPiServer 7.5 introduced really cool feature <a href="http://world.episerver.com/Documentation/Items/Developers-Guide/EPiServer-CMS/75/Content/Assets-and-media/Assets-and-media/">Asset and media</a>.</p>

<p>You need to thank and follow Martin Pickering <a href="http://world.episerver.com/Code/Martin-Pickering/ImageResizingNet-integration-for-CMS75/">hard work</a> to get both of these worlds working together which involves a bit of hacking here and there.</p>

<p>Recently I got sick of repeating these steps from project to project and came up with a <a href="http://nuget.episerver.com/en/OtherPages/Package/?packageId=ImageResizer.Plugins.EPiServerBlobReader">package of NuGet</a>.</p>

<p>Package gently modifies your web.config file in order to add new plugin to the list of <a href="http://imageresizing.net/plugins">ImageResizer plugins</a>.</p>

<h2 id="source-source">Source Source</h2>

<p>Source code is available either <a href="http://world.episerver.com/Code/Martin-Pickering/ImageResizingNet-integration-for-CMS75/">here</a> or on <a href="https://github.com/valdisiljuconoks/ImageResizer.Plugins.EPiServerBlobReader">GitHub</a>.</p>

<p>Happy coding!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term="Image Resizer" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><category term="image resizer" /><summary type="html"><![CDATA[ImageResizer is one of top choice library when it comes to optimizing media assets in web context. EPiServer 7.5 introduced really cool feature Asset and media.]]></summary></entry><entry><title type="html">Bootstrap aware EPiServer content area render</title><link href="https://tech-fellow.eu/2014/03/06/bootstrap-aware-episerver-content-area-render/" rel="alternate" type="text/html" title="Bootstrap aware EPiServer content area render" /><published>2014-03-06T12:35:00+02:00</published><updated>2014-03-06T12:35:00+02:00</updated><id>https://tech-fellow.eu/2014/03/06/bootstrap-aware-episerver-content-area-render</id><content type="html" xml:base="https://tech-fellow.eu/2014/03/06/bootstrap-aware-episerver-content-area-render/"><![CDATA[<h1 id="epibootstraparea">EPiBootstrapArea</h1>

<p>Bootstrap aware EPiServer content area renderer. Provides easy way to register display options used to customize look and feel of the blocks inside a EPiServer content area.</p>

<h2 id="getting-started">Getting Started</h2>

<p>You would need to install package from EPiServer’s NuGet <a href="http://nuget.episerver.com/">feed</a> to start using Twitter’s Bootstrap aware EPiServer Content Area renderer:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>PM&gt; Install-Package EPiBootstrapArea
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Default built-in display options are regsitered automatically. Below is described some built-in features.</p>

<h2 id="available-built-in-display-options">Available Built-in Display Options</h2>

<p>Following display options are registered by default:</p>

<ul>
  <li>Full width (<code class="language-plaintext highlighter-rouge">displaymode-full</code>)</li>
  <li>Half width (<code class="language-plaintext highlighter-rouge">displaymode-half</code>)</li>
  <li>One-third width (<code class="language-plaintext highlighter-rouge">displaymode-one-third</code>)</li>
  <li>Two-thirds width (<code class="language-plaintext highlighter-rouge">displaymode-two-thirds</code>)</li>
  <li>One-quarter width (<code class="language-plaintext highlighter-rouge">displaymode-one-quarter</code>)</li>
  <li>Three-quarter width (<code class="language-plaintext highlighter-rouge">displaymode-three-quarters</code>)</li>
</ul>

<p><img src="/assets/img/2014/02/display-modes.png" alt="" /></p>

<h3 id="display-option-fallbacks">Display Option Fallbacks</h3>
<p>For every display option there are 4 fallback width for various screen sizes based on Bootstrap grid system. According to Bootstrap v3 <a href="http://getbootstrap.com/css/#grid-options">specification</a> following screen sizes are defined:</p>

<ul>
  <li>Large screen (&gt;= 1200px)</li>
  <li>Medium devices (&gt;= 992px &amp;&amp; &lt; 1200px)</li>
  <li>Small devices (&gt;= 768px &amp;&amp; &lt; 992px)</li>
  <li>Extra small devices (&lt; 768px)</li>
</ul>

<p>These numbers are added at the end of Bootstrap grid system class (for instance 12 for Large screen -&gt; <code class="language-plaintext highlighter-rouge">'col-lg-12'</code>)</p>

<table><thead><th>Display Mode Name</th><th>Extra small devices (xs)</th><th>Small devices (sm)</th><th>Medium devices (md)</th><th>Large devices (lg)</th><thead><tbody><tr><td>`Full width`</td><td>12</td><td>12</td><td>12</td><td>12</td></tr><tr><td>`Half width`</td><td>12</td><td>12</td><td>6</td><td>6</td></tr><tr><td>`One third`</td><td>12</td><td>12</td><td>6</td><td>4</td></tr><tr><td>`Two thirds`</td><td>12</td><td>12</td><td>6</td><td>8</td></tr><tr><td>`One quarter`</td><td>12</td><td>12</td><td>6</td><td>3</td></tr><tr><td>`Three quarters`</td><td>12</td><td>12</td><td>6</td><td>9</td></tr></tbody><table>

Eventually if you choose `Half-width` display option for a block of type `EditorialBlockWithHeader` following markup will be generated:

```xml
<div class="block editorialblockwithheader col-lg-6 col-md-6 col-sm-12 col-xs-12 displaymode-half">
    ...
</div>
```

Breakdown of added classes:

* `block` : generic class added to identify a block
* `{block-name}` : name of the block type is added (in this case `EditorialBlockWithHeader`)
* `col-xs-12` : block will occupy whole width of the screen on extra small devices
* `col-sm-12` : block will occupy whole width of the screen on small devices
* `col-md-6` : block will occupy one half of the screen on medium devices
* `col-lg-6` : block will occupy one half of the screen on desktop
* `displaymode-half` : chosen display option name is added

### Example
Let's take a look at `One quarter width` block.
This is a block layout in EPiServer content area on-page edit mode (desktop view - large screen `col-lg-3`):

![](/assets/img/2014/02/one-qrt-1.png)

This is a block layout in EPiServer content area on medium devices - `col-md-6`:

![](/assets/img/2014/02/one-qrt-2.PNG)

This is a block layout in EPiServer content area on small and extra small devices - `col-sm-12` and `col-xs-12`:

![](/assets/img/2014/02/one-qrt-3.png)


## Customize Bootstrap Content Area
In order to customize available display options you need to add new ones through provider model.

### Provider Model
There is a tiny provider model inside this library to control how list of supported display modes is found. By default `DisplayModeFallbackDefaultProvider` provider is registered with following module:

```csharp
[ModuleDependency(typeof(ServiceContainerInitialization))]
[InitializableModule]
public class DisplayModeFallbackProviderInitModule : IConfigurableModule
{
    void IConfigurableModule.ConfigureContainer(ServiceConfigurationContext context)
    {
        context.Container.Configure(x =&gt; x.For<IDisplayModeFallbackProvider>()
                                          .Use<DisplayModeFallbackDefaultProvider>());
    }

    public void Initialize(InitializationEngine context)
    {
    }

    public void Uninitialize(InitializationEngine context)
    {
    }
}
```

### Register Custom Provider

You can for instance create new module and register your own new custom provider:

```csharp
[ModuleDependency(typeof(DisplayModeFallbackProviderInitModule))]
[InitializableModule]
public class CustomDisplayModeFallbackProviderInitModule : IConfigurableModule
{
    void IConfigurableModule.ConfigureContainer(ServiceConfigurationContext context)
    {
        context.Container.Configure(x =&gt; x.For<IDisplayModeFallbackProvider>()
                                          .Use<DisplayModeFallbackCustomProvider>());
    }

    public void Initialize(InitializationEngine context)
    {
    }

    public void Uninitialize(InitializationEngine context)
    {
    }
}
```

**NB!** In order to run after built-in initializable module you will need to add dependency to it in your module.

```csharp
...
[ModuleDependency(typeof(DisplayModeFallbackProviderInitModule))]
public class CustomDisplayModeFallbackProviderInitModule : IConfigurableModule
{
```

And then in your custom provider you need to specify list of available display modes by overridding `GetAll()` method.

```csharp
public class DisplayModeFallbackCustomProvider : DisplayModeFallbackDefaultProvider
{
    public override List<DisplayModeFallback> GetAll()
    {
        var original = base.GetAll();

        original.Add(new DisplayModeFallback
        {
            Name = "This is from code (1/12)",
            Tag = "one-12th-from-code",
            LargeScreenWidth = 12,
            MediumScreenWidth = 12,
            SmallScreenWidth = 12,
            ExtraSmallScreenWidth = 12
        });

        return original;
    }
}
```

There is also backward compatibility with DDS storage. You will need to switch to that provider manually:

```csharp
...
context.Container.Configure(x =&gt; x.For<IDisplayModeFallbackProvider>()
                                  .Use<DisplayModeDdsFallbackProvider>());
```

Registered display options will be stored in Dynamic Data Store under `EPiBootstrapArea.DisplayModeFallback` store type. Currently there is no built-in support for editing DisplayOptions on fly from EPiServer UI. For this reason you can choose for instance [Geta.DDSAdmin](https://github.com/Geta/DdsAdmin) plugin.


### Additional Styles
Similar to EPiServer AlloyTech sample site it's possible to define custom styles for block. You have to implement `EPiBootstrapArea.ICustomCssInContentArea` interface.

```csharp
[ContentType(GUID = "EED33EA7-D118-4D3D-BD7F-88C012DFA1F8", GroupName = SystemTabNames.Content)]
public class Divider : BaseBlockData, EPiBootstrapArea.ICustomCssInContentArea
{
    public string ContentAreaCssClass
    {
        get
        {
            return "block-with-round-borders";
        }
    }
}
```

### Localized Display Option Names
You will need to add few localization resource entries in order to get localized DisplayOptions. Following entry has to be added to get localized names for default display options:

```xml
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<languages>
  <language name="English" id="en">
    <displayoptions>
      <displaymode-full>Full (1/1)</displaymode-full>
      <displaymode-half>Half (1/2)</displaymode-half>
      <displaymode-one-third>One third (1/3)</displaymode-one-third>
      <displaymode-two-thirds>Two thirds (2/3)</displaymode-two-thirds>
      <displaymode-one-quarter>One quarter (1/4)</displaymode-one-quarter>
      <displaymode-three-quarters>Three quarters (3/4)</displaymode-three-quarters>
    </displayoptions>
  </language>
</languages>
```

Happy Bootstrapping!

[*eof*]
</DisplayModeDdsFallbackProvider></IDisplayModeFallbackProvider></DisplayModeFallback></DisplayModeFallbackCustomProvider></IDisplayModeFallbackProvider></DisplayModeFallbackDefaultProvider></IDisplayModeFallbackProvider></table></thead></thead></table>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Add-On" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="add-on" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[EPiBootstrapArea]]></summary></entry><entry><title type="html">Responsive EPiServer Tables</title><link href="https://tech-fellow.eu/2014/03/06/responsive-episerver-tables/" rel="alternate" type="text/html" title="Responsive EPiServer Tables" /><published>2014-03-06T12:35:00+02:00</published><updated>2014-03-06T12:35:00+02:00</updated><id>https://tech-fellow.eu/2014/03/06/responsive-episerver-tables</id><content type="html" xml:base="https://tech-fellow.eu/2014/03/06/responsive-episerver-tables/"><![CDATA[<p>Whenever you need to represent data on the website in table format question about responsiveness and page look &amp; feel on smaller devices arise.</p>

<p>I found an interesting <a href="http://css-tricks.com/responsive-data-tables/">solution @ CSS Tricks</a> for transforming tables from column-based into row-based on smaller devices.</p>

<p>This blog post is about how to adapt and automate a bit solution to fit for tables created by EPiServer tinyMCE editor.</p>

<p><img src="/assets/img/2014/03/1.png" alt="" /></p>

<p>Even if we specify that table has header and body:</p>

<p><img src="/assets/img/2014/03/2-1.png" alt="" /></p>

<p>Markup structure for table is following:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;table&gt;</span>
  <span class="nt">&lt;thead&gt;</span>
    <span class="nt">&lt;tr&gt;</span>
      <span class="nt">&lt;td&gt;</span>Name<span class="nt">&lt;/td&gt;</span>
      <span class="nt">&lt;td&gt;</span>1st Year<span class="nt">&lt;/td&gt;</span>
      ...
    <span class="nt">&lt;/tr&gt;</span>
  <span class="nt">&lt;/thead&gt;</span>
  <span class="nt">&lt;tbody&gt;</span>
    <span class="nt">&lt;tr&gt;</span>
      <span class="nt">&lt;td&gt;</span>..<span class="nt">&lt;/td&gt;</span>
      <span class="nt">&lt;td&gt;</span>..<span class="nt">&lt;/td&gt;</span>
      ...
    <span class="nt">&lt;/tr&gt;</span>
  <span class="nt">&lt;/tbody&gt;</span>
<span class="nt">&lt;/table&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So you can see that table has only <code class="language-plaintext highlighter-rouge">thead</code> element without proper <code class="language-plaintext highlighter-rouge">th</code> elements. That’s actually is not a problem at all.</p>

<h2 id="add-additional-tinymce-class">Add additional tinyMCE class</h2>
<p>You can try to convince editors to change markup directly – good luck! We would need to add additional class to tinyMCE editor in order to be able to mark table to act responsive on smaller screens just by adding special style for table using editor’s dropdown box.
We can add simple class to <code class="language-plaintext highlighter-rouge">editor.css</code> file:</p>

<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="nc">.responsive</span> <span class="p">{</span>
    <span class="py">EditMenuName</span><span class="p">:</span> <span class="n">Responsive</span> <span class="n">Table</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>EPiServer needs to know about our <code class="language-plaintext highlighter-rouge">editor.css</code> file. You can configure (if not done already) EPiServer to pick-up this custom CSS file for showing styles in tinyMCE editor Styles drop-down in <code class="language-plaintext highlighter-rouge">episerver.config</code> file:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;episerver&gt;</span>
  <span class="nt">&lt;applicationSettings</span> <span class="na">uiEditorCssPaths=</span><span class="s">"~/Static/css/Editor.css"</span> <span class="err">...</span> <span class="nt">/&gt;</span>

</pre></td></tr></tbody></table></code></pre></div></div>

<p>So now you are able to mark table to be responsive.</p>

<p><img src="/assets/img/2014/03/3.png" alt="" /></p>

<h2 id="add-metadata-to-the-table">Add metadata to the table</h2>
<p>As second step we need to decorate table with a bit more metadata that will be used later by CSS. We are inspecting table structure, extract count of columns, pick up appropriate <code class="language-plaintext highlighter-rouge">thead</code> row and add <code class="language-plaintext highlighter-rouge">data-</code> attribute to every row.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
</pre></td><td class="rouge-code"><pre><span class="c1">// responsive tables</span>
<span class="nf">$</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
    <span class="nf">$</span><span class="p">(</span><span class="err">‘</span><span class="nx">table</span><span class="p">.</span><span class="nx">responsive</span><span class="err">’</span><span class="p">).</span><span class="nf">each</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
        <span class="kd">var</span> <span class="nx">$table</span> <span class="o">=</span> <span class="nf">$</span><span class="p">(</span><span class="k">this</span><span class="p">),</span>
        <span class="nx">$thead</span> <span class="o">=</span> <span class="nx">$table</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="err">‘</span><span class="nx">thead</span><span class="err">’</span><span class="p">),</span>
        <span class="nx">$tbody</span> <span class="o">=</span> <span class="nx">$table</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="err">‘</span><span class="nx">tbody</span><span class="err">’</span><span class="p">);</span>

        <span class="c1">// get column count from 1st row in the body</span>
        <span class="kd">var</span> <span class="nx">columnCount</span> <span class="o">=</span> <span class="nx">$tbody</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="err">‘</span><span class="nx">tr</span><span class="p">:</span><span class="nx">first</span><span class="o">-</span><span class="nx">child</span> <span class="nx">td</span><span class="err">’</span><span class="p">).</span><span class="nx">length</span><span class="p">;</span>

        <span class="c1">// extract column titles</span>
        <span class="kd">var</span> <span class="nx">titles</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Array</span><span class="p">();</span>

        <span class="nx">$thead</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="err">‘</span><span class="nx">tr</span><span class="err">’</span><span class="p">).</span><span class="nf">each</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
            <span class="kd">var</span> <span class="nx">$cells</span> <span class="o">=</span> <span class="nf">$</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nf">find</span><span class="p">(</span><span class="err">‘</span><span class="nx">td</span><span class="err">’</span><span class="p">);</span>

            <span class="k">if </span><span class="p">(</span><span class="nx">$cells</span><span class="p">.</span><span class="nx">length</span> <span class="o">==</span> <span class="nx">columnCount</span><span class="p">)</span> <span class="p">{</span>
                <span class="nx">$cells</span><span class="p">.</span><span class="nf">each</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">ix</span><span class="p">,</span> <span class="nx">el</span><span class="p">)</span> <span class="p">{</span>
                    <span class="nx">titles</span><span class="p">[</span><span class="nx">ix</span><span class="p">]</span> <span class="o">=</span> <span class="nf">$</span><span class="p">(</span><span class="nx">el</span><span class="p">).</span><span class="nf">html</span><span class="p">();</span>
                <span class="p">});</span>
            <span class="p">}</span>
        <span class="p">});</span>

        <span class="nx">$tbody</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="err">‘</span><span class="nx">tr</span><span class="err">’</span><span class="p">).</span><span class="nf">each</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
            <span class="nf">$</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nf">find</span><span class="p">(</span><span class="err">‘</span><span class="nx">td</span><span class="err">’</span><span class="p">).</span><span class="nf">each</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">ix</span><span class="p">,</span> <span class="nx">el</span><span class="p">)</span> <span class="p">{</span>
                <span class="nf">$</span><span class="p">(</span><span class="nx">el</span><span class="p">).</span><span class="nf">attr</span><span class="p">(</span><span class="err">‘</span><span class="nx">data</span><span class="o">-</span><span class="nx">title</span><span class="err">’</span><span class="p">,</span> <span class="nx">titles</span><span class="p">[</span><span class="nx">ix</span><span class="p">]);</span>
            <span class="p">});</span>
        <span class="p">});</span>
    <span class="p">});</span>
<span class="p">});</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>After script has been executed we will end up with similar markup:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;table</span> <span class="na">border=</span><span class="s">"0"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;tbody&gt;</span>
    <span class="nt">&lt;tr&gt;</span>
      <span class="nt">&lt;td&gt;</span>Name<span class="nt">&lt;/td&gt;</span>
      <span class="nt">&lt;td&gt;</span>...<span class="nt">&lt;/td&gt;</span>
      ...
    <span class="nt">&lt;/tr&gt;</span>
    <span class="nt">&lt;tr&gt;</span>
      <span class="nt">&lt;td&gt;</span>1st Year<span class="nt">&lt;/td&gt;</span>
      <span class="nt">&lt;td&gt;</span>..<span class="nt">&lt;/td&gt;</span>
      ...
    <span class="nt">&lt;/tr&gt;</span>
  <span class="nt">&lt;/tbody&gt;</span>
<span class="nt">&lt;/table&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>To pick up proper row from <code class="language-plaintext highlighter-rouge">thead</code> is needed to support tables with merged cells acting as caption for the table.</p>

<h2 id="style-row-based-table">Style row-based table</h2>
<p>Final step is to add proper CSS to transform table from column-based into row-based table on smaller devices.</p>

<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
</pre></td><td class="rouge-code"><pre><span class="nt">table</span> <span class="p">{</span>
  <span class="nl">table-layout</span><span class="p">:</span> <span class="nb">fixed</span><span class="p">;</span>
<span class="p">}</span>

<span class="nt">table</span> <span class="nt">tbody</span> <span class="nt">tr</span><span class="nd">:nth-child</span><span class="o">(</span><span class="nt">even</span><span class="o">)</span> <span class="p">{</span>
  <span class="nl">background-color</span><span class="p">:</span> <span class="m">#f2f2f2</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">@media</span> <span class="p">(</span><span class="n">max-width</span><span class="p">:</span> <span class="m">767px</span><span class="p">)</span> <span class="p">{</span>
  <span class="nt">table</span><span class="nc">.responsive</span><span class="o">,</span>
  <span class="nt">table</span><span class="nc">.responsive</span> <span class="nt">thead</span><span class="o">,</span>
  <span class="nt">table</span><span class="nc">.responsive</span> <span class="nt">tbody</span><span class="o">,</span>
  <span class="nt">table</span><span class="nc">.responsive</span> <span class="nt">th</span><span class="o">,</span>
  <span class="nt">table</span><span class="nc">.responsive</span> <span class="nt">td</span><span class="o">,</span>
  <span class="nt">table</span><span class="nc">.responsive</span> <span class="nt">tr</span> <span class="p">{</span>
    <span class="nl">display</span><span class="p">:</span> <span class="nb">block</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="nt">table</span><span class="nc">.responsive</span> <span class="nt">thead</span> <span class="nt">tr</span> <span class="p">{</span>
    <span class="nl">position</span><span class="p">:</span> <span class="nb">absolute</span><span class="p">;</span>
    <span class="nl">top</span><span class="p">:</span> <span class="m">-9999px</span><span class="p">;</span>
    <span class="nl">left</span><span class="p">:</span> <span class="m">-9999px</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="nt">table</span><span class="nc">.responsive</span> <span class="nt">td</span> <span class="p">{</span>
    <span class="nl">border</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>
    <span class="nl">border-bottom</span><span class="p">:</span> <span class="m">1px</span> <span class="nb">solid</span> <span class="m">#eee</span><span class="p">;</span>
    <span class="nl">position</span><span class="p">:</span> <span class="nb">relative</span><span class="p">;</span>
    <span class="nl">padding-left</span><span class="p">:</span> <span class="m">35%</span><span class="p">;</span>
    <span class="nl">white-space</span><span class="p">:</span> <span class="nb">normal</span><span class="p">;</span>
    <span class="nl">text-align</span><span class="p">:</span> <span class="nb">left</span><span class="p">;</span>
    <span class="nl">width</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span>
    <span class="nl">font-size</span><span class="p">:</span> <span class="m">14px</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="nt">table</span><span class="nc">.responsive</span> <span class="nt">td</span><span class="nd">:before</span> <span class="p">{</span>
    <span class="nl">position</span><span class="p">:</span> <span class="nb">absolute</span><span class="p">;</span>
    <span class="nl">top</span><span class="p">:</span> <span class="m">6px</span><span class="p">;</span>
    <span class="nl">left</span><span class="p">:</span> <span class="m">6px</span><span class="p">;</span>
    <span class="nl">width</span><span class="p">:</span> <span class="m">30%</span><span class="p">;</span>
    <span class="nl">padding-right</span><span class="p">:</span> <span class="m">10px</span><span class="p">;</span>
    <span class="nl">white-space</span><span class="p">:</span> <span class="nb">nowrap</span><span class="p">;</span>
    <span class="nl">text-align</span><span class="p">:</span> <span class="nb">left</span><span class="p">;</span>
    <span class="nl">font-size</span><span class="p">:</span> <span class="m">14px</span><span class="p">;</span>
    <span class="nl">content</span><span class="p">:</span> <span class="n">attr</span><span class="p">(</span><span class="n">data-title</span><span class="p">);</span>
  <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Using following styles table that is marked to be responsive using tinyMCE editor will break apart and transform itself into row-based table on screens smaller than <code class="language-plaintext highlighter-rouge">768px</code> wide (particularly on ordinary mobile phone).</p>

<h2 id="demo">Demo</h2>

<p>On screen with 800px width:</p>

<p><img src="/assets/img/2014/03/4.png" alt="" /></p>

<p>On screen less that 768px width:</p>

<p><img src="/assets/img/2014/03/5.png" alt="" /></p>

<p>Happy responsive designing!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[Whenever you need to represent data on the website in table format question about responsiveness and page look &amp; feel on smaller devices arise.]]></summary></entry><entry><title type="html">Injected log4net Logger</title><link href="https://tech-fellow.eu/2014/03/03/injected-log4net-logger/" rel="alternate" type="text/html" title="Injected log4net Logger" /><published>2014-03-03T20:45:00+02:00</published><updated>2014-03-03T20:45:00+02:00</updated><id>https://tech-fellow.eu/2014/03/03/injected-log4net-logger</id><content type="html" xml:base="https://tech-fellow.eu/2014/03/03/injected-log4net-logger/"><![CDATA[<p>Blog post is for personal reference for the cases when you need to get instance of some sort of logger from the Logging library you are using.</p>

<p>It depends on logging library that you use but usually you may get instance of logger itself by providing some metadata about calling site or producer of the log entries.</p>

<p>Code usually looks somewhat similar:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">readonly</span> <span class="n">ILog</span> <span class="n">logger</span> <span class="p">=</span> <span class="n">LogManager</span><span class="p">.</span><span class="nf">GetLogger</span><span class="p">(</span><span class="n">MethodBase</span><span class="p">.</span><span class="nf">GetCurrentMethod</span><span class="p">().</span><span class="n">DeclaringType</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>As you can see it’s not really ready for injection as it requires concrete type in order to initialize an instance.
I would expect to have possibility to wait for somebody to give me correct logger already configured with concrete producer of the log entries.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">MyController</span> <span class="p">:</span> <span class="n">Controller</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">MyController</span><span class="p">(</span><span class="n">ILog</span> <span class="n">logger</span><span class="p">)</span>
    <span class="p">{</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="instruct-dependencyresolver-to-create-a-logger">Instruct DependencyResolver to create a logger</h2>

<p>It depends on type of IoC framework you are using but majority of main players in that field provide a way to initialize and customize creation of a container.
Code snippet below uses <a href="http://docs.structuremap.net/">StructureMap</a> library.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">StructureMapRegistry</span> <span class="p">:</span> <span class="n">Registry</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">StructureMapRegistry</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="nf">For</span><span class="p">().</span><span class="nf">AlwaysUnique</span><span class="p">().</span><span class="nf">Use</span><span class="p">(</span><span class="n">ctx</span> <span class="p">=&gt;</span>
            <span class="n">LogManager</span><span class="p">.</span><span class="nf">GetLogger</span><span class="p">(</span><span class="n">ctx</span><span class="p">.</span><span class="n">ParentType</span> <span class="p">??</span> <span class="n">ctx</span><span class="p">.</span><span class="n">BuildStack</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">ConcreteType</span><span class="p">));</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So whenever somebody will ask for <code class="language-plaintext highlighter-rouge">ILog</code> interface from IoC container it will be constructed with proper producer type.</p>

<p>Happy logging!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[Blog post is for personal reference for the cases when you need to get instance of some sort of logger from the Logging library you are using.]]></summary></entry><entry><title type="html">Disable script optimization per request from EPiServer</title><link href="https://tech-fellow.eu/2014/02/05/disable-script-optimization-per-request-from-episerver/" rel="alternate" type="text/html" title="Disable script optimization per request from EPiServer" /><published>2014-02-05T13:35:00+02:00</published><updated>2014-02-05T13:35:00+02:00</updated><id>https://tech-fellow.eu/2014/02/05/disable-script-optimization-per-request-from-episerver</id><content type="html" xml:base="https://tech-fellow.eu/2014/02/05/disable-script-optimization-per-request-from-episerver/"><![CDATA[<p>Image that you are running the site in production environment and following best practices for client-side page performance optimization. You are using script or style bundling and minification approach to reduce size of assets to download decreasing time to load for the page.</p>

<pre><code class="language-razor"> @System.Web.Optimization.Styles.Render(“~/Content/css”)
</code></pre>

<p>Let’s assume that you received a bug report from the customer complaining that one of the page is not loading correctly. You navigate to the page and see something similar in console output:</p>

<p><img src="/assets/img/2014/02/error-stack.png" alt="" /></p>

<p>At the top of the call stack is guilty target.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>ReferenceError: ‘a’ is not defined in /site-scripts?v=P4j3J… Line 1: Column 45669
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Viewing the source of the file does not help much either.</p>

<p><img src="/assets/img/2014/02/view-source.png" alt="" /></p>

<p>Question is <strong>now what</strong>?</p>

<p>Looking at <code class="language-plaintext highlighter-rouge">System.Web.Optimization.Styles|Scripts.Render()</code> method source code we can see that eventually code is using <code class="language-plaintext highlighter-rouge">BundleTable.EnableOptimizations</code> property which on another hand is affecting all script or style rendering – it means that be enabled or disabling optimizations – you are affecting all site users.
The case is that actually you want script or style optimization to be disabled only for your particular debugging request without affecting other site users. It means that you have to turn feature on or off conditionally.</p>

<h2 id="styles-and-scripts-conditional-optimization">Styles and Scripts conditional optimization</h2>

<p>Using <a href="https://github.com/valdisiljuconoks/FeatureSwitch/wiki#overview">FeatureSwitch</a> library it’s easily possible to turn optimization on or off only for particular request, session, context, whatever..
By using FeatureSwitch <a href="https://github.com/valdisiljuconoks/FeatureSwitch/wiki#strategies">strategies</a> you can define your own feature that relies for instance on <a href="http://msdn.microsoft.com/en-us/library/system.web.httprequest.querystring(v=vs.110).aspx">QueryString</a> value provided within the request.</p>

<p>Or you can use built-in features for disable script and style optimizations:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">FeatureSwitch.Web.Optimization</span> <span class="p">{</span>

    <span class="k">public</span> <span class="k">class</span> <span class="nc">DisableScriptOptimization</span> <span class="p">{</span> <span class="p">}</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">DisableStyleOptimization</span> <span class="p">{</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>These 2 features are waiting for particular query string and writing selection in Http session if available. Feature is defined as shown below:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">FeatureSwitch.Web.Optimization</span>
<span class="p">{</span>
    <span class="p">[</span><span class="nf">QueryString</span><span class="p">(</span><span class="n">Key</span> <span class="p">=</span> <span class="err">“</span><span class="n">DisableScriptOptimization</span><span class="err">”</span><span class="p">)]</span>
    <span class="p">[</span><span class="nf">HttpSession</span><span class="p">(</span><span class="n">Key</span> <span class="p">=</span> <span class="err">“</span><span class="n">FeatureSwitch_DisableScriptOptimization</span><span class="err">”</span><span class="p">,</span> <span class="n">Order</span> <span class="p">=</span> <span class="m">1</span><span class="p">)]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">DisableScriptOptimization</span> <span class="p">:</span> <span class="n">BaseFeature</span>
    <span class="p">{</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">FeatureSwitch.Web.Optimization</code> plugin provides new Styles and Scripts types for rendering bundles and can be used in following way:</p>

<pre><code class="language-razor">@using Scripts = FeatureSwitch.Web.Optimization.Scripts
@using Styles = FeatureSwitch.Web.Optimization.Styles

…

@(Styles.Render&lt;DisableStyleOptimization&gt;(“~/Content/css”))
@(Scripts.Render&lt;DisableScriptOptimization&gt;(“~/bundles/modernizr”))
</code></pre>

<h3 id="local-debug-environment">Local Debug environment</h3>
<p>Behind the scenes if feature is not enabled <code class="language-plaintext highlighter-rouge">FeatureSwitch.Web.Optimization</code> library relies on <code class="language-plaintext highlighter-rouge">System.Web.Optimization</code> functionality meaning that locally if you are running site in debug environment (<code class="language-plaintext highlighter-rouge">HttpContext.Current.IsDebuggingEnabled</code> is returning true) scripts or styles will not be bundled.</p>

<h2 id="episerver-control-panel-support">EPiServer Control Panel support</h2>
<p>FeatureSwitch EPiServer integration library provides an easy way to integration UI Control Panel into <a href="http://www.episerver.com">EPiServer CMS</a> platform for enabling or disabling particular feature on demand directly from EPiServer Admin Panel.</p>

<p><img src="/assets/img/2014/02/epi-control-panel.png" alt="" /></p>

<h3 id="setup">Setup</h3>
<p>No special setup is needed in order to integrate <code class="language-plaintext highlighter-rouge">FeatureSwitch</code> EPiServer’s library it’s done automatically by <code class="language-plaintext highlighter-rouge">InitializableModule</code> (<a href="https://github.com/valdisiljuconoks/FeatureSwitch/blob/master/FeatureSwitch.EPiServer/FeatureSwitchInit.cs">code</a>)</p>

<h3 id="security-setup">Security Setup</h3>
<p>Currently UI Control Panel is mapped to <code class="language-plaintext highlighter-rouge">~/modules/FeatureSwitch</code> route and is secured by <code class="language-plaintext highlighter-rouge">Administrators</code> user group access security policy.
 Currently if you are using <code class="language-plaintext highlighter-rouge">InitializableModule</code> there is no easy way to customize this other than registering route and securing location by yourself (copy code from <code class="language-plaintext highlighter-rouge">FeatureSwitchInit.cs</code>).</p>

<h2 id="availability">Availability</h2>
<p>EPiServer integration library is available on <a href="http://nuget.episerver.com/en/OtherPages/Package/?packageId=FeatureSwitch.EPiServer.Cms75">nuget.episerver.com</a> and Web.Optimization package is available on <a href="https://www.nuget.org/packages/FeatureSwitch.Web.Optimization/">nuget.org</a> feed appropriately.
FeatureSwitch package is available for EPiServer 7.x version.</p>

<h2 id="feedback">Feedback</h2>
<p>Feedback is always welcome!</p>

<p>Happy feature switching!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Add-On" /><category term="Episerver" /><category term="Optimizely" /><category term="Feature Switch" /><category term=".net" /><category term="c#" /><category term="add-on" /><category term="episerver" /><category term="optimizely" /><category term="feature switch" /><summary type="html"><![CDATA[Image that you are running the site in production environment and following best practices for client-side page performance optimization. You are using script or style bundling and minification approach to reduce size of assets to download decreasing time to load for the page.]]></summary></entry><entry><title type="html">Add back Container Pages in EPiServer 7.5</title><link href="https://tech-fellow.eu/2014/01/31/add-back-container-pages-in-episerver-7-5/" rel="alternate" type="text/html" title="Add back Container Pages in EPiServer 7.5" /><published>2014-01-31T16:35:00+02:00</published><updated>2014-01-31T16:35:00+02:00</updated><id>https://tech-fellow.eu/2014/01/31/add-back-container-pages-in-episerver-7-5</id><content type="html" xml:base="https://tech-fellow.eu/2014/01/31/add-back-container-pages-in-episerver-7-5/"><![CDATA[<p>Container pages in EPiServer 7.5 is <a href="http://world.episerver.com/Documentation/Items/Upgrading/EPiServer-CMS/75/Breaking-changes/">no more a built-in system type</a> which is actually good because now everything in based on template implementation.</p>

<p>If you are still looking for a solution for container pages code snippets below could be useful.</p>

<p>I kind of liked solution found in AlloyTech Mvc sample site for 7.0 – when you define interface and your page type is “implementing” that eventually your page instance SelectedTemplate is set to null – resulting in so called container pages.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ContentType</span><span class="p">(</span><span class="n">GroupName</span> <span class="p">=</span> <span class="n">GroupNames</span><span class="p">.</span><span class="n">MyGroup</span><span class="p">,</span>
             <span class="n">DisplayName</span> <span class="p">=</span> <span class="err">“</span><span class="n">Sample</span> <span class="n">page</span><span class="err">”</span><span class="p">,</span>
             <span class="n">GUID</span> <span class="p">=</span> <span class="err">“</span><span class="m">9</span><span class="n">B02B266</span><span class="p">-</span><span class="n">D3C9</span><span class="p">-</span><span class="m">409E-93D2</span><span class="p">-</span><span class="m">21D26657F410</span><span class="err">″</span><span class="p">,</span>
             <span class="n">AvailableInEditMode</span> <span class="p">=</span> <span class="k">true</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">SamplePage</span> <span class="p">:</span> <span class="n">BasePageData</span><span class="p">,</span> <span class="n">IContainerPage</span>
<span class="p">{</span>
    <span class="err">…</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>In EPiServer 7.5 solution is much more cleaner. All you need to do is register new <a href="http://world.episerver.com/Documentation/Class-library/?documentId=framework/7.5/47dc5e02-00ec-57c8-cc83-a4f43869b5ac">UIDescriptorInitializer</a>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ServiceConfiguration</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">IUIDescriptorInitializer</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ContainerPageUIDescriptorInitializer</span> <span class="p">:</span> <span class="n">IUIDescriptorInitializer</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">UIDescriptorRegistry</span> <span class="n">registry</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">containerTypes</span> <span class="p">=</span> <span class="n">TypeAttributeHelper</span><span class="p">.</span><span class="n">GetTypesChildOf</span><span class="p">&lt;</span><span class="n">IContainerPage</span><span class="p">&gt;();</span>
        <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">type</span> <span class="k">in</span> <span class="n">containerTypes</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">registry</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">new</span> <span class="nf">UIDescriptor</span><span class="p">(</span><span class="n">type</span><span class="p">)</span>
                <span class="p">{</span>
                    <span class="n">DefaultView</span> <span class="p">=</span> <span class="n">CmsViewNames</span><span class="p">.</span><span class="n">AllPropertiesView</span><span class="p">,</span>
                    <span class="n">IconClass</span> <span class="p">=</span> <span class="n">ContentTypeCssClassNames</span><span class="p">.</span><span class="n">Container</span>
                <span class="p">});</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This initializer searches for all types those are implementing <code class="language-plaintext highlighter-rouge">IContainerPage</code> interface and registers container page like UI descriptor for them. Interface could be of course defined by you.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="n">TypeAttributeHelper</span><span class="p">.</span><span class="n">GetTypesChildOf</span><span class="p">&lt;</span><span class="n">IContainerPage</span><span class="p">&gt;();</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is just a small helper class taken from other my plugins that finds all types that is child of specified type.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">TypeAttributeHelper</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="n">IEnumerable</span> <span class="nf">GetTypesChildOf</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">allTypes</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">List</span><span class="p">();</span>
        <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">assembly</span> <span class="k">in</span> <span class="nf">GetAssemblies</span><span class="p">())</span>
        <span class="p">{</span>
            <span class="n">allTypes</span><span class="p">.</span><span class="nf">AddRange</span><span class="p">(</span><span class="nf">GetTypesChildOfInAssembly</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">T</span><span class="p">),</span> <span class="n">assembly</span><span class="p">));</span>
        <span class="p">}</span>

        <span class="k">return</span> <span class="n">allTypes</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="k">static</span> <span class="n">IEnumerable</span> <span class="nf">GetAssemblies</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">AppDomain</span><span class="p">.</span><span class="n">CurrentDomain</span><span class="p">.</span><span class="nf">GetAssemblies</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="k">static</span> <span class="n">IEnumerable</span> <span class="nf">GetTypesChildOfInAssembly</span><span class="p">(</span><span class="n">Type</span> <span class="n">type</span><span class="p">,</span> <span class="n">Assembly</span> <span class="n">assembly</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">try</span>
        <span class="p">{</span>
            <span class="k">return</span> <span class="n">assembly</span><span class="p">.</span><span class="nf">GetTypes</span><span class="p">().</span><span class="nf">Where</span><span class="p">(</span><span class="n">t</span> <span class="p">=&gt;</span> <span class="n">t</span><span class="p">.</span><span class="nf">IsSubclassOf</span><span class="p">(</span><span class="n">type</span><span class="p">)</span> <span class="p">&amp;&amp;</span> <span class="p">!</span><span class="n">t</span><span class="p">.</span><span class="n">IsAbstract</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="c1">// there could be situations when type could not be loaded</span>
            <span class="c1">// this may happen if we are visiting *all* loaded assemblies in application domain</span>
            <span class="k">return</span> <span class="n">Enumerable</span><span class="p">.</span><span class="nf">Empty</span><span class="p">();</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Happy containering!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Add-On" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="add-on" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[Container pages in EPiServer 7.5 is no more a built-in system type which is actually good because now everything in based on template implementation.]]></summary></entry><entry><title type="html">Parse and Validate Quartz JobDataMap</title><link href="https://tech-fellow.eu/2013/10/17/parse-and-validate-quartz-job-data-map/" rel="alternate" type="text/html" title="Parse and Validate Quartz JobDataMap" /><published>2013-10-17T23:55:00+03:00</published><updated>2013-10-17T23:55:00+03:00</updated><id>https://tech-fellow.eu/2013/10/17/parse-and-validate-quartz-job-data-map</id><content type="html" xml:base="https://tech-fellow.eu/2013/10/17/parse-and-validate-quartz-job-data-map/"><![CDATA[<p>Once you start to implement web site driven by EPiServer Commerce the necessity of scheduled background job(s) sooner or later will rise. A nice approach and existing framework is used in EPiServer Commerce solutions – background jobs are scheduled and <a href="http://www.quartz-scheduler.net/">Quartz.Net</a>.</p>

<p>As we all know scheduled background jobs are sort of agents or workers that do the dirty job over night or any allowed time window to fetch, process, calculate, recalculate, push or do whatever other fancy complex operations that may take time and valuable resources to complete.</p>

<p>Nice advantage of Quartz jobs over <code class="language-plaintext highlighter-rouge">EPiServer CMS</code> scheduled jobs is option that Quartz jobs may run on separate node and not steal compute power from main node which is intended to be used to serve web pages for end-users.</p>

<p>An example of scheduled job from 1000 feet may look like this:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">SampleQuartzBackgroundJob</span> <span class="p">:</span> <span class="n">IJob</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Execute</span><span class="p">(</span><span class="n">IJobExecutionContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">throw</span> <span class="k">new</span> <span class="n">System</span><span class="p">.</span><span class="nf">NotImplementedException</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We are implementing an <code class="language-plaintext highlighter-rouge">IJob</code> (<a href="http://quartznet.sourceforge.net/tutorial/lesson_2.html">info here</a>) interface which is pretty straight forward – have a single operation to execute which is the entry point for our job.</p>

<p>However sooner or later we may come up with requirement that claims for job parameterization – for instance, if we discover that we can reuse the same job implementation (type)  for different jobs (instances). Then we would need a way to supply instance with particular parameters.</p>

<h2 id="here-is-your-guide--a-data-map">Here is your guide – a data map</h2>

<p>Job parameterization is implemented using job’s data map – which is a simple list of key / value pairs to supply job instance for behavior customization.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="rouge-code"><pre>    SampleJob
    SampleGroup
    SampleQuartzJobLibrary.SampleQuartzBackgroundJob, SampleQuartzJobLibrary


        Parameter1
        Value 1

        Parameter2
        7
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Later when the instance of the job is executed we can access job map via <code class="language-plaintext highlighter-rouge">JobExecutionContext</code>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">Execute</span><span class="p">(</span><span class="n">IJobExecutionContext</span> <span class="n">context</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">map</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">JobDetail</span><span class="p">.</span><span class="n">JobDataMap</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>In this case map is just a dictionary with “<code class="language-plaintext highlighter-rouge">IsDirty</code>” flag feature which gets set to <code class="language-plaintext highlighter-rouge">true</code> if collection has been changed.</p>

<p>The values of the map is of type <code class="language-plaintext highlighter-rouge">System.Object</code>. This is fine for storage – but when working with map it’s better to access each value as intended type – <code class="language-plaintext highlighter-rouge">int</code>, <code class="language-plaintext highlighter-rouge">string</code>, etc.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">Execute</span><span class="p">(</span><span class="n">IJobExecutionContext</span> <span class="n">context</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">map</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">JobDetail</span><span class="p">.</span><span class="n">JobDataMap</span><span class="p">;</span>
    <span class="kt">var</span> <span class="n">param1</span> <span class="p">=</span> <span class="n">map</span><span class="p">.</span><span class="nf">GetString</span><span class="p">(</span><span class="s">"Parameter1"</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">param2</span> <span class="p">=</span> <span class="n">map</span><span class="p">.</span><span class="nf">GetInt</span><span class="p">(</span><span class="s">"Parameter2"</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Job’s data map provides an easy way to access map data in “stringly-typed” way.</p>

<p>Usually data provided in job data map is the same as end-user provided in web site – that is required to be validated.</p>

<h2 id="is-map-pointing-to-the-north">Is map pointing to the North?</h2>

<p>So data which job author or administrator provided in job data map is the same candidate for data validation as submitted data to web server by end-user.</p>

<p>Easy, right?!</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">Execute</span><span class="p">(</span><span class="n">IJobExecutionContext</span> <span class="n">context</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">map</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">JobDetail</span><span class="p">.</span><span class="n">JobDataMap</span><span class="p">;</span>
    <span class="kt">var</span> <span class="n">param1</span> <span class="p">=</span> <span class="n">map</span><span class="p">.</span><span class="nf">GetString</span><span class="p">(</span><span class="s">"Parameter1"</span><span class="p">);</span>
    <span class="kt">var</span> <span class="n">param2</span> <span class="p">=</span> <span class="n">map</span><span class="p">.</span><span class="nf">GetInt</span><span class="p">(</span><span class="s">"Parameter2"</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="kt">string</span><span class="p">.</span><span class="nf">IsNullOrEmpty</span><span class="p">(</span><span class="n">param1</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="k">throw</span> <span class="k">new</span> <span class="nf">ConfigurationErrorsException</span><span class="p">(</span><span class="s">"Parameter1 is null or empty"</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">param2</span> <span class="p">&lt;=</span> <span class="m">0</span> <span class="p">||</span> <span class="n">param2</span> <span class="p">&gt;</span> <span class="m">15</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">throw</span> <span class="k">new</span> <span class="nf">ConfigurationErrorsException</span><span class="p">(</span><span class="s">"Parameter2 is out of range (1..15)"</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This may be “standard” value validation approach in Quartz jobs and probably somewhere else in .Net universe.</p>

<p>Still for me it seems boring / repetitive code that must be implemented all over the place in almost every job where job data map values would be used.</p>

<h2 id="im-going-to-south-actually">I’m going to South actually</h2>

<p>So we will take similar approach as MVC model binders took – we will let <a href="http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.aspx"><code class="language-plaintext highlighter-rouge">DataAnnotations</code></a> namespace and particularly <code class="language-plaintext highlighter-rouge">ObjectValidator</code> to do the job.</p>

<p>Instead of endless if() statements code snippet below would be much better.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">Execute</span><span class="p">(</span><span class="n">IJobExecutionContext</span> <span class="n">context</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">map</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">JobDetail</span><span class="p">.</span><span class="n">JobDataMap</span><span class="p">;</span>
    <span class="kt">var</span> <span class="n">mapTyped</span> <span class="p">=</span> <span class="n">map</span><span class="p">.</span><span class="nf">AsTyped</span><span class="p">();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Where <code class="language-plaintext highlighter-rouge">SampleJobParameters</code> is ordinary class that represents possible map parameters and those data types.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">SampleJobParameters</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Parameter1</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

    <span class="k">public</span> <span class="kt">int</span> <span class="n">Parameter2</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Then we will need a logic that will map from <code class="language-plaintext highlighter-rouge">JobDataMap</code> to our job parameter class.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">key</span> <span class="k">in</span> <span class="n">map</span><span class="p">.</span><span class="n">Keys</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">propInfo</span> <span class="p">=</span> <span class="n">result</span><span class="p">.</span><span class="nf">GetType</span><span class="p">().</span><span class="nf">GetProperty</span><span class="p">(</span><span class="n">key</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">propInfo</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">propInfo</span><span class="p">.</span><span class="n">PropertyType</span><span class="p">.</span><span class="n">IsEnum</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="kt">var</span> <span class="n">converter</span> <span class="p">=</span> <span class="n">TypeDescriptor</span><span class="p">.</span><span class="nf">GetConverter</span><span class="p">(</span><span class="n">propInfo</span><span class="p">.</span><span class="n">PropertyType</span><span class="p">);</span>
            <span class="n">propInfo</span><span class="p">.</span><span class="nf">SetValue</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">converter</span><span class="p">.</span><span class="nf">ConvertFrom</span><span class="p">(</span><span class="n">map</span><span class="p">[</span><span class="n">key</span><span class="p">]),</span> <span class="k">null</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="k">else</span>
        <span class="p">{</span>
            <span class="n">propInfo</span><span class="p">.</span><span class="nf">SetValue</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">Convert</span><span class="p">.</span><span class="nf">ChangeType</span><span class="p">(</span><span class="n">map</span><span class="p">[</span><span class="n">key</span><span class="p">],</span> <span class="n">propInfo</span><span class="p">.</span><span class="n">PropertyType</span><span class="p">),</span> <span class="k">null</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Iteration over map keys instead of parameter properties is by design – job data map values have high priority over particular parameter class. Here a reaction of absence of particular property in parameter class could also be easy added – anyway I leave the code as simple as possible for a sake of readability.</p>

<p>Now we may get back an instance of out property class</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">void</span> <span class="nf">Execute</span><span class="p">(</span><span class="n">IJobExecutionContext</span> <span class="n">context</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">map</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">JobDetail</span><span class="p">.</span><span class="n">JobDataMap</span><span class="p">;</span>
    <span class="kt">var</span> <span class="n">mapTyped</span> <span class="p">=</span> <span class="n">map</span><span class="p">.</span><span class="nf">AsTyped</span><span class="p">();</span>

    <span class="kt">var</span> <span class="n">command</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SampleCommand</span><span class="p">();</span>
    <span class="n">command</span><span class="p">.</span><span class="nf">Execute</span><span class="p">(</span><span class="n">param1</span><span class="p">,</span> <span class="n">param2</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Let’s go one step further and add a data validation to the parameter class.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">SampleJobParameters</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">Required</span><span class="p">]</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Parameter1</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

    <span class="p">[</span><span class="nf">Range</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">15</span><span class="p">)]</span>
    <span class="k">public</span> <span class="kt">int</span> <span class="n">Parameter2</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now we need a code that will handle the validation of data map / parameter class data.</p>

<p>Pretty easy!</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">validationContext</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ValidationContext</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="k">null</span><span class="p">,</span> <span class="k">null</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">results</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">List</span><span class="p">();</span>

<span class="k">if</span> <span class="p">(!</span><span class="n">Validator</span><span class="p">.</span><span class="nf">TryValidateObject</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">validationContext</span><span class="p">,</span> <span class="n">results</span><span class="p">,</span> <span class="k">true</span><span class="p">))</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">msg</span> <span class="p">=</span> <span class="kt">string</span><span class="p">.</span><span class="nf">Format</span><span class="p">(</span><span class="s">"Error in configuration.{0}"</span><span class="p">,</span>
                            <span class="kt">string</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="n">Environment</span><span class="p">.</span><span class="n">NewLine</span><span class="p">,</span> <span class="n">results</span><span class="p">.</span><span class="nf">Select</span><span class="p">(</span><span class="n">r</span> <span class="p">=&gt;</span> <span class="n">r</span><span class="p">.</span><span class="n">ErrorMessage</span><span class="p">)));</span>

    <span class="n">logger</span><span class="p">.</span><span class="nf">Error</span><span class="p">(</span><span class="n">msg</span><span class="p">);</span>
    <span class="k">throw</span> <span class="k">new</span> <span class="nf">ConfigurationErrorsException</span><span class="p">(</span><span class="n">msg</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Now if we supply invalid data types in job data map or provide incorrect data (out of range, missing, empty, etc) those will be validated.</p>

<p>Complete listing for parsing and validating job data map:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">JobDataMapExtensions</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="n">T</span> <span class="nf">Read</span><span class="p">(</span><span class="k">this</span> <span class="n">JobDataMap</span> <span class="n">map</span><span class="p">)</span> <span class="k">where</span> <span class="n">T</span> <span class="p">:</span> <span class="k">new</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">T</span><span class="p">();</span>
        <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">key</span> <span class="k">in</span> <span class="n">map</span><span class="p">.</span><span class="n">Keys</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="kt">var</span> <span class="n">propInfo</span> <span class="p">=</span> <span class="n">result</span><span class="p">.</span><span class="nf">GetType</span><span class="p">().</span><span class="nf">GetProperty</span><span class="p">(</span><span class="n">key</span><span class="p">);</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">propInfo</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">propInfo</span><span class="p">.</span><span class="n">PropertyType</span><span class="p">.</span><span class="n">IsEnum</span><span class="p">)</span>
                <span class="p">{</span>
                    <span class="kt">var</span> <span class="n">converter</span> <span class="p">=</span> <span class="n">TypeDescriptor</span><span class="p">.</span><span class="nf">GetConverter</span><span class="p">(</span><span class="n">propInfo</span><span class="p">.</span><span class="n">PropertyType</span><span class="p">);</span>
                    <span class="n">propInfo</span><span class="p">.</span><span class="nf">SetValue</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">converter</span><span class="p">.</span><span class="nf">ConvertFrom</span><span class="p">(</span><span class="n">map</span><span class="p">[</span><span class="n">key</span><span class="p">]),</span> <span class="k">null</span><span class="p">);</span>
                <span class="p">}</span>
                <span class="k">else</span>
                <span class="p">{</span>
                    <span class="n">propInfo</span><span class="p">.</span><span class="nf">SetValue</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">Convert</span><span class="p">.</span><span class="nf">ChangeType</span><span class="p">(</span><span class="n">map</span><span class="p">[</span><span class="n">key</span><span class="p">],</span> <span class="n">propInfo</span><span class="p">.</span><span class="n">PropertyType</span><span class="p">),</span> <span class="k">null</span><span class="p">);</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span>

        <span class="kt">var</span> <span class="n">validationContext</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ValidationContext</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="k">null</span><span class="p">,</span> <span class="k">null</span><span class="p">);</span>
        <span class="kt">var</span> <span class="n">results</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">List</span><span class="p">();</span>

        <span class="k">if</span> <span class="p">(!</span><span class="n">Validator</span><span class="p">.</span><span class="nf">TryValidateObject</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">validationContext</span><span class="p">,</span> <span class="n">results</span><span class="p">,</span> <span class="k">true</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="kt">var</span> <span class="n">msg</span> <span class="p">=</span> <span class="kt">string</span><span class="p">.</span><span class="nf">Format</span><span class="p">(</span><span class="s">"Error in configuration.{0}"</span><span class="p">,</span>
                                    <span class="kt">string</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="n">Environment</span><span class="p">.</span><span class="n">NewLine</span><span class="p">,</span> <span class="n">results</span><span class="p">.</span><span class="nf">Select</span><span class="p">(</span><span class="n">r</span> <span class="p">=&gt;</span> <span class="n">r</span><span class="p">.</span><span class="n">ErrorMessage</span><span class="p">)));</span>
            <span class="k">throw</span> <span class="k">new</span> <span class="nf">ConfigurationErrorsException</span><span class="p">(</span><span class="n">msg</span><span class="p">);</span>
        <span class="p">}</span>

        <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Benefits of such approach:</p>

<ul>
  <li>Code reusability in all job types.</li>
  <li>Possible custom validation logic by implementing custom ValidationAttribute classes.</li>
  <li>Strongly typed access over stringly typed access for job parameters.</li>
  <li>Sort of documentation for job data map parameters, types, allowed values, etc.</li>
</ul>

<p>Hope this helps!
Happy coding!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term=".net" /><category term="c#" /><summary type="html"><![CDATA[Once you start to implement web site driven by EPiServer Commerce the necessity of scheduled background job(s) sooner or later will rise. A nice approach and existing framework is used in EPiServer Commerce solutions – background jobs are scheduled and Quartz.Net.]]></summary></entry><entry><title type="html">Overview your EPiServer scheduled jobs interactively</title><link href="https://tech-fellow.eu/2013/10/17/overview-your-episerver-scheduled-jobs-interactively/" rel="alternate" type="text/html" title="Overview your EPiServer scheduled jobs interactively" /><published>2013-10-17T10:00:00+03:00</published><updated>2013-10-17T10:00:00+03:00</updated><id>https://tech-fellow.eu/2013/10/17/overview-your-episerver-scheduled-jobs-interactively</id><content type="html" xml:base="https://tech-fellow.eu/2013/10/17/overview-your-episerver-scheduled-jobs-interactively/"><![CDATA[<p>EPiServer scheduled jobs list in larger enterprise scale projects may get huge enough in order not to be able to overview them.</p>

<p>Few pain points around scheduled jobs presentation in administrative EPiServer interface:</p>

<ul>
  <li>Section for listing scheduled jobs usually presents list of jobs in some unpredictable order.</li>
  <li>It’s hard to tell details of the job, which of them is enabled, which of them failed last time, what is the schedule interval, etc.</li>
  <li>It’s also not easy to tell which of the jobs are running at any given moment.</li>
</ul>

<p>These are just a few points that lead me to develop EPiServer scheduled jobs overview plugin.</p>

<p>Everything you need to do in order to add a plugin is to install it via NuGet (just search for <code class="language-plaintext highlighter-rouge">scheduledjobs</code> in EPiServer NuGet feed – <a href="http://nuget.episerver.com">http://nuget.episerver.com</a>).</p>

<p><img src="/assets/img/2013/10/1.png" alt="" /></p>

<p>After package installation and site build completes plugin is accessible in “Tools” section in Admin page.</p>

<p><img src="/assets/img/2013/10/2.png" alt="" /></p>

<p>Plugin shows you all registered scheduled jobs in the system in one table with additional essential information.</p>

<p><img src="/assets/img/2013/10/3.png" alt="" /></p>

<p>It’s also possible to get information on which job is currently running (if <code class="language-plaintext highlighter-rouge">Auto-refresh</code> is enabled):</p>

<p><img src="/assets/img/2013/10/4.png" alt="" /></p>

<p>Plugin is available for following versions:
1.CMS 6 (Id: <code class="language-plaintext highlighter-rouge">TechFellow.ScheduledJobsOverview.CMS6</code>)
2.CMS 7 (Id: <code class="language-plaintext highlighter-rouge">TechFellow.ScheduledJobsOverview</code>)
3.CMS 7 as AddOn (<a href="https://github.com/valdisiljuconoks/TechFellow.ScheduledJobOverview/raw/master/ScheduledJobOverview/Packages/TechFellow.ScheduledJobOverview.AddOn.1.4.0.nupkg">on GitHub</a>)</p>

<p>Source located in GitHub – <a href="https://github.com/valdisiljuconoks/TechFellow.ScheduledJobOverview">https://github.com/valdisiljuconoks/TechFellow.ScheduledJobOverview</a></p>

<h2 id="behind-the-scene">Behind the scene</h2>

<p>While developing the plugin I discovered a few interesting things to share in following sections.</p>

<h3 id="registering-routes-in-cms7-as-plugin">Registering Routes in CMS7 as plugin</h3>

<p>In order to register some custom routes in EPiServer 7 CMS there is a special method in <code class="language-plaintext highlighter-rouge">EPiServer.Global</code> class which you can override and add your own custom routes.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">Global</span> <span class="p">:</span> <span class="n">EPiServer</span><span class="p">.</span><span class="n">Global</span>
<span class="p">{</span>
    <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">RegisterRoutes</span><span class="p">(</span><span class="n">RouteCollection</span> <span class="n">routes</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">base</span><span class="p">.</span><span class="nf">RegisterRoutes</span><span class="p">(</span><span class="n">routes</span><span class="p">);</span>
        <span class="n">routes</span><span class="p">.</span><span class="nf">MapSomething</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>However if you are developing a plugin, usually you don’t want to make your library users to add something somewhere explicitly and then upon removal you as a user of the library need to remove those additions, etc.</p>

<p>My idea is that plugin must add everything it needs and remove everything it needed upon removal. As EPiServer CMS does not provide any events or other kind of extension point around route registration what I came up is to use Http module for this which is dynamically registered using Microsoft.Web.Infrastructure library.</p>

<p>First what you need to do is to dynamically register module:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">InitializeModule</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Preload</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">parameters</span><span class="p">)</span>
    <span class="p">{</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
<span class="cp">#if !ADDON &amp;&amp; !CMS6
</span>        <span class="n">DynamicModuleUtility</span><span class="p">.</span><span class="nf">RegisterModule</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">WorkaroundRouteRegistrationHttpModule</span><span class="p">));</span>
<span class="cp">#endif
</span>     <span class="p">}</span>

     <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
     <span class="p">{</span>
     <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Compile time constants (ADDON and CMS6) are introduced in order to support multiple CMS versions and installation scenario within the same code-base (more that below).</p>

<p>Then workaround module itself is just a registration of the necessary routes:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">WorkaroundRouteRegistrationHttpModule</span> <span class="p">:</span> <span class="n">IHttpModule</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">static</span> <span class="kt">bool</span> <span class="n">isInitialized</span><span class="p">;</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Init</span><span class="p">(</span><span class="n">HttpApplication</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">isInitialized</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">return</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="n">RouteTable</span><span class="p">.</span><span class="n">Routes</span><span class="p">.</span><span class="nf">MapRoute</span><span class="p">(..);</span>

        <span class="k">lock</span> <span class="p">(</span><span class="n">context</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">isInitialized</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Dispose</span><span class="p">()</span>
    <span class="p">{</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="supporting-multiple-versions-within-the-same-code-base">Supporting multiple versions within the same code-base</h3>

<p>Goal was to enable multiple version support within the same code-base. For multiple version support I had to create separate assemblies (projects) to target different EPiServer assemblies and to define different compile time constants.</p>

<p>Following is a summary of exceptions I needed to take to workaround issues related to multiple versions:</p>

<p>1.<em>Route registration</em>. need to register routes in separate <code class="language-plaintext highlighter-rouge">Http module</code> if running in CMS7.
2.<em>Admin Plugin registration</em>. If you are supporting AddOn installation mode as well you need to register plugin with different settings.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="k">namespace</span> <span class="nn">TechFellow.ScheduledJobOverview</span>
<span class="p">{</span>
<span class="cp">#if ADDON
</span>    <span class="p">[</span><span class="nf">GuiPlugIn</span><span class="p">(</span><span class="n">DisplayName</span> <span class="p">=</span> <span class="s">"Scheduled jobs overview"</span><span class="p">,</span> <span class="n">UrlFromModuleFolder</span> <span class="p">=</span> <span class="s">"Overview"</span><span class="p">,</span> <span class="n">Area</span> <span class="p">=</span> <span class="n">PlugInArea</span><span class="p">.</span><span class="n">AdminMenu</span><span class="p">)]</span>
<span class="cp">#else
</span>    <span class="p">[</span><span class="nf">GuiPlugIn</span><span class="p">(</span><span class="n">DisplayName</span> <span class="p">=</span> <span class="s">"Scheduled jobs overview"</span><span class="p">,</span> <span class="n">Url</span> <span class="p">=</span> <span class="s">"~/modules/"</span> <span class="p">+</span> <span class="n">Const</span><span class="p">.</span><span class="n">ModuleName</span> <span class="p">+</span> <span class="s">"/Overview"</span><span class="p">,</span> <span class="n">Area</span> <span class="p">=</span> <span class="n">PlugInArea</span><span class="p">.</span><span class="n">AdminMenu</span><span class="p">)]</span>
<span class="cp">#endif
</span>    <span class="k">public</span> <span class="k">class</span> <span class="nc">ToolsPluginRegistration</span>
    <span class="p">{</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>3.<em>Client resource delivery</em>. There is difference when you install plugin as AddOn you need to deliver client side resources (like scripts, images) using <code class="language-plaintext highlighter-rouge">EPiServer.Shell.Paths</code> class to resolve location of the resource. When plugin is installed as NuGet package – files are delivered from assembly itself (more on this in section “Single-file deployment”).</p>

<p>For instance to include script on the page it’s convenient to create some helper methods:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="nf">GetJavascriptIncludes</span><span class="p">(</span><span class="k">this</span> <span class="n">ClientScriptManager</span> <span class="n">clientScript</span><span class="p">,</span> <span class="kt">string</span> <span class="n">file</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="kt">string</span><span class="p">.</span><span class="nf">Format</span><span class="p">(</span><span class="s">""</span><span class="p">,</span>
                         <span class="n">RuntimeInfo</span><span class="p">.</span><span class="nf">IsModule</span><span class="p">()</span>
                                 <span class="p">?</span> <span class="n">Paths</span><span class="p">.</span><span class="nf">ToClientResource</span><span class="p">(</span><span class="n">Const</span><span class="p">.</span><span class="n">ModuleName</span> <span class="p">+</span> <span class="s">".AddOn"</span><span class="p">,</span> <span class="s">"Scripts/"</span> <span class="p">+</span> <span class="n">file</span><span class="p">)</span>
                                 <span class="p">:</span> <span class="n">clientScript</span><span class="p">.</span><span class="nf">GetWebResourceUrl</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">ClientScriptManagerExtensions</span><span class="p">),</span>
                                                                  <span class="n">ResourceProvider</span><span class="p">.</span><span class="nf">CreateResourceUrl</span><span class="p">(</span><span class="s">"Scripts"</span><span class="p">,</span> <span class="n">file</span><span class="p">)));</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>To understand if the plugin is running in <code class="language-plaintext highlighter-rouge">AddOn</code> mode, I came up with following helper method:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</pre></td><td class="rouge-code"><pre><span class="k">using</span> <span class="nn">EPiServer.ServiceLocation</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">EPiServer.Shell.Modules</span><span class="p">;</span>

<span class="k">namespace</span> <span class="nn">TechFellow.ScheduledJobOverview</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">RuntimeInfo</span>
    <span class="p">{</span>
        <span class="k">private</span> <span class="k">static</span> <span class="kt">bool</span> <span class="n">isInitialized</span><span class="p">;</span>
        <span class="k">private</span> <span class="k">static</span> <span class="kt">bool</span> <span class="n">isModule</span><span class="p">;</span>
        <span class="k">private</span> <span class="k">static</span> <span class="k">readonly</span> <span class="kt">object</span> <span class="n">syncRoot</span> <span class="p">=</span> <span class="k">new</span> <span class="kt">object</span><span class="p">();</span>

        <span class="k">public</span> <span class="k">static</span> <span class="kt">bool</span> <span class="nf">IsModule</span><span class="p">()</span>
        <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">isInitialized</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="k">return</span> <span class="n">isModule</span><span class="p">;</span>
            <span class="p">}</span>

<span class="cp">#if !CMS6
</span>            <span class="k">if</span> <span class="p">(</span><span class="n">ServiceLocator</span><span class="p">.</span><span class="n">Current</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="k">return</span> <span class="n">isModule</span><span class="p">;</span>
            <span class="p">}</span>

            <span class="k">lock</span> <span class="p">(</span><span class="n">syncRoot</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="n">ShellModule</span> <span class="n">module</span><span class="p">;</span>
                <span class="n">isModule</span> <span class="p">=</span> <span class="n">ServiceLocator</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="nf">GetInstance</span><span class="p">().</span><span class="nf">TryGetModule</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">RuntimeInfo</span><span class="p">).</span><span class="n">Assembly</span><span class="p">,</span> <span class="k">out</span> <span class="n">module</span><span class="p">);</span>
            <span class="p">}</span>
<span class="cp">#endif
</span>            <span class="n">isInitialized</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
            <span class="k">return</span> <span class="n">isModule</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">namespace</span> <span class="nn">EPiServer.ServiceLocation</span>
<span class="p">{</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>NB!</strong> The last line with empty namespace is there just because of some <code class="language-plaintext highlighter-rouge">ReSharper</code> or any other code clean-up tool. If code will be opened in solution that is targeting different CMS version (v6) it will not compile code fragment around ServiceLocator but usage on top (<code class="language-plaintext highlighter-rouge">EPiServer.ServiceLocation</code>) will break. If you will fully qualified type name for <code class="language-plaintext highlighter-rouge">ServiceLocator</code> -&gt; next time when you will reformat code in solution that is targeting CMS 7 for instance, usually namespace before the type will be moved out to usage list. And we will be back with the same issue :)</p>

<h3 id="enabling-client-side-interactivity">Enabling client-side interactivity</h3>

<p>Feature “Auto-refresh”  in plugin is using client side interactivity based on <code class="language-plaintext highlighter-rouge">AngluarJs</code> library that is used to bind on the page Json object received back from the server. <code class="language-plaintext highlighter-rouge">Angular.js</code> library is packed together with plugin (even this is not correct) just to enable single file deployment scenarios.</p>

<p>To enable “Auto-refresh” feature we need to create 2 parts:</p>

<p>1.<em>Create a service</em>. Service that will deliver information about current state of the plugin subsystem:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">AcceptVerbs</span><span class="p">(</span><span class="n">HttpVerbs</span><span class="p">.</span><span class="n">Get</span><span class="p">)]</span>
<span class="k">public</span> <span class="n">JsonResult</span> <span class="nf">GetList</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">repository</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">JobRepository</span><span class="p">();</span>
    <span class="k">return</span> <span class="nf">Json</span><span class="p">(</span><span class="n">repository</span><span class="p">.</span><span class="nf">GetList</span><span class="p">(),</span> <span class="n">JsonRequestBehavior</span><span class="p">.</span><span class="n">AllowGet</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Repository is pretty straight forward (you need “join” scheduled job list with discovered plugins just for the reason that there might be jobs that are not yet ran and they are not registered as scheduled jobs but are discovered just as plugins):</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="n">List</span> <span class="nf">GetList</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">plugIns</span> <span class="p">=</span> <span class="n">PlugInLocator</span><span class="p">.</span><span class="nf">Search</span><span class="p">(</span><span class="k">new</span> <span class="nf">ScheduledPlugInAttribute</span><span class="p">()).</span><span class="nf">ToList</span><span class="p">();</span>

    <span class="k">return</span> <span class="p">(</span><span class="k">from</span> <span class="n">plugin</span> <span class="k">in</span> <span class="n">plugIns</span>
            <span class="k">let</span> <span class="n">job</span> <span class="p">=</span> <span class="n">ScheduledJob</span><span class="p">.</span><span class="nf">List</span><span class="p">().</span><span class="nf">FirstOrDefault</span><span class="p">(</span><span class="n">j</span> <span class="p">=&gt;</span> <span class="n">j</span><span class="p">.</span><span class="n">TypeName</span> <span class="p">==</span> <span class="n">plugin</span><span class="p">.</span><span class="n">TypeName</span> <span class="p">&amp;&amp;</span>
                                                              <span class="n">j</span><span class="p">.</span><span class="n">AssemblyName</span> <span class="p">==</span> <span class="n">plugin</span><span class="p">.</span><span class="n">AssemblyName</span><span class="p">)</span>
            <span class="k">let</span> <span class="n">attr</span> <span class="p">=</span> <span class="n">plugin</span><span class="p">.</span><span class="nf">GetAttribute</span><span class="p">()</span>
            <span class="k">select</span> <span class="k">new</span> <span class="n">JobDescriptionViewModel</span>
                       <span class="p">{</span>
                               <span class="n">Id</span> <span class="p">=</span> <span class="n">plugin</span><span class="p">.</span><span class="n">ID</span><span class="p">,</span>
                               <span class="n">InstanceId</span> <span class="p">=</span> <span class="n">job</span> <span class="p">!=</span> <span class="k">null</span> <span class="p">?</span> <span class="n">job</span><span class="p">.</span><span class="n">ID</span> <span class="p">:</span> <span class="n">Guid</span><span class="p">.</span><span class="n">Empty</span><span class="p">,</span>
                               <span class="n">Name</span> <span class="p">=</span> <span class="n">attr</span><span class="p">.</span><span class="n">DisplayName</span><span class="p">,</span>
                               <span class="n">Description</span> <span class="p">=</span> <span class="n">attr</span><span class="p">.</span><span class="n">Description</span><span class="p">,</span>
                               <span class="n">IsEnabled</span> <span class="p">=</span> <span class="p">(</span><span class="n">job</span> <span class="p">!=</span> <span class="k">null</span> <span class="p">&amp;&amp;</span> <span class="n">job</span><span class="p">.</span><span class="n">IsEnabled</span><span class="p">),</span>
                               <span class="n">Interval</span> <span class="p">=</span> <span class="n">job</span> <span class="p">!=</span> <span class="k">null</span> <span class="p">?</span> <span class="kt">string</span><span class="p">.</span><span class="nf">Format</span><span class="p">(</span><span class="s">"{0} ({1})"</span><span class="p">,</span> <span class="n">job</span><span class="p">.</span><span class="n">IntervalLength</span><span class="p">,</span> <span class="n">job</span><span class="p">.</span><span class="n">IntervalType</span><span class="p">)</span> <span class="p">:</span> <span class="s">""</span><span class="p">,</span>
                               <span class="n">IsLastExecuteSuccessful</span> <span class="p">=</span> <span class="p">(</span><span class="n">job</span> <span class="p">!=</span> <span class="k">null</span> <span class="p">&amp;&amp;</span> <span class="p">!</span><span class="n">job</span><span class="p">.</span><span class="n">HasLastExecutionFailed</span> <span class="p">?</span> <span class="k">true</span> <span class="p">:</span> <span class="p">(</span><span class="kt">bool</span><span class="p">?)</span><span class="k">null</span><span class="p">),</span>
                               <span class="n">LastExecute</span> <span class="p">=</span> <span class="n">job</span> <span class="p">!=</span> <span class="k">null</span> <span class="p">?</span> <span class="n">job</span><span class="p">.</span><span class="n">LastExecution</span> <span class="p">:</span> <span class="p">(</span><span class="n">DateTime</span><span class="p">?)</span><span class="k">null</span><span class="p">,</span>
                               <span class="n">AssemblyName</span> <span class="p">=</span> <span class="n">plugin</span><span class="p">.</span><span class="n">AssemblyName</span><span class="p">,</span>
                               <span class="n">TypeName</span> <span class="p">=</span> <span class="n">plugin</span><span class="p">.</span><span class="n">TypeName</span><span class="p">,</span>
                               <span class="n">IsRunning</span> <span class="p">=</span> <span class="n">job</span> <span class="p">!=</span> <span class="k">null</span> <span class="p">&amp;&amp;</span> <span class="n">ScheduledJob</span><span class="p">.</span><span class="nf">IsJobRunning</span><span class="p">(</span><span class="n">job</span><span class="p">.</span><span class="n">ID</span><span class="p">),</span>
                       <span class="p">}).</span><span class="nf">OrderBy</span><span class="p">(</span><span class="n">j</span> <span class="p">=&gt;</span> <span class="n">j</span><span class="p">.</span><span class="n">Name</span><span class="p">).</span><span class="nf">ToList</span><span class="p">();</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>2.<em>Create a view</em>. Client side view that will be used as template to bind received data back.
And client-side script that enables automatic fetching of current scheduled job subsystem:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
</pre></td><td class="rouge-code"><pre><span class="p">;(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
    <span class="nx">angular</span><span class="p">.</span><span class="nf">module</span><span class="p">(</span><span class="dl">'</span><span class="s1">schApp</span><span class="dl">'</span><span class="p">,</span> <span class="p">[])</span>
        <span class="p">.</span><span class="nf">controller</span><span class="p">(</span><span class="dl">'</span><span class="s1">scheduledJobsController</span><span class="dl">'</span><span class="p">,</span> <span class="nf">function</span><span class="p">(</span><span class="nx">$scope</span><span class="p">,</span> <span class="nx">$http</span><span class="p">,</span> <span class="nx">$window</span><span class="p">,</span>
                                                        <span class="nx">$timeout</span><span class="p">,</span> <span class="nx">serviceUrl</span><span class="p">,</span> <span class="nx">detailsUrl</span><span class="p">)</span> <span class="p">{</span>
            <span class="nx">$scope</span><span class="p">.</span><span class="nx">fetch</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
                <span class="k">if </span><span class="p">(</span><span class="nx">$scope</span><span class="p">.</span><span class="nx">autoRefresh</span><span class="p">)</span> <span class="p">{</span>
                    <span class="nx">$http</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="nx">serviceUrl</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">GetList</span><span class="dl">'</span><span class="p">).</span><span class="nf">success</span><span class="p">(</span><span class="nf">function </span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
                        <span class="k">try</span> <span class="p">{</span>
                            <span class="nx">$scope</span><span class="p">.</span><span class="nx">jobs</span> <span class="o">=</span> <span class="nx">angular</span><span class="p">.</span><span class="nf">fromJson</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span>
                        <span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
                            <span class="c1">// error may occur when service returns html for login page instead of json</span>
                            <span class="c1">// (unauthorized access, session expired, etc)</span>
                        <span class="p">}</span>
                    <span class="p">});</span>
                    <span class="nf">$timeout</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span> <span class="nx">$scope</span><span class="p">.</span><span class="nf">fetch</span><span class="p">();</span> <span class="p">},</span> <span class="mi">5000</span><span class="p">);</span>
                <span class="p">}</span>
            <span class="p">};</span>

            <span class="nx">$scope</span><span class="p">.</span><span class="nf">$watch</span><span class="p">(</span><span class="dl">'</span><span class="s1">autoRefresh</span><span class="dl">'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">newValue</span><span class="p">)</span> <span class="p">{</span>
                <span class="k">if </span><span class="p">(</span><span class="nx">newValue</span><span class="p">)</span> <span class="p">{</span>
                    <span class="nx">$scope</span><span class="p">.</span><span class="nf">fetch</span><span class="p">();</span>
                <span class="p">}</span>
            <span class="p">});</span>

            <span class="nx">$scope</span><span class="p">.</span><span class="nx">autoRefresh</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>

        <span class="p">})</span>
<span class="p">})();</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="customizing-episervers-scheduledjob-details-page">Customizing EPiServer’s ScheduledJob details page</h3>
<p>When accessing scheduled jobs details page new button appears that enables administrator to go back to overview page.</p>

<p><img src="/assets/img/2013/10/5.png" alt="" /></p>

<p>It’s done using Asp.Net control adapters infrastructure.
You just need to deploy <code class="language-plaintext highlighter-rouge">YourAdapterMappings.browser</code> file to <code class="language-plaintext highlighter-rouge">App_Browsers</code> folder in your target web site.</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;browsers&gt;</span>
    <span class="nt">&lt;browser</span> <span class="na">refID=</span><span class="s">"Default"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;controlAdapters&gt;</span>
            <span class="nt">&lt;adapter</span> <span class="na">controlType=</span><span class="s">"EPiServer.UI.Admin.DatabaseJob"</span>
                     <span class="na">adapterType=</span><span class="s">"TechFellow.ScheduledJobOverview.DatabaseJobAdapter"</span> <span class="nt">/&gt;</span>
        <span class="nt">&lt;/controlAdapters&gt;</span>
    <span class="nt">&lt;/browser&gt;</span>
<span class="nt">&lt;/browsers&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>DatabaseJobAdapter.cs file contains logic that adds extra button on page without changing source code of the built-in job details page.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="rouge-code"><pre><span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnInit</span><span class="p">(</span><span class="n">EventArgs</span> <span class="n">e</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">base</span><span class="p">.</span><span class="nf">OnInit</span><span class="p">(</span><span class="n">e</span><span class="p">);</span>

    <span class="kt">var</span> <span class="n">navigateButton</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Button</span>
                             <span class="p">{</span>
                                     <span class="n">Text</span> <span class="p">=</span> <span class="s">"Scheduled job overview"</span><span class="p">,</span>
                                     <span class="n">ToolTip</span> <span class="p">=</span> <span class="s">"Navigate to scheduled job overview page."</span><span class="p">,</span>
                                     <span class="n">CssClass</span> <span class="p">=</span> <span class="s">"epi-cmsButton-tools epi-cmsButton-text epi-cmsButton-Report"</span>
                             <span class="p">};</span>

    <span class="n">navigateButton</span><span class="p">.</span><span class="n">Click</span> <span class="p">+=</span> <span class="n">NavigateButtonOnClick</span><span class="p">;</span>

    <span class="kt">var</span> <span class="n">span</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">HtmlGenericControl</span><span class="p">(</span><span class="s">"span"</span><span class="p">);</span>
    <span class="n">span</span><span class="p">.</span><span class="n">Attributes</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="s">"class"</span><span class="p">,</span> <span class="s">"epi-cmsButton"</span><span class="p">);</span>
    <span class="n">span</span><span class="p">.</span><span class="n">Attributes</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="s">"style"</span><span class="p">,</span> <span class="s">"float: right;"</span><span class="p">);</span>
    <span class="n">span</span><span class="p">.</span><span class="n">Controls</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">navigateButton</span><span class="p">);</span>

    <span class="n">Control</span><span class="p">.</span><span class="nf">FindControlRecursively</span><span class="p">(</span><span class="s">"GeneralSettings"</span><span class="p">).</span><span class="n">Controls</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">span</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="execute-scheduled-job-manually">Execute Scheduled job manually</h3>

<p>To provide “Execute manually” button on overview page we have to deal with the case when plugin may not be ran before – therefore it’s not yet registered as scheduled job but is just discovered by plugin subsystem (the same case when retrieving list of jobs).</p>

<p>This is client-side code that is invoked when user presses the button:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="nx">$scope</span><span class="p">.</span><span class="nx">executeJob</span> <span class="o">=</span> <span class="nf">function </span><span class="p">(</span><span class="nx">id</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">$window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">href</span> <span class="o">=</span> <span class="nx">serviceUrl</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">/Execute/?jobId=</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">id</span><span class="p">;</span>
<span class="p">};</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Which just executes “Execute” action on controller passing in job id.</p>

<p>This is server side code that is invoked when script executes the action.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">repository</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">JobRepository</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">job</span> <span class="p">=</span> <span class="n">repository</span><span class="p">.</span><span class="nf">GetList</span><span class="p">().</span><span class="nf">FirstOrDefault</span><span class="p">(</span><span class="n">j</span> <span class="p">=&gt;</span> <span class="n">j</span><span class="p">.</span><span class="n">Id</span> <span class="p">==</span> <span class="kt">int</span><span class="p">.</span><span class="nf">Parse</span><span class="p">(</span><span class="n">jobId</span><span class="p">));</span>

<span class="k">if</span> <span class="p">(</span><span class="n">job</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">try</span>
    <span class="p">{</span>
        <span class="n">ScheduledJob</span> <span class="n">jobInstance</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">job</span><span class="p">.</span><span class="n">InstanceId</span> <span class="p">!=</span> <span class="n">Guid</span><span class="p">.</span><span class="n">Empty</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">jobInstance</span> <span class="p">=</span> <span class="n">ScheduledJob</span><span class="p">.</span><span class="nf">Load</span><span class="p">(</span><span class="n">job</span><span class="p">.</span><span class="n">InstanceId</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="k">else</span>
        <span class="p">{</span>
            <span class="n">jobInstance</span> <span class="p">=</span> <span class="k">new</span> <span class="n">ScheduledJob</span>
                              <span class="p">{</span>
                                      <span class="n">IntervalType</span> <span class="p">=</span> <span class="n">ScheduledIntervalType</span><span class="p">.</span><span class="n">Days</span><span class="p">,</span>
                                      <span class="n">IsEnabled</span> <span class="p">=</span> <span class="k">false</span><span class="p">,</span>
                                      <span class="n">Name</span> <span class="p">=</span> <span class="n">job</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span>
                                      <span class="n">MethodName</span> <span class="p">=</span> <span class="s">"Execute"</span><span class="p">,</span>
                                      <span class="n">TypeName</span> <span class="p">=</span> <span class="n">job</span><span class="p">.</span><span class="n">TypeName</span><span class="p">,</span>
                                      <span class="n">AssemblyName</span> <span class="p">=</span> <span class="n">job</span><span class="p">.</span><span class="n">AssemblyName</span><span class="p">,</span>
                                      <span class="n">IsStaticMethod</span> <span class="p">=</span> <span class="k">true</span>
                              <span class="p">};</span>

            <span class="k">if</span> <span class="p">(</span><span class="n">jobInstance</span><span class="p">.</span><span class="n">NextExecution</span> <span class="p">==</span> <span class="n">DateTime</span><span class="p">.</span><span class="n">MinValue</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="n">jobInstance</span><span class="p">.</span><span class="n">NextExecution</span> <span class="p">=</span> <span class="n">DateTime</span><span class="p">.</span><span class="n">Today</span><span class="p">;</span>
            <span class="p">}</span>

            <span class="n">jobInstance</span><span class="p">.</span><span class="nf">Save</span><span class="p">();</span>
        <span class="p">}</span>

        <span class="k">if</span> <span class="p">(</span><span class="n">jobInstance</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">jobInstance</span><span class="p">.</span><span class="nf">ExecuteManually</span><span class="p">();</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">catch</span>
    <span class="p">{</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>1.First thing you need to verify that passed in job Id exists and by that id you are able to load the job instance.
2.If instance Guid is empty that means that job has not been ran before and you need to create job instance manually, pass all necessary data and then save it.
3.Then either job was loaded by <code class="language-plaintext highlighter-rouge">Id</code> or just recently created you can call <code class="language-plaintext highlighter-rouge">.ExecuteManually()</code> method.</p>

<h2 id="single-file-deployment">Single-file deployment</h2>

<p>I’m a big fan of single file deployment especially when it comes to plugins and various other extensions. In this case plugin is deployed as single file only when its installed as NuGet package. AddOn is running normally and all necessary dependencies are deployed as physical files in AddOn installation folder.</p>

<p>1.<em>Embed resources</em>. In order to enable single file deployment everything your plugin depends on must be embedded in assembly itself and delivered via registered handler.</p>

<p><img src="/assets/img/2013/10/6.png" alt="" /></p>

<p>2.<em>Include resource in page</em>. I created small helper method in order to include scripts on page taking into account that the same code base version may run in different scenarios (different CMS version, AddOn installation mode, etc).</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="o">&lt;%=</span> <span class="nx">Page</span><span class="p">.</span><span class="nx">ClientScript</span><span class="p">.</span><span class="nc">GetJavascriptIncludes</span><span class="p">(</span><span class="dl">"</span><span class="s2">site.js</span><span class="dl">"</span><span class="p">)</span> <span class="o">%&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="nf">GetJavascriptIncludes</span><span class="p">(</span><span class="k">this</span> <span class="n">ClientScriptManager</span> <span class="n">clientScript</span><span class="p">,</span>
                                           <span class="kt">string</span> <span class="n">file</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="kt">string</span><span class="p">.</span><span class="nf">Format</span><span class="p">(</span><span class="s">""</span><span class="p">,</span>
                         <span class="n">RuntimeInfo</span><span class="p">.</span><span class="nf">IsModule</span><span class="p">()</span>
                                 <span class="p">?</span> <span class="n">Paths</span><span class="p">.</span><span class="nf">ToClientResource</span><span class="p">(</span><span class="n">Const</span><span class="p">.</span><span class="n">ModuleName</span> <span class="p">+</span> <span class="s">".AddOn"</span><span class="p">,</span> <span class="s">"Scripts/"</span> <span class="p">+</span> <span class="n">file</span><span class="p">)</span>
                                 <span class="p">:</span> <span class="n">clientScript</span><span class="p">.</span><span class="nf">GetWebResourceUrl</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">ClientScriptManagerExtensions</span><span class="p">),</span>
                                                                  <span class="n">ResourceProvider</span><span class="p">.</span><span class="nf">CreateResourceUrl</span><span class="p">(</span><span class="s">"Scripts"</span><span class="p">,</span> <span class="n">file</span><span class="p">)));</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>3.<em>Look-up resource</em>. If plugin is running in AddOn installation mode we are using <code class="language-plaintext highlighter-rouge">EPiServer.Shell.Paths</code> class to resolve path to resource, otherwise if plugin was installed via NuGet – we are in single file deployment case and need to look-up resource in assembly’s embedded resources by using <code class="language-plaintext highlighter-rouge">GetWebResourceUrl()</code> which results in something similar:</p>

<p>4.<em>Different kind of resources</em>. The same applies for other type of resources (images for instance):</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>alt="" data-ng-show="job.IsRunning" /&gt;
</pre></td></tr></tbody></table></code></pre></div></div>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="nf">GetImageIncludes</span><span class="p">(</span><span class="k">this</span> <span class="n">ClientScriptManager</span> <span class="n">clientScript</span><span class="p">,</span> <span class="kt">string</span> <span class="n">file</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="n">RuntimeInfo</span><span class="p">.</span><span class="nf">IsModule</span><span class="p">()</span>
                   <span class="p">?</span> <span class="n">Paths</span><span class="p">.</span><span class="nf">ToClientResource</span><span class="p">(</span><span class="n">Const</span><span class="p">.</span><span class="n">ModuleName</span> <span class="p">+</span> <span class="s">".AddOn"</span><span class="p">,</span> <span class="s">"Images/"</span> <span class="p">+</span> <span class="n">file</span><span class="p">)</span>
                   <span class="p">:</span> <span class="n">clientScript</span><span class="p">.</span><span class="nf">GetWebResourceUrl</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">ClientScriptManagerExtensions</span><span class="p">),</span> <span class="n">ResourceProvider</span><span class="p">.</span><span class="nf">CreateResourceUrl</span><span class="p">(</span><span class="s">"Images"</span><span class="p">,</span> <span class="n">file</span><span class="p">));</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>5.<em>Register resource provider</em>. In order to render view back to the user in single file deployment case – view markup file itself is embedded into assembly’s resources and has to be extracted and sent back to the user. For this reason we need to register custom resource provider that will understand those requests and will look-up resource in embedded resource dictionary and will serve the file as it was read from the disk or any other storage.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">ModuleDependency</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">InitializationModule</span><span class="p">))]</span>
<span class="p">[</span><span class="n">InitializableModule</span><span class="p">]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">InitializeModule</span> <span class="p">:</span> <span class="n">IInitializableModule</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">Preload</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">parameters</span><span class="p">)</span>
    <span class="p">{</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">RuntimeInfo</span><span class="p">.</span><span class="nf">IsModule</span><span class="p">())</span>
        <span class="p">{</span>
            <span class="k">return</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="n">GenericHostingEnvironment</span><span class="p">.</span><span class="n">Instance</span><span class="p">.</span><span class="nf">RegisterVirtualPathProvider</span><span class="p">(</span><span class="k">new</span> <span class="nf">ResourceProvider</span><span class="p">());</span>
        <span class="n">ViewEngines</span><span class="p">.</span><span class="n">Engines</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">new</span> <span class="nf">CustomViewEngine</span><span class="p">());</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Uninitialize</span><span class="p">(</span><span class="n">InitializationEngine</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>There is a new <code class="language-plaintext highlighter-rouge">Virtual Path Provider</code> registered in the system – <code class="language-plaintext highlighter-rouge">ResourceProvider</code>.</p>

<p>These are steps resource provider is responsible for:</p>

<ol>
  <li>It caches all embedded assembly resources just for sake of performance.</li>
  <li>Translates incoming requested file name to resource name (<code class="language-plaintext highlighter-rouge">/Dir1/SubDir2/File1.txt</code> to <code class="language-plaintext highlighter-rouge">Dir1.SubDir2.File1.txt</code>).</li>
  <li>Checks if requested file is in the list of the cached resource files.</li>
  <li>If file exists new instance of <code class="language-plaintext highlighter-rouge">ResourceVirtualFile</code> is returned.</li>
</ol>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">ResourceProvider</span> <span class="p">:</span> <span class="n">VirtualPathProvider</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">static</span> <span class="k">readonly</span> <span class="n">List</span> <span class="n">resources</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="n">ResourceProvider</span><span class="p">).</span><span class="n">Assembly</span><span class="p">.</span><span class="nf">GetManifestResourceNames</span><span class="p">().</span><span class="nf">ToList</span><span class="p">();</span>

    <span class="k">public</span> <span class="k">override</span> <span class="kt">bool</span> <span class="nf">FileExists</span><span class="p">(</span><span class="kt">string</span> <span class="n">virtualPath</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="nf">ShouldHandle</span><span class="p">(</span><span class="n">virtualPath</span><span class="p">)</span> <span class="p">||</span> <span class="k">base</span><span class="p">.</span><span class="nf">FileExists</span><span class="p">(</span><span class="n">virtualPath</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">override</span> <span class="n">CacheDependency</span> <span class="nf">GetCacheDependency</span><span class="p">(</span><span class="kt">string</span> <span class="n">virtualPath</span><span class="p">,</span> <span class="n">IEnumerable</span> <span class="n">virtualPathDependencies</span><span class="p">,</span> <span class="n">DateTime</span> <span class="n">utcStart</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="nf">ShouldHandle</span><span class="p">(</span><span class="n">virtualPath</span><span class="p">)</span>
                       <span class="p">?</span> <span class="k">new</span> <span class="nf">CacheDependency</span><span class="p">((</span><span class="kt">string</span><span class="p">)</span><span class="k">null</span><span class="p">)</span>
                       <span class="p">:</span> <span class="k">base</span><span class="p">.</span><span class="nf">GetCacheDependency</span><span class="p">(</span><span class="n">virtualPath</span><span class="p">,</span> <span class="n">virtualPathDependencies</span><span class="p">,</span> <span class="n">utcStart</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">override</span> <span class="n">VirtualFile</span> <span class="nf">GetFile</span><span class="p">(</span><span class="kt">string</span> <span class="n">virtualPath</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="nf">ShouldHandle</span><span class="p">(</span><span class="n">virtualPath</span><span class="p">)</span>
                       <span class="p">?</span> <span class="k">new</span> <span class="nf">ResourceVirtualFile</span><span class="p">(</span><span class="n">virtualPath</span><span class="p">)</span>
                       <span class="p">:</span> <span class="k">base</span><span class="p">.</span><span class="nf">GetFile</span><span class="p">(</span><span class="n">virtualPath</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="nf">CreateResourceUrl</span><span class="p">(</span><span class="kt">string</span> <span class="n">type</span><span class="p">,</span> <span class="kt">string</span> <span class="n">resource</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="kt">string</span><span class="p">.</span><span class="nf">Format</span><span class="p">(</span><span class="s">"{0}.{1}.{2}"</span><span class="p">,</span> <span class="n">Const</span><span class="p">.</span><span class="n">ModuleName</span><span class="p">,</span> <span class="n">type</span><span class="p">,</span> <span class="nf">TranslateToResource</span><span class="p">(</span><span class="n">resource</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="nf">TranslateToResource</span><span class="p">(</span><span class="kt">string</span> <span class="n">url</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">url</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="n">Const</span><span class="p">.</span><span class="n">ModuleName</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="n">url</span> <span class="p">=</span> <span class="n">url</span><span class="p">.</span><span class="nf">Substring</span><span class="p">(</span><span class="n">url</span><span class="p">.</span><span class="nf">IndexOf</span><span class="p">(</span><span class="n">Const</span><span class="p">.</span><span class="n">ModuleName</span><span class="p">,</span> <span class="n">StringComparison</span><span class="p">.</span><span class="n">Ordinal</span><span class="p">));</span>
        <span class="p">}</span>

        <span class="k">if</span> <span class="p">(</span><span class="n">url</span><span class="p">.</span><span class="nf">StartsWith</span><span class="p">(</span><span class="s">"/"</span><span class="p">))</span>
        <span class="p">{</span>
            <span class="n">url</span> <span class="p">=</span> <span class="n">url</span><span class="p">.</span><span class="nf">Substring</span><span class="p">(</span><span class="m">1</span><span class="p">);</span>
        <span class="p">}</span>

        <span class="k">return</span> <span class="n">url</span><span class="p">.</span><span class="nf">Replace</span><span class="p">(</span><span class="sc">'/'</span><span class="p">,</span> <span class="sc">'.'</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="k">static</span> <span class="kt">bool</span> <span class="nf">ShouldHandle</span><span class="p">(</span><span class="kt">string</span> <span class="n">virtualPath</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">VirtualPathUtility</span><span class="p">.</span><span class="nf">ToAppRelative</span><span class="p">(</span><span class="n">virtualPath</span><span class="p">).</span><span class="nf">Contains</span><span class="p">(</span><span class="n">Const</span><span class="p">.</span><span class="n">ModuleName</span><span class="p">)</span>
               <span class="p">&amp;&amp;</span> <span class="n">resources</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="nf">TranslateToResource</span><span class="p">(</span><span class="n">virtualPath</span><span class="p">));</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">internal</span> <span class="k">class</span> <span class="nc">ResourceVirtualFile</span> <span class="p">:</span> <span class="n">VirtualFile</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="kt">string</span> <span class="n">fileName</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">ResourceVirtualFile</span><span class="p">(</span><span class="kt">string</span> <span class="n">virtualPath</span><span class="p">)</span> <span class="p">:</span> <span class="k">base</span><span class="p">(</span><span class="n">virtualPath</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">this</span><span class="p">.</span><span class="n">fileName</span> <span class="p">=</span> <span class="n">VirtualPathUtility</span><span class="p">.</span><span class="nf">ToAppRelative</span><span class="p">(</span><span class="n">virtualPath</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">override</span> <span class="n">Stream</span> <span class="nf">Open</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="nf">GetType</span><span class="p">().</span><span class="n">Assembly</span><span class="p">.</span><span class="nf">GetManifestResourceStream</span><span class="p">(</span><span class="n">ResourceProvider</span><span class="p">.</span><span class="nf">TranslateToResource</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">fileName</span><span class="p">));</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="summary">Summary</h2>

<p>It’s pretty interesting to maintain single code-base to support various target platforms. I ran into few of the cases where you need to explicitly state which platform or installation / deployment mode you are supporting now and handle various cases a bit differently. In general to provide and share the same code-base for different platforms is doable and not a huge deal.</p>

<p>If you would like to support single file deployment – there are special steps you need to consider and take to enable assembly embedded resource delivery via new virtual path provider and resource virtual file classes.</p>

<p>Would be also great if EPiServer provide NuGet feed or something similar mechanism for delivering AddOn modules for any developers than developers.</p>

<p>Hope this helps!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Add-On" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="add-on" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[EPiServer scheduled jobs list in larger enterprise scale projects may get huge enough in order not to be able to overview them.]]></summary></entry><entry><title type="html">Matching the Patterns</title><link href="https://tech-fellow.eu/2013/09/10/matching-the-patterns/" rel="alternate" type="text/html" title="Matching the Patterns" /><published>2013-09-10T00:45:00+03:00</published><updated>2013-09-10T00:45:00+03:00</updated><id>https://tech-fellow.eu/2013/09/10/matching-the-patterns</id><content type="html" xml:base="https://tech-fellow.eu/2013/09/10/matching-the-patterns/"><![CDATA[<p>Cna yuo read this?</p>

<p>Aiccdrong to recent sefiinctic resarech fro us to be able to read teh text teh only ipmort tihng is that first adn teh last ltteer in a word aer in teh rgiht place. Teh rest of teh letetrs aucatlly does nto matter. It could be really teh gtearest of teh mssees adn we still would be able to read teh text. Your barin R-mdoe engine is able to mtach teh petatrn bsaed in teh meerst famegrnt of teh ptetarn in irneetst. Even text is taltoly msseed up yuo cna still read wohtiut a pbrloem. This is psibosle bceuase hmuan mind is nto riedang eevry letter by iestlf btu a word as wohle. It means that riadeng speed cna be insacered even more by tkiang pcicrtaes to rieongcze prteatns in wrods fstaer adn nto to read eevry single ltteer.</p>

<p>I find it rlaely aiamzng!</p>

<p>By teh wya code bleow wsa used as brain pictarce uinsg rcieursve to sfufhle this text so yuo cna mtach pattrens adn nto read each lteter in word btu word isletf:</p>

<div class="language-fsharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
</pre></td><td class="rouge-code"><pre><span class="k">open</span> <span class="nc">System</span>
<span class="k">open</span> <span class="nn">System</span><span class="p">.</span><span class="nc">Linq</span>

<span class="k">let</span> <span class="n">marks</span> <span class="p">=</span> <span class="p">[</span><span class="s2">","</span><span class="p">;</span> <span class="s2">"."</span><span class="p">;</span> <span class="s2">"?"</span><span class="p">;</span> <span class="s2">"!"</span><span class="p">;</span> <span class="s2">"?!"</span><span class="p">]</span>
<span class="k">let</span> <span class="n">rnd</span> <span class="p">=</span> <span class="k">new</span> <span class="nc">Random</span><span class="bp">()</span>

<span class="k">let</span> <span class="k">rec</span> <span class="n">insert</span> <span class="n">v</span> <span class="n">i</span> <span class="n">l</span> <span class="p">=</span>
    <span class="k">match</span> <span class="n">i</span><span class="p">,</span> <span class="n">l</span> <span class="k">with</span>
    <span class="p">|</span> <span class="mi">0</span><span class="p">,</span> <span class="n">h</span> <span class="p">-&gt;</span> <span class="n">v</span><span class="p">::</span><span class="n">h</span>
    <span class="p">|</span> <span class="n">i</span><span class="p">,</span> <span class="n">h</span><span class="p">::</span><span class="n">t</span> <span class="p">-&gt;</span> <span class="n">h</span><span class="p">::</span><span class="n">insert</span> <span class="n">v</span> <span class="p">(</span><span class="n">i</span> <span class="p">-</span> <span class="mi">1</span><span class="p">)</span> <span class="n">t</span>
    <span class="p">|</span> <span class="o">_,</span> <span class="bp">[]</span> <span class="p">-&gt;</span> <span class="n">failwith</span> <span class="s2">"index out of range"</span>

<span class="k">let</span> <span class="k">rec</span> <span class="n">remove</span> <span class="n">i</span> <span class="n">l</span> <span class="p">=</span>
    <span class="k">match</span> <span class="n">i</span><span class="p">,</span> <span class="n">l</span> <span class="k">with</span>
    <span class="p">|</span> <span class="mi">0</span><span class="p">,</span> <span class="n">h</span><span class="p">::</span><span class="n">t</span> <span class="p">-&gt;</span> <span class="n">t</span>
    <span class="p">|</span> <span class="n">i</span><span class="p">,</span> <span class="n">h</span><span class="p">::</span><span class="n">t</span> <span class="p">-&gt;</span> <span class="n">h</span><span class="p">::</span><span class="n">remove</span> <span class="p">(</span><span class="n">i</span> <span class="p">-</span> <span class="mi">1</span><span class="p">)</span> <span class="n">t</span>
    <span class="p">|</span> <span class="o">_,</span> <span class="bp">[]</span> <span class="p">-&gt;</span> <span class="n">failwith</span> <span class="s2">"index out of range"</span>

<span class="k">let</span> <span class="n">shuffleWord</span> <span class="p">(</span><span class="n">input</span><span class="p">:</span><span class="kt">string</span><span class="p">)</span> <span class="p">=</span>
    <span class="k">let</span> <span class="n">result</span> <span class="p">=</span> <span class="nn">Array</span><span class="p">.</span><span class="n">create</span> <span class="n">input</span><span class="p">.</span><span class="nc">Length</span> <span class="s2">"00"</span>

    <span class="k">let</span> <span class="k">rec</span> <span class="p">_</span><span class="n">shuffle</span> <span class="p">(</span><span class="n">inp</span><span class="p">:</span><span class="kt">list</span><span class="p">&lt;</span><span class="kt">char</span><span class="o">&gt;)</span> <span class="n">ix</span> <span class="p">=</span>
        <span class="k">match</span> <span class="n">ix</span> <span class="k">with</span>
        <span class="p">|</span> <span class="mi">0</span> <span class="p">-&gt;</span> <span class="p">[</span><span class="n">inp</span><span class="o">.[</span><span class="mi">0</span><span class="o">]]</span>
        <span class="p">|</span> <span class="p">_</span> <span class="p">-&gt;</span>
            <span class="k">let</span> <span class="n">idx</span> <span class="p">=</span> <span class="n">rnd</span><span class="p">.</span><span class="nc">Next</span><span class="p">(</span><span class="n">inp</span><span class="p">.</span><span class="nc">Length</span> <span class="p">-</span> <span class="mi">1</span><span class="p">)</span>
            <span class="n">inp</span><span class="o">.[</span><span class="n">idx</span><span class="p">]</span> <span class="p">::</span> <span class="p">_</span><span class="n">shuffle</span> <span class="p">(</span><span class="n">remove</span> <span class="n">idx</span> <span class="n">inp</span><span class="p">)</span> <span class="p">(</span><span class="n">ix</span> <span class="p">-</span> <span class="mi">1</span><span class="p">)</span>

    <span class="k">let</span> <span class="n">w</span> <span class="p">=</span>
        <span class="k">match</span> <span class="n">input</span><span class="p">.</span><span class="nc">Length</span> <span class="k">with</span>
        <span class="p">|</span> <span class="n">l</span> <span class="k">when</span> <span class="n">l</span> <span class="p">=</span> <span class="mi">1</span> <span class="p">-&gt;</span> <span class="p">[</span><span class="n">input</span><span class="o">.[</span><span class="mi">0</span><span class="o">]]</span>
        <span class="p">|</span> <span class="n">l</span> <span class="k">when</span> <span class="n">l</span> <span class="p">&lt;</span> <span class="mi">3</span> <span class="p">-&gt;</span> <span class="p">[</span><span class="n">input</span><span class="o">.[</span><span class="mi">0</span><span class="o">];</span> <span class="n">input</span><span class="o">.[</span><span class="mi">1</span><span class="o">]]</span>
        <span class="p">|</span> <span class="n">l</span> <span class="k">when</span> <span class="n">l</span> <span class="p">=</span> <span class="mi">3</span> <span class="p">-&gt;</span> <span class="p">[</span><span class="n">input</span><span class="o">.[</span><span class="mi">0</span><span class="o">];</span> <span class="n">input</span><span class="o">.[</span><span class="mi">2</span><span class="o">];</span> <span class="n">input</span><span class="o">.[</span><span class="mi">1</span><span class="o">]]</span>
        <span class="p">|</span> <span class="p">_</span> <span class="p">-&gt;</span>
            <span class="k">let</span> <span class="n">midPart</span> <span class="p">=</span> <span class="n">input</span><span class="o">.[</span><span class="mi">1</span> <span class="p">..</span> <span class="n">input</span><span class="p">.</span><span class="nc">Length</span> <span class="p">-</span> <span class="mi">2</span><span class="p">]</span> <span class="p">|&gt;</span> <span class="nn">List</span><span class="p">.</span><span class="n">ofSeq</span>
            <span class="n">input</span><span class="o">.[</span><span class="mi">0</span><span class="p">]</span> <span class="p">::</span> <span class="o">(_</span><span class="n">shuffle</span> <span class="n">midPart</span> <span class="p">(</span><span class="n">midPart</span><span class="p">.</span><span class="nc">Length</span> <span class="p">-</span> <span class="mi">1</span> <span class="o">))</span> <span class="o">@</span> <span class="p">[</span><span class="n">input</span><span class="p">.</span><span class="nc">Last</span><span class="bp">()</span><span class="p">]</span>

    <span class="n">w</span>
    <span class="p">|&gt;</span> <span class="nn">List</span><span class="p">.</span><span class="n">map</span> <span class="p">(</span><span class="k">fun</span> <span class="p">(</span><span class="n">c</span><span class="p">:</span><span class="kt">char</span><span class="p">)</span> <span class="p">-&gt;</span> <span class="n">c</span><span class="p">.</span><span class="nc">ToString</span><span class="bp">()</span><span class="p">)</span>
    <span class="p">|&gt;</span> <span class="nn">List</span><span class="p">.</span><span class="n">reduce</span> <span class="o">(+)</span>

<span class="k">let</span> <span class="k">rec</span> <span class="n">shuffle</span> <span class="p">(</span><span class="n">input</span><span class="p">:</span><span class="kt">string</span><span class="p">)</span> <span class="p">=</span>
    <span class="k">let</span> <span class="k">rec</span> <span class="p">_</span><span class="n">clear</span> <span class="p">(</span><span class="n">input</span><span class="p">:</span><span class="kt">string</span><span class="p">)</span> <span class="n">marks</span> <span class="p">=</span>
        <span class="k">match</span> <span class="n">marks</span> <span class="k">with</span>
        <span class="p">|</span> <span class="bp">[]</span> <span class="p">-&gt;</span> <span class="p">[</span><span class="n">input</span><span class="p">]</span>
        <span class="p">|</span> <span class="n">h</span><span class="p">::</span><span class="n">t</span> <span class="p">-&gt;</span>
            <span class="k">if</span> <span class="n">input</span><span class="p">.</span><span class="nc">EndsWith</span><span class="p">(</span><span class="n">h</span><span class="p">)</span> <span class="k">then</span> <span class="p">(</span><span class="n">input</span><span class="p">.</span><span class="nc">Substring</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">input</span><span class="p">.</span><span class="nc">Length</span> <span class="p">-</span> <span class="mi">1</span><span class="o">))</span> <span class="p">::</span> <span class="p">[</span><span class="n">h</span><span class="p">]</span>
            <span class="k">else</span> <span class="p">_</span><span class="n">clear</span> <span class="n">input</span> <span class="n">t</span>

    <span class="k">let</span> <span class="k">rec</span> <span class="p">_</span><span class="n">shuffle</span> <span class="kt">list</span> <span class="p">=</span>
        <span class="k">match</span> <span class="kt">list</span> <span class="k">with</span>
        <span class="p">|</span> <span class="bp">[]</span> <span class="p">-&gt;</span> <span class="bp">[]</span>
        <span class="p">|</span> <span class="n">h</span><span class="p">::</span><span class="n">t</span> <span class="p">-&gt;</span> <span class="o">((_</span><span class="n">clear</span> <span class="n">h</span> <span class="n">marks</span><span class="p">)</span> <span class="p">|&gt;</span> <span class="nn">List</span><span class="p">.</span><span class="n">map</span> <span class="n">shuffleWord</span><span class="p">)</span> <span class="o">@</span> <span class="p">_</span><span class="n">shuffle</span> <span class="n">t</span>

    <span class="k">let</span> <span class="n">arrayOfWords</span> <span class="p">=</span> <span class="p">(</span><span class="n">input</span><span class="p">.</span><span class="nc">Split</span><span class="o">([|</span><span class="s2">" "</span><span class="o">|],</span> <span class="nn">StringSplitOptions</span><span class="p">.</span><span class="nc">None</span><span class="p">)</span> <span class="p">|&gt;</span> <span class="nn">List</span><span class="p">.</span><span class="n">ofArray</span><span class="p">)</span>
    <span class="p">_</span><span class="n">shuffle</span> <span class="n">arrayOfWords</span> <span class="p">|&gt;</span> <span class="nn">List</span><span class="p">.</span><span class="n">reduce</span> <span class="p">(</span><span class="k">fun</span> <span class="n">a</span> <span class="n">b</span> <span class="p">-&gt;</span> <span class="n">a</span> <span class="o">+</span> <span class="s2">" "</span> <span class="o">+</span> <span class="n">b</span><span class="p">)</span>


<span class="p">&gt;</span> <span class="n">shuffle</span> <span class="s2">"By the way code below was used as brain practice to shuffle this text."</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="F#" /><category term=".net" /><category term="f#" /><summary type="html"><![CDATA[Cna yuo read this?]]></summary></entry><entry><title type="html">Community Attribute Builder final</title><link href="https://tech-fellow.eu/2012/06/09/community-attribute-builder-final/" rel="alternate" type="text/html" title="Community Attribute Builder final" /><published>2012-06-09T20:15:00+03:00</published><updated>2012-06-09T20:15:00+03:00</updated><id>https://tech-fellow.eu/2012/06/09/community-attribute-builder-final</id><content type="html" xml:base="https://tech-fellow.eu/2012/06/09/community-attribute-builder-final/"><![CDATA[<p>If you are working with Relate+ platform most probably you are using entities attributes to attach some additional info to particular entity type. This is a great way to extend built-in functionality but however involved a bit of manual work:</p>

<ul>
  <li>You have to define attribute for each of the entity in Relate+ administrative UI (which honestly speaking could be made more user friendly).</li>
  <li>You have to refer to the attribute via stringly-typed interface.</li>
</ul>

<p>Latter for me is most embarrassing.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="n">instance</span><span class="p">.</span><span class="nf">SetAttributeValue</span><span class="p">(</span><span class="s">"attributeName"</span><span class="p">,</span> <span class="n">attributeValue</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This approach could give you few real scenarios where such is unacceptable:</p>

<ul>
  <li>When you will margin for a grammar error when typing attribute name – that could be discovered only during runtime.</li>
  <li>You cannot use static code analysis tools. Like to search for all attribute usages.</li>
  <li>You cannot use some of the refactoring tools –&gt; like rename attribute name.</li>
  <li>You can easily change type of the attribute and forget about code that uses that, effect –&gt; runtime error(s).</li>
  <li>Use cannot leverage all the power of Visual Studio (for instance to provide Intellisense over available attributes)</li>
</ul>

<p>So therefore I created package that should relief tasks with Community entity’s attributes – <strong>Community Attribute Builder</strong>.</p>

<p>There were already some posts on this topic <a href="http://world.episerver.com/Blogs/Valdis-Iljuconoks/Dates/2012/2/Synchronize-Relate-entitys-attributes-in-a-strongly-typed-way">here</a>, <a href="http://world.episerver.com/Blogs/Valdis-Iljuconoks/Dates/2012/2/Metadata-driven-Community-queries">here</a> and <a href="http://world.episerver.com/Blogs/Valdis-Iljuconoks/Dates/2012/5/Limit-assemblies-for-scanning-for-Community-Entity-Attributes-v03">there</a>. Latest version (1.0) is out and this is just a summary of what’s supported.</p>

<ol>
  <li>Describe community entity’s attributes in code. Those attributes defined in metadata class are synced during application start-up and added to the target entity:</li>
</ol>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="p">[</span><span class="nf">CommunityEntity</span><span class="p">(</span><span class="n">TargetType</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="n">IUser</span><span class="p">))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">SampleAttributeMetadata</span>
<span class="p">{</span>
    <span class="p">[</span><span class="n">CommunityEntityMetadata</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">virtual</span> <span class="n">IList</span><span class="p">&lt;</span><span class="n">SampleType</span><span class="p">&gt;</span> <span class="n">SampleAttribute</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ol>
  <li>Limit scanning of the assemblies:</li>
</ol>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;configuration&gt;</span>
  <span class="nt">&lt;configSections&gt;</span>
    <span class="nt">&lt;section</span> <span class="na">name=</span><span class="s">"entityAttributeBuilder"</span> <span class="na">type=</span><span class="s">"Geta.Community.EntityAttributeBuilder.EntityAttributeBuilderConfiguration, Geta.Community.EntityAttributeBuilder"</span> <span class="nt">/&gt;</span>
  <span class="nt">&lt;/configSections&gt;</span>

  <span class="nt">&lt;entityAttributeBuilder&gt;</span>
    <span class="nt">&lt;scanAssembly&gt;</span>
      <span class="nt">&lt;add</span> <span class="na">assembly=</span><span class="s">"EntityAttributes"</span> <span class="nt">/&gt;</span>
      <span class="nt">&lt;remove</span> <span class="na">assembly=</span><span class="s">"RemoveAssembly"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;/scanAssembly&gt;</span>
  <span class="nt">&lt;/entityAttributeBuilder&gt;</span>

<span class="nt">&lt;/configuration&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ol>
  <li>You can set or get entity’s attribute value(s) using strongly-typed interface.</li>
</ol>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">metadata</span> <span class="p">=</span> <span class="n">instance</span><span class="p">.</span><span class="n">AsAttributeExtendable</span><span class="p">&lt;</span><span class="n">SampleAttributeMetadata</span><span class="p">&gt;();</span>
<span class="n">metadata</span><span class="p">.</span><span class="n">SampleAttribute</span> <span class="p">=</span> <span class="k">null</span><span class="p">;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ol>
  <li>Support for strongly typed queries</li>
</ol>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">query</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">UserQuery</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">qmetadata</span> <span class="p">=</span> <span class="n">query</span><span class="p">.</span><span class="n">AsMetadataQuery</span><span class="p">&lt;</span><span class="n">SampleAttributeMetadata</span><span class="p">&gt;();</span>
<span class="n">qmetadata</span><span class="p">[</span><span class="n">m</span> <span class="p">=&gt;</span> <span class="n">m</span><span class="p">.</span><span class="n">SampleAttribute</span><span class="p">]</span> <span class="p">=</span> <span class="k">new</span> <span class="n">StringCriterion</span> <span class="p">{</span> <span class="n">Value</span> <span class="p">=</span> <span class="s">"the attribute value"</span> <span class="p">};</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ol>
  <li>Added support for IList<T> type attributes. You can assign via local variable assignment and modification or using line modifications.</T></li>
</ol>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">entity</span> <span class="p">=</span> <span class="n">instance</span><span class="p">.</span><span class="n">AsAttributeExtendable</span><span class="p">&lt;</span><span class="n">SampleAttributeMetadata</span><span class="p">&gt;();</span>

<span class="c1">// getter</span>
<span class="kt">var</span> <span class="n">collection</span> <span class="p">=</span> <span class="n">entity</span><span class="p">.</span><span class="n">SampleAttribute</span><span class="p">;</span>
<span class="n">collection</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">new</span> <span class="nf">SampleType</span><span class="p">(</span><span class="m">100</span><span class="p">));</span>
<span class="c1">// setter</span>
<span class="n">entity</span><span class="p">.</span><span class="n">SampleAttribute</span> <span class="p">=</span> <span class="n">collection</span><span class="p">;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>or you can use more convenient syntax:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">entity</span> <span class="p">=</span> <span class="n">instance</span><span class="p">.</span><span class="n">AsAttributeExtendable</span><span class="p">&lt;</span><span class="n">SampleAttributeMetadata</span><span class="p">&gt;();</span>
<span class="n">entity</span><span class="p">.</span><span class="n">SampleAttribute</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">new</span> <span class="nf">SampleType</span><span class="p">(</span><span class="m">100</span><span class="p">));</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Rename, deletion and content migration for the community entity attributes need to me done manually.</p>

<p>Can be found <a href="http://nuget.episerver.com/en/OtherPages/Package/?packageId=Geta.Community.EntityAttributeBuilder">here</a> (or search by “community” in NuGet package manager).</p>

<p>Hope this helps!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Add-On" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="add-on" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[If you are working with Relate+ platform most probably you are using entities attributes to attach some additional info to particular entity type. This is a great way to extend built-in functionality but however involved a bit of manual work:]]></summary></entry><entry><title type="html">Limit assemblies for scanning for Community Entity Attributes (v0.3)</title><link href="https://tech-fellow.eu/2012/05/16/limit-assemblies-for-scanning-for-community-entity-attributes/" rel="alternate" type="text/html" title="Limit assemblies for scanning for Community Entity Attributes (v0.3)" /><published>2012-05-16T10:35:00+03:00</published><updated>2012-05-16T10:35:00+03:00</updated><id>https://tech-fellow.eu/2012/05/16/limit-assemblies-for-scanning-for-community-entity-attributes</id><content type="html" xml:base="https://tech-fellow.eu/2012/05/16/limit-assemblies-for-scanning-for-community-entity-attributes/"><![CDATA[<p>If you are working with EPiServer Relate+ product then you know that there is a extendable entities in the framework that allows you to add new attributes to existing entities to store some additional info if required.</p>

<p>Default approach to set and get values from those attributes are using stringly-typed interface, like:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">return</span> <span class="n">user</span><span class="p">.</span><span class="n">GetAttributeValue</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;(</span><span class="s">"SkypeUsername"</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>To get rid of this and to access entity in strongly-typed manner can be accomplished either using:</p>

<ul>
  <li>CustomEntityProvider</li>
  <li>Or by using some custom interceptors.</li>
</ul>

<p>Later one is implemented in <code class="language-plaintext highlighter-rouge">Geta.Community.EntityAttributeBuilder</code> library. Using this lib you can get access to entities attributes in following manner:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">userAttr</span> <span class="p">=</span> <span class="n">user</span><span class="p">.</span><span class="n">AsAttributeExtendable</span><span class="p">&lt;</span><span class="n">UserAttributes</span><span class="p">&gt;();</span>
<span class="n">userAttr</span><span class="p">.</span><span class="n">FatherName</span> <span class="p">=</span> <span class="s">"John"</span><span class="p">;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Library had to scan all the assemblies in current application domain and look for particular types decorated with known attributes for <code class="language-plaintext highlighter-rouge">Geta.Community.EntityAttributeBuilder</code>.</p>

<p>Building and using this library in a large projects where assemblies may reach up to 250 and more may cause some startup delays as it was scanning everything and trying to sync attributes. Usually such meta data is stored in few assemblies and no need for extra all assemblies scanning process to find ones.</p>

<p>Latest version of <code class="language-plaintext highlighter-rouge">Geta.Community.EntityAttributeBuilder</code> library (0.3) is released with feature that limits scanning process to known list of assemblies. One that you can found in <code class="language-plaintext highlighter-rouge">&lt;episerver.framework&gt;</code> element <code class="language-plaintext highlighter-rouge">&lt;scanAssembly&gt;</code>.</p>

<p>So using latest version you can now configure to limit scanning. Add this to your configuration file:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;configSections&gt;</span>
  <span class="nt">&lt;section</span> <span class="na">name=</span><span class="s">"entityAttributeBuilder"</span> <span class="na">type=</span><span class="s">"Geta.Community.EntityAttributeBuilder.EntityAttributeBuilderConfiguration, Geta.Community.EntityAttributeBuilder"</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;/configSections&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Add add configuration section:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;entityAttributeBuilder&gt;</span>
  <span class="nt">&lt;scanAssembly&gt;</span>
    <span class="nt">&lt;add</span> <span class="na">assembly=</span><span class="s">"YourAssemblyNameWhereAttributesAreLocated"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;add</span> <span class="na">assembly=</span><span class="s">"YourAnotherAssemblyName"</span> <span class="nt">/&gt;</span>
  <span class="nt">&lt;/scanAssembly&gt;</span>
<span class="nt">&lt;/entityAttributeBuilder&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Package as usual can be found in <a href="https://nuget.episerver.com">nuget.episerver.com</a> (Id: <code class="language-plaintext highlighter-rouge">Geta.Community.EntityAttributeBuilder</code>).</p>

<p>Hope this helps!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[If you are working with EPiServer Relate+ product then you know that there is a extendable entities in the framework that allows you to add new attributes to existing entities to store some additional info if required.]]></summary></entry><entry><title type="html">Analyzing EPiServer page type source code</title><link href="https://tech-fellow.eu/2012/03/02/analyzing-episerver-page-type-source-code/" rel="alternate" type="text/html" title="Analyzing EPiServer page type source code" /><published>2012-03-02T05:15:00+02:00</published><updated>2012-03-02T05:15:00+02:00</updated><id>https://tech-fellow.eu/2012/03/02/analyzing-episerver-page-type-source-code</id><content type="html" xml:base="https://tech-fellow.eu/2012/03/02/analyzing-episerver-page-type-source-code/"><![CDATA[<p>Creating pages in EPiServer using <code class="language-plaintext highlighter-rouge">PageTypeBuilder</code> is pretty simple and very convenient. However sometimes I run into issue that forgetting to mark page type property as virtual (I suppose this is required for property access interception).</p>

<p>Playing around <code class="language-plaintext highlighter-rouge">Microsoft Roslyn</code> project I came up with an idea to analyze the source code for page type builder classes and provide some feedback on analyze results.</p>

<p><img src="/assets/img/2012/03/1.png" alt="" /></p>

<p>Hovering over the property declaration VS gives you a small tooltip that property has to be marked as virtual otherwise runtime exception will be thrown.</p>

<p><img src="/assets/img/2012/03/2.png" alt="" /></p>

<p>Plugin scans only classes that are decorated with <code class="language-plaintext highlighter-rouge">PageType</code> attribute and  properties decorated with <code class="language-plaintext highlighter-rouge">PageTypeProperty</code> attributes.</p>

<p>There is a space to expand and enrich functionality of such a plugin as for instance develop some <code class="language-plaintext highlighter-rouge">FxCop</code> rules designed for PTB specifics, <code class="language-plaintext highlighter-rouge">CodeActions</code> to execute if code issue is found (e.g. converting property to virtual property).</p>

<p>Currently it’s only sandbox project utilizing <code class="language-plaintext highlighter-rouge">Roslyn</code> possibilities and can be distributed as VS extension (<code class="language-plaintext highlighter-rouge">.vsix</code>).</p>

<p>This is just a sneak preview of what’s could be accomplish but I wanted to ask you guys is this something that would be useful and are interested in?</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[Creating pages in EPiServer using PageTypeBuilder is pretty simple and very convenient. However sometimes I run into issue that forgetting to mark page type property as virtual (I suppose this is required for property access interception).]]></summary></entry><entry><title type="html">“Stringly typed” Composer functions</title><link href="https://tech-fellow.eu/2012/01/21/stringly-typed-composer-function/" rel="alternate" type="text/html" title="“Stringly typed” Composer functions" /><published>2012-01-21T23:25:00+02:00</published><updated>2012-01-21T23:25:00+02:00</updated><id>https://tech-fellow.eu/2012/01/21/stringly-typed-composer-function</id><content type="html" xml:base="https://tech-fellow.eu/2012/01/21/stringly-typed-composer-function/"><![CDATA[<p>When you need to create EPiServer Composer block that requires some properties we usually use Composer functions that basically are defined as page types. Ted has a really good blog post on step-by-step walkthrough how to create Composer functions using <code class="language-plaintext highlighter-rouge">PageTypeBuilder</code>.</p>

<p>Story today behind Composer functions is about so called “stringly-typed interface” approach :)</p>

<p>Somewhere up in your inheritance path you will have a base class called <code class="language-plaintext highlighter-rouge">Dropit.Extensions.Core.BaseContentFunction</code> which will give you possibility to access designed properties and its assigned value on the <code class="language-plaintext highlighter-rouge">Composer</code> page. Code for accessing property value usually looks like this:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">count</span> <span class="p">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">ContentFunctionData</span><span class="p">[</span><span class="s">"MyFunctionItemCount"</span><span class="p">];</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>It would be cool to write something like this:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">count</span> <span class="p">=</span> <span class="nf">FunctionData</span><span class="p">(</span><span class="n">f</span> <span class="p">=&gt;</span> <span class="n">f</span><span class="p">.</span><span class="n">MyFunctionItemCount</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This is pretty simplified sample code. Anyway to follow more defensive programming practices we should after receiving value back we should check for null, if return value is not null, then we can cast it to <code class="language-plaintext highlighter-rouge">PropertyData</code> and check Value property to finally get access to property value.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="k">if</span> <span class="p">(</span><span class="n">count</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">pd</span> <span class="p">=</span> <span class="n">count</span> <span class="k">as</span> <span class="n">PropertyData</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">pd</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">finalValue</span> <span class="p">=</span> <span class="p">((</span><span class="n">PropertyData</span><span class="p">)</span><span class="n">pd</span><span class="p">).</span><span class="n">Value</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The issue here is around indexer accessor that we use to access property data.</p>

<p>It would be great to have approximately the same experience as accessing page properties when using <code class="language-plaintext highlighter-rouge">PageTypeBuilder</code>.</p>

<p>This can be easily implemented using lambda expressions.</p>

<p>We should implement some kind of base class to be used for providing lambda expression approach when accessing property data from composer block.</p>

<p>Class will be inheriting from <code class="language-plaintext highlighter-rouge">BaseContentFunction</code>.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">ComposerContentFunctionBase</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;</span> <span class="p">:</span> <span class="n">BaseContentFunction</span> <span class="k">where</span> <span class="n">T</span> <span class="p">:</span> <span class="n">ComposerFunctionBase</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Class <code class="language-plaintext highlighter-rouge">ComposerFunctionBase</code> is base class mentioned in Ted’s blog which is required if building Composer functions with page type builder.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">abstract</span> <span class="k">class</span> <span class="nc">ComposerFunctionBase</span> <span class="p">:</span> <span class="n">TypedPageData</span>
<span class="p">{</span>
    <span class="c1">/// Required by Composer - do not remove</span>
    <span class="p">[</span><span class="nf">PageTypeProperty</span><span class="p">(</span><span class="n">Type</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="n">ExtensionFunctionProperty</span><span class="p">),</span> <span class="n">DefaultValueType</span> <span class="p">=</span> <span class="n">DefaultValueType</span><span class="p">.</span><span class="n">None</span><span class="p">,</span> <span class="n">DefaultValue</span> <span class="p">=</span> <span class="s">""</span><span class="p">,</span>
        <span class="n">SortOrder</span> <span class="p">=</span> <span class="m">101</span><span class="p">,</span> <span class="n">DisplayInEditMode</span> <span class="p">=</span> <span class="k">false</span><span class="p">,</span> <span class="n">Searchable</span> <span class="p">=</span> <span class="k">false</span><span class="p">,</span> <span class="n">UniqueValuePerLanguage</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span> <span class="n">Tab</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="n">ComposerTab</span><span class="p">))]</span>
    <span class="k">public</span> <span class="k">virtual</span> <span class="kt">string</span> <span class="n">ExtensionContentFunctionProperty</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="c1">/// Required by Composer - do not remove</span>
    <span class="p">[</span><span class="nf">PageTypeProperty</span><span class="p">(</span><span class="n">UniqueValuePerLanguage</span> <span class="p">=</span> <span class="k">false</span><span class="p">,</span> <span class="n">DefaultValueType</span> <span class="p">=</span> <span class="n">DefaultValueType</span><span class="p">.</span><span class="n">None</span><span class="p">,</span> <span class="n">DefaultValue</span> <span class="p">=</span> <span class="s">"false"</span><span class="p">,</span> <span class="n">SortOrder</span> <span class="p">=</span> <span class="m">122</span><span class="p">,</span>
        <span class="n">Searchable</span> <span class="p">=</span> <span class="k">false</span><span class="p">,</span> <span class="n">DisplayInEditMode</span> <span class="p">=</span> <span class="k">false</span><span class="p">,</span> <span class="n">Tab</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="n">ComposerTab</span><span class="p">))]</span>
    <span class="k">public</span> <span class="k">virtual</span> <span class="kt">bool</span> <span class="n">NeverUsedProperty</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So after implementing base class we are able to derive some child and make our Composer user control.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">partial</span> <span class="k">class</span> <span class="nc">MyComposerControl</span> <span class="p">:</span> <span class="n">ComposerContentFunctionBase</span><span class="p">&lt;</span><span class="n">MyComposerFunction</span><span class="p">&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Next thing is to write implementation of <code class="language-plaintext highlighter-rouge">FunctionData</code> method in <code class="language-plaintext highlighter-rouge">ComposerContentFunctionBase</code> class to accept lambda expression for accessing composer content function data.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="n">R</span> <span class="n">FunctionData</span><span class="p">&lt;</span><span class="n">R</span><span class="p">&gt;(</span><span class="n">Expression</span><span class="p">&lt;</span><span class="n">Func</span><span class="p">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">R</span><span class="p">&gt;&gt;</span> <span class="n">expression</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">expression</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="s">"expression"</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="kt">object</span> <span class="n">result</span> <span class="p">=</span> <span class="k">null</span><span class="p">;</span>
    <span class="kt">var</span> <span class="n">expressionBody</span> <span class="p">=</span> <span class="n">expression</span><span class="p">.</span><span class="n">Body</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">expressionBody</span><span class="p">.</span><span class="n">NodeType</span> <span class="p">==</span> <span class="n">ExpressionType</span><span class="p">.</span><span class="n">MemberAccess</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">propertyName</span> <span class="p">=</span> <span class="p">((</span><span class="n">MemberExpression</span><span class="p">)</span><span class="n">expressionBody</span><span class="p">).</span><span class="n">Member</span><span class="p">.</span><span class="n">Name</span><span class="p">;</span>
        <span class="n">result</span> <span class="p">=</span> <span class="n">ContentFunctionData</span><span class="p">[</span><span class="n">propertyName</span><span class="p">];</span>
    <span class="p">}</span>

    <span class="c1">// if using PageType builders actual expression type to access PageType property will be substituted by Castle proxy</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">expressionBody</span><span class="p">.</span><span class="n">NodeType</span> <span class="p">==</span> <span class="n">ExpressionType</span><span class="p">.</span><span class="n">Convert</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(((</span><span class="n">UnaryExpression</span><span class="p">)</span><span class="n">expressionBody</span><span class="p">).</span><span class="n">Operand</span><span class="p">.</span><span class="n">NodeType</span> <span class="p">==</span> <span class="n">ExpressionType</span><span class="p">.</span><span class="n">MemberAccess</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="kt">var</span> <span class="n">propertyName</span> <span class="p">=</span> <span class="p">((</span><span class="n">MemberExpression</span><span class="p">)((</span><span class="n">UnaryExpression</span><span class="p">)</span><span class="n">expressionBody</span><span class="p">).</span><span class="n">Operand</span><span class="p">).</span><span class="n">Member</span><span class="p">.</span><span class="n">Name</span><span class="p">;</span>
            <span class="n">result</span> <span class="p">=</span> <span class="n">ContentFunctionData</span><span class="p">[</span><span class="n">propertyName</span><span class="p">];</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">result</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="k">default</span><span class="p">(</span><span class="n">R</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">if</span> <span class="p">((</span><span class="n">result</span> <span class="k">as</span> <span class="n">PropertyData</span><span class="p">)</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="k">default</span><span class="p">(</span><span class="n">R</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">if</span> <span class="p">(((</span><span class="n">PropertyData</span><span class="p">)</span><span class="n">result</span><span class="p">).</span><span class="n">Value</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="k">default</span><span class="p">(</span><span class="n">R</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="p">(</span><span class="n">R</span><span class="p">)((</span><span class="n">PropertyData</span><span class="p">)</span><span class="n">result</span><span class="p">).</span><span class="n">Value</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So what we are doing here? We are waiting for incoming parameter to be <code class="language-plaintext highlighter-rouge">Expression&lt;Func&lt;T, R&gt;&gt;</code>. Let’s split up into smaller pieces:</p>

<ol>
  <li>
    <p><code class="language-plaintext highlighter-rouge">T</code> is the <code class="language-plaintext highlighter-rouge">Composer</code> function data type we typed when implementing user control. So this will be incoming parameter of lambda expression.</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">R</code> is returning type from the lambda expression or data type of which function data property is defined.</p>
  </li>
</ol>

<p>So in this expression: <code class="language-plaintext highlighter-rouge">(f =&gt; f.MyFunctionItemCount)</code></p>

<p><code class="language-plaintext highlighter-rouge">f –&gt; T</code> (this is of type <code class="language-plaintext highlighter-rouge">MyComposerFunction</code>)</p>

<p><code class="language-plaintext highlighter-rouge">MyFunctionItemCount –&gt; R</code> (function property is defined as <code class="language-plaintext highlighter-rouge">int</code>).</p>

<ol>
  <li>
    <p>Then we are investigating given expression and looking for member access node. <strong>NB!</strong> This implementation is pretty simplified and does not handle more complex expressions that result in member access somehow.</p>
  </li>
  <li>
    <p>Expression investigation has 2 if statements. Second (when node type is of type <code class="language-plaintext highlighter-rouge">Convert</code>) is required because <code class="language-plaintext highlighter-rouge">Castle</code> proxies are behind the scene when using <code class="language-plaintext highlighter-rouge">PageTypeBuilder</code> and we need to dig deeper into expression to find member access expression. <strong>NB!</strong> This implementation handles only 1 level within expression tree. Probably not the best solution anyway.</p>
  </li>
  <li>
    <p>Then we are investigating collected result and returning the return value.</p>
  </li>
</ol>

<p>Now we can write expressins like this in out <code class="language-plaintext highlighter-rouge">Composer</code> function user control and get proper type casting also.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="kt">int</span> <span class="n">count</span> <span class="p">=</span> <span class="nf">FunctionData</span><span class="p">(</span><span class="n">f</span> <span class="p">=&gt;</span> <span class="n">f</span><span class="p">.</span><span class="n">MyFunctionItemCount</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>If you would like to get precise info whether editor supplied value for the function property or not we can always use Nullable types to get new method to work properly when returning <code class="language-plaintext highlighter-rouge">default(R)</code>.</p>

<p>Pretty simple solution but most probably not 100% bulletproof.</p>

<p>Hope this helps!</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[When you need to create EPiServer Composer block that requires some properties we usually use Composer functions that basically are defined as page types. Ted has a really good blog post on step-by-step walkthrough how to create Composer functions using PageTypeBuilder.]]></summary></entry><entry><title type="html">Handling page name in web address</title><link href="https://tech-fellow.eu/2011/11/28/handling-page-name-in-web-address/" rel="alternate" type="text/html" title="Handling page name in web address" /><published>2011-11-28T23:35:00+02:00</published><updated>2011-11-28T23:35:00+02:00</updated><id>https://tech-fellow.eu/2011/11/28/handling-page-name-in-web-address</id><content type="html" xml:base="https://tech-fellow.eu/2011/11/28/handling-page-name-in-web-address/"><![CDATA[<p>EPiServer provides a great feature to copy and paste pages in site structure and reuse already existing content or features of particular page as a basis for the new page. However during copy page name gets set to the same name as source page has and assigned some index to the name. So for instance if we take Alloy Tech sample site copying and later paste “Alloy Track” page to the same branch in the site structure new page will get page name in address “Alloy-Track1”.</p>

<p><img src="/assets/img/2011/10/1.png" alt="" /></p>

<p>This problem also applies to the process of rename of the page. Web address remains old one.</p>

<p>However fortunately there is another great feature in EPiServer – called “Rebuild Name for Web Addresses” which iterates over all pages and looks for these kind of pages and tries to fix them. If I leave name of the new page the same as source page then there would be two identical pages in the same branch – then of course rebuilding names would not fix that. If I rename the page to reflect new content name for the web address still will remain the same as assigned during copying it. Then rebuild will fix that and page web address will be renamed.</p>

<p>However there is a problem if this rebuild takes part after some time when site has been published in the air and users have been using the site for a while. Bookmarks, favorites, etc will be broken.</p>

<p>EPiServer module <code class="language-plaintext highlighter-rouge">Geta.ErrorHandler</code> latest version provides possibility to preserve these previous addresses for pages during rebuild and guarantee that users will be redirected to the new address even they will be asking for the previous one.</p>

<p>Module actually is too far from the complex implementation.</p>

<p>EPiServer provides incredible way to plug some custom code in almost any processing pipeline or listen to any event occurring in the system.</p>

<p>By inheriting from <code class="language-plaintext highlighter-rouge">EPiServer.PlugIn.PlugInAttribute</code> you can do everything you need to hook somewhere in static <code class="language-plaintext highlighter-rouge">Start()</code> method.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">PageUrlRenameHandler</span> <span class="p">:</span> <span class="n">PlugInAttribute</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">Start</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">DataFactory</span><span class="p">.</span><span class="n">Instance</span><span class="p">.</span><span class="n">PublishingPage</span> <span class="p">+=</span> <span class="n">OnPublishingPage</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So to catch pages that are changed during page name rebuild we subscribe to publishing event.</p>

<p>During publishing event handler we can get access to old name and new name of the page.</p>

<p>This will give old address of the page.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>e.Page.LinkURL
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So by using friendly URL rewriter module we can get friendly URL for the page.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>Global.UrlRewriteProvider.ConvertToExternal(oldUrl, e.Page.PageLink, Encoding.UTF8)
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This will give new name of the page in web address (e is parameter PageEventArgs in event handler method).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>e.Page.URLSegment
</pre></td></tr></tbody></table></code></pre></div></div>

<p>So using old URL and new segment we can make a decision either page is just saved and no web address rebuild has been invoked (if old and new address match) or page is being rebuilt (old and new URL segments do not match).</p>

<p>If page is being rebuilt then we just iterate over all language branches and using PageData.LinkURL property get old URL address and write it down that that particular page.</p>

<p>We are using DDS entity with following attributes to store set of old URLs attached to that particular page.</p>

<p><img src="/assets/img/2011/10/2.png" alt="" /></p>

<p>We are storing all previous URLs for particular page in appropriate language branch.</p>

<p><strong>NB!</strong> The trick in rebuilding process is that EPiServer is touching <em>only</em> that particular page that has to be renamed. Child pages remain untouched.</p>

<p>For instance suppose we have following page structure:</p>

<p><img src="/assets/img/2011/10/3.png" alt="" /></p>

<p>And web address for page “1.2” would be <code class="language-plaintext highlighter-rouge">“/Parent-page/First-child/12”</code>.</p>

<p>If we rename <code class="language-plaintext highlighter-rouge">“Parent page”</code> to <code class="language-plaintext highlighter-rouge">“New parent page”</code> then EPiServer rebuild process will republish only this particular page leaving all child pages untouched.</p>

<p>We need to take care of rebuilding all child pages as well to write old URL for each of them – so the old web address for “1.3” page should still start with <code class="language-plaintext highlighter-rouge">“/Parent-page/..”</code>.</p>

<p>Therefore we just process all child pages in all language branches recursively.</p>

<p>Rename the top level page in a large site could influence page rebuild process performance a lot. That’s the down side of this approach.</p>

<p>Fortunately this feature can be turned off and <code class="language-plaintext highlighter-rouge">Geta.ErrorHandler</code> could be used to perform its original task – handling not found and other server side errors in friendly fashion.</p>

<p>Previous URL redirect feature can be disabled in <code class="language-plaintext highlighter-rouge">“Plug-In Manager”</code> page in admin mode.</p>

<p><img src="/assets/img/2011/10/4.png" alt="" /></p>

<p>Hope this helps!</p>

<p>Available via nuget.episerver.com</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[EPiServer provides a great feature to copy and paste pages in site structure and reuse already existing content or features of particular page as a basis for the new page. However during copy page name gets set to the same name as source page has and assigned some index to the name. So for instance if we take Alloy Tech sample site copying and later paste “Alloy Track” page to the same branch in the site structure new page will get page name in address “Alloy-Track1”.]]></summary></entry><entry><title type="html">Story behind custom error handler development</title><link href="https://tech-fellow.eu/2011/11/27/story-behind-custom-error-handler-development/" rel="alternate" type="text/html" title="Story behind custom error handler development" /><published>2011-11-27T23:15:00+02:00</published><updated>2011-11-27T23:15:00+02:00</updated><id>https://tech-fellow.eu/2011/11/27/story-behind-custom-error-handler-development</id><content type="html" xml:base="https://tech-fellow.eu/2011/11/27/story-behind-custom-error-handler-development/"><![CDATA[<p>One of the first task on my brand new path in EPiServer world was to develop custom error pages. Nothing special and no big deal at looking at the task from 10k feat.</p>

<p>We decided to take a Http module path – to plug in our module in request processing pipeline to inspect the situation on the server and make all the stuff needed to render the error page for appropriate HTTP status code.</p>

<p>Enabling custom error handler is as easy as adding following lines to your web.config file:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;add</span> <span class="na">name=</span><span class="s">"CustomErrorHandlerModule"</span> <span class="na">type=</span><span class="s">"Geta.ErrorHandler.ErrorHandlerModule, Geta.ErrorHandler"</span> <span class="nt">/&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The first trick was about Http module and HttpApplication Error event. This event is raised only when there is a unhandled exception on the server by the Asp.Net runtime. The trick is to get back to the server processing pipeline even end-user requested resource that is not really associated with Asp.Net (for instance, user is requesting http://<server>/<app>/documenthatdoesnotexist.doc).</app></server></p>

<p>What we can do about this is to instruct IIS to execute some .aspx file for 404 Http status code. Trick here is that this file should not exist on the server therefore our module will be called and application will raise error blaming that our provided IIS 404 error displaying page does not exist.</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;httpErrors</span> <span class="na">errorMode=</span><span class="s">"Custom"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;remove</span> <span class="na">statusCode=</span><span class="s">"401"</span> <span class="na">subStatusCode=</span><span class="s">"-1"</span> <span class="nt">/&gt;</span>
  <span class="nt">&lt;error</span> <span class="na">statusCode=</span><span class="s">"401"</span> <span class="na">path=</span><span class="s">"/CustomErrorHandler.aspx"</span> <span class="na">prefixLanguageFilePath=</span><span class="s">""</span> <span class="na">responseMode=</span><span class="s">"ExecuteURL"</span> <span class="nt">/&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>By calling <code class="language-plaintext highlighter-rouge">HttpContext.Current.Server.GetLastError().GetBaseException()</code> we can get back to the original error occurred in “previous” request. I quoted “previous” request because request has not been completed and response is not served yet (because of Http error “ExecuteURL” mode).</p>

<p>If there are some issues with IIS and custom error pages (usually issue is that IIS is not allow use custom error pages) look at feature delegation configuration item in IIS server root. Search for “Error pages” and verify that it’s set to “Read/Write”.</p>

<p>After we get back on track we can investigate an exception occurred previously and make assumption on what status code to set for the response and which page to render.</p>

<p>Of course before rendering error page some checks should be made: for detecting infinite loops, request for some well known resources, etc.</p>

<p>So what the module is doing actually later when decision on which page to render is made? Module has following logic:</p>

<ul>
  <li>It looks for <code class="language-plaintext highlighter-rouge">“Error{0}PageReference”</code> property of the site start page. Where place holder {0} is left for Http status code value (<code class="language-plaintext highlighter-rouge">“Error404PageReference”</code>, <code class="language-plaintext highlighter-rouge">“Error500PageReference”</code>, etc).</li>
  <li>If administrator or editor has not set page reference module is trying to locate error display page using convention: “error page should be named in name of Http error and located under root folder”. So for instance 404 error happens on the server, so module is trying to locate <code class="language-plaintext highlighter-rouge">/404</code> page (using friendly Url).</li>
  <li>If this fails again, module tries to render <code class="language-plaintext highlighter-rouge">“/{0}.htm”</code> page which is static Html fallback if everything else fails.</li>
  <li>The last step is to allow IIS to handle the exception by itself. This means that there is the possibility that module is enabled but no pages exists to render in user friendly fashion – IIS can show yellow screen of death or something unwanted information to the end-user.</li>
</ul>

<p>Lastly if the EPiServer kind page was found (step 1. or 2.) Trick was to render it correctly.</p>

<p>We ended with the following implementation:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">void</span> <span class="nf">Transfer</span><span class="p">(</span><span class="n">PageReference</span> <span class="n">reference</span><span class="p">,</span> <span class="kt">int</span> <span class="n">httpErrorCode</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">page</span> <span class="p">=</span> <span class="n">DataFactory</span><span class="p">.</span><span class="n">Instance</span><span class="p">.</span><span class="nf">GetPage</span><span class="p">(</span><span class="n">reference</span><span class="p">,</span> <span class="k">new</span> <span class="nf">LanguageSelector</span><span class="p">(</span><span class="n">ContentLanguage</span><span class="p">.</span><span class="n">PreferredCulture</span><span class="p">.</span><span class="nf">ToString</span><span class="p">()))</span> <span class="p">??</span>
               <span class="n">DataFactory</span><span class="p">.</span><span class="n">Instance</span><span class="p">.</span><span class="nf">GetPage</span><span class="p">(</span><span class="n">reference</span><span class="p">);</span>

    <span class="k">if</span><span class="p">(</span><span class="n">httpErrorCode</span> <span class="p">==</span> <span class="m">500</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">this</span><span class="p">.</span><span class="n">context</span><span class="p">.</span><span class="n">Server</span><span class="p">.</span><span class="nf">TransferRequest</span><span class="p">(</span><span class="n">page</span><span class="p">.</span><span class="n">LinkURL</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="k">else</span>
    <span class="p">{</span>
        <span class="k">this</span><span class="p">.</span><span class="n">context</span><span class="p">.</span><span class="n">Server</span><span class="p">.</span><span class="nf">Execute</span><span class="p">(</span><span class="n">page</span><span class="p">.</span><span class="n">LinkURL</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>More info in insights of <code class="language-plaintext highlighter-rouge">Server.TransferRequest()</code> and alternatives can be found here. We figured out that <code class="language-plaintext highlighter-rouge">Server.Execute()</code> does not work very well for 500 status pages. And somehow EPiServer is loosing preferred UI culture/language if method to render page is other than <code class="language-plaintext highlighter-rouge">Response.Redirect()</code>. Looking at <code class="language-plaintext highlighter-rouge">EPiServer.PageBase</code> class <code class="language-plaintext highlighter-rouge">InitializeCulture()</code> method suspicious line seemed to be:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="n">ILanguageSelectionSource</span> <span class="n">languageSelectionSource</span> <span class="p">=</span> <span class="k">this</span><span class="p">.</span><span class="n">CurrentPageHandler</span> <span class="k">as</span> <span class="n">ILanguageSelectionSource</span><span class="p">;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Haven’t so much time to investigate all this.</p>

<p>Module as NuGet package is available at – <a href="https://nuget.episerver.com">nuget.episerver.com</a>. Id: <strong>Geta.ErrorHandler</strong>.</p>

<p>Package also contains:</p>

<ul>
  <li>Some generic static Html error pages (for 401, 403, 404 and 500 statuses). Some very basic styling. Don’t blame, I’m not a web designer :)</li>
  <li>Custom page type (used PageTypeBuilder) that can be used to store view model for error pages. By default page type looks for “/Templates/Pages/GetaErrorHandlerPage.aspx” file. Contains just heading and body of the page.</li>
  <li>Base page to be used for custom error pages(Geta.ErrorHandler.BaseErrorPage<T>). Custom base page should be used to get Server.TransferRequest() and Server.Execute() work properly. We discovered that ContextMenu.OptionFlag should be turned off for target error page. Not yet figured out why. TransferRequest() seems to be very fragile and magic method to use. Avoid that.</T></li>
</ul>

<p>It uses log4net as internal logging transport according to EPiServer approach.</p>

<p>What it currently does not support is:</p>

<ul>
  <li>We do not support HTTP status subcodes. That’s most probably is coming soon.</li>
  <li>Appropriate support for AJAX requests. Should be given nice JSON object back to the caller indicating that something wrong happened on the server, so clients scripts can act appropriately.</li>
</ul>

<p>Hope this helps!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Add-On" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="add-on" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[One of the first task on my brand new path in EPiServer world was to develop custom error pages. Nothing special and no big deal at looking at the task from 10k feat.]]></summary></entry><entry><title type="html">If all you need is just Dynamic Data Store..</title><link href="https://tech-fellow.eu/2011/11/04/if-all-you-need-is-just-dynamic-data-store/" rel="alternate" type="text/html" title="If all you need is just Dynamic Data Store.." /><published>2011-11-04T19:00:00+02:00</published><updated>2011-11-04T19:00:00+02:00</updated><id>https://tech-fellow.eu/2011/11/04/if-all-you-need-is-just-dynamic-data-store</id><content type="html" xml:base="https://tech-fellow.eu/2011/11/04/if-all-you-need-is-just-dynamic-data-store/"><![CDATA[<p>We had recently task to make a module data store agnostic. This means that it shouldn’t be a problem to switch from Dynamic Data Store to some other storage implementation. Back and forth. No big deal.</p>

<p>As we currently are developing in our sandbox and making some prototypes only, idea was to bring DDS in our sandbox. We didn’t wanted to deal with all that complexity of EPiServer for now just to be able to use DDS for out testing purposes.</p>

<p>Things to happen, first we need to bring in section from web.config file.</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;section</span> <span class="na">name=</span><span class="s">"episerver.dataStore"</span> <span class="na">type=</span><span class="s">"EPiServer.Data.Configuration.EPiServerDataStoreSection, EPiServer.Data"</span><span class="nt">/&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And then we need to copy section and its content as well (for testing purposes we disabled caching):</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="nt">&lt;episerver.dataStore&gt;</span>
  <span class="nt">&lt;dataStore</span> <span class="na">defaultProvider=</span><span class="s">"EPiServerSQLServerDataStoreProvider"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;providers&gt;</span>
      <span class="nt">&lt;add</span> <span class="na">name=</span><span class="s">"EPiServerSQLServerDataStoreProvider"</span> <span class="na">description=</span><span class="s">"SQL Server implementation of Data Store"</span> <span class="na">type=</span><span class="s">"EPiServer.Data.Dynamic.Providers.SqlServerDataStoreProvider, EPiServer.Data"</span> <span class="na">connectionStringName=</span><span class="s">"EPiServerDB"</span><span class="nt">/&gt;</span>
    <span class="nt">&lt;/providers&gt;</span>
    <span class="nt">&lt;cache</span> <span class="na">defaultProvider=</span><span class="s">"nullCacheProvider"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;providers&gt;</span>
        <span class="nt">&lt;add</span> <span class="na">name=</span><span class="s">"httpCacheProvider"</span> <span class="na">description=</span><span class="s">"Http Cache implementation for DataStore"</span> <span class="na">type=</span><span class="s">"EPiServer.Data.Cache.HttpRuntimeCacheProvider,EPiServer.Data.Cache"</span><span class="nt">/&gt;</span>
        <span class="nt">&lt;add</span> <span class="na">name=</span><span class="s">"nullCacheProvider"</span> <span class="na">description=</span><span class="s">"Null Cache implementation for DataStore"</span> <span class="na">type=</span><span class="s">"EPiServer.Data.Cache.NullCacheProvider,EPiServer.Data"</span><span class="nt">/&gt;</span>
      <span class="nt">&lt;/providers&gt;</span>
    <span class="nt">&lt;/cache&gt;</span>
  <span class="nt">&lt;/dataStore&gt;</span>
<span class="nt">&lt;/episerver.dataStore&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Remember to add connection string in <connectionStrings> section as well.</connectionStrings></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre>connectionStringName="EPiServerDB"
</pre></td></tr></tbody></table></code></pre></div></div>

<p>That’s almost it.</p>

<p>We would need to reference <code class="language-plaintext highlighter-rouge">EPiServer.CMS.Core</code> and <code class="language-plaintext highlighter-rouge">EPiServer.Framework</code> NuGet packages to get <code class="language-plaintext highlighter-rouge">EPiServer.Data.Dynamic</code> namespace in codebase.</p>

<p>Next thing is to initialize store to get a working copy. After sniffing around EPiServer source code we found that particular initialization module is doing required stuff.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="n">EPiServer</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">InitializationModule</span><span class="p">.</span><span class="n">_initializationEngine</span><span class="p">.</span><span class="nf">Add</span><span class="p">((</span><span class="n">System</span><span class="p">.</span><span class="n">Action</span><span class="p">)</span> <span class="p">(()</span> <span class="p">=&gt;</span> <span class="n">EPiServer</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">InitializationModule</span><span class="p">.</span><span class="nf">InitializeDynamicDataStore</span><span class="p">()),</span> <span class="k">new</span> <span class="n">System</span><span class="p">.</span><span class="nf">Action</span><span class="p">(</span><span class="n">EPiServer</span><span class="p">.</span><span class="n">Web</span><span class="p">.</span><span class="n">InitializationModule</span><span class="p">.</span><span class="n">UninitializeDynamicDataStore</span><span class="p">));</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And particularly this method:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">InitializeDynamicDataStore</span><span class="p">()</span>
<span class="p">{</span>
  <span class="p">...</span>
    <span class="n">DynamicDataStoreFactory</span><span class="p">.</span><span class="n">Instance</span> <span class="p">=</span> <span class="p">(</span><span class="n">DynamicDataStoreFactory</span><span class="p">)</span> <span class="k">new</span> <span class="nf">EPiServerDynamicDataStoreFactory</span><span class="p">();</span>

  <span class="p">...</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And looking at TypeExtensions that provide convenient way to get store instance:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">public</span> <span class="k">static</span> <span class="n">DynamicDataStore</span> <span class="nf">GetOrCreateStore</span><span class="p">(</span><span class="k">this</span> <span class="n">Type</span> <span class="n">type</span><span class="p">)</span>
<span class="p">{</span>
  <span class="k">return</span> <span class="n">DynamicDataStoreFactory</span><span class="p">.</span><span class="n">Instance</span><span class="p">.</span><span class="nf">GetStore</span><span class="p">(</span><span class="n">type</span><span class="p">)</span> <span class="p">??</span> <span class="n">DynamicDataStoreFactory</span><span class="p">.</span><span class="n">Instance</span><span class="p">.</span><span class="nf">CreateStore</span><span class="p">(</span><span class="n">type</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>We found a way if we set store instance property to EPiServerDynamicDataStoreFactory. instance – everything works correctly and you are ready to go with DDS support in your very disconnected from the EPiServer sandbox project.</p>

<p>But to make it more easier for testing, imagine that it would classical requirement to be able to mock store and test against some simpler or even mocked instance of the DynamicDataStore type. We adjusted our data store facade to be able to accept various kinds of factories which would make instances of data store as required.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="rouge-code"><pre><span class="k">private</span> <span class="k">readonly</span> <span class="n">DynamicDataStoreFactory</span> <span class="n">storeFactory</span><span class="p">;</span>

<span class="k">public</span> <span class="nf">OurEPiServerStore</span><span class="p">()</span>
<span class="p">{</span>
    <span class="k">if</span><span class="p">(</span><span class="n">DynamicDataStoreFactory</span><span class="p">.</span><span class="n">Instance</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">this</span><span class="p">.</span><span class="n">storeFactory</span> <span class="p">=</span> <span class="n">DynamicDataStoreFactory</span><span class="p">.</span><span class="n">Instance</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">EPiServerDynamicDataStoreFactory</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="k">this</span><span class="p">.</span><span class="n">storeFactory</span> <span class="p">=</span> <span class="n">DynamicDataStoreFactory</span><span class="p">.</span><span class="n">Instance</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">public</span> <span class="nf">OurEPiServerStore</span><span class="p">(</span><span class="n">DynamicDataStoreFactory</span> <span class="n">factory</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">this</span><span class="p">.</span><span class="n">storeFactory</span> <span class="p">=</span> <span class="n">factory</span><span class="p">;</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And then it’s just more easier to unit test our store behaviour and surrounding environment with something like this:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="kt">var</span> <span class="n">factoryMock</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Mock</span><span class="p">&lt;</span><span class="n">DynamicDataStoreFactory</span><span class="p">&gt;();</span>
<span class="kt">var</span> <span class="n">storeMock</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Mock</span><span class="p">&lt;</span><span class="n">DynamicDataStore</span><span class="p">&gt;();</span>

<span class="n">factoryMock</span><span class="p">.</span><span class="nf">Setup</span><span class="p">(</span><span class="n">f</span> <span class="p">=&gt;</span> <span class="n">f</span><span class="p">.</span><span class="nf">GetStore</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">EmailModel</span><span class="p">))).</span><span class="nf">Returns</span><span class="p">(</span><span class="n">storeMock</span><span class="p">.</span><span class="n">Object</span><span class="p">);</span>

<span class="kt">var</span> <span class="n">store</span> <span class="p">=</span> <span class="k">new</span> <span class="n">NewsletterStore</span><span class="p">&lt;</span><span class="n">ModelType</span><span class="p">&gt;(</span><span class="n">factoryMock</span><span class="p">.</span><span class="n">Object</span><span class="p">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>That’s it!
Hope this helps!</p>

<p>[<em>eof</em>]</p>]]></content><author><name>valdis</name></author><category term=".NET" /><category term="C#" /><category term="Add-On" /><category term="Episerver" /><category term="Optimizely" /><category term=".net" /><category term="c#" /><category term="add-on" /><category term="episerver" /><category term="optimizely" /><summary type="html"><![CDATA[We had recently task to make a module data store agnostic. This means that it shouldn’t be a problem to switch from Dynamic Data Store to some other storage implementation. Back and forth. No big deal.]]></summary></entry></feed>