<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Owain Williams</title>
    <description>The latest articles on DEV Community by Owain Williams (@owaincodes).</description>
    <link>https://dev.to/owaincodes</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F65179%2F6d4edfad-60c3-431a-a35f-885393a83259.jpg</url>
      <title>DEV Community: Owain Williams</title>
      <link>https://dev.to/owaincodes</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/owaincodes"/>
    <language>en</language>
    <item>
      <title>The coffee log, rebuilt in .NET</title>
      <dc:creator>Owain Williams</dc:creator>
      <pubDate>Fri, 02 Oct 2026 11:24:10 +0000</pubDate>
      <link>https://dev.to/owaincodes/the-coffee-log-rebuilt-in-net-25md</link>
      <guid>https://dev.to/owaincodes/the-coffee-log-rebuilt-in-net-25md</guid>
      <description>&lt;h1&gt;
  
  
  The coffee log, rebuilt in .NET
&lt;/h1&gt;

&lt;p&gt;Back in June I wrote about &lt;a href="https://owain.codes/blog/2026/june/its-coffee-time" rel="noopener noreferrer"&gt;my coffee machine writing my blog&lt;/a&gt;. Smart plug watches the coffee machine, Raspberry Pi watches the plug, bit of Python tells Umbraco I've made a coffee. If you've not read that one, go and read it first, it covers the plug, the KLAP handshake, the controller on the site, all of it. None of that has changed.&lt;/p&gt;

&lt;p&gt;So why am I writing about it again? Because I've ripped out the middle bit and rewritten it in .NET. And I know, I know, "it worked, why touch it?" Fair question. Let me explain.&lt;/p&gt;

&lt;h2&gt;
  
  
  It worked. I just couldn't remember how.
&lt;/h2&gt;

&lt;p&gt;Here's the thing. I write C# all day. I don't write Python all day. So when I came back to the coffee log after a few months, I opened the script and had to learn it all over again. Which virtual env was it? Why is that library pinned to that version? Why is that one line commented out?!&lt;/p&gt;

&lt;p&gt;The Python version was written for a Pi Zero, which meant pure Python only and being very careful about what got installed. All sensible at the time. But six months on it just felt like someone else's project.&lt;/p&gt;

&lt;p&gt;The Pi has since been upgraded to a 64 bit model, and that opened a door I couldn't resist. .NET can publish self contained. One binary, no runtime to install, no pip, no package manager, nothing. Copy it over, run it. That alone was enough for me to fire up a new solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a month of data taught me
&lt;/h2&gt;

&lt;p&gt;In June the state machine had two ideas. Power goes up and stays up for a few seconds, that's a brew starting. Power drops and stays down for a while, that's a brew finished. Simple, and it mostly worked, because my machine switches itself off after brewing so every on, brew, off is one clean session.&lt;/p&gt;

&lt;p&gt;Mostly. Every so often it would log a coffee I hadn't made, and I couldn't tell you why, because all I had was the post on the site and a vague memory of what I'd been doing that morning.&lt;/p&gt;

&lt;p&gt;This time round the service writes every brew it detects to a JSON file on the Pi as well as posting it, and honestly that file turned out to be the best thing in the whole project. A month of it and I could see exactly what was going on. Have you ever looked at a month of your own coffee habits as JSON? No? Just me then.&lt;/p&gt;

&lt;p&gt;So the detector now has a few more rules. It needs a run of readings above the threshold before it'll commit to a brew, a run below before it'll call one finished, a minimum duration so the short blips get binned, and a cooldown afterwards. That last one is the guard rail I care about most. If I make two or three cups in quick succession, say when we've got people round, it counts as one. I'm not after 100% accuracy here, it's a blog post about coffee, not a billing system. I'd much rather miss the odd cup than post about ones I never made.&lt;/p&gt;

&lt;h2&gt;
  
  
  Replay mode, or how to tune a coffee machine without drinking 40 coffees
&lt;/h2&gt;

&lt;p&gt;The service logs every raw reading to a CSV, one file per day. And it has a replay mode. Point it at a CSV instead of the plug and it runs the whole day through the detector in about a second, using the timestamps from the file rather than the clock on the wall.&lt;/p&gt;

&lt;p&gt;The trick is that the detector doesn't know or care where its readings come from. There's one interface for "give me a power reading", and either the real plug or a CSV file sits behind it. Everything downstream is identical.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://mermaid.live/edit#pako:eNpljstugzAQRX_Fmk03gCCAHLzoJtm06ktNVanBWVh4QmjBRrZpkiL-vYAaVWp3586cefRQaInAYF_rY3EQxpG7Z264auuuzF9Eq8lEO-L716RBh2ZqFvYzf0M7JinOV5asNq9_jBn6_uZJH9HcT2EYZkOOXDht8vUP7Cb9Up2Vd6tVfrt5fCD7qsb_fVs5zPVRVCqYnrc78KA0lQTmTIceNGgaMUXouSKEgztggxzYiAZld_KlMB9-oWttOHA1jPOtUFutm8sKo7vyAGwvajumrpXC4boSpRG_Co5fmZXulAOWLuYVwHo4AaM0iGiYJMswS2gahUsPzsCiNAyiRZLROF7QOMyyePDgaz4aBkuaDt9W14RT" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;mermaid.live&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Swap the box on the left and nothing else changes. That's the whole reason it's tunable.&lt;/p&gt;

&lt;p&gt;Nothing gets written in replay mode. No CSV, no state, no posts to the site, it doesn't even need credentials. So I can copy a month of captures off the Pi, replay them on the desktop with different settings, and check the results against the times I know I made a coffee. Change a number, run it, a second later I know if it helped. No standing at the machine pulling shots I don't want. No risk of publishing a post about a coffee from August either, which, trust me, I thought about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I stopped retrying
&lt;/h2&gt;

&lt;p&gt;Where a brew goes is now pluggable. There's a JSON file sink, an Umbraco sink, and a mode that does both, and I run both.&lt;/p&gt;

&lt;p&gt;In June the Pi had a little pending queue that kept retrying a post until the site answered. Sensible, right? Until you remember the controller creates a node every single time it's called, and there's nothing in the request that lets the site spot a repeat. So if the site processed the request but the response got lost on the way back, the retry publishes the same coffee twice. Two blog posts, one coffee. Nobody needs that.&lt;/p&gt;

&lt;p&gt;So the .NET sink deliberately never retries. If a post fails it gets logged and the brew's still sitting in the JSON file on the Pi. A missing post I can fix by hand in a minute. A duplicate one I have to notice first, and I won't.&lt;/p&gt;

&lt;h2&gt;
  
  
  The afternoon I lost to two keys
&lt;/h2&gt;

&lt;p&gt;Right, confession time. Wiring the Pi back up to the site after a few months away, I went into the backoffice and created an API user. Because that's how you talk to Umbraco from outside, right? Management API, client id, secret, OAuth, all of that.&lt;/p&gt;

&lt;p&gt;Not here it isn't. The controller from the June post isn't the Management API at all, it's a plain controller sat inside the site, and the only thing guarding it is one shared secret in an &lt;code&gt;X-Api-Key&lt;/code&gt; header. No OAuth, no client id, nothing to create in the backoffice. The same string just has to live in two places, an environment variable on the Live environment in Umbraco Cloud, and the env file on the Pi. That's it. I'd built the thing and forgotten how it worked. Again.&lt;/p&gt;

&lt;p&gt;And then, because one mistake is never enough, I put the secret in the wrong setting. The site also needs to know which node to create posts under, and that's a GUID in a setting called BlogParentKey, which sits right next to the API key in the Cloud portal. So for a good while I had a password sat in a field that wanted a GUID and was staring at 401s wondering what on earth was going on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying is one command now
&lt;/h2&gt;

&lt;p&gt;The service runs under systemd as its own service account, credentials in a separate env file, and the unit file locks it right down. It can only write its own data folder, it can't see home directories, and it never gives up restarting after a power cut, which on a Pi is a matter of when, not if.&lt;/p&gt;

&lt;p&gt;Deploying is a single script. Build for arm64, copy the binary over SSH, stop the service, install, start, print the status. It only ever replaces the binary and the default settings. It never touches the env file, the captured data or the detector's saved state, so I can run it at three in the afternoon and nothing gets lost.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what's actually different?
&lt;/h2&gt;

&lt;p&gt;Same plug. Same site. Same controller. Same daft idea. What's changed is that I can open this project after six months away, run the tests, replay a day of data to see what the detector thinks, and deploy with one command. It went from a thing I built to a thing I can actually maintain. Which, if you read my last post, is sort of the point I've been circling round for a while now.&lt;/p&gt;

&lt;p&gt;Right then. Coffee. You'll know when I have.&lt;/p&gt;

</description>
      <category>umbraco</category>
      <category>dotnet</category>
      <category>raspberrypi</category>
    </item>
    <item>
      <title>AI as a learning tool</title>
      <dc:creator>Owain Williams</dc:creator>
      <pubDate>Fri, 02 Oct 2026 09:34:35 +0000</pubDate>
      <link>https://dev.to/owaincodes/ai-as-a-learning-tool-1iec</link>
      <guid>https://dev.to/owaincodes/ai-as-a-learning-tool-1iec</guid>
      <description>&lt;h1&gt;
  
  
  Using AI to Become a Better Developer (A Promise to Myself)
&lt;/h1&gt;

&lt;p&gt;Alright, let's be honest. I ask Claude for code. I read maybe three lines of it. I think "yeah that looks right" and paste it into my editor or just accept it in to my repo. Quick test. Ship it. Move on.&lt;/p&gt;

&lt;p&gt;That's my current workflow. Sloppy but honest.&lt;/p&gt;

&lt;p&gt;And it works. Most of the time. Which is the exact problem.&lt;/p&gt;

&lt;p&gt;When something works, there's no incentive to understand it. No incentive to question it. No incentive to actually learn anything from it. I'm not becoming a better developer. I'm becoming faster at not thinking.&lt;/p&gt;

&lt;p&gt;This ends next week.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;I've got enough experience that I can get away with this for a while. But I can feel it. The edges are getting blurry. There's code in repos I've written that I couldn't explain to someone else. Not because it's complex. Because I never actually understood it in the first place.&lt;/p&gt;

&lt;p&gt;That's not sustainable. That's not how you stay sharp.&lt;/p&gt;

&lt;p&gt;The difference between using AI as a tool and using AI as a crutch is simple. It's the difference between asking "why" and just accepting.&lt;/p&gt;

&lt;p&gt;When I stop asking why, I stop learning. And when I stop learning, I stop being useful.&lt;/p&gt;

&lt;p&gt;So next week, that changes. I'm going to Claude with a different mindset. Not "give me the answer." But "help me understand this."&lt;/p&gt;

&lt;h2&gt;
  
  
  How I'm Going to Use It Differently
&lt;/h2&gt;

&lt;p&gt;Instead of copy, paste, ship, I'm going to actually engage with it. When Claude gives me something, I'm going to ask myself better questions.&lt;/p&gt;

&lt;p&gt;Why did it choose this approach? What's the alternative? What could go wrong here? Is there a trade-off I'm missing?&lt;/p&gt;

&lt;p&gt;Sometimes Claude's right and I'll learn why. Sometimes it's half-right and I'll learn how to adapt it. Sometimes it's confidently wrong and I'll learn more from fixing it than if it had been perfect.&lt;/p&gt;

&lt;p&gt;The key thing is that I'm actually thinking now. Claude's the rubber duck that talks back.&lt;/p&gt;

&lt;p&gt;What changes:&lt;/p&gt;

&lt;p&gt;I stop asking for solutions. I start asking for explanations.&lt;/p&gt;

&lt;p&gt;I stop reading three lines. I read it all and actually process it.&lt;/p&gt;

&lt;p&gt;I stop shipping immediately. I challenge the output. Play devil's advocate with the code.&lt;/p&gt;

&lt;p&gt;I use it to learn new patterns, not to skip learning patterns I should already know.&lt;/p&gt;

&lt;p&gt;I ask "why this way" instead of just accepting "here's a way."&lt;/p&gt;

&lt;h2&gt;
  
  
  The Challenge to You
&lt;/h2&gt;

&lt;p&gt;If you're doing what I'm doing right now, I get it. It's faster. But you're missing out on actually learning anything.&lt;/p&gt;

&lt;p&gt;Start next week. Change one habit. When you get an answer from AI, before you do anything else, ask it why it chose that approach. Make it explain its reasoning. Make it justify it.&lt;/p&gt;

&lt;p&gt;You'll be surprised how often that extra five minutes of questioning reveals something you didn't know.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Prompts That Actually Work
&lt;/h2&gt;

&lt;p&gt;These are the ones I'm going to use. Steal them if they help.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stop saying:&lt;/strong&gt; "Write me a function that does X"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start saying:&lt;/strong&gt; "Show me how to [specific task]. Walk me through why you'd approach it this way instead of [alternative approach]."&lt;/p&gt;

&lt;p&gt;Forces them to explain the thinking, not just dump code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stop saying:&lt;/strong&gt; "Fix this code"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start saying:&lt;/strong&gt; "This code does X but I think there's a better way. What are the trade-offs between my current approach and alternatives? Which would you recommend and why?"&lt;/p&gt;

&lt;p&gt;Now you get the reasoning behind the fix, not just a quick patch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stop saying:&lt;/strong&gt; "How do I do X"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start saying:&lt;/strong&gt; "I need to [outcome]. What are the three most common approaches? What's the trade-off between them? What would you pick for [your specific context] and why?"&lt;/p&gt;

&lt;p&gt;Forces options and reasoning, not just one answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stop saying:&lt;/strong&gt; "Write me some code"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start saying:&lt;/strong&gt; "I'm trying to solve [problem]. Before you write code, help me understand the concepts and patterns I should know about. Then show me how they apply here."&lt;/p&gt;

&lt;p&gt;Learn the foundation first. The code comes after.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And always follow up with:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;"I don't understand why you chose this. Explain it like I've never seen this pattern before. What could break? What are the limitations?"&lt;/p&gt;

&lt;p&gt;Push back. Ask the hard questions. Don't accept the first answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Actually Doing This
&lt;/h2&gt;

&lt;p&gt;The developers getting real value from AI aren't the ones who use it to skip thinking. They're using it to think better.&lt;/p&gt;

&lt;p&gt;So next week. That's when I start. I'm going to use Claude to learn, not just to ship. I'm going to ask why instead of just accepting the answer.&lt;/p&gt;

&lt;p&gt;And maybe you should too.&lt;/p&gt;

&lt;p&gt;We'll see how this goes.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
    </item>
    <item>
      <title>Umbraco "hidden" properties - umbracoUrlName and umbracoUrlAlias</title>
      <dc:creator>Owain Williams</dc:creator>
      <pubDate>Wed, 06 Jan 2021 00:00:00 +0000</pubDate>
      <link>https://dev.to/owaincodes/umbraco-hidden-properties-umbracourlname-and-umbracourlalias-4mjl</link>
      <guid>https://dev.to/owaincodes/umbraco-hidden-properties-umbracourlname-and-umbracourlalias-4mjl</guid>
      <description>&lt;p&gt;While working on a project I came across an issue where having the ability to give a different url for a page within the CMS would be beneficial. &lt;/p&gt;

&lt;p&gt;In the past, I've always just used &lt;code&gt;umbracoUrlAlias&lt;/code&gt; but it was suggested that &lt;code&gt;umbracoUrlName&lt;/code&gt; might be a better option. This short blog will hopefully bring these properties to light for some of you. &lt;/p&gt;

&lt;h2&gt;
  
  
  How do you use them?
&lt;/h2&gt;

&lt;p&gt;Both properties can be use on any document type that is accessible via the front end of your site e.g. &lt;a href="http://www.owain.codes/about" rel="noopener noreferrer"&gt;http://www.owain.codes/about&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add a text string to your document type and make sure that the alias is &lt;code&gt;umbracoUrlAlias&lt;/code&gt; or &lt;code&gt;umbracoUrlName&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;An example is below for &lt;code&gt;umbracoUrlName&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fowain.codes%2Fmedia%2F8d8b27e1a7c69f0%2Fpropertyeditor.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fowain.codes%2Fmedia%2F8d8b27e1a7c69f0%2Fpropertyeditor.jpg" alt="enter image description here" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Of course, you can change the Name from &lt;code&gt;umbracoUrlName&lt;/code&gt; but make sure the alias, the bit  next to the padlock, remains &lt;code&gt;umbracoUrlName&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's the difference between the two?
&lt;/h2&gt;

&lt;p&gt;I'll use the description that is used within the &lt;a href="https://our.umbraco.com/Documentation/Reference/Routing/routing-properties" rel="noopener noreferrer"&gt;Umbraco Documentation&lt;/a&gt;, &lt;/p&gt;

&lt;h3&gt;
  
  
  umbracoUrlAlias
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;This property when created as a text string lets you provide a comma separated list of alternate full URL paths for the node. For example, if your URL was /some-category/some-page/content-node, by adding an umbracoUrlAlias of "flowers", a user can navigate to the node by going to /flowers. The URL alias remains in the browser address bar as a 'mask' over the real URL. You can also specify paths like "flowers/roses/red".&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One thing to note is that the original URL is also still accessible. To help understand this, if you think about this property as a url shorterner then it will hopefully make it a bit clearer. &lt;/p&gt;

&lt;h3&gt;
  
  
  umbracoUrlName
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;This property when created as a text string lets you provide a different URL name to what is created by default by the name of the node. If you enter a value for this property and save/publish the content node, you will see that its main URL is updated with a new path suffix.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If we use the example that was used above and use the path &lt;code&gt;/some-category/some-page/content-node&lt;/code&gt;, if we use &lt;code&gt;umbracoUrlName&lt;/code&gt; property and use the word &lt;code&gt;flowers&lt;/code&gt;as the value, the url for this page / node is now &lt;code&gt;/flowers&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;The longer path name now doesn't exist and the only way to access this node is via &lt;code&gt;/flowers&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Other routing options
&lt;/h3&gt;

&lt;p&gt;There are two other options built in to Umbraco that you can use when handling routing. &lt;br&gt;
&lt;code&gt;umbracoRedirect&lt;/code&gt; and &lt;code&gt;umbracoRedirectId&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In short, &lt;code&gt;umbracoRedirect&lt;/code&gt; performs a 302 redirect by using a Content Picker and &lt;code&gt;umbracoRedirectId&lt;/code&gt; does a url rewrite. &lt;/p&gt;

&lt;p&gt;For more info, check out the &lt;a href="https://our.umbraco.com/Documentation/Reference/Routing/routing-properties" rel="noopener noreferrer"&gt;Umbraco Documentation&lt;/a&gt;&lt;/p&gt;

</description>
      <category>umbraco</category>
    </item>
    <item>
      <title>Null Conditional Operator for fallback images</title>
      <dc:creator>Owain Williams</dc:creator>
      <pubDate>Thu, 10 Dec 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/owaincodes/null-conditional-operator-for-fallback-images-4akg</link>
      <guid>https://dev.to/owaincodes/null-conditional-operator-for-fallback-images-4akg</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4t1vobhcjaccdaulmf89.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4t1vobhcjaccdaulmf89.jpg" alt="Generic Header image" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Last night when working on my new version of &lt;a href="https://www.owain.codes" rel="noopener noreferrer"&gt;Owain.Codes&lt;/a&gt; I managed to blow up the site. &lt;/p&gt;

&lt;p&gt;The reason? &lt;/p&gt;

&lt;p&gt;I hadn't put an image in to the CMS and when I rendered out the image or the lack of an image on the front end, I got a null exception error.&lt;/p&gt;

&lt;p&gt;I started to write a bit of code to handle this which looked a bit like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@if(Model.Image.Url() == null)
{
  set default image as fallback.jpg
}
else{
  use the image from the CMS
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But then I thought, there must be a nicer way to handle fallbacks, and I believe I have found that nicer option and its by using the &lt;a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators--and-" rel="noopener noreferrer"&gt;Null Conditional Operator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So I am now using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; var blogImage = Model.PageBanner?.Url() ?? "assets/images/noImage.jpg";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So if the &lt;code&gt;Model.PageBanner&lt;/code&gt; is null, give me the noImage.jpg fall back string, else give me the &lt;code&gt;Model.PageBanner.Url()&lt;/code&gt;. I then use the variable blogImage on my page.&lt;/p&gt;

&lt;p&gt;I now don't need to worry about whether I set an image for a blog or not. Either way I will have an image on my page.&lt;/p&gt;

</description>
      <category>csharp</category>
    </item>
    <item>
      <title>Restart Visual Studio as Admin in seconds</title>
      <dc:creator>Owain Williams</dc:creator>
      <pubDate>Fri, 04 Dec 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/owaincodes/restart-visual-studio-as-admin-in-seconds-2jj9</link>
      <guid>https://dev.to/owaincodes/restart-visual-studio-as-admin-in-seconds-2jj9</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fblpq5opj2d49443oovdq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fblpq5opj2d49443oovdq.jpg" alt="blogcomputerimagelrg" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Last week &lt;a href="https://twitter.com/HotChilliCode" rel="noopener noreferrer"&gt;@HotChilliCode&lt;/a&gt; aka Nik shared this &lt;a href="https://twitter.com/shanselman/" rel="noopener noreferrer"&gt;Scott Hanselman&lt;/a&gt; video with me : "Overwhelmed with Programming? Here's small things to help - Computer Stuff They Didn't Teach You #14"&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/5CmjW_8ief4" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;During the video Scott talks about finding ways to reduce repetition. If you find yourself doing something over and over again, is there a way to speed it up? Can you automate it in some way.&lt;/p&gt;

&lt;p&gt;Well today I found myself, for probably the 100th day in a row, needing to attach my debugger in Visual Studio to my local IIS instance. The only issue was, I wasn't running in Admin mode.&lt;/p&gt;

&lt;p&gt;I needed to close visual studio, right click the icon, open as Admin then reload my solution. Not a massive issue but I had noticed I've been doing this a lot recently as Visual Studio for me doesn't automatically run in Admin mode. I know, I could set it up to run in Admin mode straight away but then if I am doing screen shares, the person I'm sharing with can't interact with my VS screen so then I need to shutdown VS, remove the setting to start as Admin. It's just a pain.&lt;/p&gt;

&lt;p&gt;Anyway, I found an Visual Studio Extension called &lt;a href="https://github.com/ilmax/vs-restart" rel="noopener noreferrer"&gt;Visual Studio Restart&lt;/a&gt; and all it does is, it adds a Link in your File menu that will shutdown VS, restart it in Admin mode and also reload the solution you are working on. Brilliant! &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note: I am using VS2019 Community Edition, I've not tested this in any other versions.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The next thing I did was I &lt;a href="https://docs.microsoft.com/en-us/visualstudio/ide/identifying-and-customizing-keyboard-shortcuts-in-visual-studio?view=vs-2019" rel="noopener noreferrer"&gt;assigned a shortcut key&lt;/a&gt; to the restart command. The key combo I used is &lt;code&gt;Ctrl+ '&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;So now, if I am working on a project that I haven't loaded as Admin, I tap &lt;code&gt;Ctrl + '&lt;/code&gt; and boom, I'm up and running in Admin mode in seconds.&lt;/p&gt;

</description>
      <category>visualstudio</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Load Windows Terminal from Explorer Window</title>
      <dc:creator>Owain Williams</dc:creator>
      <pubDate>Wed, 02 Dec 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/owaincodes/load-windows-terminal-from-explorer-window-30f4</link>
      <guid>https://dev.to/owaincodes/load-windows-terminal-from-explorer-window-30f4</guid>
      <description>&lt;p&gt;Today I found myself once again trying to be more efficient with my keystrokes and mouse movements and it got me wondering. If I am in a folder, can I open up a Windows Terminal from that folder?&lt;/p&gt;

&lt;p&gt;First of all, let me tell you what Windows Terminal is - basically, its Windows Command Prompt on steroids.&lt;/p&gt;

&lt;p&gt;Official description is: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Windows Terminal is a modern, fast, efficient, powerful, and productive terminal application for users of command-line tools and shells like Command Prompt, PowerShell, and WSL. Its main features include multiple tabs, panes, Unicode and UTF-8 character support, a GPU accelerated text rendering engine, and custom themes, styles, and configurations."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's also open source so you can play around with it and really customise things if you wants.&lt;/p&gt;

&lt;p&gt;You can download Windows Terminal from &lt;a href="https://www.microsoft.com/en-gb/p/windows-terminal/9n0dx20hk701?activetab=pivot:overviewtab" rel="noopener noreferrer"&gt;Microsoft.com&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Solve the problem
&lt;/h2&gt;

&lt;p&gt;I know that if I type &lt;code&gt;cmd&lt;/code&gt; in to the explorer path area it will load up the command prompt.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fe0o61i02khirxlpeehpg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fe0o61i02khirxlpeehpg.gif" alt="cmdprompt" width="800" height="185"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What I didn't realise was if I type in 'wt' it will load up a new instance of Windows Terminal. However, this just opens up a new Terminal but you still need to navigate to the folder you were in via the command line. That's not really any saving in time.&lt;/p&gt;

&lt;p&gt;After a bit of googling, what I found was, you can edit the settings for Windows Terminal.&lt;/p&gt;

&lt;p&gt;If you open up Setting via the dropdown menu in your Windows Terminal....&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fm7a3wdsnwl03op5w7c9m.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fm7a3wdsnwl03op5w7c9m.gif" alt="wtsetup" width="800" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then you need to add the &lt;code&gt;"startingDirectory": "."&lt;/code&gt; to each of the profiles within the settings.json file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwsljmkw6a925iet3z8tk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwsljmkw6a925iet3z8tk.png" alt="settingswt" width="800" height="1064"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now when you save this file, and go back to Explorer and type in wt, your terminal window will load and direct you to the folder path that you were originally in.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bonus content
&lt;/h3&gt;

&lt;p&gt;I also decided to add a bit of transparency to the Windows Terminal by adding the two additional values - &lt;code&gt;"useAcrylic": true&lt;/code&gt; and &lt;code&gt;"acrylicOpacity": 0.5&lt;/code&gt;you can obviously change the 0.5 to any value you like to make the transparency work better for you. One thing to look out for though, if you don't have transparceny effect turned on in your Windows settings, it doesn't matter what you do in the settings.json file, your terminal won't show any difference.&lt;/p&gt;

&lt;p&gt;To turn transparency on, go to Start Menu -&amp;gt; Settings -&amp;gt; Personalisation -&amp;gt; Colours and then toggle the Transparency Effects to On.&lt;/p&gt;

&lt;p&gt;Now load up a terminal and it should have a transparent background, you can even put an image there instead and have a different image for different terminal windows. Check out the &lt;a href="https://docs.microsoft.com/en-us/windows/terminal/customize-settings/profile-settings" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt; for all your options - go wild!&lt;/p&gt;

</description>
      <category>terminal</category>
      <category>howto</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Obsolete Umbraco Property Types.</title>
      <dc:creator>Owain Williams</dc:creator>
      <pubDate>Thu, 09 Jul 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/owaincodes/obsolete-umbraco-property-types-2bh9</link>
      <guid>https://dev.to/owaincodes/obsolete-umbraco-property-types-2bh9</guid>
      <description>&lt;p&gt;Yesterday I had a bit of a panic. I was bug fixing something for a client and I changed the property editor from (Obsolete) Media Picker to Media Pick... &lt;a href="https://www.owain.codes/blog/posts/2020/july/obsolete-umbraco-property-types/" rel="noopener noreferrer"&gt;Continue reading&lt;/a&gt;&lt;/p&gt;

</description>
      <category>umbraco</category>
      <category>configuration</category>
    </item>
    <item>
      <title>Umbraco Uno - A first glance</title>
      <dc:creator>Owain Williams</dc:creator>
      <pubDate>Thu, 18 Jun 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/owaincodes/umbraco-uno-a-first-glance-3f6b</link>
      <guid>https://dev.to/owaincodes/umbraco-uno-a-first-glance-3f6b</guid>
      <description>&lt;p&gt;Umbraco Uno - A first glance Umbraco Uno - The one-stop website platform for creative agencies. That's the tag line Umbraco have given their latest... &lt;a href="https://www.owain.codes/blog/posts/2020/june/umbraco-uno/" rel="noopener noreferrer"&gt;Continue reading&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Convert HTML to Markdown</title>
      <dc:creator>Owain Williams</dc:creator>
      <pubDate>Thu, 04 Jun 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/owaincodes/convert-html-to-markdown-3l77</link>
      <guid>https://dev.to/owaincodes/convert-html-to-markdown-3l77</guid>
      <description>&lt;p&gt;After a discussion with a fellow developer on Slack one evening (Cheers Nik!), I found I had a side project to play with. I have been trying to do som... &lt;a href="https://www.owain.codes/blog/posts/2020/june/convert-a-html-blog-in-to-markdown/" rel="noopener noreferrer"&gt;Continue reading&lt;/a&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>markdown</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Umbraco MVPs of 2019</title>
      <dc:creator>Owain Williams</dc:creator>
      <pubDate>Tue, 08 Oct 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/owaincodes/umbraco-mvps-of-2019-58mn</link>
      <guid>https://dev.to/owaincodes/umbraco-mvps-of-2019-58mn</guid>
      <description>&lt;p&gt;&lt;a href="https://www.owain.codes/blog/posts/2019/october/umbraco-mvps-of-2019/" rel="noopener noreferrer"&gt;Continue reading&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>White screen on umbraco backoffice after an upgrade</title>
      <dc:creator>Owain Williams</dc:creator>
      <pubDate>Mon, 08 Jul 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/owaincodes/white-screen-on-umbraco-backoffice-after-an-upgrade-f9b</link>
      <guid>https://dev.to/owaincodes/white-screen-on-umbraco-backoffice-after-an-upgrade-f9b</guid>
      <description>&lt;p&gt;This week I had an issue where I had upgraded a website from Umbraco 7.7 to 7.14. The bit that really confused me was the site worked prefectly on my ... &lt;a href="https://www.owain.codes/blog/posts/2019/july/white-screen-on-umbraco-backoffice-after-an-upgrade/" rel="noopener noreferrer"&gt;Continue reading&lt;/a&gt;&lt;/p&gt;

</description>
      <category>umbraco</category>
    </item>
    <item>
      <title>Really? Is that your job title??</title>
      <dc:creator>Owain Williams</dc:creator>
      <pubDate>Thu, 15 Jun 2017 00:00:00 +0000</pubDate>
      <link>https://dev.to/owainwilliams/really-is-that-your-job-title-1kcg</link>
      <guid>https://dev.to/owainwilliams/really-is-that-your-job-title-1kcg</guid>
      <description>&lt;p&gt;Why do I say that? When it comes to getting jobs, it's not easy for me, I go to the interview, answer all their questions with confidence and ease unt... &lt;a href="https://www.owain.codes/blog/posts/2017/june/senior-developer-really-is-that-your-job-title/"&gt;Continue reading&lt;/a&gt;&lt;/p&gt;

</description>
      <category>impostersyndrome</category>
      <category>thoughts</category>
    </item>
  </channel>
</rss>
