Jekyll2024-01-07T21:57:34+00:00https://brendoneus.com//feed.xmlBrendan Enrick’s BlogBrendan Enrick's Blog about all things tech.Brendan EnrickBuilding Minesweeper - Showing Why Logic Should Not Be in the UI2022-12-12T00:00:00+00:002022-12-12T00:00:00+00:00https://brendoneus.com//post/Why-To-Keep-Logic-Away-from-UI-in-DotNet<p>Hello and welcome! This post is part of the <a href="https://dotnet.christmas/">2022 .NET Advent Calendar</a> series of posts, but you can enjoy the content without worrying about that!</p>
<p>For this event, I thought I’d build a program that can show why you don’t want to have any logic in your controllers, pages, views, forms, etc. in your .NET application. I also figured we’d make it a fun little game.</p>
<h2 id="picking-an-application-front-end">Picking an Application Front-End</h2>
<p>Now you might be wondering which choice I made for the UI of the application, since I mentioned a few types of front-ends and there are quite a few to choose from in each of those I mentioned above.</p>
<p>I could have chosen: WPF, UWP, WinForms, or even a Console application. This isn’t even considering the 3rd party options and variations on the first party ones!</p>
<p>As the title may have given the game away already, I’m not going to mention which UI we’re using yet. Why? I don’t need to! We can build the game and decide the UI later!</p>
<p>You’re likely also wondering which game I chose to make? I decided to make a Minesweeper-style game as I don’t even have a copy of it on my Windows PC anymore! A shame!</p>
<p>Shameless self-promoting side note: I did a coding live stream with Guy Royse (after writing this game) on my <a href="https://www.twitch.tv/devchatter/">DevChatter programming channel on Twitch</a> where we created a simple, static HTML and JavaScript version of Minesweeper from scratch. You can watch the recording of us <a href="https://youtu.be/9ssOoL_Wj8I">Coding Minesweeper in Static HTML with JavaScript</a> on YouTube.</p>
<h2 id="what-is-minesweeper">What is Minesweeper?</h2>
<p>If you aren’t lucky enough to have played minesweeper when it was one of the few included games on Windows, I’ll explain the basic rules of the game.</p>
<p>When it loads, you have a grid of blank squares and an indicator of how many bombs are unmarked on the board.</p>
<p>When you left click a square, it will reveal that square (and possibly others).</p>
<ul>
<li>If the square is a bomb, you lose.</li>
<li>If the square is adjacent to a bomb, it will display a number indicating how many of the 8 squares surrounding it contain bombs (1-8).</li>
<li>Otherwise, the square is blank, and the game will automatically reveal all contiguous blank spaces and the numbered spaces next to them.</li>
</ul>
<p>When you right click a square, it will mark that space with a flag. This is mostly to remind you that you think a bomb is there. You can remove it by right clicking it again. These are also not required to use in order to win the game.</p>
<p>To win the game, you need only reveal the spaces that are not bombs, and the game will automatically mark the remaining spaces as bombs.</p>
<h2 id="initial-game-object">Initial Game Object</h2>
<p>One of basic rules with dotnet is to create types when I want them and to get names that are “good enough for now”. Refactoring is the name of the game, because we have tools like Visual Studio, Rider, etc. that are quite good at handling renames.</p>
<p>Following that logic, I created a class to handle interactions with the game called… <code class="language-plaintext highlighter-rouge">Game</code>. I gave that game class a field containing a multidimensional array of integers positives are a bomb hint, 0 is no adjacent bombs, and negatives indicate a bomb is in the space.</p>
<p>Why did I start so simple? Easy, I may not have needed a <code class="language-plaintext highlighter-rouge">Cell</code> or a <code class="language-plaintext highlighter-rouge">Grid</code> class to implement a basic version of the game! I recommend people always stat simple like this, as it’s easy to add complexity when it’s needed, but harder to remove complexity.</p>
<p>My initial game looked a bit like this:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">class</span> <span class="nc">Game</span>
<span class="p">{</span>
<span class="k">private</span> <span class="k">readonly</span> <span class="kt">int</span> <span class="n">_size</span><span class="p">;</span>
<span class="k">public</span> <span class="k">readonly</span> <span class="kt">int</span><span class="p">[,]</span> <span class="n">Grid</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">Start</span><span class="p">(</span><span class="kt">int</span> <span class="n">size</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Grid</span> <span class="p">=</span> <span class="k">new</span> <span class="kt">int</span><span class="p">[</span><span class="n">size</span><span class="p">,</span> <span class="n">size</span><span class="p">];</span>
<span class="nf">FillWithBombs</span><span class="p">(</span><span class="m">0.1</span><span class="p">);</span>
<span class="nf">SetHintValues</span><span class="p">(</span><span class="n">size</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">FillWithBombs</span><span class="p">(</span><span class="kt">double</span> <span class="n">bombPercent</span><span class="p">)</span>
<span class="p">{</span>
<span class="c1">// Get bombs as a percent of all spaces</span>
<span class="kt">int</span> <span class="n">bombCount</span> <span class="p">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)(</span><span class="n">Grid</span><span class="p">.</span><span class="n">Length</span> <span class="p">*</span> <span class="n">bombPercent</span><span class="p">);</span>
<span class="c1">// Get an array of indexes as if the grid were one array.</span>
<span class="kt">var</span> <span class="n">possibles</span> <span class="p">=</span> <span class="n">Enumerable</span><span class="p">.</span><span class="nf">Range</span><span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="n">Grid</span><span class="p">.</span><span class="n">Length</span><span class="p">).</span><span class="nf">ToArray</span><span class="p">();</span>
<span class="c1">// Pick a random selection of those indexes to receive bombs.</span>
<span class="kt">var</span> <span class="n">locations</span> <span class="p">=</span> <span class="n">possibles</span><span class="p">.</span><span class="nf">OrderBy</span><span class="p">(</span><span class="n">x</span> <span class="p">=></span> <span class="n">_random</span><span class="p">.</span><span class="nf">Next</span><span class="p">()).</span><span class="nf">Take</span><span class="p">(</span><span class="n">bombCount</span><span class="p">);</span>
<span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">index</span> <span class="k">in</span> <span class="n">locations</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Grid</span><span class="p">[</span><span class="n">index</span> <span class="p">%</span> <span class="n">_size</span><span class="p">,</span> <span class="n">index</span> <span class="p">/</span> <span class="n">_size</span><span class="p">]</span> <span class="p">=</span> <span class="n">_random</span><span class="p">.</span><span class="nf">Next</span><span class="p">(-</span><span class="m">5</span><span class="p">,</span> <span class="m">0</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">public</span> <span class="kt">bool</span> <span class="nf">IsBomb</span><span class="p">(</span><span class="kt">int</span> <span class="n">rowIndex</span><span class="p">,</span> <span class="kt">int</span> <span class="n">colIndex</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="n">Grid</span><span class="p">[</span><span class="n">rowIndex</span><span class="p">,</span> <span class="n">colIndex</span><span class="p">]</span> <span class="p"><</span> <span class="m">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">SetHintValues</span><span class="p">(</span><span class="kt">int</span> <span class="n">size</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">rowIndex</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">rowIndex</span> <span class="p"><</span> <span class="n">size</span><span class="p">;</span> <span class="n">rowIndex</span><span class="p">++)</span>
<span class="p">{</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">colIndex</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">colIndex</span> <span class="p"><</span> <span class="n">size</span><span class="p">;</span> <span class="n">colIndex</span><span class="p">++)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nf">IsBomb</span><span class="p">(</span><span class="n">rowIndex</span><span class="p">,</span> <span class="n">colIndex</span><span class="p">))</span>
<span class="p">{</span>
<span class="nf">SafeIncrement</span><span class="p">(</span><span class="n">rowIndex</span><span class="p">-</span><span class="m">1</span><span class="p">,</span> <span class="n">colIndex</span><span class="p">);</span>
<span class="nf">SafeIncrement</span><span class="p">(</span><span class="n">rowIndex</span><span class="p">+</span><span class="m">1</span><span class="p">,</span> <span class="n">colIndex</span><span class="p">);</span>
<span class="nf">SafeIncrement</span><span class="p">(</span><span class="n">rowIndex</span><span class="p">,</span> <span class="n">colIndex</span><span class="p">-</span><span class="m">1</span><span class="p">);</span>
<span class="nf">SafeIncrement</span><span class="p">(</span><span class="n">rowIndex</span><span class="p">,</span> <span class="n">colIndex</span><span class="p">+</span><span class="m">1</span><span class="p">);</span>
<span class="nf">SafeIncrement</span><span class="p">(</span><span class="n">rowIndex</span><span class="p">-</span><span class="m">1</span><span class="p">,</span> <span class="n">colIndex</span><span class="p">-</span><span class="m">1</span><span class="p">);</span>
<span class="nf">SafeIncrement</span><span class="p">(</span><span class="n">rowIndex</span><span class="p">+</span><span class="m">1</span><span class="p">,</span> <span class="n">colIndex</span><span class="p">+</span><span class="m">1</span><span class="p">);</span>
<span class="nf">SafeIncrement</span><span class="p">(</span><span class="n">rowIndex</span><span class="p">+</span><span class="m">1</span><span class="p">,</span> <span class="n">colIndex</span><span class="p">-</span><span class="m">1</span><span class="p">);</span>
<span class="nf">SafeIncrement</span><span class="p">(</span><span class="n">rowIndex</span><span class="p">-</span><span class="m">1</span><span class="p">,</span> <span class="n">colIndex</span><span class="p">+</span><span class="m">1</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">SafeIncrement</span><span class="p">(</span><span class="kt">int</span> <span class="n">rowIndex</span><span class="p">,</span> <span class="kt">int</span> <span class="n">colIndex</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">rowIndex</span> <span class="p"><</span> <span class="m">0</span>
<span class="p">||</span> <span class="n">colIndex</span> <span class="p"><</span> <span class="m">0</span>
<span class="p">||</span> <span class="n">rowIndex</span> <span class="p">>=</span> <span class="n">_size</span>
<span class="p">||</span> <span class="n">colIndex</span> <span class="p">>=</span> <span class="n">_size</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">Grid</span><span class="p">[</span><span class="n">rowIndex</span><span class="p">,</span> <span class="n">colIndex</span><span class="p">]++;</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>Notice that I’m able to create the grid with some basic values without too much trouble. I randomly placed some bombs and mark the hint values. Efficient? Fancy? Nope. Nope. But it works!</p>
<p>With this little bit of code, I was able to get a basic test that the board could get created. What was my initial UI? Console Application. Why? I could easily print out the contents of that array to see if the board looked like I expected. Yeah, the test confirmed that it created positive and negative numbers in a 2 dimensional array, but that’s not much gameplay tested yet. Next we’ll need to be able to hide and reveal spaces on the board.</p>
<h2 id="hiding-and-revealing-spaces">Hiding and Revealing Spaces</h2>
<p>Before we can play this game, we’ll need to hide the spaces, so we can reveal them when the player picks them later. Displaying everything was great for confirming that the application was creating the grid as we expected it.</p>
<p>Since we need to keep track of whether a space has been revealed or not, we either need two grids of data, one with the status and one for the value, or we could upgrade our grid to have an object that knows its value and the revealed state.</p>
<p>To start with, I created a <code class="language-plaintext highlighter-rouge">Cell</code> class and gave it properties for the <code class="language-plaintext highlighter-rouge">Count</code> of neighboring bombs and a <code class="language-plaintext highlighter-rouge">Revealed</code> boolean value to know when it should be displayed.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">class</span> <span class="nc">Cell</span>
<span class="p">{</span>
<span class="k">public</span> <span class="kt">int</span> <span class="n">Count</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span>
<span class="k">public</span> <span class="kt">bool</span> <span class="n">Revealed</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="k">false</span><span class="p">;</span>
<span class="k">public</span> <span class="k">static</span> <span class="n">Cell</span> <span class="k">operator</span> <span class="p">++(</span><span class="n">Cell</span> <span class="n">x</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">x</span><span class="p">.</span><span class="n">Count</span> <span class="p">+=</span> <span class="m">1</span><span class="p">;</span>
<span class="k">return</span> <span class="n">x</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>Now in order to make it an easier refactoring, I can add some implicit operator methods to the type, so our number operations on it will modify the <code class="language-plaintext highlighter-rouge">Count</code> property. That looks like this:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">class</span> <span class="nc">Cell</span>
<span class="p">{</span>
<span class="k">public</span> <span class="kt">int</span> <span class="n">Count</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span>
<span class="k">public</span> <span class="kt">bool</span> <span class="n">Revealed</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="k">false</span><span class="p">;</span>
<span class="k">public</span> <span class="k">static</span> <span class="n">Cell</span> <span class="k">operator</span> <span class="p">++(</span><span class="n">Cell</span> <span class="n">x</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">x</span><span class="p">.</span><span class="n">Count</span> <span class="p">+=</span> <span class="m">1</span><span class="p">;</span>
<span class="k">return</span> <span class="n">x</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">implicit</span> <span class="k">operator</span> <span class="kt">int</span><span class="p">(</span><span class="n">Cell</span> <span class="n">x</span><span class="p">)</span> <span class="p">=></span> <span class="n">x</span><span class="p">.</span><span class="n">Count</span><span class="p">;</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">implicit</span> <span class="k">operator</span> <span class="nf">Cell</span><span class="p">(</span><span class="kt">int</span> <span class="n">number</span><span class="p">)</span> <span class="p">=></span> <span class="k">new</span><span class="p">()</span> <span class="p">{</span> <span class="n">Count</span> <span class="p">=</span> <span class="n">number</span> <span class="p">};</span>
<span class="p">}</span></code></pre></figure>
<p>The code where I did this will work on the cells the same way it did when these were numbers:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">private</span> <span class="k">void</span> <span class="nf">SafeIncrement</span><span class="p">(</span><span class="kt">int</span> <span class="n">rowIndex</span><span class="p">,</span> <span class="kt">int</span> <span class="n">colIndex</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">rowIndex</span> <span class="p"><</span> <span class="m">0</span>
<span class="p">||</span> <span class="n">colIndex</span> <span class="p"><</span> <span class="m">0</span>
<span class="p">||</span> <span class="n">rowIndex</span> <span class="p">>=</span> <span class="n">_size</span>
<span class="p">||</span> <span class="n">colIndex</span> <span class="p">>=</span> <span class="n">_size</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">Grid</span><span class="p">[</span><span class="n">rowIndex</span><span class="p">,</span> <span class="n">colIndex</span><span class="p">]++;</span> <span class="c1">// Works for int or Cell now!</span>
<span class="p">}</span></code></pre></figure>
<h2 id="handling-game-over">Handling Game Over</h2>
<p>Minesweeper wouldn’t be much fun if we don’t lose by clicking a bomb, so let’s make sure that this causes an end game. To solve this, we have a few options. We could send a message then reset the game, or we could wait until the user starts a new game and change our “state” to be “Game Over”.</p>
<p>I like the idea of remaining in the “game over” state, so that the player can see the grid and their mistake that lost the game. That means we need to store that somewhere. We could use booleans for things like <code class="language-plaintext highlighter-rouge">IsStarted</code>, <code class="language-plaintext highlighter-rouge">IsWon</code>, <code class="language-plaintext highlighter-rouge">IsLost</code>, etc. to know the state. I think we’re only ever going to be in one state at a time, so an enum for this might be the simpler solution. Let’s create a <code class="language-plaintext highlighter-rouge">GameState</code> enum to handle this.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">enum</span> <span class="n">GameState</span>
<span class="p">{</span>
<span class="n">NotStarted</span><span class="p">,</span>
<span class="n">Started</span><span class="p">,</span>
<span class="n">Won</span><span class="p">,</span>
<span class="n">Lost</span>
<span class="p">}</span></code></pre></figure>
<p>Now we can adjust the reveal method to trigger a <code class="language-plaintext highlighter-rouge">Lost</code> state if we reveal a bomb while we’re in the <code class="language-plaintext highlighter-rouge">Started</code> state. We can also restrict the player selecting to reveal a space, so that it only happens if we’re in the <code class="language-plaintext highlighter-rouge">Started</code> state.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">void</span> <span class="nf">Reveal</span><span class="p">(</span><span class="kt">int</span> <span class="n">rowIndex</span><span class="p">,</span> <span class="kt">int</span> <span class="n">columnIndex</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">State</span> <span class="p">!=</span> <span class="n">GameState</span><span class="p">.</span><span class="n">Started</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
<span class="n">Cell</span><span class="p">?</span> <span class="n">cell</span> <span class="p">=</span> <span class="n">Grid</span><span class="p">.</span><span class="nf">SafeGet</span><span class="p">(</span><span class="n">rowIndex</span><span class="p">,</span> <span class="n">columnIndex</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">cell</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
<span class="n">cell</span><span class="p">.</span><span class="nf">Reveal</span><span class="p">();</span>
<span class="k">if</span> <span class="p">(</span><span class="n">cell</span><span class="p">.</span><span class="n">IsBomb</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">State</span> <span class="p">=</span> <span class="n">GameState</span><span class="p">.</span><span class="n">Lost</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<h2 id="handling-winning-the-game">Handling Winning the Game</h2>
<p>We can lose the game, but I think we’d all rather win. It’s time to add in the condition to allow a player to win! As we mentioned, that happens when the player has revealed every non-bomb space and not revealing any bomb spaces.</p>
<p>As we already created the <code class="language-plaintext highlighter-rouge">Won</code> value on the <code class="language-plaintext highlighter-rouge">GameState</code> enum, we can use it now to indicate that the player has won the game.</p>
<p>Thankfully, we already locked the revealing of spaces to require that it be in the <code class="language-plaintext highlighter-rouge">Started</code> state, which means that we won’t have to worry about accidentally clicking a bomb space after we’ve revealed all of the other spaces.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">void</span> <span class="nf">Reveal</span><span class="p">(</span><span class="kt">int</span> <span class="n">rowIndex</span><span class="p">,</span> <span class="kt">int</span> <span class="n">columnIndex</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">State</span> <span class="p">!=</span> <span class="n">GameState</span><span class="p">.</span><span class="n">Started</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
<span class="n">Cell</span><span class="p">?</span> <span class="n">cell</span> <span class="p">=</span> <span class="n">Grid</span><span class="p">.</span><span class="nf">SafeGet</span><span class="p">(</span><span class="n">rowIndex</span><span class="p">,</span> <span class="n">columnIndex</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">cell</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
<span class="n">cell</span><span class="p">.</span><span class="nf">Reveal</span><span class="p">();</span>
<span class="k">if</span> <span class="p">(</span><span class="n">cell</span><span class="p">.</span><span class="n">IsBomb</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">State</span> <span class="p">=</span> <span class="n">GameState</span><span class="p">.</span><span class="n">Lost</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">Grid</span><span class="p">.</span><span class="nf">OnlyBombsLeft</span><span class="p">())</span>
<span class="p">{</span>
<span class="n">State</span> <span class="p">=</span> <span class="n">GameState</span><span class="p">.</span><span class="n">Won</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<h2 id="playing-the-game-without-a-ui">Playing the Game without a UI</h2>
<p>Now I’ll reveal the secret that I was able to run these tests before writing most of the code. My tests just needed to call methods on the <code class="language-plaintext highlighter-rouge">Game</code> object, because I could automate playing the game without a UI at all. I can do this, because I kept all of the logic out of the UI.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="k">class</span> <span class="nc">FullGameTests</span>
<span class="p">{</span>
<span class="k">private</span> <span class="k">readonly</span> <span class="n">Game</span> <span class="n">_game</span> <span class="p">=</span> <span class="k">new</span><span class="p">();</span>
<span class="p">[</span><span class="n">Fact</span><span class="p">]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">ClearAllSpacesSafely</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">_game</span><span class="p">.</span><span class="n">State</span><span class="p">.</span><span class="nf">Should</span><span class="p">().</span><span class="nf">Be</span><span class="p">(</span><span class="n">GameState</span><span class="p">.</span><span class="n">NotStarted</span><span class="p">);</span>
<span class="n">_game</span><span class="p">.</span><span class="nf">Start</span><span class="p">(</span><span class="m">4</span><span class="p">,</span> <span class="n">Difficulty</span><span class="p">.</span><span class="n">Reindeer</span><span class="p">);</span>
<span class="n">_game</span><span class="p">.</span><span class="n">State</span><span class="p">.</span><span class="nf">Should</span><span class="p">().</span><span class="nf">Be</span><span class="p">(</span><span class="n">GameState</span><span class="p">.</span><span class="n">Started</span><span class="p">);</span>
<span class="nf">ClickAllNonBombs</span><span class="p">();</span>
<span class="n">_game</span><span class="p">.</span><span class="n">State</span><span class="p">.</span><span class="nf">Should</span><span class="p">().</span><span class="nf">Be</span><span class="p">(</span><span class="n">GameState</span><span class="p">.</span><span class="n">Won</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">[</span><span class="n">Fact</span><span class="p">]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">ClickBombFirst</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">_game</span><span class="p">.</span><span class="n">State</span><span class="p">.</span><span class="nf">Should</span><span class="p">().</span><span class="nf">Be</span><span class="p">(</span><span class="n">GameState</span><span class="p">.</span><span class="n">NotStarted</span><span class="p">);</span>
<span class="n">_game</span><span class="p">.</span><span class="nf">Start</span><span class="p">(</span><span class="m">4</span><span class="p">,</span> <span class="n">Difficulty</span><span class="p">.</span><span class="n">Reindeer</span><span class="p">);</span>
<span class="n">_game</span><span class="p">.</span><span class="n">State</span><span class="p">.</span><span class="nf">Should</span><span class="p">().</span><span class="nf">Be</span><span class="p">(</span><span class="n">GameState</span><span class="p">.</span><span class="n">Started</span><span class="p">);</span>
<span class="nf">ClickBomb</span><span class="p">();</span>
<span class="n">_game</span><span class="p">.</span><span class="n">State</span><span class="p">.</span><span class="nf">Should</span><span class="p">().</span><span class="nf">Be</span><span class="p">(</span><span class="n">GameState</span><span class="p">.</span><span class="n">Lost</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>If I’d tied code into the UI, I’d have to spin up controllers, views or other context objects, which I’d rather not do in tests. I also haven’t tied myself to MVVM, MVC, MVP, etc. either. We can easily add those as wrappers, or directly put the concept on these classes.</p>
<h2 id="optional-homework">Optional Homework</h2>
<p>I built only the interface for the Console Application, but I left an empty WinForms and WPF application referencing the game library. The nice part is that you can build a front-end using any of the front-end technologies in the .NET space. I’ve put the <a href="https://github.com/DevChatter/MineSweeper-DotNet">Minesweeper in DotNet with C#</a> code on GitHub with some empty projects that you could wire up a UI for and make buttons to reveal spaces and play the game.</p>
<h2 id="outro">Outro</h2>
<p>One of my favorite things to do while programming in any language is to try to keep the application code away from the UI, because it gives us so much power of it when it’s just in a referenced class library.</p>
<p>Thanks for participating in this year’s .NET Advent Calendar! I hope you enjoy the next couple of weeks of these dotnet posts from members of the developer community.</p>
<p>If you don’t know me, my name is Brendan Enrick, and I’m a regular speaker at conferences and user groups. I host a live coding streams and create coding videos on my <a href="https://www.twitch.tv/DevChatter">DevChatter Twitch</a> and <a href="https://www.YouTube.com/c/DevChatter">DevChatter YouTube</a> channels. You can also follow me as <a href="https://twitter.com/brendoneus">@Brendoneus</a> on Twitter or <a href="https://our.devchatter.com/@Brendoneus">@Brendoneus@Our.DevChatter.com</a> on Mastodon.</p>
<p>Lastly, and most importantly, I want to be sure to thank the organizers and other authors of the <a href="https://dotnet.christmas/">.NET Advent Calendar</a> for making this an awesome bit of fun for everyone!</p>Brendan EnrickHello and welcome! This post is part of the 2022 .NET Advent Calendar series of posts, but you can enjoy the content without worrying about that!11 Ways of Making Your C# Harder to Use2022-12-11T04:00:00+00:002022-12-11T04:00:00+00:00https://brendoneus.com//post/Ways-Of-Making-CSharp-Mistakes<p>Hello and welcome! This post is part of the <a href="https://www.csadvent.christmas/">2022 C# Advent Calendar</a> series of posts, but you can enjoy the content without worrying about that! For the series, there will be 2 C# posts every day from 1st until the 24th of December from an awesome group of content creators!</p>
<p>Programming is hard. Most of us work in teams, building software that other people are going to work with. For that reason, it’s important that we try to make things easier for our team.</p>
<p>I think, however, it’s more fun that this post lightheartedly suggest making the code worse! And as this post is scheduled for the 11th of December, I figured I’d make a list of 11 ways of writing C# that will make our code harder for our team to work with, earning us a spot on the naughty list.</p>
<p>On the 11th day of C# Advent, I give to you, <strong>11 things you should NOT do in your C# code</strong>.</p>
<h2 id="abusing-for-loop-expressions"><a href="#abusing-for-loop-expressions">Abusing for Loop Expressions</a></h2>
<p>The “for” loop exists in many languages. It’s a useful structure for creating consistent loops, and it’s no different in C#. I’m sure you’ve seen this a million times:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="p"><</span> <span class="m">100</span><span class="p">;</span> <span class="n">i</span><span class="p">++)</span>
<span class="p">{</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="n">i</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<h3 id="understanding-the-for-loop"><a href="#understanding-the-for-loop">Understanding the For Loop</a></h3>
<p>Doing that is OK, but what might upset some people is if you start getting too creative with your loops. Let’s jump back and explain the structure of the for loop, so we can discuss how someone might abuse it.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">for</span> <span class="p">(</span><span class="n">before</span> <span class="n">statement</span><span class="p">;</span> <span class="n">conditional</span> <span class="n">statement</span><span class="p">;</span> <span class="n">after</span> <span class="n">each</span> <span class="n">statement</span><span class="p">)</span>
<span class="p">{</span>
<span class="p">}</span></code></pre></figure>
<p>The 3 statements inside of the parentheses have conditions for when they run, but they’re just statements like any others you might have in your code. For this reason, you can put whatever you want in them.</p>
<h3 id="non-standard-for-loops"><a href="#non-standard-for-loops">Non-Standard For Loops</a></h3>
<p>Let’s start by creating an infinite loop by leaving each of the 3 statements blank.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="c1">// Instead of this:</span>
<span class="k">while</span> <span class="p">(</span><span class="k">true</span><span class="p">)</span> <span class="p">{}</span>
<span class="c1">// You could write this:</span>
<span class="k">for</span> <span class="p">(;</span> <span class="p">;)</span> <span class="p">{}</span></code></pre></figure>
<p>That’s not really useful though. We could also try leaving out the increment step by just incrementing in the conditional.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="p">++</span><span class="n">i</span> <span class="p"><</span> <span class="m">100</span><span class="p">;)</span>
<span class="p">{</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="n">i</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>Yes, I switched from a post increment to a pre-increment to keep the usual structure, but we’re able to skip that third statement now!</p>
<p>Let’s get serious by using strings in a for loop instead of numbers. Let’s slowly remove letters from a string as part of a for loop.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">for</span> <span class="p">(</span><span class="kt">string</span> <span class="n">name</span> <span class="p">=</span> <span class="s">"Brendan"</span><span class="p">;</span> <span class="n">name</span><span class="p">.</span><span class="n">Length</span> <span class="p">></span> <span class="m">0</span><span class="p">;</span> <span class="n">name</span> <span class="p">=</span> <span class="n">name</span><span class="p">.</span><span class="nf">Substring</span><span class="p">(</span><span class="m">1</span><span class="p">))</span>
<span class="p">{</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="n">name</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>OK, but what if we want to get really crazy. Let’s create multiple variables and use them in the loop! We <em>can</em> as long as we use tuple construction and deconstruction! <strong>Not Subtle Foreshadowing</strong></p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">for</span> <span class="p">(</span><span class="kt">var</span> <span class="p">(</span><span class="n">number</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span> <span class="p">=</span> <span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="s">"Brendan"</span><span class="p">);</span> <span class="n">number</span> <span class="p"><</span> <span class="m">7</span><span class="p">;</span> <span class="n">name</span> <span class="p">+=</span> <span class="n">number</span><span class="p">.</span><span class="nf">ToString</span><span class="p">(),</span> <span class="n">number</span> <span class="p">+=</span> <span class="m">1</span><span class="p">)</span> <span class="p">{</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="n">name</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<h2 id="tuple-construction-and-deconstruction-as-constructor-assignment"><a href="#tuple-construction-and-deconstruction-as-constructor-assignment">Tuple Construction and Deconstruction as Constructor Assignment</a></h2>
<p>As we just saw, you can construct and deconstruct tuples in the same line. Awesome! Now to upset the rest of our team, because we can put our entire constructor in <strong>one line</strong> now!</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="nf">Person</span><span class="p">(</span><span class="kt">string</span> <span class="n">prefix</span><span class="p">,</span> <span class="kt">string</span> <span class="n">first</span><span class="p">,</span> <span class="kt">string</span> <span class="n">middle</span><span class="p">,</span> <span class="kt">string</span> <span class="n">last</span><span class="p">,</span> <span class="kt">string</span> <span class="n">suffix</span><span class="p">,</span> <span class="kt">string</span> <span class="n">nickname</span><span class="p">,</span> <span class="n">DateTime</span> <span class="n">birthday</span><span class="p">,</span> <span class="kt">string</span> <span class="n">favoriteColor</span><span class="p">)</span>
<span class="p">{</span>
<span class="p">(</span><span class="n">Prefix</span><span class="p">,</span> <span class="n">First</span><span class="p">,</span> <span class="n">Middle</span><span class="p">,</span> <span class="n">Last</span><span class="p">,</span> <span class="n">Suffix</span><span class="p">,</span> <span class="n">Nickname</span><span class="p">,</span> <span class="n">Birthday</span><span class="p">,</span> <span class="n">FavoriteColor</span><span class="p">)</span> <span class="p">=</span> <span class="p">(</span><span class="n">prefix</span><span class="p">,</span> <span class="n">first</span><span class="p">,</span> <span class="n">middle</span><span class="p">,</span> <span class="n">last</span><span class="p">,</span> <span class="n">nickname</span><span class="p">,</span> <span class="n">suffix</span><span class="p">,</span> <span class="n">birthday</span><span class="p">,</span> <span class="n">favoriteColor</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>Now some people might do this in some select places, but if you start writing things this way often, it gets a lot harder for people to see what’s going on. These are also deconstructed in order, so it would be very easy for me to have these mixed up especially if parameters get changed or removed.</p>
<p>Did you notice? It is messed up. Look again!</p>
<p>Yep, nickname and suffix get flipped in this constructor! And there won’t be a compiler error for this one, since they’re the same type.</p>
<h2 id="overusing-or-underusing-var"><a href="#overusing-or-underusing-var">Overusing or Underusing Var</a></h2>
<p>With all of the complex types we can get by using linq in C#, var was necessary. In fact, it’s an awesome addition to the language to not have to specify the type of variable, since the compiler knows the type already.</p>
<p>Let’s start by talking about why <code class="language-plaintext highlighter-rouge">var</code> is good and useful in C# coding. Hint: it’s not useful for just avoiding writing types in C# code. It’s useful when the type is more complicated than is needed. Exhibit A, the GroupBy.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="c1">// Clear, but lengthy.</span>
<span class="n">IEnumerable</span><span class="p"><</span><span class="n">IGrouping</span><span class="p"><</span><span class="n">DateOnly</span><span class="p">,</span> <span class="n">Person</span><span class="p">>></span> <span class="n">peopleGroupedByBirthdate</span> <span class="p">=</span> <span class="n">people</span><span class="p">.</span><span class="nf">GroupBy</span><span class="p">(</span>
<span class="n">person</span> <span class="p">=></span> <span class="n">person</span><span class="p">.</span><span class="n">Birthdate</span><span class="p">,</span>
<span class="n">person</span> <span class="p">=></span> <span class="n">person</span><span class="p">);</span>
<span class="c1">// Less clear, but concise.</span>
<span class="kt">var</span> <span class="n">peopleGroupedByBirthdate</span> <span class="p">=</span> <span class="n">people</span><span class="p">.</span><span class="nf">GroupBy</span><span class="p">(</span>
<span class="n">person</span> <span class="p">=></span> <span class="n">person</span><span class="p">.</span><span class="n">Birthdate</span><span class="p">,</span>
<span class="n">person</span> <span class="p">=></span> <span class="n">person</span><span class="p">);</span></code></pre></figure>
<p>It’s for complicated types like these (and anonymous types) that <code class="language-plaintext highlighter-rouge">var</code> became necessary. In fact, nearly everywhere that a GroupBy result is stored in a variable, you’re likely to see <code class="language-plaintext highlighter-rouge">var</code> in the code. Sometimes that’s because the result needs to get turned into a new anonymous type.</p>
<p>Now, dear reader, you’re likely wondering why we wouldn’t just use this <em>everywhere</em>. We <em>can</em> just write <code class="language-plaintext highlighter-rouge">var</code> for nearly every variable we create!</p>
<p>That’s because knowing the type of a variable can be useful to us as programmers. When you use <code class="language-plaintext highlighter-rouge">var</code>, you’ve hidden the information. We no longer know the type. If the type was somewhere else on the line, that’s probably ok, but if it’s not there, it better be super clear what the type is.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="kt">var</span> <span class="n">author1</span> <span class="p">=</span> <span class="nf">GetAuthor1</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">author2</span> <span class="p">=</span> <span class="nf">GetAuthor2</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">authorName</span> <span class="p">=</span> <span class="nf">GetAuthorName</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">authorFullName</span> <span class="p">=</span> <span class="nf">GetAuthorFullName</span><span class="p">();</span></code></pre></figure>
<p>Notice that we can’t tell the type of <strong>any</strong> of these variables without putting a cursor on the type. At-a-glance, you might guess that <code class="language-plaintext highlighter-rouge">GetAuthorName</code> and <code class="language-plaintext highlighter-rouge">GetAuthorFullName</code> return the same type, but it’s not clear that they do. Let’s see this example without <code class="language-plaintext highlighter-rouge">var</code>.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="n">Person</span> <span class="n">author1</span> <span class="p">=</span> <span class="nf">GetAuthor1</span><span class="p">();</span>
<span class="kt">string</span> <span class="n">author2</span> <span class="p">=</span> <span class="nf">GetAuthor2</span><span class="p">();</span>
<span class="kt">string</span> <span class="n">authorName</span> <span class="p">=</span> <span class="nf">GetAuthorName</span><span class="p">();</span>
<span class="n">FullName</span> <span class="n">authorFullName</span> <span class="p">=</span> <span class="nf">GetAuthorFullName</span><span class="p">();</span></code></pre></figure>
<p>This is useful for immediately knowing what type of sequence you have, enumerable, list, array, etc. or what other type you have. With the native number types, it would catch your eye immediately if you noticed a <code class="language-plaintext highlighter-rouge">double</code> used for a financial transaction or for something consistently rounded like an age of a person. If the information isn’t at-a-glance, you won’t consider it.</p>
<p>And if you’re wondering, I have been fighting against this <a href="https://brendoneus.com/post/Overusing-var-in-C/">overreliance on var in C#</a> for a long time as this 13.5 year old post illustrates.</p>
<h2 id="working-with-disposable-types-without-a-using-statement"><a href="#working-with-disposable-types-without-a-using-statement">Working With Disposable Types Without a Using Statement</a></h2>
<p>In the C# world, we work with “disposable” types all the time. When we say that, we usually mean that the type implements the IDisposable interface. There’s even a language feature called using statements that was built for these. When you create your variable in one, it is supposed to dispose when you reach the ending curly brace.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">using</span> <span class="p">(</span><span class="n">StreamWriter</span> <span class="n">streamWriter</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">StreamWriter</span><span class="p">(</span><span class="n">filePath</span><span class="p">,</span> <span class="k">true</span><span class="p">))</span>
<span class="p">{</span>
<span class="n">streamWriter</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">"Brendan Enrick"</span><span class="p">);</span>
<span class="n">streamWriter</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">"C# Advent"</span><span class="p">);</span>
<span class="n">streamWriter</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">"2022-12-11"</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>If you want to upset your team, stop using the using statements. Ignore what’s special about disposable types. <em>What could go wrong?</em></p>
<p>Well, a lot can go wrong. When a type implements IDisposable, it’s so that it can be cleaned up correctly. These are for types that have resources that need to be cleaned up before the type is disposed of. Often these are network connections, file system connections, etc. that we don’t want to leave open. If we don’t dispose of them correctly, these get left open.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="c1">// Normal way - GOOD</span>
<span class="k">using</span> <span class="p">(</span><span class="n">SqlConnection</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="p">(</span><span class="n">connectionString</span><span class="p">))</span>
<span class="p">{</span>
<span class="n">SqlCommand</span> <span class="n">command</span> <span class="p">=</span> <span class="k">new</span> <span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">connection</span><span class="p">);</span>
<span class="n">connection</span><span class="p">.</span><span class="nf">Open</span><span class="p">();</span>
<span class="k">using</span><span class="p">(</span><span class="n">SqlDataReader</span> <span class="n">reader</span> <span class="p">=</span> <span class="n">command</span><span class="p">.</span><span class="nf">ExecuteReader</span><span class="p">())</span>
<span class="p">{</span>
<span class="k">while</span> <span class="p">(</span><span class="n">reader</span><span class="p">.</span><span class="nf">Read</span><span class="p">())</span>
<span class="p">{</span>
<span class="c1">// Use reader here.</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">// Skipping those Disposables - BAD</span>
<span class="n">SqlConnection</span> <span class="n">connection</span> <span class="p">=</span> <span class="k">new</span> <span class="p">(</span><span class="n">connectionString</span><span class="p">)</span>
<span class="n">SqlCommand</span> <span class="n">command</span> <span class="p">=</span> <span class="k">new</span> <span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">connection</span><span class="p">);</span>
<span class="n">connection</span><span class="p">.</span><span class="nf">Open</span><span class="p">();</span>
<span class="n">SqlDataReader</span> <span class="n">reader</span> <span class="p">=</span> <span class="n">command</span><span class="p">.</span><span class="nf">ExecuteReader</span><span class="p">()</span>
<span class="k">while</span> <span class="p">(</span><span class="n">reader</span><span class="p">.</span><span class="nf">Read</span><span class="p">())</span>
<span class="p">{</span>
<span class="c1">// Use reader here.</span>
<span class="p">}</span>
<span class="c1">// GAHHH!!</span></code></pre></figure>
<p>And if you’re thinking that it’s nice to not be so nested, please don’t use that as an excuse. The language no longer requires {} and nesting with a using statement. It will dispose at the end of the current context.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">using</span> <span class="p">(</span><span class="n">StreamWriter</span> <span class="n">streamWriter</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">StreamWriter</span><span class="p">(</span><span class="n">filePath</span><span class="p">,</span> <span class="k">true</span><span class="p">));</span>
<span class="n">streamWriter</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">"Brendan Enrick"</span><span class="p">);</span>
<span class="n">streamWriter</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">"C# Advent"</span><span class="p">);</span>
<span class="n">streamWriter</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">"2022-12-11"</span><span class="p">);</span></code></pre></figure>
<p>So only skip the using statements if you’re <strong>trying</strong> to write bad code.</p>
<h2 id="throwing-exceptions-instead-of-returning"><a href="#throwing-exceptions-instead-of-returning">Throwing Exceptions Instead of Returning</a></h2>
<p>One thing you can do as a programmer to get my attention on a code review is to handle an expected or likely situation by throwing an exception instead of just escaping and returning a value.</p>
<p>Did a user forget to enter a value? That’s a validation error that we can return, not an exceptional case! We can (and should) return an error result from our method and inform the user of the issue. If the value were missing during some internal calculatoin, that’s a data integrity issue after validation, an exceptional case that might require stopping the code to prevent further issues.</p>
<p>So how could we upset our team? Well, in theory, you don’t have to return values from your methods at all! You could throw exceptions for everything!</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">private</span> <span class="k">void</span> <span class="nf">UpdateProfileData</span><span class="p">(</span><span class="n">ProfileData</span> <span class="n">data</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">data</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">data</span><span class="p">));</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="kt">string</span><span class="p">.</span><span class="nf">IsNullOrWhiteSpace</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">FullName</span><span class="p">))</span>
<span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentException</span><span class="p">(</span><span class="s">"Missing Name"</span><span class="p">,</span> <span class="k">nameof</span><span class="p">(</span><span class="n">data</span><span class="p">));</span>
<span class="p">}</span>
<span class="c1">// Save changes here</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">ProfileDataUpdatedSuccessfully</span><span class="p">(</span><span class="n">data</span><span class="p">);</span> <span class="c1">// (╯°□°)╯︵ ┻━┻</span>
<span class="p">}</span></code></pre></figure>
<p>Never thought of that, did you?! Well now you can write some truly terrible code. These act kind of like events that require that you handle them or your application crashed.</p>
<h2 id="suppress-all-your-build-warnings-instead-of-fixing-them"><a href="#suppress-all-your-build-warnings-instead-of-fixing-them">Suppress All Your Build Warnings instead of Fixing Them</a></h2>
<p>Not much to say here. Some compiler warnings may not be issues, but often they’re indicative of a place where an error is likely to go unnoticed. Some of us like the property to treat warnings as errors in dotnet, because it forces us to fix every warning. This keeps the signal to noise ratio low, increasing the chance that we’ll catch bugs earlier.</p>
<p>Adding a warning or two to a code library can be necessary sometimes, so they have a <code class="language-plaintext highlighter-rouge">NoWarn</code> property that you can set in the project, allowing you to specify the warnings to ignore.</p>
<p>If you really want to upset your team, just add another warning to ignore with every commit that created a warning. Then your code will be warning free!</p>
<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="nt"><NoWarn></span>12345,23456,34567,45678,56789<span class="nt"></NoWarn></span></code></pre></figure>
<p>On a more serious note, I’ve worked with many clients (development teams) whose code bases had hundreds of warnings that just sat there. It would’ve been difficult to know where to start with fixing them.</p>
<p>If this is your situation, I highly recommend setting up a metric to watch that number and use the <a href="https://brendoneus.com/post/Boy-Scout-Rule/">scout rule in programming</a> to clean up a warning or two each time you’re in a file.</p>
<h2 id="using-unclear-abbreviations-for-variable-names"><a href="#using-unclear-abbreviations-for-variable-names">Using Unclear Abbreviations for Variable Names</a></h2>
<p>When naming a variable, it’s far more important for a reader to know what the variable’s purpose is. If you’re trying to make your codebase difficult, you might embrace this ambiguity, which can arise from abbreviations.</p>
<p>Even if an abbreviation is common in your codebase or domain, you could have a collision or just confusion you haven’t thought of yet.Clarity can prevent headaches from forming among the development team!</p>
<p>When you have a bunch of this internal, required domain knowledge, it makes your codebase much harder for new people to join, since they’ll have to learn a list of abbreviations just to get started.</p>
<h3 id="unclear-variable-names"><a href="#unclear-variable-names">Unclear Variable Names</a></h3>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="kt">var</span> <span class="n">st</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SimpleTransfer</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">st</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ServiceTime</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">st</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SecretTunnel</span><span class="p">();</span></code></pre></figure>
<h3 id="clear-variable-names"><a href="#clear-variable-names">Clear Variable Names</a></h3>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="kt">var</span> <span class="n">simpleTransfer</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SimpleTransfer</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">serviceTime</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">ServiceTime</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">secretTunnel</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SecretTunnel</span><span class="p">();</span> <span class="c1">// Through the mountain!</span></code></pre></figure>
<p><strong>Note:</strong> For this example, assume these were in different scopes, so the compiler would allow it, but seeing <code class="language-plaintext highlighter-rouge">st</code> in the code wouldn’t tell you which <code class="language-plaintext highlighter-rouge">st</code> <em>this</em> was!</p>
<h3 id="real-world-examples-of-abbreviations"><a href="#real-world-examples-of-abbreviations">Real World Examples of Abbreviations</a></h3>
<p>These are some abbreviations I’ve come across in code bases that aren’t what you might first think they are:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>"E2E" and it wasn't End-to-End like I thought.
"IRS" and it wasn't related to taxes.
"IBM" and it wasn't the computer company.
"S3" and it wasn't the AWS storage.
"NES" and it wasn't the video game console.
"DDL" and it wasn't a DataDefinitionLanguage or a DropDownList.
"DLL" and it wasn't a DynamicLinkLibrary.
</code></pre></div></div>
<h2 id="using-single-letter-variables"><a href="#using-single-letter-variables">Using Single Letter Variables</a></h2>
<p>There are only two places where a single letter variable can be OK. Even then, it might be better to use a full variable name.</p>
<h3 id="acceptable-single-letter-variables"><a href="#acceptable-single-letter-variables">Acceptable Single Letter Variables</a></h3>
<p>You’ll often find that classic “i” as the variable in a basic for loop. If you’re not <em>using</em> the i itself, but it’s just the number of times you looped, this can be OK.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="p"><</span> <span class="n">greetingCount</span><span class="p">;</span> <span class="n">i</span><span class="p">++)</span>
<span class="p">{</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="n">greetingMessage</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>Also, for a lambda selector where the collection name makes the <code class="language-plaintext highlighter-rouge">x</code> obvious, it <em>can</em> be OK. Once you start chaining, LINQ extensions, you’re no longer OK.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="c1">// This is an OK alternative</span>
<span class="kt">int</span> <span class="n">maxTemperature</span> <span class="p">=</span> <span class="n">dailyForecasts</span><span class="p">.</span><span class="nf">Max</span><span class="p">(</span><span class="n">x</span> <span class="p">=></span> <span class="n">x</span><span class="p">.</span><span class="n">Temperature</span><span class="p">);</span>
<span class="c1">// to this</span>
<span class="kt">int</span> <span class="n">maxTemperature</span> <span class="p">=</span> <span class="n">dailyForecasts</span><span class="p">.</span><span class="nf">Max</span><span class="p">(</span><span class="n">forecast</span> <span class="p">=></span> <span class="n">forecast</span><span class="p">.</span><span class="n">Temperature</span><span class="p">);</span></code></pre></figure>
<h3 id="unacceptable-single-letter-variables"><a href="#unacceptable-single-letter-variables">Unacceptable Single Letter Variables</a></h3>
<p>Pretty much, if you’re doing anything other than what’s listed above, you’ve found your way onto the team’s naughty list. When you start chaining LINQ extensions in your code, the data will often change from the initial type that started the chain. Unlike a fluent API, where the return value is often the same type that all the methods extend, these will return new and different objects. As a result, the types of those object matter!</p>
<p>Here’s a not-too-complex example that shows that even in the simpler cases, it could be nicer to have variable names.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="kt">var</span> <span class="n">maxTemperatures</span> <span class="p">=</span>
<span class="n">allTemperatures</span>
<span class="p">.</span><span class="nf">GroupBy</span><span class="p">(</span><span class="n">x</span> <span class="p">=></span> <span class="n">x</span><span class="p">.</span><span class="n">DayOfWeek</span><span class="p">)</span>
<span class="p">.</span><span class="nf">Select</span><span class="p">(</span><span class="n">y</span> <span class="p">=></span> <span class="k">new</span> <span class="p">{</span> <span class="n">DayOfWeek</span> <span class="p">=</span> <span class="n">y</span><span class="p">.</span><span class="n">Key</span><span class="p">,</span> <span class="n">HighTemp</span> <span class="p">=</span> <span class="n">y</span><span class="p">.</span><span class="nf">Max</span><span class="p">(</span><span class="n">z</span> <span class="p">=></span> <span class="n">z</span><span class="p">.</span><span class="n">Temperature</span><span class="p">)</span> <span class="p">})</span>
<span class="p">.</span><span class="nf">OrderBy</span><span class="p">(</span><span class="n">o</span> <span class="p">=></span> <span class="n">o</span><span class="p">.</span><span class="n">HighTemp</span><span class="p">)</span>
<span class="p">.</span><span class="nf">ToList</span><span class="p">();</span></code></pre></figure>
<p>Notice <code class="language-plaintext highlighter-rouge">x</code>, <code class="language-plaintext highlighter-rouge">y</code>, <code class="language-plaintext highlighter-rouge">z</code>, and <code class="language-plaintext highlighter-rouge">o</code> are all different types. Even if I tried using <code class="language-plaintext highlighter-rouge">g</code> for the group, there’s the risk that it might have an alternate interpretation.</p>
<h2 id="heavily-nesting-code-with-conditionals"><a href="#heavily-nesting-code-with-conditionals">Heavily Nesting Code with Conditionals</a></h2>
<p>Want a quick and easy way to make your code harder to read? Nest your conditionals needlessly deep by adding separate checks instead of using <code class="language-plaintext highlighter-rouge">&&</code> or a quick null conditional or null coalescing operation.</p>
<p>You can end up with code like this:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">if</span> <span class="p">(</span><span class="n">building</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">building</span><span class="p">.</span><span class="n">Office</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">building</span><span class="p">.</span><span class="n">Office</span><span class="p">.</span><span class="n">IsAvailable</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">user</span><span class="p">.</span><span class="n">CanReserve</span><span class="p">)</span>
<span class="p">{</span>
<span class="nf">ReserveOffice</span><span class="p">(</span><span class="n">user</span><span class="p">,</span> <span class="n">building</span><span class="p">.</span><span class="n">Office</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>When you could have just done this, but you’d miss that sweet pyramid of code.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">if</span> <span class="p">(</span><span class="n">building</span><span class="p">?.</span><span class="n">Office</span><span class="p">?.</span><span class="n">IsAvailable</span> <span class="p">==</span> <span class="k">true</span> <span class="p">&&</span> <span class="n">user</span><span class="p">.</span><span class="n">CanReserve</span><span class="p">)</span>
<span class="p">{</span>
<span class="nf">ReserveOffice</span><span class="p">(</span><span class="n">user</span><span class="p">,</span> <span class="n">building</span><span class="p">.</span><span class="n">Office</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<h2 id="using-a-one-to-one-interface-to-class-for-a-model"><a href="#using-a-one-to-one-interface-to-class-for-a-model">Using a One-to-One Interface to Class for a Model</a></h2>
<p>As people learn about Dependency Inversion and mocking, some take this to the extreme, adding an interface to every class regardless of whether there will be multiple implementations or a need to be mocked.</p>
<p>For clarity, I’m not saying you can’t have interfaces for models. You might have interfaces for all cached objects, all printable objects, etc. in your codebase. These are likely to have multiple implementations, and there’s polymorphic reasons to have these.</p>
<p>The problem is when you get <code class="language-plaintext highlighter-rouge">IStudent</code> for <code class="language-plaintext highlighter-rouge">Student</code>, <code class="language-plaintext highlighter-rouge">ITeacher</code> for <code class="language-plaintext highlighter-rouge">Teacher</code>, and <code class="language-plaintext highlighter-rouge">ILesson</code> for <code class="language-plaintext highlighter-rouge">Lesson</code>. None of those objects likely need a mock for testing, since you could just create instances of those models for testing.</p>
<p>Some useful interfaces might be things like, <code class="language-plaintext highlighter-rouge">ISchoolMember</code> for <code class="language-plaintext highlighter-rouge">Student</code>, <code class="language-plaintext highlighter-rouge">Teacher</code>, and <code class="language-plaintext highlighter-rouge">Administrator</code>, which requires a <code class="language-plaintext highlighter-rouge">SchoolID</code> property on these objects.</p>
<h2 id="putting-regions-inside-methods"><a href="#putting-regions-inside-methods">Putting Regions Inside Methods</a></h2>
<p>Yes, we saved the worst for last. I won’t shame anyone for using a region in their code, however, nearly all uses of them are better replaced by a change t the code.</p>
<p>Plenty of people do use regions, and like being able to define sections of code in those named blocks. A region inside of a method, however, better have a <em>really</em> good reason to exist. By labeling that section of code with a region, you’re begging for a method to be extracted for that code.</p>
<p>Have you done this? Are you the one?!</p>
<h3 id="region-inside-a-method"><a href="#region-inside-a-method">Region Inside a Method</a></h3>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="n">ProcessResult</span> <span class="nf">ProcessStatusUpdate</span><span class="p">(</span><span class="n">ChangeLog</span> <span class="n">changes</span><span class="p">)</span>
<span class="p">{</span>
<span class="err">#</span><span class="n">region</span> <span class="n">Validate</span> <span class="n">Changes</span>
<span class="k">if</span> <span class="p">(</span><span class="n">changes</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">throw</span> <span class="nf">InvalidChangeLogException</span><span class="p">(</span><span class="n">changes</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">changes</span><span class="p">.</span><span class="n">Actions</span> <span class="p"><=</span> <span class="n">MinimumActions</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">throw</span> <span class="nf">InvalidChangeLogException</span><span class="p">(</span><span class="n">changes</span><span class="p">);</span>
<span class="p">}</span>
<span class="err">#</span><span class="n">end</span> <span class="n">region</span>
<span class="err">#</span><span class="n">region</span> <span class="n">Print</span> <span class="n">Changes</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="n">changes</span><span class="p">.</span><span class="n">Title</span><span class="p">);</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="n">changes</span><span class="p">.</span><span class="n">SubTitle</span><span class="p">);</span>
<span class="k">foreach</span><span class="p">(</span><span class="kt">var</span> <span class="n">changeAction</span> <span class="k">in</span> <span class="n">changes</span><span class="p">.</span><span class="n">Actions</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="n">changeAction</span><span class="p">.</span><span class="n">Message</span><span class="p">);</span>
<span class="p">}</span>
<span class="err">#</span><span class="n">endregion</span>
<span class="c1">// More code here</span>
<span class="p">}</span></code></pre></figure>
<h3 id="extracted-method-instead-of-region"><a href="#extracted-method-instead-of-region">Extracted Method Instead of Region</a></h3>
<p>Instead of the regions, we could’ve just created methods for those named parts of the code.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">public</span> <span class="n">ProcessResult</span> <span class="nf">ProcessStatusUpdate</span><span class="p">(</span><span class="n">ChangeLog</span> <span class="n">changes</span><span class="p">)</span>
<span class="p">{</span>
<span class="nf">ValidateChanges</span><span class="p">(</span><span class="n">changes</span><span class="p">);</span>
<span class="nf">PrintChanges</span><span class="p">(</span><span class="n">changes</span><span class="p">);</span>
<span class="c1">// More code here</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">ValidateChanges</span><span class="p">(</span><span class="n">ChangeLog</span> <span class="n">changes</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">changes</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">throw</span> <span class="nf">InvalidChangeLogException</span><span class="p">(</span><span class="n">changes</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">changes</span><span class="p">.</span><span class="n">Actions</span> <span class="p"><=</span> <span class="n">MinimumActions</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">throw</span> <span class="nf">InvalidChangeLogException</span><span class="p">(</span><span class="n">changes</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">PrintChanges</span><span class="p">(</span><span class="n">ChangeLog</span> <span class="n">changes</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="n">changes</span><span class="p">.</span><span class="n">Title</span><span class="p">);</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="n">changes</span><span class="p">.</span><span class="n">SubTitle</span><span class="p">);</span>
<span class="k">foreach</span><span class="p">(</span><span class="kt">var</span> <span class="n">changeAction</span> <span class="k">in</span> <span class="n">changes</span><span class="p">.</span><span class="n">Actions</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="n">changeAction</span><span class="p">.</span><span class="n">Message</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<h2 id="outro"><a href="#outro">Outro</a></h2>
<p>Thanks for participating in this year’s <a href="https://www.csadvent.christmas/">C# Advent</a>! I hope you enjoy the next couple of weeks of these C# posts from members of the developer community.</p>
<p>If you don’t know me, my name is Brendan Enrick, and I’m a regular speaker at conferences and user groups. I host a live coding streams and create coding videos on my <a href="https://www.twitch.tv/DevChatter">DevChatter Twitch</a> and <a href="https://www.YouTube.com/c/DevChatter">DevChatter YouTube</a> channels. You can also follow me as <a href="https://twitter.com/brendoneus">@Brendoneus</a> on Twitter or <a href="https://our.devchatter.com/@Brendoneus">@Brendoneus@Our.DevChatter.com</a> on Mastodon.</p>
<p>Lastly, and most importantly, I want to thank <a href="https://twitter.com/mgroves">Matt Groves @mgroves</a> for organizing the C# Advent, which has been an awesome way to flood our feeds with great C# content! I’m grateful to have been able to help out and add to the C# fun this year!</p>Brendan EnrickHello and welcome! This post is part of the 2022 C# Advent Calendar series of posts, but you can enjoy the content without worrying about that! For the series, there will be 2 C# posts every day from 1st until the 24th of December from an awesome group of content creators!3 Things You Didn’t Know VS Code Can Do - Part 4, Custom File Icons, Keyboard Shortcuts, and Import Keymaps2022-10-07T05:00:00+00:002022-10-07T05:00:00+00:00https://brendoneus.com//post/Cool-VSCode-Things-4<p>Did you know that you can customize the file icons in VS Code explorer, customize and search the keyboard shortcuts in VS Code, view a printable keyboard shortcut cheat sheet, and import the keymaps from other editors into VS Code?</p>
<div class="message">
I've been creating a series of videos on YouTube about cool things in VS Code that you may not know about. Check out the [DevChatter YouTube Channel](https://www.youtube.com/c/devchatter) if you want to see all of my videos, or you can see the [VS Code Tips](https://youtube.com/playlist?list=PLfRLz7YT8uz36VdgSMATJj2chNtbixokI) Playlist.
</div>
<div class="video-container">
<iframe width="560" height="315" src="https://www.youtube.com/embed/204EW3cX1zM" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
</div>
<h2 id="changing-the-file-icons-in-vs-code">Changing the File Icons in VS Code</h2>
<p>You can change the theme of the file icons in VS Code Explorer Sidebar by opening up the File Icon Theme menu. You can open it from the manage menu (the gear in the sidebar) by selecting <code class="language-plaintext highlighter-rouge">File Icon Theme</code> or by opening the commands menu <code class="language-plaintext highlighter-rouge">[F1]</code> or <code class="language-plaintext highlighter-rouge">[Ctrl]</code> + <code class="language-plaintext highlighter-rouge">[Shift]</code> + <code class="language-plaintext highlighter-rouge">[P]</code> and searching for “File Icon Theme”.</p>
<h3 id="opening-file-icon-menu-from-manage-menu">Opening File Icon Menu from Manage Menu</h3>
<p><img src="/images/files/2022-posts/VSCodeTips/Part4/FileIconMenuFromManageMenu.png" alt="Opening File Icon Menu from Manage Menu" /></p>
<h3 id="opening-file-icon-menu-from-command-menu">Opening File Icon Menu from Command Menu</h3>
<p><img src="/images/files/2022-posts/VSCodeTips/Part4/FileIconMenuFromCommandMenu.png" alt="Opening File Icon Menu from Command Menu" /></p>
<p>Once open, you can preview the file icon themes by using the up and down arrows to select each of the installed icon themes. You can click on the theme you like to change to it. If you select the last item, <code class="language-plaintext highlighter-rouge">Install Additional File Icon Themes...</code>, it will open the <code class="language-plaintext highlighter-rouge">Extensions</code> sidebar showing results for extensions to change the file icon theme.</p>
<p><img src="/images/files/2022-posts/VSCodeTips/Part4/FileIconExtensionsSearch.png" alt="File Icon Extension Search Results in VS Code" /></p>
<p>You can open and see details of each extension to choose which (if any) you want to install. Just install them by clicking the <code class="language-plaintext highlighter-rouge">Install</code> button (like a normal extension). Once installed, you can open up the <code class="language-plaintext highlighter-rouge">File Icon Menu</code> again to preview or change your newly installed file icon themes.</p>
<h2 id="keyboard-shortcuts-in-vs-code">Keyboard Shortcuts in VS Code</h2>
<p>There are more keyboard shortcuts in VS Code than most of us can remember. Luckily, we don’t have to remember them all, since VS Code has a <code class="language-plaintext highlighter-rouge">Keyboard Shortcuts</code> window that allows searching for shortcuts.</p>
<p>You can open the <code class="language-plaintext highlighter-rouge">Keyboard Shortcuts</code> window from the manage menu (the gear in the sidebar), from <code class="language-plaintext highlighter-rouge">File</code> -> <code class="language-plaintext highlighter-rouge">Preferences</code> -> <code class="language-plaintext highlighter-rouge">Keyboard Shortcuts</code>, by opening the commands menu <code class="language-plaintext highlighter-rouge">[F1]</code> or <code class="language-plaintext highlighter-rouge">[Ctrl]</code> + <code class="language-plaintext highlighter-rouge">[Shift]</code> + <code class="language-plaintext highlighter-rouge">[P]</code> and searching for “Open Keyboard Shortcuts”, or by using the keyboard shortcut <code class="language-plaintext highlighter-rouge">[Ctrl]</code> + <code class="language-plaintext highlighter-rouge">[K]</code> + <code class="language-plaintext highlighter-rouge">[S]</code>.</p>
<h3 id="opening-keyboard-shortcuts-from-manage-menu">Opening Keyboard Shortcuts from Manage Menu</h3>
<p><img src="/images/files/2022-posts/VSCodeTips/Part4/KeyboardShortcutsMenuFromManageMenu.png" alt="Opening Keyboard Shortcuts from Manage Menu" /></p>
<h3 id="opening-keyboard-shortcuts-from-command-menu">Opening Keyboard Shortcuts from Command Menu</h3>
<p><img src="/images/files/2022-posts/VSCodeTips/Part4/OpenKeyboardShortcutsFromCommandMenu.png" alt="Opening Keyboard Shortcuts from Command Menu" /></p>
<h3 id="opening-keyboard-shortcuts-from-file-menu">Opening Keyboard Shortcuts from File Menu</h3>
<p><img src="/images/files/2022-posts/VSCodeTips/Part4/KeyboardShortcutsMenuFromFileMenu.png" alt="Opening Keyboard Shortcuts from File Menu" /></p>
<p>Once you’ve opened the keyboard shortcuts window, you can use the search box to search for any possible actions that can have a keyboard shortcut set for it. With any of the items in the list, you can also change any of the shortcuts if you want to.</p>
<p><img src="/images/files/2022-posts/VSCodeTips/Part4/KeyboardShortcutsMenuSearchResults.png" alt="Search VS Code Keyboard Shortcuts" /></p>
<p>If you want a printable set of the default keyboard shortcuts, you can find a link to it inside of VS Code (for your operating system) by opening the commands menu <code class="language-plaintext highlighter-rouge">[F1]</code> or <code class="language-plaintext highlighter-rouge">[Ctrl]</code> + <code class="language-plaintext highlighter-rouge">[Shift]</code> + <code class="language-plaintext highlighter-rouge">[P]</code> and searching for “Keyboard Shortcuts Reference” or by using the keyboard shortcut <code class="language-plaintext highlighter-rouge">[Ctrl]</code> + <code class="language-plaintext highlighter-rouge">[K]</code> + <code class="language-plaintext highlighter-rouge">[R]</code> (remember it as <strong>K</strong>eyboard <strong>R</strong>eference).</p>
<ul>
<li><a href="https://code.visualstudio.com/shortcuts/keyboard-shortcuts-windows.pdf">VS Code Windows Keyboard Shortcut Reference</a></li>
<li><a href="https://code.visualstudio.com/shortcuts/keyboard-shortcuts-linux.pdf">VS Code Linux Keyboard Shortcut Reference</a></li>
<li><a href="https://code.visualstudio.com/shortcuts/keyboard-shortcuts-macos.pdf">VS Code Mac Keyboard Shortcut Reference</a></li>
</ul>
<h2 id="importing-other-ide-keymaps-into-vs-code">Importing Other IDE Keymaps into VS Code</h2>
<p>VS Code isn’t the first editor I’ve ever used. In fact, I’ve used and know the keyboard shortcuts to Visual Studio, Rider, WebStorm, Notepad++, etc. When I’m switching between them, it’s definitely a challenge to switch my brain to thinking of the correct set of shortcuts. If I wanted to make it easier, I could import the full keymap of another IDE into VS Code.</p>
<p>To migrate your keyboard shortcuts from another editor, open the manage menu (the gear in the sidebar) and choose <code class="language-plaintext highlighter-rouge">Migrate Keyboard Shortcuts from...</code>, which will open up the <code class="language-plaintext highlighter-rouge">Extensions</code> sidebar showing the results of a search for keymaps.</p>
<p><img src="/images/files/2022-posts/VSCodeTips/Part4/MigrateKeyboardShortcutsFromManageMenu.png" alt="Open VS Code Keymaps Import" /></p>
<p><img src="/images/files/2022-posts/VSCodeTips/Part4/KeymapExtensionsResults.png" alt="VS Code Keymaps Extensions Install" /></p>
<p>Many of these will do more than just a keymap import, so read the extension details for how to use the one for your editor.</p>
<p>Have fun!</p>Brendan EnrickDid you know that you can customize the file icons in VS Code explorer, customize and search the keyboard shortcuts in VS Code, view a printable keyboard shortcut cheat sheet, and import the keymaps from other editors into VS Code?I’m Speaking at CodeMash 20232022-10-04T05:00:00+00:002022-10-04T05:00:00+00:00https://brendoneus.com//post/Speaking-At-CodeMash-2023<p>I am very excited and honored to announce that 2 of my workshops have been accepted at CodeMash 2023! This will be my 10th year speaking at CodeMash (including times as a secondary speaker). I’m looking forward to making it back to this event, which I’ve not attended for years due to the global pandemic.</p>
<p>If you’ll be attending the event, be sure to say “hello” to me in the hallways of the event or before/after one of my pre-compiler workshops.</p>
<h2 id="session-details">Session Details</h2>
<p>If you’re wondering about my workshops for the event, I’ll be doing 2 workshops to help people build up their TDD skills, and I’ll have an awesome co-speaker helping me make these workshops awesome!</p>
<h3 id="establishing-good-tdd-habits---workshop-at-codemash-2023">Establishing Good TDD Habits - Workshop at CodeMash 2023</h3>
<p>Learn fundamental techniques to improve your code through TDD and Pair Programming. You’ll sharpen your skills working with your peers on programming exercises designed to instill good techniques that you’ll be ready to apply on your current and future projects.</p>
<p><a href="https://www.codemash.org/session-details/?id=379843"><img src="/images/files/2022-posts/CodeMash/Establishing_Good_TDD_Habits_Banner.jpeg" alt="Establishing Good TDD Habits by Brendan Enrick - CodeMash Banner" /></a></p>
<h3 id="mastering-tdd-in-legacy-code---workshop-at-codemash-2023">Mastering TDD in Legacy Code - Workshop at CodeMash 2023</h3>
<p>Learn to effectively use the principles and practices of increasing the reliability and maintainability of your code through testing and pair programming. Sharpen your skills working with your peers on programming exercises designed to instill good practices that you’ll be ready to apply to non-trivial code-bases.</p>
<p><a href="https://www.codemash.org/session-details/?id=379844"><img src="/images/files/2022-posts/CodeMash/Mastering_TDD_in_Legacy_Code_Banner.jpeg" alt="Mastering TDD in Legacy Code by Brendan Enrick - CodeMash Banner" /></a></p>Brendan EnrickI am very excited and honored to announce that 2 of my workshops have been accepted at CodeMash 2023! This will be my 10th year speaking at CodeMash (including times as a secondary speaker). I’m looking forward to making it back to this event, which I’ve not attended for years due to the global pandemic.3 Things You Didn’t Know VS Code Can Do - Part 3, Color Theme, Settings Search, and Settings Sync2022-10-02T05:00:00+00:002022-10-02T05:00:00+00:00https://brendoneus.com//post/Cool-VSCode-Things-3<p>Did you know that you can change your themes in VS Code, use a keyboard shortcut to open the VS Code settings, make changes by searching the settings window, and synchronize your settings across multiple instances of VS Code?</p>
<div class="message">
I've been creating a series of videos on YouTube about cool things in VS Code that you may not know about. Check out the [DevChatter YouTube Channel](https://www.youtube.com/c/devchatter) if you want to see all of my videos, or you can see the [VS Code Tips](https://youtube.com/playlist?list=PLfRLz7YT8uz36VdgSMATJj2chNtbixokI) Playlist.
</div>
<div class="video-container">
<iframe width="560" height="315" src="https://www.youtube.com/embed/1eiMpsEWigI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
</div>
<h2 id="changing-the-theme-in-vs-code">Changing the Theme in VS Code</h2>
<p>You can change the theme in VS Code by opening up the Color Theme menu. You can open it in one of 3 ways: opening it from the manage menu (the gear in the sidebar), opening it with the keyboard shortcut <code class="language-plaintext highlighter-rouge">[Ctrl]</code> + <code class="language-plaintext highlighter-rouge">[K]</code> + <code class="language-plaintext highlighter-rouge">[T]</code>, or opening the commands menu <code class="language-plaintext highlighter-rouge">[F1]</code> or <code class="language-plaintext highlighter-rouge">[Ctrl]</code> + <code class="language-plaintext highlighter-rouge">[Shift]</code> + <code class="language-plaintext highlighter-rouge">[P]</code> and searching for “Color Theme”.</p>
<p>Opening Theme Menu from Manage Menu</p>
<p><img src="/images/files/2022-posts/VSCodeTips/Part3/ManageMenuOpenTheme.png" alt="Opening Theme Menu from Manage Menu" /></p>
<p>Opening Theme Menu from Command Menu</p>
<p><img src="/images/files/2022-posts/VSCodeTips/Part3/CommandMenuOpenTheme.png" alt="Opening Theme Menu from Command Menu" /></p>
<h2 id="searching-the-settings-in-vs-code">Searching the Settings in VS Code</h2>
<p>There are many settings built into VS Code, and many others included as part of extensions. For this reason, it can be hard to keep track of and know all of the different settings, which is why VS Code allows you to search for settings. You can open the <code class="language-plaintext highlighter-rouge">Settings</code> window from the manage menu (the gear in the sidebar), from <code class="language-plaintext highlighter-rouge">File</code> -> <code class="language-plaintext highlighter-rouge">Preferences</code> -> <code class="language-plaintext highlighter-rouge">Settings</code>, or by using the keyboard shortcut <code class="language-plaintext highlighter-rouge">[Ctrl]</code> + <code class="language-plaintext highlighter-rouge">[,]</code>.</p>
<p>Opening Settings from Manage Menu</p>
<p><img src="/images/files/2022-posts/VSCodeTips/Part3/ManageMenuOpenSettings.png" alt="Opening Settings from Manage Menu" /></p>
<p>Opening Settings from Command Menu</p>
<p><img src="/images/files/2022-posts/VSCodeTips/Part3/CommandMenuOpenSettings.png" alt="Opening Settings from Command Menu" /></p>
<p>Opening Settings from File Menu</p>
<p><img src="/images/files/2022-posts/VSCodeTips/Part3/FileMenuOpenSettings.png" alt="Opening Settings from Command Menu" /></p>
<p>Once you’ve opened the settings screen, you can use the search box to search for a term and it will filter the results to those settings matching your search term. In addition, notice that the left navigation of settings also filters down to the settings matching your search.</p>
<p><img src="/images/files/2022-posts/VSCodeTips/Part3/SearchSettings.png" alt="Search VS Code Settings" /></p>
<h2 id="syncing-the-settings-in-vs-code">Syncing the Settings in VS Code</h2>
<p>I’m writing this post on my laptop using VS Code. On a daily basis, I work on multiple laptop computers and desktop computers. Each of these machines has VS Code installed on it. If I make changes to the settings in one, it would be nice if that replicated to the others. In years past, many of us found ways of automating this process in our various editors using cloud file storage to transfer settings file changes (and similar solutions).</p>
<p>No longer must we implement our own syncing, since VS Code has a built-in settings synchronization system. As long as you have a GitHub or Microsoft account to log into, you can have VS Code sync your settings.</p>
<p>Open up your settings menu as we did above and click on the <code class="language-plaintext highlighter-rouge">Turn on Settings Sync</code> button in the upper right side of the Settings window.</p>
<p><img src="/images/files/2022-posts/VSCodeTips/Part3/VSCodeSettingSyncButton.png" alt="Turn on Settings Sync in VS Code Button" /></p>
<p>Once open, you’ll need to choose which settings you want to sync and then click the button to log into your account to sync the settings.</p>
<p><img src="/images/files/2022-posts/VSCodeTips/Part3/VSCodeSettingSyncOptions.png" alt="Settings Sync Options in VS Code" /></p>
<p>After clicking log in, you’ll need to choose which type of account to log into.</p>
<p><img src="/images/files/2022-posts/VSCodeTips/Part3/VSCodeSettingSyncLoginOptions.png" alt="Settings Sync Options in VS Code" /></p>
<p>This should now open a browser that takes you to the appropriate authentication screen and allows you to login. After logging in through the browser, it should share that permission with VS Code and syncing should now be happening.</p>
<p>Have fun!</p>Brendan EnrickDid you know that you can change your themes in VS Code, use a keyboard shortcut to open the VS Code settings, make changes by searching the settings window, and synchronize your settings across multiple instances of VS Code?Migrating Blog to Jekyll on GitHub Pages2022-09-29T05:00:00+00:002022-09-29T05:00:00+00:00https://brendoneus.com//post/moved-to-GitHub-Pages<p>I recently <a href="/post/Moved-My-Site-to-GitHub-Pages/">moved my blog</a> (this one) from BlogEngine.NET to a Jekyll site on GitHub Pages. I tried to keep all of my posts working with the same URLs for the content. I didn’t worry about the tags, categories, etc. pages remaining the same. I figured that no one linked to those anyway, so the redirects would only be important on the posts.</p>
<p>Hopefully this post will help you migrate an old site from any platform (not just BlogEngine.NET) to Jekyll on GitHub Pages.</p>
<h2 id="exporting-existing-blog-content">Exporting Existing Blog Content</h2>
<p>Before we can create all of the posts on the new site, we’ll need to export the posts from our existing site. For this, most sites have an export function. In BlogEngine.NET, you’ll want to got to the Admin Dashboard by navigating to <code class="language-plaintext highlighter-rouge">/admin/</code> or clicking on <code class="language-plaintext highlighter-rouge">Dashboard</code> in the Admin widget.</p>
<p><img src="/images/files/2022-posts/BlogMigration/AdministrationMenu.png" alt="Administration Widget in BlogEngine.NET" /></p>
<p>From here, we need to open up <code class="language-plaintext highlighter-rouge">Settings -> Import export</code> then click on the <code class="language-plaintext highlighter-rouge">Export</code> button in the <code class="language-plaintext highlighter-rouge">Export</code> section of that page.</p>
<p><img src="/images/files/2022-posts/BlogMigration/ImportExportScreen.png" alt="Export Screen in BlogEngine.NET" /></p>
<p>When we click this button, the site will create a <code class="language-plaintext highlighter-rouge">BlogML.xml</code> and your browser will download it. That’s an XML containing your posts, comments, metadata, etc. from your site.</p>
<p class="message">I exported my comments, since I didn't care about preserving them. I did some googling and found that some people created tools to assist in moving this data to Disqus, but I haven't bothered with that yet.</p>
<h2 id="setting-up-jekyll-site-on-github-pages">Setting Up Jekyll Site on GitHub Pages</h2>
<p>Now I needed a new GitHub repository to host the content for my site, so I created <a href="https://github.com/benrick/benrick.github.io/">benrick.github.io</a> to host my site.</p>
<h3 id="types-of-github-pages-sites">Types of GitHub Pages sites</h3>
<p>For GitHub Pages, you can set up <code class="language-plaintext highlighter-rouge">User</code>, <code class="language-plaintext highlighter-rouge">Organization</code>, or <code class="language-plaintext highlighter-rouge">Project</code> sites to be hosted by GitHub Pages.</p>
<p>I did a user site with repository name <code class="language-plaintext highlighter-rouge">benrick.github.io</code>, which followed the required repository name pattern of <code class="language-plaintext highlighter-rouge">[username].github.io</code> (will be the same as the address).</p>
<p>If I’d done a site for my <code class="language-plaintext highlighter-rouge">DevChatter</code> organization, it would’ve been <code class="language-plaintext highlighter-rouge">devchatter.github.io</code>, following the <code class="language-plaintext highlighter-rouge">[organization].github.io</code> pattern.</p>
<p>If I did a project site, it could’ve had any name, but would be hosted at <code class="language-plaintext highlighter-rouge">[username].github.io/[project-name]</code> or <code class="language-plaintext highlighter-rouge">[organization].github.io/[project-name]</code>. So if you’re going to do this, be warned of the subfolder, which can be avoided with a custom domain (discussed below).</p>
<h3 id="configuring-the-repository-as-a-github-pages-site">Configuring the Repository as a GitHub Pages Site</h3>
<p>Navigate to the <code class="language-plaintext highlighter-rouge">Settings</code> of the repository and click on the <code class="language-plaintext highlighter-rouge">Pages</code> menu item in the <code class="language-plaintext highlighter-rouge">Code and automation</code> section of the sidebar navigation.</p>
<p><img src="/images/files/2022-posts/BlogMigration/GitHubPagesSettings.png" alt="Settings page showing Pages in sidebar" /></p>
<ul>
<li><strong>Source</strong> should be set to <code class="language-plaintext highlighter-rouge">Deploy from a branch</code> for our simple case.</li>
<li>I set <strong>Branch</strong> to <code class="language-plaintext highlighter-rouge">main</code> and I keep the site in the root, so folder of <code class="language-plaintext highlighter-rouge">/(root)</code>.</li>
<li>Don’t fiddle with the <strong>Custom domain</strong> yet, we’ll come back to that later.</li>
</ul>
<p>Now that it’s configured, make sure that everything is working. Create an <code class="language-plaintext highlighter-rouge">index.md</code> file in the root of your GitHub repository with anything you like. Here’s an example:</p>
<figure class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt"><p></span>Hello World!<span class="nt"></p></span></code></pre></figure>
<p>Next, we’ll make our <code class="language-plaintext highlighter-rouge">_config.yml</code> file in the root of your GitHub repository with these initial values:</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="ss">title: </span><span class="no">Your</span> <span class="no">Site</span>
<span class="ss">description: </span><span class="no">A</span> <span class="n">site</span> <span class="n">you</span> <span class="n">built</span> <span class="n">on</span> <span class="no">GitHub</span> <span class="no">Pages</span><span class="o">!</span>
<span class="ss">theme: </span><span class="n">jekyll</span><span class="o">-</span><span class="n">theme</span><span class="o">-</span><span class="n">minimal</span></code></pre></figure>
<p>If you created these files directly on GitHub, you can just wait, but if you created these locally, push them to GitHub. Now you’ll want to wait a few minutes for it to deploy, and try to visit your site at the <code class="language-plaintext highlighter-rouge">*.github.io</code> address that you chose earlier. If all is set up, you’ll see your</p>
<p><a href="https://docs.github.com/en/pages/quickstart">Official GitHub Page Get Started Documentation</a></p>
<h3 id="choosing-and-customizing-a-theme">Choosing and Customizing a Theme</h3>
<p>Selecting a theme can offer a lot of benefits. Setting it up to work locally will require setting up ruby, installing the gems for the theme and its dependencies, etc.</p>
<p>If you’re just planning to deploy without running it locally, you can skip those for now (you can add local running later).</p>
<p>Here are a few places to find free themes (there are many more):</p>
<ul>
<li>https://pages.github.com/themes/</li>
<li>https://jekyllthemes.io/free</li>
<li>https://jekyll-themes.com/free/</li>
</ul>
<p>And if you want to (and have the money to) support content creators, there are many paid Jekyll themes as well.</p>
<p>Once you’ve chosen a theme, you’ll either be setting the <code class="language-plaintext highlighter-rouge">theme:</code> or <code class="language-plaintext highlighter-rouge">remote_theme:</code> in the <code class="language-plaintext highlighter-rouge">_config.yml</code> file in the root of your site. Most of the themes you find will have their own instructions, which are often for running it locally. Setting these properties will let it work with the GitHub Pages workflow.</p>
<h2 id="converting-blog-posts-to-jekyll-markdown-posts">Converting Blog Posts to Jekyll Markdown Posts</h2>
<p>After exporting your content from your previous blog, check to see if there’s a tool created to convert that export into markdown files. Once completed, you’ll put all of those markdown files (if the tool didn’t do it) into the <code class="language-plaintext highlighter-rouge">_posts</code> directory in your repository.</p>
<p>For my conversion from BlogML.xml (the data exported by BlogEngine.NET), I started with this <a href="https://gist.github.com/eduncan911/10331596">blogml.rb</a> file and made a few tweaks to it. You can start with that one, but it’s written for Octopress, a framework based on jekyll. It’s close enough to Jekyll to get you started. Alternately, you can use my tweaked version of the <a href="https://gist.github.com/benrick/b378fc50abf850681cf9539940ec08aa">BlogML.xml to Jekyll import script</a>.</p>
<p>Regardless of the one you’re using, with ruby installed on your computer and the <code class="language-plaintext highlighter-rouge">BlogML.xml</code> file and the <code class="language-plaintext highlighter-rouge">blogml.rb</code> file in the same folder, run the following command in that folder.</p>
<pre><code class="language-pwsh">ruby -r './blogml.rb' -e Jekyll::BlogML.process('BlogML.xml')
</code></pre>
<p>After running this, you should have a <code class="language-plaintext highlighter-rouge">_posts</code> folder full of your posts.</p>
<h3 id="content-fixes">Content Fixes</h3>
<p>Be sure to check through your pages, articles, etc. since you’ll want to be sure they transferred correctly. There could be issues in the “frontmatter” (metadata at the top of the file), so be sure to check titles, permalinks, and tags.</p>
<p>Some of these issues can be fixed by hand, but anything that happened in a large number of files will require some clever finding and replacing.</p>
<h2 id="migrating-files-and-images-from-blogenginenet-to-jekyll">Migrating Files and Images from BlogEngine.NET to Jekyll</h2>
<p>In the root of your new site, create two folders named <code class="language-plaintext highlighter-rouge">files</code> and <code class="language-plaintext highlighter-rouge">images</code>. These are where your files and images will go.</p>
<p>Download the <code class="language-plaintext highlighter-rouge">/App_Data/files</code> folder from your old BlogEngine.NET site. Use whatever means you have of accessing your old site’s file system. I used FTP access to it.</p>
<p>You now need to split the files and images into their respective folders, maintaining the original structure.</p>
<p>To make this easier, I recommend that you put a copy of the files into each of the two folders. Then delete the images from the <code class="language-plaintext highlighter-rouge">/files</code> folder and the files from the <code class="language-plaintext highlighter-rouge">/images</code> folder.</p>
<h2 id="deploying-and-verifying">Deploying and Verifying</h2>
<p>Commit your changes and push them all to the GitHub repository. As we’re using GitHub Pages default deployment, you should be able to navigate to the <code class="language-plaintext highlighter-rouge">Actions</code> section on the repository before it completes the deployment to see that it is building and deploying the static site.</p>
<p><a href="/images/files/2022-posts/BlogMigration/NavToActions.png">Nav to GitHub Actions in Repository</a></p>
<p>You should see deployments from our previous changes to the repository.</p>
<p>After confirming that it has a deployment (it should be green), you’ll want to navigate to your <code class="language-plaintext highlighter-rouge">*.github.io</code> site as we did earlier and confirm that the site has your content.</p>
<h2 id="setting-up-custom-domain-optional">Setting up Custom Domain (Optional)</h2>
<p>If you want to have a custom domain, you’ll need to set up your DNS to point to your GitHub Pages and then tell your GitHub Pages repository about your custom domain. By doing it in this order, GitHub will be able to verify that your DNS settings are pointing to the GitHub Pages site.</p>
<h3 id="set-up-dns-a-records">Set Up DNS A Records</h3>
<p>TO set up the A Records for your domain, create it with these IP Addresses pointing at GitHub Pages, so it looks like these:</p>
<p><img src="/images/files/2022-posts/GDomainsCustomRecordsView.png" alt="Google Domains Custom Records View" /></p>
<p>For the first record, leave the <code class="language-plaintext highlighter-rouge">Host name</code> blank, set the <code class="language-plaintext highlighter-rouge">Type</code> to “A”, and the <code class="language-plaintext highlighter-rouge">Data</code> to the first IP Address. In some DNS systems you add more records (like this one), but in other systems, you create 4 separate A records with these addresses.</p>
<ul>
<li>185.199.108.153</li>
<li>185.199.109.153</li>
<li>185.199.110.153</li>
<li>185.199.111.153</li>
</ul>
<p>You can check the <a href="https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/managing-a-custom-domain-for-your-github-pages-site#configuring-an-apex-domain">GitHub Pages Custom Domain Docs</a> for the most up-to-date list of IP Addresses.</p>
<h3 id="set-up-dns-cname-record">Set Up DNS CNAME Record</h3>
<p>Next, you’ll set up a CNAME Record to point to the subdomain you have at GitHub, mine is <code class="language-plaintext highlighter-rouge">benrick.github.io</code>. Create the CNAME record like this:</p>
<p><img src="/images/files/2022-posts/GDomainsCustomRecordsEdit.png" alt="Google Domains Custom Records Edit" /></p>
<p>Just be sure that you set the <code class="language-plaintext highlighter-rouge">Host name</code> to “www”, the <code class="language-plaintext highlighter-rouge">Type</code> to “CNAME” and the <code class="language-plaintext highlighter-rouge">Data</code> to your “*github.io” subdomain.</p>
<h3 id="set-custom-domain-in-github">Set Custom Domain in GitHub</h3>
<p>After configuring DNS, we need to tell GitHub by going to the <code class="language-plaintext highlighter-rouge">Settings</code> tab in your repository, and clicking on the “GitHub Pages” link in the sidebar navigation.</p>
<p><img src="/images/files/2022-posts/GitHubRepoSettingsNav.png" alt="GitHub Settings Side Nav" /></p>
<p>Now change the Custom domain to your domain name that we just configured and save that change, which causes GitHub to run a check of the DNS settings.</p>
<p><img src="/images/files/2022-posts/GitHubCustomDomainSetting.png" alt="GitHub Pages Settings Custom Domain" /></p>
<p>After verification, the page will look like this:</p>
<p><img src="/images/files/2022-posts/GitHubCustomDomainSettingVerified.png" alt="GitHub Pages Settings Custom Domain Verified" /></p>
<h2 id="additional-resources">Additional Resources</h2>
<p>If you want full instructions for setting up the custom domain name for GitHub using Google Domains, check my post about <a href="/post/Custom-GitHub-Pages-Domain-with-Google-Domains/">how to set up a custom domain from google domains for GitHub pages</a>.</p>Brendan EnrickI recently moved my blog (this one) from BlogEngine.NET to a Jekyll site on GitHub Pages. I tried to keep all of my posts working with the same URLs for the content. I didn’t worry about the tags, categories, etc. pages remaining the same. I figured that no one linked to those anyway, so the redirects would only be important on the posts.3 Things You Didn’t Know VS Code Can Do - Part 2, Customizing Sidebar and Going to Definition in VS Code2022-09-28T05:00:00+00:002022-09-28T05:00:00+00:00https://brendoneus.com//post/Cool-VSCode-Things-2<p>Did you know, you can customize the sidebar’s position and contents in VS Code, create files immediately without deciding their location fro the home screen, and go to definition in almost anything in VS Code?</p>
<p>I’ve been creating a series of videos on YouTube about cool things in VS Code that you may not know about. Check out the <a href="https://www.youtube.com/c/devchatter">DevChatter YouTube Channel</a> if you want to see all of my videos, or you can see the <a href="https://youtube.com/playlist?list=PLfRLz7YT8uz36VdgSMATJj2chNtbixokI">VS Code Tips</a> Playlist.</p>
<div class="video-container">
<iframe width="560" height="315" src="https://www.youtube.com/embed/rx-RHQmL1mU" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
</div>
<h2 id="customizing-the-vs-code-sidebar">Customizing the VS Code Sidebar</h2>
<p>Not only can you decide whether you want the VS Code Sidebar on the left or the right, you can decide what to include in the sidebar.</p>
<h3 id="moving-the-sidebar-to-the-right-or-left-in-vs-code">Moving the Sidebar to the Right or Left in VS Code</h3>
<p>To move the sidebar to the left or the right, simply right click on the sidebar to open this context menu.</p>
<p><img src="/images/files/2022-posts/VSCodeTips/Sidebar/SidebarContextMenu.png" alt="VS Code Sidebar Context Menu" /></p>
<p>Once you’ve made the change, either of these are possible:</p>
<h4 id="vs-code-sidebar-on-the-right">VS Code Sidebar on the Right</h4>
<p><img src="/images/files/2022-posts/VSCodeTips/Sidebar/VSCode-Right.png" alt="VS Code with Sidebar on the Right" /></p>
<h4 id="vs-code-sidebar-on-the-left">VS Code Sidebar on the Left</h4>
<p><img src="/images/files/2022-posts/VSCodeTips/Sidebar/VSCode-Standard.PNG" alt="VS Code with Sidebar on the Left" /></p>
<h3 id="removing-items-from-vs-code-sidebar">Removing Items from VS Code Sidebar</h3>
<p>Each of the items in the sidebar of VS Code can also be hidden, so you don’t have a cluttered sidebar where you can’t find the section you’re looking for. To remove the items, right-click on the sidebar to open the same context menu we used to move the sidebar from side to side.</p>
<p><img src="/images/files/2022-posts/VSCodeTips/Sidebar/SidebarContextMenu.png" alt="VS Code Sidebar Context Menu" /></p>
<p>From this context menu, you can click on each item to show or hide it from the list. All with a checkmark are shown on the sidebar. Here’s a nice, clean sidebar.</p>
<p><img src="/images/files/2022-posts/VSCodeTips/Sidebar/CleanSidebar.png" alt="VS Code with Clean Context Menu" /></p>
<h2 id="create-files-with-double-click-in-vs-code">Create Files with Double Click in VS Code</h2>
<p>When you have no files open in VS Code, you can double click on the empty background to immediately open a new editor. At any point, you can save the text in the editor to a file.</p>
<p>This is a quick, easy way to get an editor open to type something, even just to hold onto for a minute.</p>
<h2 id="go-to-definition-with-ctrl-click-in-vs-code">Go to Definition with Ctrl-Click in VS Code</h2>
<p>In VS Code, you can go to definition in many different contexts by holding the <code class="language-plaintext highlighter-rouge">Ctrl</code> key and left-clicking on things in the editor.</p>
<ul>
<li>Clicking on a type name takes you to the type definition.</li>
<li>Clicking on a type members like methods, properties, or fields takes you the their definition on the type.</li>
<li>Clicking on a variable takes you to the declaration of that variable.</li>
</ul>Brendan EnrickDid you know, you can customize the sidebar’s position and contents in VS Code, create files immediately without deciding their location fro the home screen, and go to definition in almost anything in VS Code?3 Things You Didn’t Know VS Code Can Do - Part 1, JSON as Classes, Search By Words, and Visible Whitespace2022-09-26T15:00:00+00:002022-09-26T15:00:00+00:00https://brendoneus.com//post/Cool-VSCode-Things-1<p>Did you know, you can create types from sample JSON VS Code, search for files based on the first letter of each word, and view the whitespace in VS Code?</p>
<p>I’ve been creating a series of videos on YouTube about cool things in VS Code that you may not know about. Check out the <a href="https://www.youtube.com/c/devchatter">DevChatter YouTube Channel</a> if you want to see all of my videos, or you can see the <a href="https://youtube.com/playlist?list=PLfRLz7YT8uz36VdgSMATJj2chNtbixokI">VS Code Tips</a> Playlist.</p>
<div class="video-container">
<iframe width="560" height="315" src="https://www.youtube.com/embed/dwBgIxgXlFU" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
</div>
<h2 id="paste-json-as-code-in-vs-code">Paste JSON as Code in VS Code</h2>
<p>While VS Code doesn’t have a built-in way of pasting json from clipboard as code, there is an extension that will do it. Grab the <a href="https://marketplace.visualstudio.com/items?itemName=quicktype.quicktype">Paste JSON as Code Visual Studio Code Extension</a>.</p>
<p><img src="/images/files/2022-posts/VSCodeTips/PasteJsonExtension.png" alt="Paste JSON as Code in VS Code Extension" /></p>
<p>Copy the JSON you want code of onto your clipboard, and open the file where you want to paste the types. Then press <code class="language-plaintext highlighter-rouge">F1</code> or <code class="language-plaintext highlighter-rouge">Ctrl</code> + <code class="language-plaintext highlighter-rouge">Shift</code> + <code class="language-plaintext highlighter-rouge">P</code> to open the commands menu, and search for “paste” to find the commands for <code class="language-plaintext highlighter-rouge">Paste JSON as...</code>.</p>
<p><img src="/images/files/2022-posts/VSCodeTips/VSCodePaseCommand.png" alt="Commands Menu Showing Paste JSON as Results" /></p>
<p>If it can’t infer the language from the file extension you’re pasting into, it will ask you to choose a language. If it did know, it will skip this question.</p>
<p><img src="/images/files/2022-posts/VSCodeTips/PasteJsonLanguageSelection.png" alt="Selection View for Languages in Paste JSON as Code" /></p>
<p>JSON always has a root object (the outer curly braces), but that object doesn’t have a name, so the extension will now ask you to name that root object.</p>
<p><img src="/images/files/2022-posts/VSCodeTips/TopLevelTypeNameSelection.png" alt="Top-Level Type Naming In Paste JSON as Code" /></p>
<p>After clicking enter, there will be one or more types created in your file, depending on the complexity of the JSON you were using. It will try to detect types and includes metadate. You can change this data as you like. The command was just to help get you started.</p>
<p><img src="/images/files/2022-posts/VSCodeTips/SampleJsonCode.png" alt="Sample JSON Code Created by Paste JSON as Code" /></p>
<h2 id="search-for-files-by-word-in-vs-code">Search for Files By Word in VS Code</h2>
<p>When you’re looking for a file using the search in VS Code, you can search based on the first letters of the words in the name of the file.</p>
<p>To see this in action, open up the file search using Ctrl P. Then type in upper case letters, only the first letter of each word, so if you wanted to find <code class="language-plaintext highlighter-rouge">SpecialBikeFactory.cs</code>, you might type “SBF” into the search box.</p>
<p><img src="/images/files/2022-posts/VSCodeTips/SCF-SearchResult.png" alt="File Search Results in VS Code with First Word Letters Only" /></p>
<p>In addition, you can continue searching more of the word after each of those capitals, so “SpBiFa” would be a great search term if your codebase is large and has more than one type for “SBF”.</p>
<p><img src="/images/files/2022-posts/VSCodeTips/BaCaFa-SearchResult.png" alt="File Search Results in VS Code with Starting Word Letters" /></p>
<h2 id="make-whitespace-visible-in-vs-code">Make Whitespace Visible in VS Code</h2>
<p>In some languages, like Python, whitespace matters. In languages where whitespace matters less, it’s still important for formatting. In Visual Studio Code, you can make the whitespace visible. To do this, go to the <code class="language-plaintext highlighter-rouge">View</code> menu and select <code class="language-plaintext highlighter-rouge">Render Whitespace</code>. Doing this will show spaces as dots and tabs as arrows.</p>
<p><img src="/images/files/2022-posts/VSCodeTips/RenderedWhitespace.png" alt="Visible Whitespace in Visual Studio Code" /></p>Brendan EnrickDid you know, you can create types from sample JSON VS Code, search for files based on the first letter of each word, and view the whitespace in VS Code?What’s the Difference Between .NET, .NET Core, and .NET Framework2022-09-20T17:00:00+00:002022-09-20T17:00:00+00:00https://brendoneus.com//post/Difference-Between-DotNet-DotNetCore-DotNetFramework<p>Even years after the changes, many people are confused by all of the different “dot nets” that have existed and still exist. Read on to find out what’s going on and we’ll remove that confusion around .NET Framework, .NET Core, .NET.</p>
<p class="message">If you'd rather watch a video on this topic, you can check out my [What's the Difference between .NET Framework and .NET Core?](https://youtu.be/dLRd_LjVjNs) video on YouTube (or watch here).</p>
<div class="video-container">
<iframe width="560" height="315" src="https://www.youtube.com/embed/dLRd_LjVjNs" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
</div>
<h2 id="abbreviated-history-of-net">Abbreviated History of .NET</h2>
<p>Let’s understand the confusion by looking quickly at the history of our .NETs.</p>
<h3 id="brief-early-net-history">Brief Early .NET History</h3>
<p>The first of these “.NETs” we got was the .NET Framework, which was a framework for building Windows applications. It’s been around for decades and still runs many applications to this day.</p>
<p><img src="/images/files/2022-posts/CoreFrameworkConfusion/NET-Framework-Logo-2002.png" alt="Early .NET Framework Logo" width="50%" /></p>
<p>We had some variations of this that we won’t cover for now, but Microsoft eventually created an alternate option called .NET Core. Core removed the dependence on Windows, which allowed it to be cross-platform. It was neither a subset nor a superset of the existing .NET Framework, since they did take the chance to change some things as they removed some of the old baggage.</p>
<p><img src="/images/files/2022-posts/CoreFrameworkConfusion/NET_Core_Logo.svg.png" alt=".NET Core Logo" width="25%" /></p>
<h3 id="the-time-of-parallel-nets">The Time of Parallel .NETs</h3>
<p>After .NET Core came around, most of the people with connections to the developer division at Microsoft likely told you that .NET Core was the future, despite the many reassuring statements from Microsoft about fully supporting and maintaining the .NET Framework for years.</p>
<p>All of my new projects (that could be) were created on .NET Core, and I insisted to all of my clients that they follow the same policy. I’m glad we did, because .NET was/is the future of .NET (more on that below).</p>
<p>At this point, we had 2 separate .NET implementations, one that had a lot of legacy and was windows-focused and another without that legacy and was cross-platform. This alone had some confusion, since people didn’t know which to use for new projects. Some people thought that Framework was if you were on Windows only and Core was for non-Windows or both. That was wrong, but understandable how that mistake was made.</p>
<p>Many companies were not switching to .NET Core, because they thought it was an “alternate path”, not the future of .NET.</p>
<h3 id="the-union-of-the-nets">The Union of the .NETs</h3>
<p>I wasn’t in the backroom at Microsoft when they decided this, but I’m sure they were trying to figure out how to get everyone to switch to .NET Core and leave .NET Framework as a relic. Many companies were reluctant to put in the effort, so they decided to “merge” the two together into “.NET”.</p>
<p><img src="/images/files/2022-posts/CoreFrameworkConfusion/Microsoft_.NET_logo.svg.png" alt=".NET Logo" width="25%" /></p>
<p>Since .NET Core’s and .NET Framework’s major version numbers were on 3 and 4 respectively, they decided to start the “merged” .NET at 5 (an increased number regardless of your starting point).</p>
<p>Awesome! So you might be wondering, what is this new .NET that isn’t Core or Framework, well, it is .NET Core, but they dropped “Core” from the name to make it clear that it’s the future and not an alternative. In doing this, they’ve removed the “is this the new path or an alternate path?” question.</p>
<h2 id="the-takeaway">The Takeaway</h2>
<p>At this point, we’re in the same place we have been for a while. Your answer for, “which should I choose” is .NET latest version, not “Core” or “Framework” anymore.</p>
<p><img src="/images/files/2022-posts/CoreFrameworkConfusion/Microsoft_.NET_logo.svg.png" alt=".NET Logo" width="25%" /></p>
<p>If you <strong>require</strong> Core or Framework for some reason (highly unlikely that you do), you can create those, but the future is the .NET for any project you may start.</p>
<p>If you’re building a Windows application, you can build WinForms, WPF, UWP, MAUI, etc. using .NET, so there’s very little reason to pick Framework for those.</p>
<h2 id="intentionally-not-covered-topics">Intentionally Not Covered Topics</h2>
<p>You may have noticed that I didn’t talk about any of the other .NETs that exist. I may explain those in future posts and/or videos, but I wanted to clear up this confusion without adding those extra bits that might make it harder to come across.</p>
<p>Have a great day, and happy coding, everyone!</p>Brendan EnrickEven years after the changes, many people are confused by all of the different “dot nets” that have existed and still exist. Read on to find out what’s going on and we’ll remove that confusion around .NET Framework, .NET Core, .NET.How To Stop Websites Asking For Notifications And Locations2022-09-19T19:30:00+00:002022-09-19T19:30:00+00:00https://brendoneus.com//post/Stop-Websites-Asking-For-Notifications-And-Locations<p>Stop asking to send me notifications! I don’t want them! I also don’t want to tell your site my location.</p>
<p>Are you tired of being asked if sites can send you notifications or get your location? Yeah, me too. Let’s fix that.</p>
<h2 id="how-to-stop-sites-in-chrome-asking-to-send-notifications-or-location">How to Stop Sites In Chrome Asking to Send Notifications or Location</h2>
<p>Open up Chrome, and look for the 3 dots in the upper right corner of the window. That will open up the options menu that looks like this.</p>
<p><img src="/images/files/2022-posts/ChromeSettings/ChromeDotsMenu.png" alt="Chrome Options Menu" /></p>
<p>From that menu, click on <code class="language-plaintext highlighter-rouge">Settings</code> seen here:</p>
<p><img src="/images/files/2022-posts/ChromeSettings/ChromeDotsMenu-Highlighted.png" alt="Chrome Options Menu with Settings Highlighted" /></p>
<p>Once on the settings screen, you’ll see a search bar like this. Click into it.</p>
<p><img src="/images/files/2022-posts/ChromeSettings/ChromeSettingsSearchBar.png" alt="Chrome Settings Search Bar" /></p>
<p>Type the word “notifications” into the search to yield results like this.</p>
<p><img src="/images/files/2022-posts/ChromeSettings/ChromeSettingsSearchForNotifications.png" alt="Chrome Settings Search Notification Results" /></p>
<p>From here, you’ll want to open up the <code class="language-plaintext highlighter-rouge">Site Settings</code> section of the results, highlighted here. Notice that the search is also indicating that it found results in there.</p>
<p><img src="/images/files/2022-posts/ChromeSettings/ChromeSettingsSearchForNotifications-Highlighted.png" alt="Chrome Settings Search Notification Results Highlighted" /></p>
<p>In the <code class="language-plaintext highlighter-rouge">Site Settings</code> screen, you’ll find a section called <code class="language-plaintext highlighter-rouge">Permissions</code>, which is where we’ll be making our changes.</p>
<p><img src="/images/files/2022-posts/ChromeSettings/ChromeSitePermissions.png" alt="Chrome Site Permissions" /></p>
<p>Two sections in <code class="language-plaintext highlighter-rouge">Permissions</code> matter to us, the <code class="language-plaintext highlighter-rouge">Location</code> and <code class="language-plaintext highlighter-rouge">Notification</code> sections. Open up the <code class="language-plaintext highlighter-rouge">Notifications</code> first.</p>
<p><img src="/images/files/2022-posts/ChromeSettings/ChromeSitePermissions-Hightlighted.png" alt="Chrome Site Permissions Highlighted" /></p>
<h3 id="disabling-chrome-notification-request-permissions">Disabling Chrome Notification Request Permissions</h3>
<p>On the <code class="language-plaintext highlighter-rouge">Notifications Permissions</code> screen, you’ll likely find these settings (the default).</p>
<p><img src="/images/files/2022-posts/ChromeSettings/DefaultNotificationSettings.png" alt="Chrome Site Notification Default Permissions" /></p>
<p>To remove the permissions from all sites asking to send notifications, select the <code class="language-plaintext highlighter-rouge">Don't allow sites to send notifications</code> option, which will prevent sites from even asking to send notifications.</p>
<p><img src="/images/files/2022-posts/ChromeSettings/BlockedNotificationSetting.png" alt="Chrome Site Notification Blocked Permissions" /></p>
<p>Now click the back button to also remove <code class="language-plaintext highlighter-rouge">Location Request</code> permissions.</p>
<h3 id="disabling-chrome-location-request-permissions">Disabling Chrome Location Request Permissions</h3>
<p>Open up the <code class="language-plaintext highlighter-rouge">Location Permissions</code> screen, and you’ll likely find these settings (the default).</p>
<p><img src="/images/files/2022-posts/ChromeSettings/DefaultLocationSettings.png" alt="Chrome Site Location Default Permissions" /></p>
<p>To remove the permissions from all sites asking to request your location, select the <code class="language-plaintext highlighter-rouge">Don't allow sites to see your location</code> option, which will prevent sites from even asking to know your location.</p>
<p><img src="/images/files/2022-posts/ChromeSettings/BlockedLocationSetting.png" alt="Chrome Site Location Blocked Permissions" /></p>
<p class="message">Keep in mind that some sites will not work if knowing your location is required for the site to work. If this happens, you can come back to site settings and configure the permissions for that site, giving it location permissions.</p>
<h2 id="how-to-stop-sites-in-firefox-asking-to-send-notifications-or-location">How to Stop Sites in Firefox Asking to Send Notifications or Location</h2>
<p>Open up Firefox, and look for the 3 lines (hamburger menu) in the upper right corner of the window. That will open up the options menu that looks like this.</p>
<p><img src="/images/files/2022-posts/FirefoxSettings/FirefoxOptionsMenu.png" alt="Firefox Options Menu" /></p>
<p>From that menu, click on <code class="language-plaintext highlighter-rouge">Settings</code> as seen here.</p>
<p><img src="/images/files/2022-posts/FirefoxSettings/FirefoxOptionsMenu-Highlighted.png" alt="Firefox Options Menu with Settings Highlighted" /></p>
<p>Once on the settings screen, you’ll see a search bar like this. Click into it.</p>
<p><img src="/images/files/2022-posts/FirefoxSettings/FirefoxSettingsSearchBar.png" alt="Firefox Settings Search Bar" /></p>
<h3 id="disabling-firefox-notification-request-permissions">Disabling Firefox Notification Request Permissions</h3>
<p>Type the word “notifications” into the search to yield results like this.</p>
<p><img src="/images/files/2022-posts/FirefoxSettings/FirefoxSettingsNotificationSearchResults.png" alt="Firefox Settings Search Notification Results" /></p>
<p>The <code class="language-plaintext highlighter-rouge">Settings...</code> button that has the <code class="language-plaintext highlighter-rouge">notification</code> note above it is the one we want to open, which will bring us to this screen with the checkbox we want.</p>
<p><img src="/images/files/2022-posts/FirefoxSettings/FirefoxNotificationPermissions.png" alt="Firefox Settings Notification Permissions" /></p>
<p>To disable these requests from all sites, check the <code class="language-plaintext highlighter-rouge">Block new requests asking to allow notifications</code> checkbox and click save.</p>
<p><img src="/images/files/2022-posts/FirefoxSettings/FirefoxNotificationPermissions-Blocked.png" alt="Firefox Settings Notification Permissions Blocked" /></p>
<h3 id="disabling-firefox-location-request-permissions">Disabling Firefox Location Request Permissions</h3>
<p>Type the word “location” into the search to yield results like this.</p>
<p><img src="/images/files/2022-posts/FirefoxSettings/FirefoxSettingsLocationSearchResults.png" alt="Firefox Settings Search Location Results" /></p>
<p>The <code class="language-plaintext highlighter-rouge">Settings...</code> button that has the <code class="language-plaintext highlighter-rouge">location</code> note above it is the one we want to open, which will bring us to this screen with the checkbox we want.</p>
<p><img src="/images/files/2022-posts/FirefoxSettings/FirefoxLocationPermissions.png" alt="Firefox Settings Location Permissions" /></p>
<p>To disable these requests from all sites, check the <code class="language-plaintext highlighter-rouge">Block new requests asking to access your location</code> checkbox and click save.</p>
<p><img src="/images/files/2022-posts/FirefoxSettings/FirefoxLocationPermissions-Blocked.png" alt="Firefox Settings Location Permissions Blocked" /></p>
<p class="message">Keep in mind that some sites will not work if knowing your location is required for the site to work. If this happens, you can come back to site settings and configure the permissions for that site, giving it location permissions.</p>
<h2 id="how-to-stop-sites-in-edge-asking-to-send-notifications-or-location">How to Stop Sites in Edge Asking to Send Notifications or Location</h2>
<p>Open up Edge, and look for the 3 dots in the upper right corner of the window. That will open up the options menu that looks like this.</p>
<p><img src="/images/files/2022-posts/EdgeSettings/EdgeOptionsMenu.png" alt="Edge Options Menu" /></p>
<p>From that menu, click on <code class="language-plaintext highlighter-rouge">Settings</code> as seen here.</p>
<p><img src="/images/files/2022-posts/EdgeSettings/EdgeOptionsMenu-Highlighted.png" alt="Edge Options Menu with Settings Highlighted" /></p>
<p>Once on the settings screen, you’ll see a search bar like this. Click into it.</p>
<p><img src="/images/files/2022-posts/EdgeSettings/EdgeSettingsSearchBar.png" alt="Edge Settings Search Bar" /></p>
<h3 id="disabling-edge-notification-request-permissions">Disabling Edge Notification Request Permissions</h3>
<p>Type the word “notifications” into the search to yield results like this (scrolled down to this point).</p>
<p><img src="/images/files/2022-posts/EdgeSettings/EdgeSettingsNotificationSearchResults.png" alt="Edge Settings Search Notification Results" /></p>
<p>The <code class="language-plaintext highlighter-rouge">Notifications</code> button in <code class="language-plaintext highlighter-rouge">All permission</code> is the one we want to open (it’s marked by the search result indicator). Clicking it will bring us to this screen with the toggle we want.</p>
<p><img src="/images/files/2022-posts/EdgeSettings/EdgeNotificationPermissions.png" alt="Edge Settings Notification Permissions" /></p>
<p>To disable these requests from all sites, toggle the <code class="language-plaintext highlighter-rouge">Ask before sending (recommended)</code> option off like this.</p>
<p><img src="/images/files/2022-posts/EdgeSettings/EdgeNotificationPermissions-Blocked.png" alt="Edge Settings Notification Permissions Blocked" /></p>
<h3 id="disabling-edge-location-request-permissions">Disabling Edge Location Request Permissions</h3>
<p>Type the word “location” into the search to yield results like this.</p>
<p><img src="/images/files/2022-posts/EdgeSettings/EdgeSettingsLocationSearchResults.png" alt="Edge Settings Search Location Results" /></p>
<p>The <code class="language-plaintext highlighter-rouge">Location</code> button in <code class="language-plaintext highlighter-rouge">All permissions</code> is the one we want to open (it’s marked by the search result indicator). Clicking it will bring us to this screen with the toggle we want.</p>
<p><img src="/images/files/2022-posts/EdgeSettings/EdgeLocationPermissions.png" alt="Edge Settings Location Permissions" /></p>
<p>To disable these requests from all sites, toggle the <code class="language-plaintext highlighter-rouge">Ask before accessing (recommended)</code> option off like this.</p>
<p><img src="/images/files/2022-posts/EdgeSettings/EdgeLocationPermissions-Blocked.png" alt="Edge Settings Location Permissions Blocked" /></p>
<p class="message">Keep in mind that some sites will not work if knowing your location is required for the site to work. If this happens, you can come back to site settings and configure the permissions for that site, giving it location permissions.</p>Brendan EnrickStop asking to send me notifications! I don’t want them! I also don’t want to tell your site my location.