<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        <title>Harvey Williams</title>
        <description>Web development blog and other things. Mainly focusing on Umbraco.</description>
        
            <item>
                <title>Getting started with Docker Compose</title>
                <link>https://harveywilliams.net/blog/getting-started-with-docker-compose</link>
                <description>How to use Docker Compose with Traefik reverse proxy to manage dependencies in your projects.</description>
                
                    <category>docker</category>
                
                <pubDate>Mon, 26 Oct 2020 00:00:00 GMT</pubDate>
                <content:encoded><![CDATA[<pre style="max-height:none;"><code>

                                      -/////:
                                      +ysysss
                                      +sossss
                           `yssssyssssyyyyyys            .o/`
                           `yyyyyysssssysyyys            soos:
                      `----:hyyyyyssssyyyyyyy-----      .y+++s:``
                      :yysysyssssysyyyysssssyysysh      `y+++oyssssso`
                      :yysysysssyysyyyyssyssyysyyh       /y+ooooosss/
                  ////+yysysyssssysyysysssssyysysy/////+oooossoo+/-`
              .`  hssooooooooooooooooooooooooooooooooo++oooss`` `.
           `.:oo/:ysssyyysooooossyyyysoooossyyyssoooossyyyys:--/os:.`
                 `+yyyssssssssssssssssssssssssssssssyyyyyy+`
                  `syysssssssssso+osssssssssssssssyyyyyys-
                   .syyyysssssssoosssssssssssssyyyyyyys/`
                    `/o+/::::--+ssssssssssyyyyyyyyyso-`
                      `:+/:--..-/osyyyyyyyyyyyyss+:.
                         .-////:::/oyyysssso+/-.
                             `...-----...`
                   .o-                      -o.
              ```` -h/    ````       `````  /h:  ``    ````        ``
            :ossssooh/ `/osssso:   .+sssss- /h:.+s/ `:osssso:`  `/oss:
           oh+.  `:yh/`yy:`  ./h+ :ho.  `.` /hsys-  sh:`  -sh+ .yy-`
          `hs      :h//h:      sh`sh`       /hh/   -ho  .+ys-  +h-
           sy-    `sh-.hs`    -yy /h/`      /hhy/` `yy:oy+-`   oh.
           `+ys++oys-  -syo++oy+`  /yyo+os: :h::sy: .oyhs+os`  +h.
             `--:-`      .-:--`      .-:-.  `-`  -.   `--:-`   .-

</code></pre>

<h2 id="contents">Contents</h2>
<ul>
<li><a href="#intro">Intro</a></li>
<li><a href="#developing-with-docker-compose">Developing with Docker Compose</a></li>
<li><a href="#why-use-docker-and-docker-compose-">Why use Docker and Docker Compose?</a></li>
</ul>
<h2 id="intro">Intro</h2>
<p>This guide is for getting developers started with using Docker Compose for development. It&#39;s targeted at devs who have experience with Docker but are sick of writing out one liners into their terminal to start a container.</p>
<p>You will see:</p>
<ul>
<li>how to run a service with Docker Compose</li>
<li>how to use Traefik as a reverse proxy (makes accessing services from your browser way easier)</li>
<li>the benefits of using Docker vs traditional installation of services</li>
</ul>
<h2 id="developing-with-docker-compose">Developing with Docker Compose</h2>
<p>You will need to have <a target="_blank" href="https://docs.docker.com/get-docker/">Docker and Docker Compose</a> installed before you get started. </p>
<p>I&#39;m using Docker 19.03.13 and Docker Compose 1.27.4.</p>
<p>In this example, I will be using <a target="_blank" href="https://www.postgresql.org/">PostgreSQL</a> (a database similar to MySQL/MSSQL).</p>
<h3 id="running-postgresql-with-docker-compose-instead-of-docker">Running PostgreSQL with Docker Compose instead of Docker</h3>
<p>You could write a one liner into your terminal to run your service:</p>
<pre><code>$ docker run -p &quot;5432:5432&quot; --name postgres -e POSTGRES_USER=username -e POSTGRES_PASSWORD=password postgres:10.8-alpine
</code></pre><p>This is equal to using this <code>docker-compose.yaml</code> file:</p>
<pre><code>version: &#39;3&#39;

services:

  postgres:
    image: postgres:10.8-alpine
    environment:
      POSTGRES_USER: &quot;username&quot;
      POSTGRES_PASSWORD: &quot;password&quot;
    ports:
      - &quot;5432:5432&quot;
</code></pre><p>Just run:</p>
<pre><code>$ docker-compose up postgres
</code></pre><p>With either approach, any application can access Postgres over <a target="_blank" href="http://localhost:5432">http://localhost:5432</a></p>
<p>We can see what containers we have running by running:</p>
<pre><code>$ docker container ls
</code></pre><p>The output should be similar to:</p>
<pre><code>CONTAINER ID        IMAGE                  COMMAND                  CREATED        STATUS              PORTS                    NAMES
89897d61fcaa        postgres:10.8-alpine   &quot;docker-entrypoint.s…&quot;   27 seconds ago Up 26 seconds       0.0.0.0:5432-&gt;5432/tcp   dev_postgres_1
</code></pre><p>You can see that the name of the container has been set to <code>postgres-</code> and the name of the folder that the <code>docker-compose.yaml</code> file is in.</p>
<h3 id="adding-pgadmin">Adding pgAdmin</h3>
<p>PgAdmin is a web UI for managing Postgres.</p>
<p>You could go and download the executable and run it, or you could use a container to run it. This is possible because the management UI is just a website.</p>
<pre><code>version: &#39;3&#39;

services:

  postgres:
    image: postgres:10.8-alpine
    environment:
      POSTGRES_USER: &quot;username&quot;
      POSTGRES_PASSWORD: &quot;password&quot;
    ports:
      - &quot;5432:5432&quot;

  pgadmin:
    image: dpage/pgadmin4:4.11
    ports:
      - &quot;1111:1111&quot;
    environment:
      PGADMIN_LISTEN_PORT: &quot;1111&quot;
      PGADMIN_DEFAULT_EMAIL: &quot;pgadmin@example.com&quot;
      PGADMIN_DEFAULT_PASSWORD: &quot;password&quot;
    depends_on:
      - postgres
</code></pre><p>Now run:</p>
<pre><code>$ docker-compose up pgadmin
</code></pre><p>Because <code>pgadmin</code> depends on <code>postgres</code>, Docker Compose will run <code>postgres</code> first.</p>
<p>Now you can access pgAdmin via your web browser with <a target="_blank" href="http://localhost:1111">http://localhost:1111</a></p>
<p>The <code>pgadmin</code> container can also access the database server using the hostname <code>postgres</code> as all containers in the same <code>docker-compose.yml</code> have their own network created where they can access each other.</p>
<p><img src="/media/blog/getting-started-with-docker-compose/pgadmin.png" alt="pgAdmin control panel with configuration to connect to Postgres"></p>
<h3 id="using-traefik">Using Traefik</h3>
<p><a target="_blank" href="https://docs.traefik.io/">Traefik</a> is a reverse proxy gateway server. For developing, it can allow you to have easily accessible URLs on your local dev environment.</p>
<p>Here&#39;s an example <code>docker-compose.yml</code> that uses Postgres, with pgAdmin, with Traefik for the reverse proxy:</p>
<pre><code>version: &#39;3&#39;

services:

  postgres:
    image: postgres:10.8-alpine
    environment:
      POSTGRES_USER: &quot;username&quot;
      POSTGRES_PASSWORD: &quot;password&quot;
    expose:
      - &quot;5432&quot;
    labels:
      traefik.http.services.postgres.loadbalancer.server.port: 5432
    depends_on:
      - traefik

  pgadmin:
    image: dpage/pgadmin4:4.11
    expose:
      - &quot;1111&quot;
    environment:
      PGADMIN_LISTEN_PORT: &quot;1111&quot;
      PGADMIN_DEFAULT_EMAIL: &quot;pgadmin@example.com&quot;
      PGADMIN_DEFAULT_PASSWORD: &quot;password&quot;
    labels:
      traefik.http.services.pgadmin.loadbalancer.server.port: 1111
    depends_on:
      - traefik
      - postgres

  traefik:
    image: traefik:2.2
    command:
      - --providers.docker.defaultRule=Host(`{{ normalize .Name }}.docker.localhost`)
      - --api.insecure=true
    ports:
      - &quot;80:80&quot;
      - &quot;8080:8080&quot;
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
</code></pre><p>Run all the containers using:</p>
<pre><code>$ docker-compose up
</code></pre><p>Navigate to <a target="_blank" href="http://localhost:8080">http://localhost:8080</a> to see the Traefik dashboard.</p>
<p><img src="/media/blog/getting-started-with-docker-compose/traefik.png" alt="Traefik"></p>
<h4 id="connecting-to-services">Connecting to services</h4>
<p>Navigate to <a target="_blank" href="http://pgadmin-{folder-name}.docker.localhost">http://pgadmin-{folder-name}.docker.localhost</a> to access pgAdmin, make sure to replace <code>{folder-name}</code> with the name of the folder which your <code>docker-compose.yml</code> is stored in!</p>
<p>This works by default in Chrome (and other Chromium based browsers such as Edge), but not with Firefox or cURL. Chrome can resolve the URL. There&#39;s a good StackOverflow post <a target="_blank" href="https://stackoverflow.com/questions/45838847/docker-localhost-only-works-in-chrome">here</a> which can get you started on this rabbit hole.</p>
<p>My advice to the Firefox users is to modify your hosts file to include this line:</p>
<pre><code>127.0.0.1 pgadmin-{folder-name}.docker.localhost
</code></pre><h2 id="why-use-docker-and-docker-compose-">Why use Docker and Docker Compose?</h2>
<p>The traditional way of installing a service (such as database server) is to:</p>
<ul>
<li>download an executable and install it</li>
<li>run through the setup wizard</li>
</ul>
<p>This mean dealing with these problems:</p>
<ul>
<li>sharing the setup process with a coworker is difficult</li>
<li>the service (often) runs on startup</li>
<li>the service keeps running in the background even when not developing</li>
<li>running parallel versions is difficult</li>
<li>deleting the service from file system leaves artifacts behind</li>
<li>each service ties up a port, causing conflicts if 2 services try to use the same one</li>
</ul>
<p>Docker solves these issues. Docker itself can cause some overhead when running services, but everything inside it is encapsulated. If a service is no longer needed, only the container needs to be deleted, and it&#39;s like it was never on the computer. If a service misbehaves, it can be quickly binned and recreated to resolve any issues.</p>
<p>Docker Compose streamlines the installation of installing a service. There&#39;s no need for an installation wizard to guide the process, instead just a single config file defines everything. The config files can be shared with other people, or saved into the code repository so anyone can see an applications requirements.</p>
<h2 id="resources">Resources</h2>
<ul>
<li><a target="_blank" href="https://docs.traefik.io/">https://docs.traefik.io/</a></li>
<li><a target="_blank" href="https://hub.docker.com/_/traefik/">https://hub.docker.com/_/traefik/</a></li>
<li><a target="_blank" href="https://blog.thesparktree.com/traefik-advanced-config">https://blog.thesparktree.com/traefik-advanced-config</a></li>
<li><a target="_blank" href="https://docs.docker.com/compose/compose-file">https://docs.docker.com/compose/compose-file</a></li>
</ul>
]]></content:encoded>
            </item>
        
            <item>
                <title>Why Google Wants to Break Adblock</title>
                <link>https://harveywilliams.net/blog/why-google-wants-to-break-adblock</link>
                <description>Google plans to remove support for an API which gives extensions such as Adblock and uBlock Origin full-control over which content is loaded in your browser. Here&#39;s why it might be a good idea.</description>
                
                    <category>miscellaneous</category>
                
                <pubDate>Mon, 28 Jan 2019 00:00:00 GMT</pubDate>
                <content:encoded><![CDATA[<p><img src="/media/blog/why-google-wants-to-break-adblock/web-extensions-why-google-wants-to-break-adblock-ascii.png" alt="Web Extensions - Why Google Wants to Break Adblock"></p>
<p><em>A note to non-technical readers</em> - an API (application programming interface) allows developers to hook into code which has been provided to them. For example, a phone may have an camera API which allows developers to interact with the camera of that phone.</p>
<p><strong>If you&#39;re short on time</strong> - skip to <a href="#but-now-google-wants-to-deprecate-another-api">But now Google wants to deprecate another API</a>.</p>
<h2 id="change-is-good-">Change is... good?</h2>
<p>Back in Firefox 57 (released late 2017), <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Archive/Add-ons/Legacy_add_ons">Mozilla deprecated their older legacy extensions API</a> in favour of the newer <code>WebExtensions</code> API. The legacy API gave developers a huge amount of control over the browser which allowed them to completely change how the browser looked and behaved, but the new API was not nearly as capable.</p>
<p>Users and developers were furious as some addons simply couldn&#39;t be ported over to the newer API.</p>
<p>However, Mozilla had some very good reasons for doing this, namely, the newer API:</p>
<ul>
<li>was much easier to use</li>
<li>had cross platform support, so an extension written for Firefox would mostly work with Chrome (and didn&#39;t need a full rewrite)</li>
</ul>
<p>Also the legacy API also had some big issues:</p>
<ul>
<li>it perhaps gave too much control to developers (making Firefox unstable)</li>
<li><strong>but most importantly, it was not compatible with &quot;e10s&quot; (multiprocess) Firefox</strong></li>
</ul>
<h2 id="firefox-was-slower">Firefox was slower</h2>
<p>The Firefox codebase had been partially rewritten to support multiprocessing - this allows Firefox to be a noticeably faster.</p>
<p>Firefox was losing a lot of users because it was painfully slow when compared to Chrome, a browser which had multiprocessing from the start.</p>
<p><strong>Mozilla had to make a hard decision</strong> - either remove the legacy API (hurting a small number of power users), or keep the API and watch as the browser became comparatively slower (hurting all users). <strong>Although I miss the old extensions which improved the browsing experience, I think they made the right choice.</strong></p>
<p>These days, public sentiment towards Firefox has changed a lot. To me, the browser feels noticeably faster and less buggy. In fact, Chrome is often stated to be a resource hog, as it eats RAM like there&#39;s no tomorrow. There&#39;s even memes about it:</p>
<p><img src="/media/blog/why-google-wants-to-break-adblock/google-chrome-ram.jpg" alt="Google Chrome Eating RAM"></p>
<p>Further reading: <a target="_blank" href="https://www.extremetech.com/internet/250930-firefox-54-finally-supports-multithreading-claims-higher-ram-efficiency-chrome">the differences between multiprocessing in Firefox and Chrome, and why Chrome eats RAM in favour of stability and speed</a></p>
<h2 id="but-now-google-wants-to-deprecate-another-api">But now Google wants to deprecate another API</h2>
<p>Recently there have been discussions about Chrome removing support for the <code>webRequest</code> API, in favour of the <code>declaritiveNetRequest</code> API.</p>
<p>The current API allows developers to make a request to any website on the web, on your behalf. They can even steal cookie information, so if you&#39;ve just logged into your banking website, a malicious addon could secretly tell the website to transfer funds out of your account.</p>
<p>I myself have made an extension which actively uses cookie information to authenticate with a website to make web requests on the users behalf (non-maliciously of course) - it&#39;s not hard to do.</p>
<h3 id="would-this-affect-me-">Would this affect me?</h3>
<p>uBlock Origin is one of the most popular content blocking extensions available today. If you haven&#39;t heard of it, it&#39;s like an adblocker, but it doesn&#39;t just block ads, it blocks anything that could harm your privacy.</p>
<p>In short, the newer API doesn&#39;t have the level of control the older API has, so uBlock would be severely neutered in its capabilities.</p>
<h4 id="but-i-use-opera-brave-vivaldi-microsoft-edge">But I use Opera/Brave/Vivaldi/Microsoft Edge</h4>
<p>Opera, Brave, Vivaldi (and <a target="_blank" href="https://blogs.windows.com/windowsexperience/2018/12/06/microsoft-edge-making-the-web-better-through-more-open-source-collaboration/">soon Microsoft Edge</a>), are all based on Chromium, which is an open source version of Chrome. Basically, anything which happens in Chrome, will likely happen in Chromium based browsers too.</p>
<h4 id="but-i-use-firefox">But I use Firefox</h4>
<p>Firefox and Chrome would prefer to keep their <code>WebExtensions</code> API similar so the extensions can be easily ported between the platforms. And there&#39;s a good reason for Mozilla to go along with Google - it improves security...</p>
<h2 id="security">Security</h2>
<p>Here&#39;s the thing. When a developer makes a change to an extension, they can publish that change to both the Firefox addon store, and the Chrome extension store. Once it&#39;s published, any user who currently has that addon would then get the updated version.</p>
<p><strong>But that developer could update their extension to include malicious code.</strong> The extension would then be stealing passwords without anyone realising for days.</p>
<p>There&#39;s one key difference between publishing on Firefox and Chrome:</p>
<p><strong>Publishing to the Firefox store takes less than minute</strong> - Mozilla do a quick automated check then releases the extension.</p>
<p><strong>Publishing to the Chrome store can take days</strong> - Chrome also does automated tests, but they seem to actually have a real person look over the code to check that nothing dangerous is going on.</p>
<p>With my personal extension, I find that publishing a new version to the Chrome store tends to take about 5 days (because I&#39;m asking for these specific permissions that give me full access to everything).</p>
<h2 id="cost">Cost</h2>
<p>Since Google has to pay a real person to look over the code, this becomes quite costly. I can see why Google is interested in removing this potentially dangerous feature. Not only would it protect their users, but also it would save them a lot of time and money.</p>
<h2 id="my-verdict">My verdict</h2>
<p>Most other articles on this topic only mention that this would stop adblockers such as uBlock from working (which is of course in Google&#39;s interest), but they don&#39;t mention how insecure extensions really are.</p>
<p>Based on the fact that Mozilla deprecated their legacy extensions API knowing that it would hurt some users, I think Google will also change their extensions API in order to protect the user from malicious extensions.</p>
<h2 id="the-final-problem">The final problem</h2>
<p>I just want to wrap up here and say that the <code>WebExtensions</code> API, to my surprise, is <strong><a target="_blank" href="https://www.w3.org/community/browserext/">not a W3C standard</a></strong>.</p>
<p>This means as a developer, I&#39;m constantly finding small differences between the Chrome and Firefox <code>WebExtensions</code>. It seems they can&#39;t quite agree on how things should be implemented, and means that they&#39;re free to make changes how they want.</p>
<p>My hope is that this API can become an open standard in the future.</p>
]]></content:encoded>
            </item>
        
            <item>
                <title>35 YouTube Channels I Love</title>
                <link>https://harveywilliams.net/blog/35-youtube-channels-i-love</link>
                <description>I spend a lot of time watching YouTube, but finding good quality content can be hard. This is a list of my favourite YouTube channels which I think you should be watching too.</description>
                
                    <category>miscellaneous</category>
                
                <pubDate>Mon, 07 Jan 2019 00:00:00 GMT</pubDate>
                <content:encoded><![CDATA[<p>Trying find good quality content can be pretty hit or miss on YouTube. Most of the good YouTubers get drowned out by sensationalist one-hit mainstream videos. Sadly, the platform doesn&#39;t do a very good job of promoting new and upcoming channels.</p>
<p>Below I have compiled a list of channels which I actively follow and avidly wait for new content from. I have put a suggested video with some of the channels so you can see if you like them, right here. I hope you find it useful.</p>
<h2 id="the-channels">The Channels</h2>
<p>I&#39;ve loosely bundled together all of my most watched channels into some categories.</p>
<h3 id="somewhat-educational">Somewhat educational</h3>
<p>Most of the videos I watch are somewhat educational by nature. I like the feeling coming away from a video thinking I&#39;ve learned something, rather than just watching funny trash.</p>
<h4 id="tom-scott"><a target="_blank" href="https://www.youtube.com/user/enyay">Tom Scott</a></h4>
<p>By far one of my favourite YouTubers. One of his best series is <a target="_blank" href="https://www.youtube.com/playlist?list=PL96C35uN7xGK_y459BdHCtGeftqs5_nff">Amazing Places</a>.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/vULUkp7Ttss" target="_blank" style="background-image:url('https://img.youtube.com/vi/vULUkp7Ttss/maxresdefault.jpg')" data-id="vULUkp7Ttss"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">Listening for Nuclear Tests at the Top of the World</div></a>
<h4 id="austinmcconnell"><a target="_blank" href="https://www.youtube.com/user/austinmcconnell">austinmcconnell</a></h4>
<p>Austin McConnell is a filmmaker who creates high quality videos on on particular subject.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/d8IEhcN9aFo" target="_blank" style="background-image:url('https://img.youtube.com/vi/d8IEhcN9aFo/maxresdefault.jpg')" data-id="d8IEhcN9aFo"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">Why Do Reporters Talk Like That?</div></a>
<h4 id="matt-d-avella"><a target="_blank" href="https://www.youtube.com/user/blackboxfilmcompany">Matt D&#39;Avella</a></h4>
<p>Matt D&#39;Avella is a filmmaker. His YouTube channels features crisp, well crafted videos that attempt to advertise the benefits of being a minimalist in everyday life.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/tG2GJZcBKOE" target="_blank" style="background-image:url('https://img.youtube.com/vi/tG2GJZcBKOE/maxresdefault.jpg')" data-id="tG2GJZcBKOE"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">A Day in the Life of a Minimalist</div></a>
<h4 id="sterling-grinnell"><a target="_blank" href="https://www.youtube.com/channel/UCKsSfFmlMiPkkCRC4KrYo5g">Sterling Grinnell</a></h4>
<p>Sterling was recently popularised by Matt D&#39;Avella by a fantastic video which copies Matt&#39;s video style. Sterling is still young but the quality of his videos is already very high.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/YIHBJE4llnY" target="_blank" style="background-image:url('https://img.youtube.com/vi/YIHBJE4llnY/maxresdefault.jpg')" data-id="YIHBJE4llnY"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">How To Make Craft Coffee: An in depth look at brewing with the Hario V60</div></a>
<h4 id="second-thought"><a target="_blank" href="https://www.youtube.com/channel/UCJm2TgUqtK1_NLBrjNQ1P-w">Second Thought</a></h4>
<p>An animated channel which mostly considers &quot;what would happen if&quot; scenarios.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/qVWaBjR58Ew" target="_blank" style="background-image:url('https://img.youtube.com/vi/qVWaBjR58Ew/maxresdefault.jpg')" data-id="qVWaBjR58Ew"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">What if Someone Tries to Claim a Planet?</div></a>
<h4 id="polymatter"><a target="_blank" href="https://www.youtube.com/channel/UCgNg3vwj3xt7QOrcIDaHdFg">PolyMatter</a></h4>
<p>Another animated channel similar to Second Thought.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/PEoZLGHKvy8" target="_blank" style="background-image:url('https://img.youtube.com/vi/PEoZLGHKvy8/maxresdefault.jpg')" data-id="PEoZLGHKvy8"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">Kim Jong-Un&#39;s New Strategy: Explained</div></a>
<h4 id="cpg-grey"><a target="_blank" href="https://www.youtube.com/user/CGPGrey">CPG Grey</a></h4>
<p>A fun animated channel. The videos are somewhat sciency.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/LO1mTELoj6o" target="_blank" style="background-image:url('https://img.youtube.com/vi/LO1mTELoj6o/maxresdefault.jpg')" data-id="LO1mTELoj6o"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">7 Ways to Maximize Misery 😞</div></a>
<h4 id="tapakapa"><a target="_blank" href="https://www.youtube.com/channel/UCz9mH-PsyV4ZuMGAQqeS8IQ">Tapakapa</a></h4>
<p>Tapakapa is essentially an Austrian version of CPG Grey - the videos are done in a similar animated style and they cover similar topics.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/NwJeMa0Mb4U" target="_blank" style="background-image:url('https://img.youtube.com/vi/NwJeMa0Mb4U/maxresdefault.jpg')" data-id="NwJeMa0Mb4U"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">Sealand - The Country That Doesn&#39;t Exist</div></a>
<h3 id="tech">Tech</h3>
<h4 id="marques-brownlee"><a target="_blank" href="https://www.youtube.com/user/marquesbrownlee">Marques Brownlee</a></h4>
<p>MKBHD makes super high quality videos on up and coming tech. Half of the reason I watch him is because the quality of his filmography is top notch. He&#39;s known for reviewing smart phones, I recommend watching his review on a smart phone before you buy it.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/UIwdCN4dV6w" target="_blank" style="background-image:url('https://img.youtube.com/vi/UIwdCN4dV6w/maxresdefault.jpg')" data-id="UIwdCN4dV6w"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">Dope Tech: Camera Robots!</div></a>
<h4 id="linus-tech-tips"><a target="_blank" href="https://www.youtube.com/user/LinusTechTips">Linus Tech Tips</a></h4>
<p>LTT releases plenty of videos almost daily. They cover anything from building computers with hardware to reviewing cheap Amazon steals.</p>
<p>He feels a bit like he&#39;s a shill (as in he&#39;s getting paid to say good things about certain products), but for the most part it&#39;s a great channel.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/HDDLTwS4zgs" target="_blank" style="background-image:url('https://img.youtube.com/vi/HDDLTwS4zgs/maxresdefault.jpg')" data-id="HDDLTwS4zgs"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">$69 Gaming PC</div></a>
<h4 id="techlinked"><a target="_blank" href="https://www.youtube.com/channel/UCeeFfhMcJa1kjtfZAGskOCA">TechLinked</a></h4>
<p>A spin off from Linus Tech Tips, TechLinked releases 3 videos a week which briefly explain what new things have happened with tech.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/RAFBTM3Wwxo" target="_blank" style="background-image:url('https://img.youtube.com/vi/RAFBTM3Wwxo/maxresdefault.jpg')" data-id="RAFBTM3Wwxo"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">Apple&#39;s Reign is OVER!</div></a>
<h3 id="news">News</h3>
<h4 id="bloomberg"><a target="_blank" href="https://www.youtube.com/user/Bloomberg">Bloomberg</a></h4>
<p>Bloomberg is a well known news outlet. They mostly focus on market and business news.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/dcio8mXpC94" target="_blank" style="background-image:url('https://img.youtube.com/vi/dcio8mXpC94/maxresdefault.jpg')" data-id="dcio8mXpC94"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">How a $5k Luxury Leather Jacket is Made</div></a>
<h4 id="vox"><a target="_blank" href="https://www.youtube.com/user/voxdotcom">Vox</a></h4>
<p>Vox features a mishmash of content, which is probably aimed at younger more liberal audiences.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/n-mUZRP-fpo" target="_blank" style="background-image:url('https://img.youtube.com/vi/n-mUZRP-fpo/maxresdefault.jpg')" data-id="n-mUZRP-fpo"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">Why Cuban cab drivers earn more than doctors</div></a>
<h4 id="tldr-news"><a target="_blank" href="https://www.youtube.com/channel/UCSMqateX8OA2s1wsOR2EgJA">TLDR News</a></h4>
<p>A very new channel with a simple animated art style. They have mostly been attempting to explain what going on with Brexit in an easy to digest way. They&#39;re also experimenting in creating a &quot;This Week In Parliament&quot; series where they explain the latest going-ons in the British parliament.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/F6RNIdqhiBc" target="_blank" style="background-image:url('https://img.youtube.com/vi/F6RNIdqhiBc/maxresdefault.jpg')" data-id="F6RNIdqhiBc"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">Will the UK Cancel Brexit? - Brexit Explained</div></a>
<h3 id="educational">Educational</h3>
<h4 id="two-cents"><a target="_blank" href="https://www.youtube.com/channel/UCL8w_A8p8P1HWI3k6PR5Z6w">Two Cents</a></h4>
<p>This channel helps explain the everyday economics of life in a simple way.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/TtJXl6pk0Z4" target="_blank" style="background-image:url('https://img.youtube.com/vi/TtJXl6pk0Z4/maxresdefault.jpg')" data-id="TtJXl6pk0Z4"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">How Cars Keep You POOR!</div></a>
<h4 id="crashcourse"><a target="_blank" href="https://www.youtube.com/user/crashcourse">CrashCourse</a></h4>
<p>CrashCourse has a number of different series where they quickly explain subjects such as economics, history, psychology and many more.</p>
<h3 id="music">Music</h3>
<h4 id="middle-8"><a target="_blank" href="https://www.youtube.com/channel/UCfeppgcy70ERp4gQrsYijsg">Middle 8</a></h4>
<p>A fairly new channel which covers mostly newer music artists in details.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/IMMlwjWyHxA" target="_blank" style="background-image:url('https://img.youtube.com/vi/IMMlwjWyHxA/maxresdefault.jpg')" data-id="IMMlwjWyHxA"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">MGMT and their Little Dark Age</div></a>
<h3 id="video-games">Video games</h3>
<h4 id="upisnotjump"><a target="_blank" href="https://www.youtube.com/user/hamlin351">UpIsNotJump</a></h4>
<p>UpIsNotJump used to mostly focus on recreating scenes from popular TV using a video game such as Fallout... I have to say I&#39;m not a fan.</p>
<p>But recently his channel has taken a turn and he&#39;s recently been making a series where he explains, with plenty of funny jokes, why a specific game is good or bad in VR.</p>
<p>I can safely say that his videos are one of the big reasons why I want to get into VR.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/6-JD18kS0GQ" target="_blank" style="background-image:url('https://img.youtube.com/vi/6-JD18kS0GQ/maxresdefault.jpg')" data-id="6-JD18kS0GQ"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">Fallout 4 VR Is An Absolute Nightmare – This Is Why</div></a>
<h4 id="sovietwomble"><a target="_blank" href="https://www.youtube.com/user/SovietWomble">SovietWomble</a></h4>
<p>SovietWomble creates compilations of him making jokes and otherwise having fun with his friends in a variety of multiplayer games.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/3LTNwwA8csQ" target="_blank" style="background-image:url('https://img.youtube.com/vi/3LTNwwA8csQ/maxresdefault.jpg')" data-id="3LTNwwA8csQ"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">Random Pavlov Bullshittery (Counterstrike in Virtual Reality)</div></a>
<h3 id="travel">Travel</h3>
<h4 id="abroad-in-japan"><a target="_blank" href="https://www.youtube.com/user/cmbroad44">Abroad In Japan</a></h4>
<p>Since I was young I had wanted to travel to Japan. In 2018 I finally got the chance and I wanted to find out about Japan and I came across Abroad In Japan. This channel features a British guy, making rubbish (British) jokes, while explaining his experiences of living in Japan.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/wwH3rA8Evow" target="_blank" style="background-image:url('https://img.youtube.com/vi/wwH3rA8Evow/maxresdefault.jpg')" data-id="wwH3rA8Evow"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">DON&#39;T GET FAT IN JAPAN</div></a>
<h4 id="monkey-abroad"><a target="_blank" href="https://www.youtube.com/user/monkeyhead360">Monkey Abroad</a></h4>
<p>Monkey Abroad makes a very good series where he shows how cheap you can travel abroad - for just $20 a day he&#39;ll shows what&#39;s possible.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/_QkRJXHux2A" target="_blank" style="background-image:url('https://img.youtube.com/vi/_QkRJXHux2A/maxresdefault.jpg')" data-id="_QkRJXHux2A"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">Hanoi, Vietnam: Traveling for $20 A Day - Ep 13</div></a>
<h3 id="science">Science</h3>
<h4 id="kurzgesagt"><a target="_blank" href="https://www.youtube.com/user/Kurzgesagt">Kurzgesagt</a></h4>
<p>Kurzgesagt always makes super high quality, beautifully animated videos. They don&#39;t release very regularly but I&#39;m always looking forward to their next video.</p>
<p>Their videos also have a strong chance of giving you existential dread.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/sNhhvQGsMEc" target="_blank" style="background-image:url('https://img.youtube.com/vi/sNhhvQGsMEc/maxresdefault.jpg')" data-id="sNhhvQGsMEc"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">The Fermi Paradox — Where Are All The Aliens? (1/2)</div></a>
<h4 id="vsauce"><a target="_blank" href="https://www.youtube.com/user/Vsauce">Vsauce</a></h4>
<p>Vsauce is likely the most popular science based YouTube channel.</p>
<p>It covers science in a pretty simple way which I feel that anyone can understand. The science has perhaps been dumbed down a little bit and it also he tends to go on these crazy tangents which aren&#39;t directly related to the topic of the video.</p>
<p>For example, in the video below (called &quot;What If Everyone JUMPED At Once?&quot;), the video also covers what &quot;decimated&quot; means and what &quot;Dunbar&#39;s Number&quot; is (nothing to do with jumping). However, the videos are very entertaining.</p>
<p>Vsauce also does this weird thing where, between cuts of the video, he sort of springs upwards. It&#39;s easy to ignore at the start but I notice it every time now.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/jHbyQ_AQP8c" target="_blank" style="background-image:url('https://img.youtube.com/vi/jHbyQ_AQP8c/maxresdefault.jpg')" data-id="jHbyQ_AQP8c"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">What If Everyone JUMPED At Once?</div></a>
<h4 id="veritasium"><a target="_blank" href="https://www.youtube.com/user/1veritasium">Veritasium</a></h4>
<p>Veritasium is a lot like Vsauce in the topics which he covers, except I feel like his approach is more aimed at properly teaching science.</p>
<p>In a number of his videos, he will explain an idea by first asking the general public what they think the answer is. He&#39;s done research showing that videos which just explain what something is don&#39;t tend to teach us anything. By showing telling us what other people might answer, then telling us the correct answer, apparently it helps us retain the lesson learned.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/zUDqI9PJpc8" target="_blank" style="background-image:url('https://img.youtube.com/vi/zUDqI9PJpc8/maxresdefault.jpg')" data-id="zUDqI9PJpc8"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">How Much Information?</div></a>
<h4 id="minutephysics"><a target="_blank" href="https://www.youtube.com/user/minutephysics">minutephysics</a></h4>
<p>Minutephysics has a cool hand drawn art style which is used to explain physics.</p>
<p>It&#39;s worth noting that the videos are rarely a minute long.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/tmNXKqeUtJM" target="_blank" style="background-image:url('https://img.youtube.com/vi/tmNXKqeUtJM/maxresdefault.jpg')" data-id="tmNXKqeUtJM"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">Why is the Solar System Flat?</div></a>
<h4 id="minuteearth"><a target="_blank" href="https://www.youtube.com/channel/UCeiYXex_fwgYDonaTcSIk6w">MinuteEarth</a></h4>
<p>MinuteEarth is a lot like minutephysics but it covers topics such as biology and geography.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/kZJ_3_cTGoI" target="_blank" style="background-image:url('https://img.youtube.com/vi/kZJ_3_cTGoI/maxresdefault.jpg')" data-id="kZJ_3_cTGoI"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">Why Bird Penises Are So Weird</div></a>
<h4 id="numberphile"><a target="_blank" href="https://www.youtube.com/channel/UCoxcjq-8xIDTYp3uz647V5A">Numberphile</a></h4>
<p>Numberphile is pretty nerdy. It mostly features maths professors talking about maths while scribbling on a bit of paper.</p>
<p>My favourite video is the one below, where a (<del>crazy</del> enthusiastic) man has klein bottles hand made and stored in boxes under his house. The space under his house is quite small, so he built a cute little robot which can grab the boxes for him.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/-k3mVnRlQLU" target="_blank" style="background-image:url('https://img.youtube.com/vi/-k3mVnRlQLU/maxresdefault.jpg')" data-id="-k3mVnRlQLU"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">The man with 1,000 Klein Bottles UNDER his house - Numberphile</div></a>
<h3 id="programming">Programming</h3>
<h4 id="devin-crawford"><a target="_blank" href="https://www.youtube.com/channel/UCDrekHmOnkptxq3gUU0IyfA">Devin Crawford</a></h4>
<p>Devin Crawford is an enthusiastic programmer who&#39;s at uni. He records himself building his projects.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/lU1GVVU9gLU" target="_blank" style="background-image:url('https://img.youtube.com/vi/lU1GVVU9gLU/maxresdefault.jpg')" data-id="lU1GVVU9gLU"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">DIY LED Music Visualizer | Real-Time Animations (Arduino)</div></a>
<h4 id="liveoverflow"><a target="_blank" href="https://www.youtube.com/channel/UClcE-kVhqyiHCcjYwcpfj9w">LiveOverflow</a></h4>
<p>LiveOverflow makes videos about programming and hacking.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/iJFnYBJJiuQ" target="_blank" style="background-image:url('https://img.youtube.com/vi/iJFnYBJJiuQ/maxresdefault.jpg')" data-id="iJFnYBJJiuQ"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">How do SIM Cards work? - SIMtrace</div></a>
<h3 id="motorbiking">Motorbiking</h3>
<h4 id="fortnine"><a target="_blank" href="https://www.youtube.com/channel/UCNSMdQtn1SuFzCZjfK2C7dQ">FortNine</a></h4>
<p>ForNine is unlike most motorbiking channels on YouTube, where it&#39;s just some douche riding his bike around, or they&#39;re just trying to sell you something with a vaguely educational video...</p>
<p>FortNine makes cinematic videos which tell tale about a bike. Production value of the videos is pretty high and they try pretty hard to make each video feel new.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/EhoegoARVa0" target="_blank" style="background-image:url('https://img.youtube.com/vi/EhoegoARVa0/maxresdefault.jpg')" data-id="EhoegoARVa0"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">$400 Motorcycle - 400km Adventure</div></a>
<h3 id="existential-crisis">Existential crisis</h3>
<h4 id="exurb1a"><a target="_blank" href="https://www.youtube.com/user/willunicycleforfood">exurb1a</a></h4>
<p>Exurb1a creates videos which appear to be designed to give existential dread.</p>
<p>The creator also has a channel called <a target="_blank" href="https://www.youtube.com/channel/UCcoO-8J0EYQHGPFQqwmAzVQ">exurb2a</a> which features content which doesn&#39;t quite fit with the main channel.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/dLRLYPiaAoA" target="_blank" style="background-image:url('https://img.youtube.com/vi/dLRLYPiaAoA/maxresdefault.jpg')" data-id="dLRLYPiaAoA"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">27</div></a>
<h3 id="film-study">Film study</h3>
<h4 id="every-frame-a-painting"><a target="_blank" href="https://www.youtube.com/channel/UCjFqcJQXGZ6T6sxyFB-5i6A">Every Frame a Painting</a></h4>
<p>Every Frame A Painting covers cinematic techniques which are used in movies. Since watching this channel, I find myself looking more at how a scene is filmed. For example, the video below explains how movies make use of single takes. I&#39;ve really begun to notice when movies are using single takes, such as in Children of Men which for me, is a pretty iconic movie.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/8q4X2vDRfRk" target="_blank" style="background-image:url('https://img.youtube.com/vi/8q4X2vDRfRk/maxresdefault.jpg')" data-id="8q4X2vDRfRk"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">The Spielberg Oner</div></a>
<h4 id="now-you-see-it"><a target="_blank" href="https://www.youtube.com/channel/UCWTFGPpNQ0Ms6afXhaWDiRw">Now You See It</a></h4>
<p>Now You See It is a lot like Every Frame A Painting, it&#39;s worth checking them both out.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/X3FlrbaHN2o" target="_blank" style="background-image:url('https://img.youtube.com/vi/X3FlrbaHN2o/maxresdefault.jpg')" data-id="X3FlrbaHN2o"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">What Long Takes Can&#39;t Do</div></a>
<h3 id="languages">Languages</h3>
<h4 id="language-transfer"><a target="_blank" href="https://www.youtube.com/user/LanguageTransfer">Language Transfer</a></h4>
<p>I&#39;ve used this <strong>free</strong> language training course to help me learn German, and I have to say that the style of teaching is very good for those of us who hate memorising languages. I strongly recommend Language Transfer for anyone who wants to start learning a new language.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/1wRGdwf7b_o" target="_blank" style="background-image:url('https://img.youtube.com/vi/1wRGdwf7b_o/maxresdefault.jpg')" data-id="1wRGdwf7b_o"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">Complete German, Track 01 - Language Transfer, The Thinking Method</div></a>
<h3 id="trash">Trash</h3>
<h4 id="apandah"><a target="_blank" href="https://www.youtube.com/channel/UCVQ9S8LoggEepxMYDiRpeeg">apandah</a></h4>
<p>Apandah makes videos are purely post modern trash. Viewer discretion is advised.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/LBnUc09MK2w" target="_blank" style="background-image:url('https://img.youtube.com/vi/LBnUc09MK2w/maxresdefault.jpg')" data-id="LBnUc09MK2w"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">uganda knuckles</div></a>
<h4 id="an0nymooose"><a target="_blank" href="https://www.youtube.com/user/an0nymooose">an0nymooose</a></h4>
<p>More random trash.</p>
<a class="youtube-video" href="https://www.youtube.com/embed/l8wMVmY7Zpw" target="_blank" style="background-image:url('https://img.youtube.com/vi/l8wMVmY7Zpw/maxresdefault.jpg')" data-id="l8wMVmY7Zpw"><div class="icon-play youtube-video-play"></div><div class="youtube-video-title">[SFM] Berdst friend</div></a>
<h2 id="have-something-to-say-">Have something to say?</h2>
<p>I hope you found this list of videos somewhat helpful.</p>
<p>If you have a list of videos you want to share, or a specific channel you&#39;re really into, please share it below!</p>
]]></content:encoded>
            </item>
        
            <item>
                <title>Better task scheduling in Umbraco</title>
                <link>https://harveywilliams.net/blog/better-task-scheduling-in-umbraco</link>
                <description>ScheduledTasks are an antiquated way of handling scheduling events in .NET. Here&#39;s three better solutions you should be considering instead.</description>
                
                    <category>umbraco</category>
                
                    <category>programming</category>
                
                <pubDate>Thu, 01 Jun 2017 00:00:00 GMT</pubDate>
                <content:encoded><![CDATA[<p>This blog post has also been published to <a target="_blank" href="https://growcreate.co.uk/blog/better-task-scheduling-in-umbraco/">GrowCreate&#39;s blog</a>.</p>
<p>Some web applications need to be able to trigger tasks to occur as set times. A good task scheduler should be able to do the following:</p>
<ul>
<li>schedule one off tasks</li>
<li>create reoccurring tasks</li>
<li>set a time and date for a future task to occur</li>
<li>allow access a UI which can be used and understood by anyone</li>
<li>allow for error handling</li>
</ul>
<p>Tasks which you may want a task scheduler to do include:</p>
<ul>
<li>triggering CSV imports to update site content</li>
<li>ensuring that repeat payments or orders occur</li>
<li>sending emails to users which haven&#39;t been active in a while</li>
</ul>
<p>Umbraco has a built-in way of handling task scheduling. Add the following code in a <code>YourUmbracoSite.Web/config/umbracoSettings.config</code> file and you&#39;re away:</p>
<pre><code>&lt;scheduledTasks&gt;
    &lt;!-- add tasks that should be called with an interval (seconds) --&gt;
    &lt;task log=&quot;true&quot; alias=&quot;My Scheduled Task&quot; interval=&quot;3600&quot; url=&quot;https://website.com/umbraco/api/tasks/method&quot; /&gt;
&lt;/scheduledTasks&gt;
</code></pre><p>You can read more about using this <a target="_blank" href="https://our.umbraco.org/Documentation/Reference/Config/umbracoSettings/#scheduledtasks">here</a>.</p>
<p>This works by visiting the given URL at a set interval (in seconds). But this method has a lot of drawbacks:</p>
<ul>
<li>you can&#39;t set a specific time for a task to occur (such as once per day)</li>
<li>the only way to check to see if a task triggered or completed is to look in the Umbraco log which isn&#39;t transparent for non-developers</li>
<li>it&#39;s possible that two instances of the same task could run simultaneously as this method doesn&#39;t check for an existing running task</li>
<li>the task can be interrupted by a server or website restart and there&#39;s no built in error handling</li>
<li>tasks have to be publicly accessible by a URL and the built in Umbraco authorisation doesn&#39;t work</li>
</ul>
<p>It&#39;s about time we did away with this and used something better!</p>
<h2 id="okay-what-s-the-solution-">Okay! What&#39;s the solution?</h2>
<p>There&#39;s a few ways to schedule tasks in .NET. Here are some options:</p>
<ul>
<li><a href="#quartz">Quartz</a></li>
<li><a href="#hangfire">Hangfire</a></li>
<li><a href="#windows-task-scheduler">Windows Task Scheduler</a></li>
</ul>
<h3 id="quartz">Quartz</h3>
<p><a target="_blank" href="https://www.quartz-scheduler.net/">Quartz</a> is an open source .NET scheduler and is a port of a popular Java job scheduler.</p>
<p>I have used Quartz on an internal project and my experience was good. You can either schedule tasks using the built in LINQ methods, or if you understand <a target="_blank" href="http://www.adminschoice.com/crontab-quick-reference">crontabs</a> then you can build complex schedules with one line strings.</p>
<p>Tasks can either be stored in memory or you can configure Quartz to save tasks to a database. The former option is simpler to setup, but would require you schedule the tasks on site startup if you want to have commonly occurring tasks.</p>
<p>The only downside of Quartz I can think of is <strong>there&#39;s no UI to view tasks</strong>, so it&#39;s still not transparent to non-developers what is going on.</p>
<p>There is an Umbraco package called <a target="_blank" href="https://our.umbraco.org/projects/backoffice-extensions/url-task-scheduler-for-v7/">Url Task Scheduler for V7</a> which uses Quartz for scheduling and provides a UI on an Umbraco dashboard. Though you should note this package is targeted at developers and there haven&#39;t been any recent updates to the package. Use at your own risk!</p>
<h3 id="hangfire">Hangfire</h3>
<p><a target="_blank" href="https://www.hangfire.io/">Hangfire</a> is a full-featured solution for task scheduling as it even includes a beautiful UI which you can access via your browser. The UI can tell you when tasks have been called, when they completed and if an error occurred.</p>
<p>Hangfire assumes you have a MS SQL database and setting it up to use the database is super simple. But the best thing is some other Umbracians have written blog posts on integrating Hangfire with Umbraco. Check them out <a target="_blank" href="http://camaya.co/posts/2016/07/31/how-to-integrate-hangfire-with-umbraco/">here</a> and <a target="_blank" href="http://www.abstractmethod.co.uk/blog/2016/4/better-task-scheduling-in-umbraco/">here</a>.</p>
<p>Hangfire might be a little overkill if you want to setup a couple of simple reoccurring tasks, but for bigger websites, there is a real benefit from using it.</p>
<h3 id="windows-task-scheduler">Windows Task Scheduler</h3>
<p>Windows has a task scheduler built straight into it which can be used by programs or users.</p>
<p>The Task Scheduler is a similar solution to using the Umbraco built in scheduler, but with three clear advantages:</p>
<ul>
<li>you can set a time and date for a task to be called</li>
<li>the task scheduling isn&#39;t affected by site and server restarts</li>
<li>you can add error handling in (such as calling the task again if an error occurs)</li>
</ul>
<p>The steps involve creating a script (such as a PowerShell script) which calls a web URL and waits for a response. A simple example of the code is:</p>
<pre><code>$url=&quot;https://website.com/umbraco/api/tasks/method&quot;
(New-Object System.Net.WebClient).DownloadString(&quot;$url&quot;);
</code></pre><p>The downsides of this approach are:</p>
<ul>
<li>the task sits outside of the application which isn&#39;t transparent and can add technical debt to a project</li>
<li>the UI can only be accessed by RDPing into the server</li>
<li>tasks have to be publicly accessible by a URL</li>
</ul>
<h2 id="my-verdict">My verdict</h2>
<p>It&#39;s often that more complicated websites need to be able to run reoccurring tasks. Umbraco Scheduled Tasks can solve this issue, but it&#39;s not a silver bullet and can cause more problems than it solves.</p>
<p>My personal favourite solution is Hangfire because of the user friendly UI. But ultimately, what you use depends on how critical tasks that you need carrying out are and the budget of your client.</p>
<p>Have you got a solution you prefer? Or do you think Umbraco should include a better task scheduler in the core? You can contact me on <a target="_blank" href="https://twitter.com/Harvzor">Twitter</a> to let me know what you think!</p>
]]></content:encoded>
            </item>
        
            <item>
                <title>The best Umbraco packages of 2017</title>
                <link>https://harveywilliams.net/blog/best-umbraco-packages-2017</link>
                <description>Discover some of the best Umbraco packages which can help you build Umbraco websites.</description>
                
                    <category>umbraco</category>
                
                    <category>programming</category>
                
                <pubDate>Sun, 02 Mar 2017 00:00:00 GMT</pubDate>
                <content:encoded><![CDATA[<p>2017 is still in it&#39;s infancy and using the best packages in your Umbraco installations can help make your experience of using Umbraco much more enjoyable. I have been working with Umbraco for three years now, packages have come and gone, but some have stuck around for longer. Here you can read about the packages which I have used and recommend trying out.</p>
<h2 id="show-me-the-packages">Show me the packages</h2>
<h3 id="301-url-tracker">301 URL Tracker</h3>
<p><a target="_blank" href="https://our.umbraco.org/projects/developer-tools/301-url-tracker/">https://our.umbraco.org/projects/developer-tools/301-url-tracker/</a></p>
<p>As of <a target="_blank" href="https://umbraco.com/follow-us/blog-archive/2016/6/15/umbraco-75-beta-out-now/">Umbraco 7.5</a>, the CMS comes with its own 301 redirecter. What this does is when you move or rename a page in Umbraco, the 301 redirecter will put a redirect in place to send the user from the old pages URL to the new one. This helps a lot with SEO as Google hates it when it finds a 404 where a page used to be.</p>
<p>However, the 301 redirecter is not perfect. It is fast but it doesn&#39;t allow you to setup your own redirects. This can be a pain if you&#39;re migrating from an old site, or you need to set up some more comprehensive redirects.</p>
<p>This is where 301 Url Tracker comes in. This package has been around since Umbraco 4. It was actually the inspiration for the new built in redirector. It also tracks page changes and automatically adds new redirects, but you can set up your own redirects if required, which can also use regular expressions. The package doesn&#39;t 100% fit in with the Umbraco aesthetic, and it has some bugs mainly to do with performance, but these issues are small and can generally be fixed by upgrading to the latest version of the package.</p>
<h3 id="nested-content">Nested Content</h3>
<p><img src="/media/blog/best-umbraco-packages-2017/nested-content.png" alt="Nested Content in the back office."></p>
<p><a target="_blank" href="https://our.umbraco.org/projects/backoffice-extensions/nested-content/">https://our.umbraco.org/projects/backoffice-extensions/nested-content/</a></p>
<p>Nested Content is a package I simply cannot live without when building even the most simple of Umbraco websites. It&#39;s a property editor that allows you to create repeatable content in Umbraco on a node using a doc type schema to model the repeatable content. This beats a host of other ideas such as using real nodes as it keeps all of the content for a page on one node. It&#39;s quick and easy to setup and it supports almost any property type you throw at it. Another great feature is that the data maps straight to <code>IPublishedContent</code> so you don&#39;t even need to learn anything new. One last reason to use Nested Content is there is instant Models Builder support.</p>
<p>An alternative to NC is Archetype, which offers nearly the same functionality but doesn&#39;t use the built in Umbraco doc types.</p>
<h3 id="usync">uSync</h3>
<p><img src="/media/blog/best-umbraco-packages-2017/usync.png" alt="uSync in the back office"></p>
<p><a target="_blank" href="https://our.umbraco.org/projects/developer-tools/usync/">https://our.umbraco.org/projects/developer-tools/usync/</a></p>
<p>If you&#39;re not using Umbraco Cloud (aka, Umbraco as a Service (UaaS)), then you may need something like uSync to help with managing schema changes in Umbraco between dev/staging/live instances of your website. uSync can output some files which describe an Umbraco website, these files can then be copied to another Umbraco website which can then be used to update that website to be the same as the original website.</p>
<p>This saves anyone from needing to do the tedious work of adding new document types, templates, properties and whatever else to multiple Umbraco instances. Just copy the files over and it&#39;s all managed for you.</p>
<p>My original experience with uSync was a bit buggy, but I soon learned that using the packages manual mode made the package a bit more predictable.</p>
<h3 id="models-builder">Models Builder</h3>
<p><a target="_blank" href="https://github.com/zpqrtbnk/Zbu.ModelsBuilder/wiki">https://github.com/zpqrtbnk/Zbu.ModelsBuilder/wiki</a></p>
<p>Before this package came along, I was writing custom C# models which reflect individual Umbraco nodes. These models would handle getting data out of Umbraco and made managing long lasting websites much easier. However, writing these models is potentially time consuming. This is where the Models Builder comes in. With the click of a button, a DLL or set of automatically generated C# files can be created which does all of this for you. This basically hands you strongly typed models which can be used with Visual Studios Intellisense for a better developing experience. The Models Builder truly has  improved the way which I build websites and saves me time everyday.</p>
<p>This package actually comes built into Umbraco. Generally it is turned on by default, which can be a little confusing if you haven&#39;t built with Umbraco before. However, I strongly recommend reading the documentation on this package as it will help you in the long run.</p>
<p>If you&#39;re not into having models generated automatically (as this can give you less control over the resultant code), you may want to look into using <a target="_blank" href="https://our.umbraco.org/projects/developer-tools/ditto/">Ditto</a> as it can help speed up the rate which you can write your own models. I have not personally used Ditto as I love the Models Builder, but I think Ditto would have been great otherwise.</p>
<h3 id="umbraco-core-property-value-converters">Umbraco Core Property Value Converters</h3>
<p><a target="_blank" href="https://our.umbraco.org/projects/developer-tools/umbraco-core-property-value-converters/">https://our.umbraco.org/projects/developer-tools/umbraco-core-property-value-converters/</a></p>
<p>This package is a huge helper for anyone who uses the Models Builder as it changes the property types for core property editors in Umbraco from simplistic ones to something more useful. For example, if you use a Content Picker (node picker) in Umbraco, rather than giving you an integer to use in your code, you automatically get an <code>IPublishedContent</code> then and there. This saves time as you don&#39;t need to manually retrieve the document from the Umbraco cache and this also ensures that you can&#39;t make any errors in this process.</p>
<p>A note on using this package - it&#39;s best not to add it after a site has been built as it will change what the Models Builder outputs. This means that if your code expects a integer and is instead now being handed an <code>IPublishedContent</code>, your code will error!</p>
<h3 id="umbraco-forms-contour-">Umbraco Forms (Contour)</h3>
<video loop controls><source src="https://player.vimeo.com/external/110229004.hd.mp4?s=823f701836260bd08fb783d38389f628" type="video/mp4">Sorry, you don&#39;t have HTML5 video and we didn&#39;t catch this properly in javascript.</video>

<p><a target="_blank" href="https://our.umbraco.org/projects/developer-tools/umbraco-forms/">https://our.umbraco.org/projects/developer-tools/umbraco-forms/</a></p>
<p>I have written about Umbraco Forms <a target="_blank" href="https://growcreate.co.uk/blog/umbraco-review-2017-developing-websites-with-umbraco/">before</a>, but would just like to reiterate for anyone else that this package is really quite nice. Umbraco Forms allows content editors in Umbraco to create forms of their liking which can then be added to the front end. This is great as it saves developers from needing to add or remove fields in the long run - the content editor can do all this as they need.</p>
<p>Umbraco Forms also saves form submissions into a database table which can all be accessed through the backoffice. This is great because if the SMTP details on your website suddenly stop working (it&#39;s happened before and I guarantee it will happen again), form submissions will still be saved in an easy to reach place.</p>
<p>The only downside of this package is that it costs 129 euros per a domain. However, you can test it on a localhost for free before you buy.</p>
<h3 id="iconator">Iconator</h3>
<p><img src="/media/blog/best-umbraco-packages-2017/icon-picker-dialogue.png" alt="Iconator in the back office"></p>
<p><a target="_blank" href="https://our.umbraco.org/projects/backoffice-extensions/iconator/">https://our.umbraco.org/projects/backoffice-extensions/iconator/</a></p>
<p>No article would be complete without some shameless self-promoting... That&#39;s why I&#39;m sharing my own personal package called Iconator with you. It&#39;s a simple package which scans a CSS file for icon classes (using a regex) and allows a backend user to select the icon they want in a friendly and visual way.</p>
<p>I&#39;ve used this package on a number of client websites as it solves an everyday problem. If you&#39;re not sure about icon fonts, you can see why they&#39;re great <a target="_blank" href="https://css-tricks.com/examples/IconFont/">here</a>.</p>
<h3 id="multi-url-picker">Multi Url Picker</h3>
<p><a target="_blank" href="https://our.umbraco.org/projects/backoffice-extensions/multi-url-picker/">https://our.umbraco.org/projects/backoffice-extensions/multi-url-picker/</a></p>
<p>Multi Url Picker is another package which never misses an Umbraco installation for me. It&#39;s a simple property editor that allows you to pick either an internal Umbraco node or allows you to input a link to another website. The backend user can also supply a name for the picked link (which is great for putting in an anchor) and whether the link should open in a new tab.</p>
<p>A DLL is supplied with this package which gives you a model which you can cast the data to. This actually works really well as it just supplies you with a URL to print onto the page, no need to use the <code>UmbracoHelper</code> to get an <code>IPublishedContent</code> - it&#39;s all done for you.</p>
<h3 id="documento">Documento</h3>
<p><img src="/media/blog/best-umbraco-packages-2017/documento.png" alt="Documento in the back office."></p>
<p><a target="_blank" href="https://our.umbraco.org/projects/backoffice-extensions/documento/">https://our.umbraco.org/projects/backoffice-extensions/documento/</a></p>
<p>This package made by GrowCreate isn&#39;t a must have, but it&#39;s nice to have regardless. It replaces the standard dashboard when you login to your Umbraco website with a slightly more helpful one which lists out all of the document types that have been setup in Umbraco, with some information about what each field does. It&#39;s pretty and it includes a link to an Umbraco editor manual which can be useful for new Umbraco editors.</p>
<h3 id="umbraco-v6-mvc-razor-cheatsheets">Umbraco v6 MVC Razor Cheatsheets</h3>
<p><a target="_blank" href="https://our.umbraco.org/projects/developer-tools/umbraco-v6-mvc-razor-cheatsheets">https://our.umbraco.org/projects/developer-tools/umbraco-v6-mvc-razor-cheatsheets</a></p>
<p>This package is perhaps a little outdated by now but it&#39;s still quite relevant to Umbraco 7 since Umbraco 6 is architecturally very similar. This package is just a PDF cheatsheet which lists out all of the methods that are available to an Umbraco developer. I can remember referring to this sheet many times when I first got started with Umbraco and C#, and I would still recommend it to newer members of the community who aren&#39;t yet used to the ASP.NET stack.</p>
<h3 id="doc-type-grid-editor">Doc Type Grid Editor</h3>
<p><a target="_blank" href="https://our.umbraco.org/projects/backoffice-extensions/doc-type-grid-editor">https://our.umbraco.org/projects/backoffice-extensions/doc-type-grid-editor</a></p>
<p>This package is a must have if you&#39;re creating complicated Grid layouts in Umbraco. The idea of the package is simple yet revolutionary as it allows you to use Umbraco document types, much like Nested Content, except inside of the Umbraco Grid. This is great because adding functionality to the Grid can be a slow and cumbersome process. This package makes the process much quicker and cleaner by uniting different components of the backoffice together. Next time you work with the Grid and you need to output something a little more than a few columns (and you want to avoid the soon to be deprecated macro), then this package may fill you with happiness.</p>
<h3 id="ucomponents-umbraco-6-">uComponents (Umbraco 6)</h3>
<p><img src="/media/blog/best-umbraco-packages-2017/ucomponents.png" alt="uComponents in the back office"></p>
<p><a target="_blank" href="https://our.umbraco.org/projects/backoffice-extensions/ucomponents">https://our.umbraco.org/projects/backoffice-extensions/ucomponents</a></p>
<p>If you&#39;re lucky enough to be supporting an Umbraco 6 (or even Umbraco 4!) website then uComponents adds a bunch of functionality to the backoffice including my favourite pre-Umbraco 7 property editor called &#39;DataType Grid&#39;. This property allows for repeatable content (a little like Nested Content but a lot less pretty and less developer friendly) in Umbraco.</p>
<p>I won&#39;t dwell on this package as it&#39;s back from the dark days. It&#39;s definitely worth noting that there is no clear path for upgrading a website from Umbraco 6 to Umbraco 7 when the data is stored in uCompontents data types. You must either manually migrate the data or figure out some programmatic route. Either way, it can take some time.</p>
<h2 id="round-up">Round up</h2>
<p>There are some more packages which I use but nothing super essential. This list is already pretty comprehensive and should give any Umbraco user an idea of what&#39;s out there. If there&#39;s anything extra then you should mention it below, maybe there&#39;s something I haven&#39;t heard of yet which needs adding to this list!</p>
]]></content:encoded>
            </item>
        
            <item>
                <title>Determining the length in seconds of a folder of MP3 files using NodeJS</title>
                <link>https://harveywilliams.net/blog/getting-the-length-in-seconds-for-mp3-files-in-a-folder</link>
                <description>NodeJS is a great quick and easy tool which allows you to quickly hack together any script which can save you time. In this post I show how I used Node to get the length in seconds of a bunch of MP3 files in the folder.</description>
                
                    <category>nodejs</category>
                
                    <category>programming</category>
                
                <pubDate>Sun, 08 Jan 2017 00:00:00 GMT</pubDate>
                <content:encoded><![CDATA[<p>Recently I came across a problem where I needed to get the length for a group of MP3 files in a folder. Windows displays the length in hours, minutes and seconds, but I purely needed the length of each file in only seconds. Originally my plan was to get the length of the files using a calculator, but this was error prone, time consuming and also.. I mean, I&#39;m a programmer. Surely there&#39;s a simple script that can do this for me?</p>
<p>Judging from <a target="_blank" href="http://stackoverflow.com/questions/119404/time-length-of-an-mp3-file">this Stack Overflow thread</a>, it was very easy to do using Python, but I don&#39;t have Python installed (although I should probably find some time to actually learn the languages basics). I do however have NodeJS installed.</p>
<p>After discovering and installing <a target="_blank" href="https://www.npmjs.com/package/mp3-duration">this package</a> that can find the length of a single MP3 file, the next step was easy. Simply get all of the files in a folder, and get the length of each file:</p>
<pre><code>const mp3Duration = require(&#39;mp3-duration&#39;);
const fs = require(&#39;fs&#39;);

const folder = &#39;./mp3s/&#39;;

fs.readdir(folder, (err, files) =&gt; {
    if (err) {
        return console.log(err.message);
    }

    for (let file of files) {
        mp3Duration(folder + file, (err, duration) =&gt; {
            if (err) {
                return console.log(err.message);
            }

            console.log(file + &#39; is &#39; + duration + &#39; seconds long&#39;);
        });
    }
});
</code></pre><p>After running this script and waiting a couple of seconds, the console began to spit out of all of data I needed:</p>
<pre><code>...
37.mp3 is 366.733 seconds long
05.mp3 is 372.297 seconds long
29.mp3 is 379.376 seconds long
28.mp3 is 380.735 seconds long
19.mp3 is 413.022 seconds long
11.mp3 is 420.206 seconds long
12.mp3 is 424.751 seconds long
20.mp3 is 426.632 seconds long
03.mp3 is 437.316 seconds long
01.mp3 is 445.1 seconds long
26.mp3 is 457.822 seconds long
06.mp3 is 466.495 seconds long
07.mp3 is 466.625 seconds long
18.mp3 is 462.785 seconds long
32.mp3 is 481.176 seconds long
24.mp3 is 470.518 seconds long
...
</code></pre><p>Hurrah! Oh wait, the files aren&#39;t quite in order here. I wanted the files to be read in alphabetical order. Obviously a race condition was occuring. Generally the shortest file was being printed at the top, and the longest at the bottom.</p>
<p>A quick change ensured that each file would be read in the correct order:</p>
<pre><code>const mp3Duration = require(&#39;mp3-duration&#39;);
const fs = require(&#39;fs&#39;);

const folder = &#39;./mp3s/&#39;;

const readFiles = (files, index) =&gt; {
    let file = files[index];

    mp3Duration(folder + file, (err, duration) =&gt; {
        if (err) {
            return console.log(err.message);
        }

        console.log(file + &#39; is &#39; + duration + &#39; seconds long&#39;);

        if (files.length != index + 1) {
            readFiles(files, index + 1);
        }
    });
};

fs.readdir(folder, (err, files) =&gt; {
    if (err) {
        return console.log(err.message);
    }

    readFiles(files, 0);
});
</code></pre><p>This causes this output:</p>
<pre><code>01.mp3 is 445.1 seconds long
02.mp3 is 320.183 seconds long
03.mp3 is 437.316 seconds long
04.mp3 is 356.415 seconds long
05.mp3 is 372.297 seconds long
06.mp3 is 466.495 seconds long
07.mp3 is 466.625 seconds long
08.mp3 is 357.982 seconds long
09.mp3 is 585.117 seconds long
10.mp3 is 344.842 seconds long
11.mp3 is 420.206 seconds long
12.mp3 is 424.751 seconds long
...
</code></pre><p>This script is significantly slower than the last, because the program waits until each files length is figured out before reading the next file.</p>
<p>My challenge was now complete, but still, I wanted to produce the fastest script I could. The <code>Promise</code> API is really useful for this:</p>
<pre><code>const mp3Duration = require(&#39;mp3-duration&#39;);
const fs = require(&#39;fs&#39;);

const folder = &#39;./mp3s/&#39;;

const promises = [];
const results = [];

fs.readdir(folder, (err, files) =&gt; {
    if (err) {
        return console.log(err.message);
    }

    for (let file of files) {
        promises.push(new Promise((resolve, reject) =&gt; {
            mp3Duration(folder + file, (err, duration) =&gt; {
                if (err) {
                    reject(err.message);
                }

                results.push(file + &#39; is &#39; + duration + &#39; seconds long&#39;);

                resolve();
            });
        }));
    }

    Promise.all(promises).then(() =&gt; {
        console.log(results.sort());
    }).catch((err) =&gt; {
        console.log(&#39;error:&#39;, err);
    });
});
</code></pre><p>After a few seconds of waiting, this outputs an array of sorted values:</p>
<pre><code>[ &#39;01.mp3 is 445.1 seconds long&#39;,   
  &#39;02.mp3 is 320.183 seconds long&#39;, 
  &#39;03.mp3 is 437.316 seconds long&#39;, 
  &#39;04.mp3 is 356.415 seconds long&#39;, 
  &#39;05.mp3 is 372.297 seconds long&#39;, 
  &#39;06.mp3 is 466.495 seconds long&#39;, 
  &#39;07.mp3 is 466.625 seconds long&#39;, 
  &#39;08.mp3 is 357.982 seconds long&#39;, 
  &#39;09.mp3 is 585.117 seconds long&#39;, 
  &#39;10.mp3 is 344.842 seconds long&#39;, 
  &#39;11.mp3 is 420.206 seconds long&#39;, 
  ...]
</code></pre><h2 id="conclusion">Conclusion</h2>
<p>I&#39;m sure that there&#39;s an even faster way of getting the length in seconds of a group of MP3 files, but for my purposes this worked great. However, writing this saved me time, it&#39;s reusable for the next time I need to do it and as always, writing anything with JS is a lot of fun for me.</p>
]]></content:encoded>
            </item>
        
            <item>
                <title>Umbraco Review 2017. Developing Websites With Umbraco</title>
                <link>https://harveywilliams.net/blog/umbraco-review-2017-developing-websites-with-umbraco</link>
                <description>For three years I have been using Umbraco as my Content Management System (CMS) for developing websites. This is a review of what’s good, and what could do with improvement within the Umbraco CMS.</description>
                
                    <category>umbraco</category>
                
                    <category>programming</category>
                
                <pubDate>Mon, 02 Jan 2017 00:00:00 GMT</pubDate>
                <content:encoded><![CDATA[<p>This blog post has also been published to <a target="_blank" href="https://growcreate.co.uk/blog/umbraco-review-2017-developing-websites-with-umbraco/">GrowCreate&#39;s blog</a>.</p>
<h2 id="the-learning-curve">The learning curve</h2>
<p>When I first started using Umbraco at <a target="_blank" href="https://growcreate.co.uk/">GrowCreate</a>, I only had experience with the PHP stack, so trying to learn ASP.NET and C# was a big hurdle for me. It took me quite a few months to understand the new stack including the use of the MS SQL database, IIS, and Visual Studio. This was not an easy time, although looking back on my days of PHP I can say that using ASP.NET feels far more structured.</p>
<p>As a developer it can be hard to get started with Umbraco; luckily I had someone helping me through the basics. From a developer and a content editor’s point of view, Umbraco is very usable. The near perfectly built Angular interface of Umbraco 7 is quick and seamless to interact with and feels modern compared to other content management systems.</p>
<h2 id="features">Features</h2>
<p>Umbraco comes packed full of features that allow for most designs to be completed without requiring any extra packages (add-ons). This is great because you don’t have to rely on support outside of Umbraco HQ which means fewer dependencies and an easier upgrade path in the future. Below I have outlined some of the features that come with Umbraco:</p>
<h3 id="front-end-freedom">Front end freedom</h3>
<p>One reason why we chose Umbraco as our CMS is that it doesn’t impose any kind of restriction on what kind of markup you have to write. This means that you can have the front end built as an entirely different step to the Umbraco implementation. This appears to differ to perhaps a Wordpress site, where everyone I have seen has tons of junk in the HTML which increases page weight and impacts performance. Umbraco takes a different approach by giving you a blank slate and with it the freedom to design and code whatever you want.</p>
<h3 id="media">Media</h3>
<p><img src="/media/blog/umbraco-review-2017-developing-websites-with-umbraco/umbraco-media-backend.jpg" alt="Umbraco media backend"></p>
<p>The media section of Umbraco is one of the most obvious features. Simply put, it allows content editors to upload images and files that can then be referenced from other parts of the website.</p>
<p>The media section over the years has received a number of improvements despite holding the same core functionality. The beauty of the media section is that it can be changed as per the developer&#39;s ideas much like the rest of the templates can within the implementation. It’s all built using the same system, so no extra learning is required.</p>
<h3 id="members">Members</h3>
<p>Umbraco still has the member section which hasn’t changed much since Umbraco 4. This area of the back office allows the administration of members (users) of the site. New members can be created here, or old ones edited. You can also quite easily programmatically create members whenever one signs up using the methods and classes provided by the Umbraco installation.
The grid</p>
<p>The grid has been around since Umbraco 7.2. It allows content editors to create a more custom template with a column layout. The editor can create multi-column layouts to display content on the front end.</p>
<blockquote>
<p>Our clients love the grid</p>
</blockquote>
<p>My personal experience developing with the grid has been pretty bad. When it first came out there were a number of bugs and not much documentation and this meant a lot of time faffing around. The code you have to write isn’t pretty and given the choice I would not develop with the grid, but there’s one big problem; our clients love the grid!</p>
<p>The grid really does allow a lot of freedom to the content editor. This means you have to code for a wide array of uses and this can take a long time. I guess as long as clients keep requesting the grid we will work to build better implementations until we’re grid masters.</p>
<h3 id="umbraco-forms">Umbraco Forms</h3>
<p><img src="/media/blog/umbraco-review-2017-developing-websites-with-umbraco/umbraco-forms-backend.jpg" alt="Umbraco forms backend"></p>
<p>Although technically not included in Umbraco, the <a target="_blank" href="https://umbraco.com/products-and-support/forms/">Forms</a> (previously called <del>Courier</del> Contour) package is maintained by Umbraco HQ and costs 99 euros per domain or is free for Umbraco Gold Partners.</p>
<p>Umbraco Forms allows content editors to create custom forms which can then be placed on the website. The package works well for simple forms and can be extended to do more complicated things. Form submissions are automatically stored in the back office which editors can easily view, which ensures that if an email doesn’t get sent, there’s always a record of the submission.</p>
<p>Personally, I love the Forms package because it cuts down on work for the developer when content editors want to add or remove a field from a form or have it send the email to someone else. While this functionality could be custom built into Umbraco, it’s not worth the effort. For the price, Umbraco Forms covers a lot of use cases.</p>
<h3 id="models-builder">Models Builder</h3>
<p><img src="/media/blog/umbraco-review-2017-developing-websites-with-umbraco/visual-studio-models.jpg" alt="Visual Studio C# models"></p>
<p>The <a target="_blank" href="https://github.com/zpqrtbnk/Zbu.ModelsBuilder/wiki">Models Builder</a> is a purely technical feature of Umbraco that developers can utilise to speed up Umbraco development. Umbraco is not a code first CMS (although there are some packages out there which can make it code first), this means that the code has to be written to mirror the data the CMS contains. As a C# developer, this may mean writing models which reflect the data. However, with the Models Builder, this step can be automated meaning at a click of a button, a DLL or some C# files can be generated. Personally, I love this, even if it can be a little buggy.</p>
<h3 id="the-open-source-aspect">The open source aspect</h3>
<p>This may be an obvious thing for some people, but I just want to iterate this. Umbraco being open source is a massive feature. Unlike some other CMS platforms (<em>cough</em>, Sitecore), I can look at the Umbraco source code and know where the code needs improvement. You may be asking, “Why would I want to see the ugly code?” Well, being able to know where a CMS needs improvement allows me to really get comfortable with the CMS. All software has warts and bugs, but if they’re in plain sight, I can at least improve the code or avoid using it altogether.</p>
<p>Even better, if I find a bug in Umbraco which I can’t avoid, I can find it in the code base and try to fix it myself, or I can point out the issue to someone else (either the community or Umbraco HQ) who can then fix it for me. This is something I love about Umbraco. In fact, I could probably write another paragraph about how awesome the Umbraco community is, but you really have to experience that yourself.</p>
<h3 id="easily-extendable">Easily extendable</h3>
<p>It’s fair to say that extending Umbraco is a breeze. That’s not to say a little more documentation wouldn’t be handy, but with a little knowledge of how to use the (reasonably well documented) <a target="_blank" href="https://our.umbraco.org/documentation/reference/routing/surface-controllers">Umbraco surface controller API</a>, and a quick and dirty understanding of how the front end works with Angular, you can create new dashboards and sections in Umbraco.</p>
<p>At GrowCreate, we have built integrations into Umbraco with SharePoint, Salesforce, and MS Dynamics. We have even built our own packages such as <a target="_blank" href="https://our.umbraco.org/projects/backoffice-extensions/pipeline-crm/">Pipeline CRM</a> and <a target="_blank" href="https://our.umbraco.org/projects/backoffice-extensions/iconator/">Iconator</a>. I think being able to extend Umbraco is one of it’s greatest strengths.</p>
<h2 id="the-future">The future</h2>
<p>The future of Umbraco is bright. And I’m not just saying this because GrowCreate main sale is Umbraco integrations. I genuinely believe it.</p>
<p>Despite packing more features, Umbraco itself seems to be getting faster with every release. And with the release of Umbraco 8 in the coming year (hopefully early 2017), we can expect some tremendous improvements, such as:</p>
<ul>
<li><a target="_blank" href="https://www.zpqrtbnk.net/posts/step-by-step-little-by-little-3">cache improvements</a> (moving away from an XML cache to an in-memory cache, much faster!);</li>
<li>using GUIDs (unique IDs) rather than standard IDs allowing for easier syncing of data between Umbraco instances;</li>
<li>cutting down of the Umbraco code base (if I remember from Code Garden, the cut down may be as large as 30%);</li>
<li>the latest minor version of Angular (better experience developing packages for Umbraco).</li>
</ul>
<p>You can read up on the status of Umbraco 8 <a target="_blank" href="https://our.umbraco.org/contribute/releases/800">here</a>.</p>
<p>On the ASP.NET site of things, Microsoft appears to be moving towards open sourcing and making their technologies cross-platform. This includes:</p>
<ul>
<li>the release of <a target="_blank" href="https://www.microsoft.com/net/core/platform">.NET Core</a> (a newly rebuilt version of .NET which is 100% cross platform, Umbraco HQ hopes to get Umbraco 9 built on .NET Core which would allow Umbraco websites to be hosted on a Linux server)</li>
<li>the release of <a target="_blank" href="https://www.microsoft.com/en-gb/sql-server/sql-server-2016">SQL Server 2016</a> which can be run on Linux (beta now available)</li>
<li>the release of different types of Windows Servers, including <a target="_blank" href="https://technet.microsoft.com/en-us/windows-server-docs/get-started/getting-started-with-nano-server">Nano Server</a> which is a massively cut down version of Windows (weighing around 1GB and comes without a GUI) which is perfect for hosting small websites or for building lightweight Docker containers</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>Umbraco has plenty of features which, if you can get past the development learning curve, can be extremely flexible and a joy to program with. The fact that the technology is open source and backed by a profitable company and an amazing community only sweetens the deal. Finally, the future of Umbraco looks very promising, and I can’t wait for the following releases of the .NET technology stack along with newer versions of Umbraco.</p>
]]></content:encoded>
            </item>
        
            <item>
                <title>Understanding Threads and Static Classes in C#</title>
                <link>https://harveywilliams.net/blog/understanding-threads-and-static-classes-in-csharp</link>
                <description>Writing static classes can cause problems if thread safety isn&#34;t properly considered. In a program I helped write, some surprising results occured which could have easily been avoided by ensuring my properties weren&#34;t getting shared between threads. Read on to find out what I learned...</description>
                
                    <category>csharp</category>
                
                    <category>programming</category>
                
                <pubDate>Wed, 26 Oct 2016 00:00:00 GMT</pubDate>
                <content:encoded><![CDATA[<p>Thread safety sounds complicated, but with a couple of examples, a simple understanding of how threads work can be made.</p>
<p>This became an area of interest to me recently when some strange behaviour occured in a program that I had helped write. The program was originally written as a simple static class, but as time went on, more and more features were added, until the class was a monstrosity. We&#39;ve all been there...</p>
<p>Eventually thread safety became a problem with the program because a second process (or thread) of the static method was called while the first method was still running.</p>
<p>Here is a simplified example of the buggy program:</p>
<pre><code>namespace StaticTest
{
    public class Program
    {
        static void Main(string[] args)
        {
            while (true)
            {
                // Run the method asynchronously.
                new Task(Worker.Work).Start();

                Thread.Sleep(5000);

                new Task(Worker.Work).Start();

                Console.ReadLine();
            }
        }
    }

    /// &lt;summary&gt;
    /// A class that will do &quot;work&quot;.
    /// &lt;/summary&gt;
    public static class Worker
    {
        /// &lt;summary&gt;
        /// A simple logging variable which has text appended to it.
        /// &lt;/summary&gt;
        public static string Log;

        /// &lt;summary&gt;
        /// An indicator that stops the process from being ran twice.
        /// &lt;/summary&gt;
        public static bool InProgress;

        /// &lt;summary&gt;
        /// A fake method that will work for 10 seconds before logging.
        /// &lt;/summary&gt;
        public static void Work()
        {
            Log = &quot;&quot;;

            var startTime = DateTime.Now;

            Log += &quot;Started at: &quot; + startTime.ToString() + Environment.NewLine;

            if (InProgress)
            {
                Log += &quot;Process already started before. Exiting out.&quot; + Environment.NewLine;

                return;
            }

            InProgress = true;

            Log += &quot;Doing work for 10 seconds...&quot; + Environment.NewLine;

            Thread.Sleep(10000);

            Log += &quot;Finished work.&quot; + Environment.NewLine;

            Log += &quot;Ended at: &quot; + DateTime.Now.ToString() + Environment.NewLine;

            Console.Write(Log);

            InProgress = false;
        }
    }
}
</code></pre><p>This program had a little bit of consideration put into it to ensure some simple safety:</p>
<ul>
<li>the log was set to an empty string when the <code>Work()</code> method was called</li>
<li>an <code>InProgress</code> boolean is set to true to ensure that the work can&#39;t be done twice at the same time</li>
</ul>
<p>I expected the following to be logged to the terminal:</p>
<pre><code>Started at: 26/10/2016 20:11:27
Finished work.
Ended at: 26/10/2016 20:11:27
</code></pre><p>But instead, this was logged:</p>
<pre><code>Started at: 26/10/2016 20:11:27
Process already started before. Exiting out.
Finished work.
Ended at: 26/10/2016 20:11:32
</code></pre><p>This can be a little bit confusing, but as it turns out, the static properties on a static class are not thread safe. What this means is that the property is shared between threads.</p>
<p>Here&#39;s a step by step on what happened:</p>
<ul>
<li>Main started running</li>
<li>the Work method was ran (on a new thread, which we will call &quot;Work (1)&quot;)</li>
<li>Main then paused on Thread.Sleep(5000)</li>
<li>Work (1) continued and set the Log string to empty. It then added &quot;Started at: 26/10/2016 20:11:27&quot;</li>
<li>Process.InProgress was currently set to false, so Work skipped the if block</li>
<li>Process.InPogress was set to true</li>
<li>&quot;Doing work for 10 seconds...&quot; is added to the log</li>
<li>Work (1) then waited at Thread.Sleep(10000)</li>
<li>Main finished waiting and started a new thread for the next Work (2) method</li>
<li>Work (2) sets the Log string to empty. It then added &quot;Started at: 26/10/2016 20:11:32&quot;</li>
<li>Work (2) saw that the InProgress boolean was set to true, and added &quot;Process already started before. Exiting out.&quot; to the Log</li>
<li>Work (1) finished waiting added &quot;Finished work.&quot; and &quot;Ended at: 26/10/2016 20:11:32&quot; to the Log</li>
<li>Work (1) writes the Log to the console</li>
</ul>
<p>This program can be fixed by either making the Worker class non-static (along with the properties and methods inside of it), or by making the Log thread static. This can be done with a simple attribute:</p>
<pre><code>[ThreadStatic]
public static string Log;
</code></pre><h2 id="the-moral-of-the-story">The moral of the story</h2>
<p>Generally in a majority of my classes I won&#39;t use static classes. Although static classes are quicker to instantiate (in terms of processing time and developer writing time), they&#39;re not exactly perfect for all situations.</p>
<p>The only time I would consider using a static class is if I want to implement a helper method - such as changing a DateTime into a specific format. These kinds of methods can be useful, but can be slightly annoying to call if a class has to be instantiated.</p>
]]></content:encoded>
            </item>
        
            <item>
                <title>Potentially useful programs for the budding computerphile</title>
                <link>https://harveywilliams.net/blog/potentially-useful-programs-for-the-budding-computerphile</link>
                <description>There are many programs I use in day to day life to help speed up or complement my workflow. Here are a few of the nicher ones which you may not have heard of.</description>
                
                    <category>miscellaneous</category>
                
                <pubDate>Sun, 25 Sep 2016 00:00:00 GMT</pubDate>
                <content:encoded><![CDATA[<p>Below I have collated a short list of some slightly obscure programs that I have installed on just about any computer that I own. You won&#39;t find obvious choices such as Firefox or Chrome, but the type of programs that you may not know you needed.. Until now.</p>
<h2 id="the-programs">The programs</h2>
<h3 id="audacity-osx-windows-linux">Audacity - OSX, Windows, Linux</h3>
<p>The obvious choice for any simple audio editing. This can also be used to record your voice. Although I rarely need to edit audio, this program is small enough and bloat-free enough that I won&#39;t second guess it on a new machine.</p>
<p><img src="/media/blog/potentially-useful-programs-for-the-budding-computerphile/audacity.png" alt="Audacity"></p>
<p><a target="_blank" href="http://alternativeto.net/software/audacity/">AlternativeTo</a></p>
<p><a target="_blank" href="http://www.audacityteam.org/">Website</a></p>
<p>Chocolatey: choco install audacity</p>
<h3 id="bluescreenview-windows">BlueScreenView - Windows</h3>
<p>Every time a blue screen happens on a Windows machine, a log is created and an event is recorded. Looking at the event doesn&#39;t give much information, and the log file is impossible to read, but BlueScreenView allows you to see a little more into what caused the blue screen.</p>
<p>I came across this software when a nearly brand new laptop of mine started BSODing over and over. Using this software, I quickly discovered that there was something wrong with the Windows filesystem, which led me to fixing it.</p>
<p><img src="/media/blog/potentially-useful-programs-for-the-budding-computerphile/bluescreenview.png" alt="BlueScreenView"></p>
<p><a target="_blank" href="http://alternativeto.net/software/bluescreenview/">AlternativeTo</a></p>
<p><a target="_blank" href="http://www.nirsoft.net/utils/blue_screen_view.html">Website</a></p>
<p>Choco: choco install bluescreenview</p>
<h3 id="bulk-rename-utility-windows">Bulk Rename Utility - Windows</h3>
<p>BRU is a god send if you have a bunch of files that need renaming. It&#39;s a small light-weight program but doesn&#39;t skimp on features.</p>
<p><img src="/media/blog/potentially-useful-programs-for-the-budding-computerphile/bulkrenameutility.png" alt="Bulk Rename Utility"></p>
<p><a target="_blank" href="http://alternativeto.net/software/bulk-rename-utility/">AlternativeTo</a></p>
<p><a target="_blank" href="http://www.bulkrenameutility.co.uk/Main_Intro.php">Website</a></p>
<p>Choco: choco install bulkrenameutility</p>
<h3 id="calibre-osx-windows-linux">Calibre - OSX, Windows, Linux</h3>
<p>Calibre is a great program for managing your book library. Just drop a book file (such as an EPUB or MOBI) into the program and it will slot the book into its file system. Attach an eReader such as a Kindle and with the click of a button, Calibre will (if necessary) convert the file to a type that the reader will understand, and upload it.</p>
<p><img src="/media/blog/potentially-useful-programs-for-the-budding-computerphile/bulkrenameutility.png" alt="Bulk Rename Utility"></p>
<p><a target="_blank" href="http://alternativeto.net/software/calibre/">AlternativeTo</a></p>
<p><a target="_blank" href="http://calibre-ebook.com/">Website</a></p>
<p>Choco: choco install calibre</p>
<h3 id="chocolatey-windows">Chocolatey - Windows</h3>
<p>Chocolatey is a CLI package manager a little bit like Aptitude except it works on Windows. Chocolatey cuts out the tediousness of downloading an installer and running through the installation wizard, and does this all automatically. Chocolatey can also be used to auto update all of your programs.</p>
<p>One of the best things about Chocolatey is that you can be fairly sure that none of the packages that are available on it will try to install any extra bloat-ware (such as browser toolbars or anti-virus programs). This is because each package is maintained by someone who chooses the best settings for that program. This best settings options can however sometimes be not what you want, especially when a program chooses to install itself somewhere unusual. However, 90% of the time I find that Chocolatey installs the program just fine.</p>
<p>The other great thing about Chocolatey is that you can export all of the programs you have installed via it to a list, and then get Chocolatey to run through that list on another computer. This can be used to replace Ninite when you are setting up a new computer. I find that this process saves me a lot of time - just input the command and Chocolatey will happily install as many programs as you want while you walk away and think about less tedious things.</p>
<p>The main syntax of Chocolatey is easy to learn. &quot;choco search {program-name}&quot; will return a list of programs that match your name. &quot;choco install {program-name} -y&quot; will install a program without asking if you accept the terms and condtions.</p>
<p><img src="/media/blog/potentially-useful-programs-for-the-budding-computerphile/chocolatey.png" alt="Chocolatey"></p>
<p><a target="_blank" href="http://alternativeto.net/software/chocolatey/">AlternativeTo</a></p>
<p><a target="_blank" href="https://chocolatey.org/">Website</a></p>
<h3 id="clover-windows">Clover - Windows</h3>
<p>Having tabs on a file browser makes as much sense to me as having tabs on your browser. Unfortunately, Windows has yet to implement this feature into even their latest OS. There are alternative file browsers (such as Q-Dir) that you can use instead of the default Explorer, but I find that they don&#39;t integrate with Windows as nicely as the default does. Fortunately, there is a program called Clover which adds Chrome-like tabs to your ordinary Explorer. The integration is seamless and works near perfectly.</p>
<p><img src="/media/blog/potentially-useful-programs-for-the-budding-computerphile/clover.png" alt="Clover"></p>
<p><a target="_blank" href="http://alternativeto.net/software/clover">AlternativeTo</a></p>
<p><a target="_blank" href="http://ejie.me/">Website</a></p>
<p>Choco: choco install clover</p>
<h3 id="conemu-windows">ConEmu - Windows</h3>
<p>For those who like Windows, like the terminal but hate the Cmd prompt, there is ConEmu. This program allows for an overwhelming amount of customisation on the terminal including tabs and theming.</p>
<p><img src="/media/blog/potentially-useful-programs-for-the-budding-computerphile/conemu.png" alt="ConEmu"></p>
<p><a target="_blank" href="http://alternativeto.net/software/conemu/">AlternativeTo</a></p>
<p><a target="_blank" href="http://conemu.github.io/">Website</a></p>
<p>Choco: choco install conemu</p>
<h3 id="foobar2000-windows">Foobar2000 - Windows</h3>
<p>Foobar is a fairly simplistic but highly customizable music player. There is advanced theming for people who can work out how to use that, but for me, I like to use the layout editing mode to get everything where I want.</p>
<p>One simple feature that I like is that the music in your library can be viewed by folder structure, and since I have a organised folder structure this is something which really appeals to me.</p>
<p><img src="/media/blog/potentially-useful-programs-for-the-budding-computerphile/foobar2000.png" alt="Foobar2000"></p>
<p><a target="_blank" href="http://alternativeto.net/software/foobar2000/">AlternativeTo</a></p>
<p><a target="_blank" href="http://www.foobar2000.org/">Website</a></p>
<p>Choco: choco install foobar2000</p>
<h3 id="honeyview-windows">Honeyview - Windows</h3>
<p>Honeyview is a fairly configurable image viewer. It is very fast and can view just about any image format, including GIF.</p>
<p><img src="/media/blog/potentially-useful-programs-for-the-budding-computerphile/honeyview.png" alt="Honeyview"></p>
<p><a target="_blank" href="http://alternativeto.net/software/honeyview/">AlternativeTo</a></p>
<p><a target="_blank" href="http://www.bandisoft.com/honeyview/en/">Website</a></p>
<p>Choco: choco install honeyview</p>
<h3 id="keepass2-osx-windows-linux-android">KeePass2 - OSX, Windows, Linux, Android</h3>
<p>KeePass is a program which stores passwords in a locked database. Enter the right master password (or attach the correct keyfile), and the database will open up. This program doesn&#39;t store the password file online so unless someone gets your local machine, you can be fairly sure that the passwords are completely safe. KeePass also allows you to generate random password of varying sizes and complexity which I always use now to ensure that my passwords can not be bruteforced.</p>
<p>If you need the passwords file to be accessible, consider uploading the file into the cloud (by using something like Dropbox).</p>
<p>One key feature for me is that password databases can be merged which is very useful for if I make changes to two versions of the same file. Using this feature I can quickly merge the two versions back into one without needing to worry about missing new passwords.</p>
<p><img src="/media/blog/potentially-useful-programs-for-the-budding-computerphile/keepass.png" alt="KeePass"></p>
<p><a target="_blank" href="http://alternativeto.net/software/keepass/">AlternativeTo</a></p>
<p><a target="_blank" href="http://keepass.info/">Website</a></p>
<p>Choco: choco install keepass</p>
<h3 id="launchy-osx-windows-linux">Launchy - OSX, Windows, Linux</h3>
<p>It seems like every time a new a new version of any operating system comes out, they add bloat to the search tool of the OS. With Windows we now have the search looking for files on the computer, doing Bing searches and also looking for programs. 99% of the time all I want to do is get a program open that I don&#39;t have in my quick launch bar. Launchy solves this issue by only searching for programs within the OS. It is very fast and can be configured to be opened by a keypress or two. I have left it so it is opened when I press alt-space together. A box then pops up which I can type the name of the program in.</p>
<p>Launchy seems to learn what to search for based on what you have opened before with it. For example, if I type &quot;c&quot; into Launchy, it knows that I want to open up Clover because before I skipped the option that was Control Panel, and went straight for Clover. However, the inbuilt search for Windows never learns that I am more likely to use Clover than the Control Panel.</p>
<p>One of the best things about Launchy is that it&#39;s cross platform, which means that regardless of the operating system, I can access my programs fast without needing to learn that systems search.</p>
<p>Something to note is that Launchy can take a couple of minutes to put a program into its index. This means that if I install something, I can either tell Launchy to reindex, or open the program another way. When I next come to using Launchy, the program should then be in the index.</p>
<p><img src="/media/blog/potentially-useful-programs-for-the-budding-computerphile/launchy.png" alt="Launchy"></p>
<p><a target="_blank" href="http://alternativeto.net/software/launchy/">AlternativeTo</a></p>
<p><a target="_blank" href="http://www.launchy.net/">Website</a></p>
<p>Choco: choco install launchy</p>
<h3 id="open-broadcaster-software-osx-windows-linux">Open Broadcaster Software - OSX, Windows, Linux</h3>
<p>OBS can be a little hard to understand if you&#39;re new to it, but the main feature which I use it for is screen recording, which it really excels at. It&#39;s totally free (including open-source) and has many features including the option to live-stream to other people.</p>
<p><img src="/media/blog/potentially-useful-programs-for-the-budding-computerphile/obs.png" alt="OBS"></p>
<p><a target="_blank" href="http://alternativeto.net/software/open-broadcaster-software/">AlternativeTo</a></p>
<p><a target="_blank" href="https://obsproject.com/">Website</a></p>
<p>Choco: choco install obs</p>
<h3 id="thunderbird-osx-windows-linux">Thunderbird - OSX, Windows, Linux</h3>
<p>For mail clients, I have to say, Thunderbird is the best of a bad bunch. Email is always slightly dodgy because the technology basically died years ago, and for this reason, Thunderbird does not need to innovate. Instead, Mozilla chooses to push other features onto the mail client that has nothing to do with email (such as a calendar).</p>
<p>However, if you want your email to be quickly accessible (and accessible offline), all in one interface, then Thunderbird will do the trick.</p>
<p><img src="/media/blog/potentially-useful-programs-for-the-budding-computerphile/thunderbird.png" alt="Thunderbird"></p>
<p><a target="_blank" href="http://alternativeto.net/software/mozilla-thunderbird/">AlternativeTo</a></p>
<p><a target="_blank" href="https://www.mozilla.org/en-GB/thunderbird/">Website</a></p>
<p>Choco: choco install thunderbird</p>
<h3 id="mpc-hc-windows">MPC-HC - Windows</h3>
<p>MPC-HC is barely different from VLC, but a lot of nerds will swear by it. These nerds will claim that MPC can render better than VLC and with less glitches.. Or whatever.</p>
<p>For me, I quite like MPC simply because by default, the video player will only show the controls (when in full screen) when the cursor is actually brought over them, rather than whenever the mouse moves. Otherwise, the two programs appear to be basically identical to me.</p>
<p><img src="/media/blog/potentially-useful-programs-for-the-budding-computerphile/mpc-hc.png" alt="MPC-HC"></p>
<p><a target="_blank" href="http://alternativeto.net/software/mpc-hc/">AlternativeTo</a></p>
<p><a target="_blank" href="https://mpc-hc.org/">Website</a></p>
<p>Choco: choco install mpc-hc</p>
<h3 id="mumble-osx-windows-linux-osx-android">Mumble - OSX, Windows, Linux, OSX, Android</h3>
<p>There are many voice clients that can be used such as Ventrillo or Team Speak, but Mumble works reasonable well for me. It ensures that users set up the sound profile properly before entering any chat rooms which helps keep the chat clean.</p>
<p>The software is opensource, and you can install Murmur (the Mumble server) on any machine you like. Configuration for Murmur is relatively straight forward, but will most likely require port-forwarding if you are running it from a home network.</p>
<p>There is also an Android client which allows you to connect to Murmur, called Plumble. There is a free version of the client which I have only briefly used, but seems to work very well.</p>
<p><img src="/media/blog/potentially-useful-programs-for-the-budding-computerphile/mumble.png" alt="Mumble"></p>
<p><a target="_blank" href="http://alternativeto.net/software/mumble/">AlternativeTo</a></p>
<p><a target="_blank" href="http://wiki.mumble.info/wiki/Main_Page">Website</a></p>
<p>Choco: choco install mumble</p>
<h3 id="qbittorrent-osx-windows-linux">qBittorrent - OSX, Windows, Linux</h3>
<p>While uTorrent is still a very popular client for torrenting, many of the users has started moving away from it because it is shoveling advertisements into its UI. Otehr people instead choose to stay on an older version of uTorrent before it changed its way. However, for me, qBittorrent is a fine replacement. The UI is very familiar and easy to use, and the project is opensource so it&#39;s unlikely to go the way of uTorrent. Previously, people had common problems with torrents stalling for ages, but this problem seems to have been fixed.</p>
<p><img src="/media/blog/potentially-useful-programs-for-the-budding-computerphile/qbittorrent.png" alt="qBittorrent"></p>
<p><a target="_blank" href="http://alternativeto.net/software/qbittorrent/">AlternativeTo</a></p>
<p><a target="_blank" href="http://www.qbittorrent.org/">Website</a></p>
<p>Choco: choco install qbittorrent</p>
<h3 id="recuva-windows">Recuva - Windows</h3>
<p>A while ago I accidentally formatted one of my USB drives which meant I lost a couple of useful files. I quickly found myself looking for a program to recover the lost files, and although a lot of programs can do this, a lot will then charge you to actually recover the files. Recuva is an excellent recovery tall made by Piriform that does file recovery without any hassle.</p>
<p><img src="/media/blog/potentially-useful-programs-for-the-budding-computerphile/recuva.png" alt="Recuva"></p>
<p><a target="_blank" href="http://alternativeto.net/software/recuva/">AlternativeTo</a></p>
<p><a target="_blank" href="http://www.piriform.com/recuva">Website</a></p>
<p>Choco: choco install recuva</p>
<h3 id="rdcman-windows">RDCMan - Windows</h3>
<p>RDCMan or Remote Desktop Connection Manager is a program much like the Windows inbuilt Remote Desktop Connection except it allows you to save servers into groups for easy management of multiple servers at the same time.</p>
<p><img src="/media/blog/potentially-useful-programs-for-the-budding-computerphile/rdcman.png" alt="RDC Man"></p>
<p><a target="_blank" href="http://alternativeto.net/software/remote-desktop-connection-manager/">AlternativeTo</a></p>
<p><a target="_blank" href="https://www.microsoft.com/en-gb/download/details.aspx?id=44989">Website</a></p>
<p>Choco: choco install rdcman</p>
<h3 id="truecrypt-osx-windows-linux">TrueCrypt - OSX, Windows, Linux</h3>
<p>Although TrueCrypt has been abandoned by the owners of the project in 2014, it is still a tried and tested solution to drive encryption. The project was large enough that an entirely separate project was instigated to simply test the programs implementation and ensure that the encryption was entirely secure.</p>
<p><img src="/media/blog/potentially-useful-programs-for-the-budding-computerphile/truecrypt.png" alt="Truecrypt"></p>
<p><a target="_blank" href="http://alternativeto.net/software/truecrypt/">AlternativeTo</a></p>
<p><a target="_blank" href="https://truecrypt.ch">Website</a></p>
<p>Choco: choco install truecrypt</p>
<h3 id="windirstat-windows">WinDirStat - Windows</h3>
<p>WinDirStat is a simple program that runs through a drive on your computer and finds out the sizes of each of the files within. It then displays a simple UI where each folder and file is visually shown to help you see where space is being used. This can be helpful if you need to free up some space and you want to know where the big culprits are.</p>
<p>One of my colleagues found that about 40GB of their drive had mysteriously gone missing, and they couldn&#39;t find it in any of the usual folders. After running WinDirStat for a few minutes, we discovered that a huge portion of the computers drive had been taken up by a log file that had grown excessively large. This log file was being stored in an unusual place in the file system which without WinDirStats visual representation of the file system would have been very hard to find.</p>
<p><img src="/media/blog/potentially-useful-programs-for-the-budding-computerphile/windirstat.png" alt="WinDirStat"></p>
<p><a target="_blank" href="http://alternativeto.net/software/windirstat/">AlternativeTo</a></p>
<p><a target="_blank" href="http://windirstat.info/">Website</a></p>
<p>Choco: choco install windirstat</p>
<h2 id="thoughts-and-other-things">Thoughts and other things</h2>
<p>There are probably many good alternatives to the list that I have put up above, but these are the ones that I currently use. One property of a program that I always look out for is if the program is cross-platform and if it is open-source. Generally, only if the program truly excels despite not having these two properties will I then use it. The reason being that if I ever choose to swap operating system then it&#39;s important to me that I can use as many of the old programs as possible. As for the open-source issue, it&#39;s comforting knowing that even if the main developers dropped support, other developers could continue to keep new releases coming out. Having the source to a program can also help ensure that there is nothing malicious hidden.</p>
<p>Along with all of the programs, I have included a link to AlternativeTo which is a great site that I always check before installing a new program. The program finds alternatives to just about any application or website and can help you find the best tool for your needs. AlternativeTo also allows people to comment, which can help steer you clear of any dodgy programs that may try to install malware.</p>
<p>If you have any other programs you think should belong in this list, comment below and tell us why you think it&#39;s great.</p>
]]></content:encoded>
            </item>
        
            <item>
                <title>Making Umbraco Nodes with the Models Builder</title>
                <link>https://harveywilliams.net/blog/making-umbraco-nodes-with-the-models-builder</link>
                <description>In my latest Umbraco website built I have been getting friendly with the new Models Builder that is included by default. In this post I show how the Models Builder can be used with the Content Service to create new Umbraco nodes programmatically.</description>
                
                    <category>umbraco</category>
                
                    <category>csharp</category>
                
                    <category>programming</category>
                
                <pubDate>Sun, 20 Mar 2016 00:00:00 GMT</pubDate>
                <content:encoded><![CDATA[<p>With the latest release of Umbraco 7.4, the <a target="_blank" href="https://github.com/zpqrtbnk/Zbu.ModelsBuilder">Models
Builder</a> has been
included by default with Umbraco. The Models Builder allows us to
strongly link our published content models with what is happening in the
Umbraco backend.</p>
<h2 id="so-">So?</h2>
<p>A common example of code that resides in Umbraco views is:</p>
<pre><code>var content = node.GetPropertyValue(&quot;content&quot;);
</code></pre><p>This is all great until someone removes the content property in Umbraco
and suddenly the view breaks because there isn&#39;t a content property type
on the node. The Models Builder helps point out any errors (generally in
the Intellisense or on build) that have occured due to any changes in
Umbraco.</p>
<h2 id="using-this-with-the-content-service-to-create-nodes">Using this with the content service to create nodes</h2>
<p>Occasionally it is necessary to create nodes in Umbraco
programmatically. You can do this using the ContentService. Here is a
document type that I have created in Umbraco:</p>
<p><img src="/media/blog/making-umbraco-nodes-with-the-models-builder/umbraco-post-document-type.png" alt="An Umbraco document type that creates a post node"></p>
<p>We can see that there are three properties on my post document type;
postTitle, content and postDate. Without the Models Builder, we would&#39;ve
created new Umbraco nodes this way:</p>
<pre><code>var contentService = ApplicationContext.Current.Services.ContentService;
var parentId = 1053;

// Create the new node.
var post = contentService.CreateContent(&quot;My Post&quot;, parentId, &quot;post&quot;);

// Add content to the node.
post.SetValue(&quot;postTitle&quot;, &quot;Alternate Title&quot;);
post.SetValue(&quot;postDate&quot;, DateTime.Now);
post.SetValue(&quot;content&quot;, &quot;&lt;p&gt;...&lt;/p&gt;&quot;);

// Save and publish the node.
contentService.PublishWithStatus(post);
</code></pre><p>The above works, but it has the age old problem where if the document
type changes in Umbraco, there&#39;s no way of knowing what code has become
out of date and needs updating. The below code remedies this by using the
new Models Builder.</p>
<pre><code>var contentService = ApplicationContext.Current.Services.ContentService;
var parentId = 1;

// Create the new node.
var post = contentService.CreateContent(&quot;My Post&quot;, parentId, ContentModels.Post.ModelTypeAlias);

// Add content to the node.
post.SetValue(ContentModels.Post.GetModelPropertyType(x =&gt; x.PostTitle).PropertyTypeAlias, &quot;Alternate Title&quot;);
post.SetValue(ContentModels.Post.GetModelPropertyType(x =&gt; x.PostDate).PropertyTypeAlias, DateTime.Now);
post.SetValue(ContentModels.Post.GetModelPropertyType(x =&gt; x.Content).PropertyTypeAlias, &quot;&lt;p&gt;...&lt;/p&gt;&quot;);

// Save and publish the node.
contentService.PublishWithStatus(post);
</code></pre><p>This updated code might be longer, but it should help with site
maintenance in the long run.</p>
]]></content:encoded>
            </item>
        
            <item>
                <title>How to render MVC emails with CSHTML</title>
                <link>https://harveywilliams.net/blog/rendering-mvc-emails-with-cshtml</link>
                <description>Tired of using string formatting to create emails in your code? Read here to find out about how to build HTML emails using MVC, Razor and CSHTML.</description>
                
                    <category>csharp</category>
                
                    <category>programming</category>
                
                <pubDate>Wed, 06 Feb 2016 00:00:00 GMT</pubDate>
                <content:encoded><![CDATA[<p>Almost every website that I build for a client needs to have some sort of way to contact the outside world; the most common way of doing this is to send an email.</p>
<p>The thing is, developers get lazy when they start making emails. The technology is stuck in the past and it&#39;s not a fun front end experience to try and create complicated layouts using tables. All of this together makes creating emails a hack and slash job. Here&#39;s the simple way a lot of emails are made:</p>
<pre><code>public bool Send()
{
    var mailServer = new SmtpClient();
    var mail = new MailMessage();

    mail.From = new MailAddress(&quot;foo.bar@net&quot;, &quot;Foo Bar&quot;);
    mail.To.Add(&quot;bar@foo.net&quot;);
    mail.Subject = &quot;Thank you for signing up!&quot;;
    mail.IsBodyHtml = true;

    // Don&#39;t do this!!
    mail.Body = String.Format(&quot;&lt;h2&gt;Dear {0},&lt;/h2&gt;&lt;p&gt;Thank you for signing up. We value you as a customer etc etc...&lt;/p&lt;&lt;p&gt;From the team at {1}.&lt;/p&gt;&quot;,
        &quot;Bar Foo&quot;,
        &quot;foo.bar.net&quot;);

    try
    {
        mailServer.Send(mail);
    }
    catch (SmtpException e)
    {
        LogHelper.Error(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType, &quot;Error sending welcome email.&quot;, e);
        return false;
    }

    return true;
}
</code></pre><p>The above doesn&#39;t look crazy bad, but just wait until the email starts getting complicated. If you want to have real formatting, then it&#39;s going to quickly get out of hand.</p>
<h2 id="rendering-mvc-emails-with-razor-and-cshtml-templates">Rendering MVC emails with Razor and CSHTML templates</h2>
<p>Enough of string formatting! We have a better method now. We&#39;re used to using Razor and some sort of MVC to build our ordinary website views. Surely there is some way we can incorporate that into our email design? Well there is!</p>
<h3 id="the-west-wind-toolkit-way">The West Wind Toolkit Way</h3>
<p>Fortunately there is a tool out there which allows us to easily render a CSHTML view with a model of our choosing. This tool is called the <a target="_blank" href="https://github.com/RickStrahl/WestwindToolkit">West Wind Toolkit</a>. It&#39;s opensource and under the MIT license, meaning we can use it in our projects.</p>
<p>The particular part of the toolkit we plan on using is the <a target="_blank" href="https://github.com/RickStrahl/WestwindToolkit/blob/master/Westwind.Web.Mvc/Utils/ViewRenderer.cs">view renderer</a>. Since I didn&#39;t want to bloat my project with anything more than necessary, I ripped apart this piece of C# that West Wind has provided us with, and only kept the core methods in the end result:</p>
<pre><code>using System;
using System.Web;
using System.Web.Mvc;
using System.IO;
using System.Web.Routing;

namespace YourNamespace
{
    /// 
    /// Class that renders MVC views to a string using the
    /// standard MVC View Engine to render the view.
    /// 
    /// Requires that ASP.NET HttpContext is present to
    /// work, but works outside of the context of MVC
    /// 
    /// Particularly useful for rendering CSHTML for emails.
    /// 
    /// Code extracted from:
    /// https://github.com/RickStrahl/WestwindToolkit/blob/master/Westwind.Web.Mvc/Utils/ViewRenderer.cs
    /// 
    public class ViewRenderer
    {
        /// 
        /// Required Controller Context
        /// 
        protected ControllerContext Context { get; set; }

        /// 
        /// Initializes the ViewRenderer with a Context.
        /// 
        /// 
        /// If you are running within the context of an ASP.NET MVC request pass in
        /// the controller&#39;s context. 
        /// Only leave out the context if no context is otherwise available.
        /// 
        public ViewRenderer(ControllerContext controllerContext = null)
        {
            // Create a known controller from HttpContext if no context is passed
            if (controllerContext == null)
            {
                if (HttpContext.Current != null)
                {
                    controllerContext = CreateController().ControllerContext;
                }
                else
                {
                    throw new InvalidOperationException(
                        &quot;ViewRenderer must run in the context of an ASP.NET &quot; +
                        &quot;Application and requires HttpContext.Current to be present.&quot;);
                }
            }

            Context = controllerContext;
        }

        /// 
        /// Renders a partial MVC view to string. Use this method to render
        /// a partial view that doesn&#39;t merge with _Layout and doesn&#39;t fire
        /// _ViewStart.
        /// 
        /// 
        /// The path to the view to render. Either in same controller, shared by 
        /// name or as fully qualified ~/ path including extension
        /// 
        /// The model to pass to the viewRenderer
        /// Active controller context
        /// String of the rendered view or null on error
        public static string RenderView(string viewPath, object model = null, ControllerContext controllerContext = null)
        {
            var renderer = new ViewRenderer(controllerContext);
            return renderer.RenderViewToString(viewPath, model);
        }

        /// 
        /// Renders a partial MVC view to string. Use this method to render
        /// a partial view that doesn&#39;t merge with _Layout and doesn&#39;t fire
        /// _ViewStart.
        /// 
        /// 
        /// The path to the view to render. Either in same controller, shared by 
        /// name or as fully qualified ~/ path including extension
        /// 
        /// The model to pass to the viewRenderer
        /// String of the rendered view or null on error
        public string RenderViewToString(string viewPath, object model = null)
        {
            return RenderViewToStringInternal(viewPath, model, true);
        }

        /// 
        /// Internal method that handles rendering of either partial or 
        /// or full views.
        /// 
        /// 
        /// The path to the view to render. Either in same controller, shared by 
        /// name or as fully qualified ~/ path including extension
        /// 
        /// Model to render the view with
        /// Determines whether to render a full or partial view
        /// String of the rendered view
        private string RenderViewToStringInternal(string viewPath, object model, bool partial = false)
        {
            // first find the ViewEngine for this view
            ViewEngineResult viewEngineResult = null;
            if (partial)
                viewEngineResult = ViewEngines.Engines.FindPartialView(Context, viewPath);
            else
                viewEngineResult = ViewEngines.Engines.FindView(Context, viewPath, null);

            //if (viewEngineResult == null || viewEngineResult.View == null)
            //throw new FileNotFoundException(Resources.ViewCouldNotBeFound);

            // get the view and attach the model to view data
            var view = viewEngineResult.View;
            Context.Controller.ViewData.Model = model;

            string result = null;

            using (var sw = new StringWriter())
            {
                var ctx = new ViewContext(Context, view,
                    Context.Controller.ViewData,
                    Context.Controller.TempData,
                    sw);

                view.Render(ctx, sw);
                result = sw.ToString();
            }

            return result;
        }

        /// 
        /// Creates an instance of an MVC controller from scratch 
        /// when no existing ControllerContext is present       
        /// 
        /// Type of the controller to create
        /// Controller Context for T
        /// thrown if HttpContext not available
        public static T CreateController(RouteData routeData = null) where T : Controller, new()
        {
            // create a disconnected controller instance
            T controller = new T();

            // get context wrapper from HttpContext if available
            HttpContextBase wrapper = null;
            if (HttpContext.Current != null)
            {
                wrapper = new HttpContextWrapper(System.Web.HttpContext.Current);
            }
            else
            {
                throw new InvalidOperationException(
                    &quot;Can&#39;t create Controller Context if no active HttpContext instance is available.&quot;);
            }

            if (routeData == null)
                routeData = new RouteData();

            // add the controller routing if not existing
            if (!routeData.Values.ContainsKey(&quot;controller&quot;) &amp;&amp; !routeData.Values.ContainsKey(&quot;Controller&quot;))
            {
                routeData.Values.Add(&quot;controller&quot;, controller.GetType().Name
                    .ToLower()
                    .Replace(&quot;controller&quot;, &quot;&quot;));
            }

            controller.ControllerContext = new ControllerContext(wrapper, routeData, controller);
            return controller;
        }
    }

    /// 
    /// Empty MVC Controller instance used to 
    /// instantiate and provide a new ControllerContext
    /// for the ViewRenderer
    /// 
    public class EmptyController : Controller { }
}
</code></pre><p>You can also view the latest version that I will be using in my projects <a target="_blank" href="https://gist.github.com/HarveyWilliams/0405edd6719c16171329">here</a>.</p>
<p>Include this view renderer in your project, and you can use it to render Razor CSHTML views with a model.</p>
<h3 id="building-the-model">Building the Model</h3>
<p>Before we start using the view renderer in our project, we will need to set up a model to use with our view. Below is a very simple one that covers the two properties that our model will need:</p>
<pre><code>public class NewSignUpModel
{
    public string Recipient { get; set; }
    public string Team { get; set; }
}
</code></pre><h3 id="building-the-view">Building the view</h3>
<p>Our view will need to reference the model we just made using @model at the top of the template:</p>
<pre><code>@model NewSignUpModel
&lt;h2&gt;Dear @(Model.Recipient),&lt;/h2&gt;
&lt;p&gt;Thank you for signing up. We value you as a customer etc etc...&lt;/p&gt;
&lt;p&gt;From the team at @(Model.Team).&lt;/p&gt;
</code></pre><p>The @model reference allows use to then write @(Model.Recipient) where we want the parameter to be shown. But I&#39;m sure you&#39;re used to doing this kind of thing by now.</p>
<h3 id="updating-the-mail-sending-method">Updating the mail sending method</h3>
<p>Finally, we need to update our original mail send method to use the view renderer. Pass in the path to your view as the first parameter to the ViewRenderer.RenderView method, and the model you intend the view to use as the second:</p>
<pre><code>public bool Send()
{
    var mailServer = new SmtpClient();
    var mail = new MailMessage();

    mail.From = new MailAddress(&quot;foo.bar@net&quot;, &quot;Foo Bar&quot;);
    mail.To.Add(&quot;bar@foo.net&quot;);
    mail.Subject = &quot;Thank you for signing up!&quot;;
    mail.IsBodyHtml = true;

    mail.Body = ViewRenderer.RenderView(&quot;~/Views/Mail/NewSignUp.cshtml&quot;, new NewSignUpModel
    {
        Recipient = &quot;Bar Foo&quot;,
        Team = &quot;foo.bar.net&quot;
    });

    try
    {
        mailServer.Send(mail);
    }
    catch (SmtpException e)
    {
        LogHelper.Error(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType, &quot;Error sending welcome email.&quot;, e);
        return false;
    }

    return true;
}
</code></pre><p>Using the above method will get an email sent off but with the view that we created as the body of the email.</p>
]]></content:encoded>
            </item>
        
            <item>
                <title>Caching Umbraco web API controllers</title>
                <link>https://harveywilliams.net/blog/caching-umbraco-web-controllers</link>
                <description>Caching improves load time for everyone. Here I explain how easily make caching work with Web API controllers.</description>
                
                    <category>csharp</category>
                
                    <category>umbraco</category>
                
                    <category>programming</category>
                
                <pubDate>Tue, 26 Jan 2016 00:00:00 GMT</pubDate>
                <content:encoded><![CDATA[<p>Caching is a great way to reduce server load and reduce client load times. It should be an easy thing to do, but after a little research I found that the standard way of caching most ordinary methods does not work with Web API controllers.</p>
<h2 id="how-to-cache-standard-mvc-controllers-using-the-outputcache-attribute">How to cache standard MVC controllers using the OutputCache attribute</h2>
<p>Caching an MVC controller is very easy. All you need to do is shove [OutputCache] before your method (or even class) and it will be cached on the server:</p>
<pre><code>public class PageController : Umbraco.Web.Mvc.RenderMvcController
{
    // Warning!! Won&#39;t work in a UmbracoApiController!!
    [System.Web.Mvc.OutputCache(Duration = 60)]
    public override ActionResult Index(RenderModel model)
    {
        var pageModel = new PageModel(model.Content);

        // some code

        return CurrentTemplate(pageModel);
    }
}
</code></pre><p>The Duration parameter sets how long to cache in seconds.</p>
<p>One way to test to see if this has worked is to set a breakpoint in the code and refresh the page that the controller controls. The first time it will hit the breakpoint, the second (provided that you refresh before the time runs out) it won&#39;t! That&#39;s because the output has been cached.</p>
<p>However, if you try the same attribute on a controller that inherits from a UmbracoApiController, you will find that it has no effect. <a target="_blank" href="http://shamenun.com/">Shame!!</a></p>
<p>This is because the <a target="_blank" href="https://github.com/umbraco/Umbraco-CMS/blob/d50e49ad37fd5ca7bad2fd6e8fc994f3408ae70c/src/Umbraco.Web/WebApi/UmbracoApiController.cs#L14">UmbracoApiController</a> inherits from the <a target="_blank" href="https://github.com/umbraco/Umbraco-CMS/blob/d50e49ad37fd5ca7bad2fd6e8fc994f3408ae70c/src/Umbraco.Web/WebApi/UmbracoApiControllerBase.cs#L15">UmbracoApiControllerBase</a> which in turn inherits from the basic ApiController. So? Well, as it turns out, the ApiController does not take notice of our fancy OutputCache. You can read all about it <a target="_blank" href="http://stackoverflow.com/questions/17287144/how-to-cache-net-web-api-requests-use-w-angularjs-http">here</a>.</p>
<p>This is different from the <a target="_blank" href="https://github.com/umbraco/Umbraco-CMS/blob/2c63866cb35c59803d5649131438305c56aece38/src/Umbraco.Web/Mvc/RenderMvcController.cs#L15">RenderMvcController</a> because it inherits from the <a target="_blank" href="https://github.com/umbraco/Umbraco-CMS/blob/d50e49ad37fd5ca7bad2fd6e8fc994f3408ae70c/src/Umbraco.Web/Mvc/UmbracoController.cs#L15">UmbracoController</a> which in turn inherits from the basic MVC Controller. This one does take notice of our OutputCache.</p>
<h2 id="the-fix-cacheoutput">The fix: CacheOutput</h2>
<p>Fortunately for us, someone clever has made an alternative - the <a target="_blank" href="https://github.com/filipw/AspNetWebApi-OutputCache">CacheOutput</a> attribute. This sounds similar, so try not to it with the built in cache attribute.</p>
<p>On your project, install the package &quot;WebApi2&quot; using the NuGet console in VS:</p>
<pre><code>PM&gt; Install-Package Strathweb.CacheOutput.WebApi2
</code></pre><p>After the package has successfully installed, you can use the CacheOutput attribute instead of the built in MVC one:</p>
<pre><code>public class MySurfaceController : UmbracoApiController
{
    [WebApi.OutputCache.V2.CacheOutput(ClientTimeSpan = 60, ServerTimeSpan = 60)]
    public MyObject Umbraco.Web.WebApi.GetInformation(string someParam)
    {
        var myObject = new MyObject();

        // some code..?

        return myObject;
    }
}
</code></pre><p>Now visiting /umbraco/api/mycontroller/getinformation?someparam=somevalue and running the same breakpoint test as before will show that the CacheOutput attribute has worked.</p>
<p>This time, ClientTimeSpan gets the clients browser to cache the first result - next time a request won&#39;t even make it to the target server because the browser will reach into its&#39; own cache and retrieve the data it received before. This should be done with a &quot;200 (cached)&quot; or a &quot;304 Not Modifed&quot; HTTP status if you view the call in your network tools of your browser. Meanwhile, ServerTimeSpan works in the same way as before.</p>
<h2 id="wrapping-up">Wrapping up</h2>
<p>As always, be careful with caching. Caching on the server in this basic way will cause the same results to be shown to everyone, so make sure that no user sensitive data is being cached. Caching on the client can be great but can lead to out of date content if the cache period is too long.</p>
<h2 id="resources">Resources</h2>
<ul>
<li><a target="_blank" href="https://our.umbraco.org/forum/developers/api-questions/63516-UmbracoApiController-caching">Our Umbraco</a></li>
</ul>
]]></content:encoded>
            </item>
        
            <item>
                <title>Installing IISNode for production</title>
                <link>https://harveywilliams.net/blog/installing-iisnode</link>
                <description>Developing Node.js applications on Windows is easy, but getting them setup for production can be a little more difficult. Read this post to discover how to set up IISNode in Windows and get a Node application running within IIS.</description>
                
                    <category>nodejs</category>
                
                <pubDate>Mon, 25 Jan 2016 00:00:00 GMT</pubDate>
                <content:encoded><![CDATA[<p>This website is was my first website which I built in Node.js. It started out being just a static website because I knew I would be the only maintainer, and I&#39;m happy to dive into code to change some content. However, I quickly found that the site was getting out of hand as more pages were created - to make even a small change to any common element meant copy and pasting accross each page.</p>
<h2 id="the-solution-node-js-">The solution? Node.js!</h2>
<p>I decided that I had to add some backend logic to piece together my pages. First I questioned if PHP was the answer, but I&#39;ve always found that PHP would also get out of hand with bits of code getting lost in places. I asked my coworker from GrowCreate for their oponion, and they said that I should try building in Node.</p>
<h2 id="the-problem">The problem</h2>
<p>Developing Node applications on Windows is very simple. All you have to do is just open up a cmd window (after installing Node) and type &quot;node server.js&quot;, where server.js is your server configuration file. However, doing this on a live Windows server was impractical. Having a cmd window open to host the website all the time would be a bad idea. Intead, I wanted my site to be hosted through IIS, as it meant that all of my sites would be clearly visible from one applicaion on my server. Currently, only way to do this is by installing IISNode.</p>
<p>Getting IISNode running is easy once you&#39;ve done it before, but understanding the steps required to get there can be a little difficult.</p>
<h2 id="getting-started">Getting started</h2>
<p>I suggest doing this on your development machine before doing this on a server. Below is a list of things you will need already set up before you can get IISNode set up.</p>
<ul>
<li>IIS7/8 installed</li>
<li>Node installed</li>
</ul>
<h2 id="installing-iisnode">Installing IISNode</h2>
<p>I accidentally went down the path of trying to build IISNode from source which can be pain if you&#39;ve never done that sort of thing before. As it turns out, you can download a compiled install file from <a target="_blank" href="https://github.com/azure/iisnode/wiki/iisnode-releases">here</a>. Choose the correct build for your system (either 64bit or 32bit). I will be using v0.2.11 as it is the latest version at the time of writing.</p>
<p>After downloading this file, install it!</p>
<h3 id="testing-iisnode">Testing IISNode</h3>
<p>If you want to test that IISNode installed correctly, you can use the setupsamples.bat script to create an instance of IISNode. To run this file, you will need to open up an administrator window of cmd and cd to either &quot;C:\Program Files\iisnode&quot; (or &quot;C:\Program Files (x86)\iisnode&quot; if you installed the 32bit version). Type &quot;setupsamples.bat&quot; into the cmd prompt and the script should run. Read the output to check if the script ran successfully. The output should be similar to the one below.</p>
<p><img src="/media/blog/installing-iisnode/setupsamples.png" alt=""></p>
<p>Now provided that you have the &quot;Default Web Site&quot; running, you should be able to go to <a target="_blank" href="http://localhost/node">localhost/node&quot;</a> in your browser. If your browser just tells you that it is unable to connect to this, then it&#39;s likely that the &quot;Default Web Site&quot; is not running. If it gives you an &quot;HTTP Error 404.0 - Not Found&quot;, then the script did not run correctly. Otherwise you should be on a page similar to the one below.</p>
<p><img src="/media/blog/installing-iisnode/localhost.png" alt=""></p>
<p>Clicking on the first link &quot;helloworld&quot; will show you a running example of a Node site running in IISNode. You can actually see the source code for this in &quot;C:\Program Files\iisnode\www&quot;.</p>
<h2 id="url-rewriting">URL Rewriting</h2>
<p>In &quot;localhost:8080/node&quot; try navigating to the &quot;urlrewrite&quot; part of the site by following the link. If you get an error on the page, then Url Rewriting has not been installed. This is going to be necessary if you want to run an Express site. You can download URL Rewrite from Microsoft <a target="_blank" href="http://www.iis.net/downloads/microsoft/url-rewrite">here</a>. Click on the &quot;Install this extension&quot; button and download the file. After downloading the file, run it. It should bring up a Web Platform Installer which will guide you through the simple installation procedure.</p>
<p>Once URL Rewriting is installed, go back to the page on your localhost and refresh to test if it&#39;s working.</p>
<h2 id="express">Express</h2>
<p>If you want to get Express working with IISNode, you will only need to create two files; a JS file which will control your server, and a web.config for IIS.</p>
<h3 id="server-js">server.js</h3>
<p>Your server.js has to be tweaked just a little bit to make it work with IISNode. Notice the past line where the app has to listen using &quot;process.env.PORT&quot;. This port is decided by IIS.</p>
<pre><code>var express = require(&#39;express&#39;);

var app = express();

app.get(&#39;/&#39;, function (req, res) {
    res.send(&#39;Express is working on IISNode!&#39;);
});

app.listen(process.env.PORT);
</code></pre><p>I found that many other tutorials said that &quot;var app = express.createServer();&quot; was the correct line to use, but I found that this just created an error. This may be due to the other tutorials using an older version of Express.</p>
<h3 id="web-config">web.config</h3>
<p>The web.config file is the configuration for this website. A handler is required to specify that the application is handled by IISNode. The rewrite allows the server.js deal with incoming connections rather than IIS.</p>
<pre><code>&lt;configuration&gt;
    &lt;system.webServer&gt;

        &lt;!-- indicates that the server.js file is a node.js application
        to be handled by the iisnode module --&gt;

        &lt;handlers&gt;
            &lt;add name=&quot;iisnode&quot; path=&quot;server.js&quot; verb=&quot;*&quot; modules=&quot;iisnode&quot; /&gt;
        &lt;/handlers&gt;

        &lt;rewrite&gt;
            &lt;rules&gt;
                &lt;rule name=&quot;sendToNode&quot;&gt;
                    &lt;match url=&quot;/*&quot; /&gt;
                    &lt;action type=&quot;Rewrite&quot; url=&quot;server.js&quot; /&gt;
                &lt;/rule&gt;
            &lt;/rules&gt;
        &lt;/rewrite&gt;

    &lt;/system.webServer&gt;
&lt;/configuration&gt;
</code></pre><h3 id="install-the-express-module">Install the Express module</h3>
<p>You will also need to install the express module before this Node server will work. Open a cmd prompt and cd to your folder (which has the server.js and web.config files) and type &quot;npm install express&quot;.</p>
<h2 id="adding-your-site-to-iis-">Adding your site to IIS.</h2>
<p>The last step is adding your site to IIS Manager. Open up the program and on your Sites, right click and select &quot;Add Website...&quot;. Fill out the details and link it to your folder with the server.js and web.config files inside of it.</p>
<p><img src="/media/blog/installing-iisnode/iismanager.png" alt=""></p>
<p>After adding your host name to your systems hosts file, navigate to the url in a web browser and see the result.</p>
<p><img src="/media/blog/installing-iisnode/expressrunning.png" alt=""></p>
<h2 id="resources">Resources</h2>
<ul>
<li><a target="_blank" href="https://github.com/azure/iisnode/wiki/iisnode-releases">IISNode GitHub</a></li>
</ul>
]]></content:encoded>
            </item>
        
    </channel>
</rss>


