<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.5">Jekyll</generator><link href="https://stemp.dev/feed.xml" rel="self" type="application/atom+xml" /><link href="https://stemp.dev/" rel="alternate" type="text/html" /><updated>2024-09-24T20:19:09+10:00</updated><id>https://stemp.dev/feed.xml</id><title type="html">Robin Stemp</title><subtitle>Robin Stemp is a software architect, devops, web and desktop application developer</subtitle><author><name>Robin Stemp</name></author><entry><title type="html">Some very important lessons learned</title><link href="https://stemp.dev/blog/some-very-important-llessons-learned-copy/" rel="alternate" type="text/html" title="Some very important lessons learned" /><published>2023-12-30T00:00:00+10:00</published><updated>2023-12-30T00:00:00+10:00</updated><id>https://stemp.dev/blog/some-very-important-llessons-learned%20copy</id><content type="html" xml:base="https://stemp.dev/blog/some-very-important-llessons-learned-copy/"><![CDATA[<h2 id="absorb-what-is-useful-discard-what-is-not">Absorb what is useful, discard what is not</h2>

<p>I think this is something incredibly useful in life, to absorb information that is useful and discard what is not. While simple in theory, it’s learning to determine the difference between what is useful and what is not that is the difficult part.</p>

<p>Take for instance some examples:</p>

<h3 id="source-control">Source Control</h3>

<p>I have worked with cvs, svn (subversion), tfs, hg (mercurial) and git.</p>

<p>With subversion, we would often have large repositories using nested folders to separate projects, this can work fine with the older versions  subversions indexing at a folder level. However with mercurial or git. We would create smaller more isolated repositories. I guess the svn was often the monolith, and git the micro version.</p>

<p>We would have sourceforge and codeplex hosting open source codebases, now it’s all github.</p>]]></content><author><name>Robin Stemp</name></author><category term="Blog" /><category term="Software development" /><category term="Source Control" /><category term="git" /><category term="mercurial" /><category term="subversion" /><summary type="html"><![CDATA[Absorb what is useful, discard what is not]]></summary></entry><entry><title type="html">NodeJS or .NET For new projects</title><link href="https://stemp.dev/blog/nodejs-or-dotnet-for-new-projects/" rel="alternate" type="text/html" title="NodeJS or .NET For new projects" /><published>2023-11-13T00:00:00+10:00</published><updated>2023-11-13T00:00:00+10:00</updated><id>https://stemp.dev/blog/nodejs-or-dotnet-for-new-projects</id><content type="html" xml:base="https://stemp.dev/blog/nodejs-or-dotnet-for-new-projects/"><![CDATA[<p>Often the decision comes up when starting new software projects, what platform, language to develop with…..</p>

<p>Often this is decided by the architects, software developers knowledge of the languages, the platforms used within the business etc, all fairly common sense stuff.</p>

<p>I have worked on a lot of different platforms over the years, and find that they are often suited to different purposes, despite the fact you can still acheive results with them. I often see really bizaare decisions made that come back to bite later on.</p>

<p>Here I will go over 2 very popular and widely used general server side platforms. Some of the pros and cons for each, and what factors truly matter for scalable robust software applications.</p>

<h1 id="components-of-platforms">Components of platforms</h1>

<ul>
  <li>The language, syntax, design.</li>
  <li>The platform, runtimes, os support</li>
  <li>Runtime Performance</li>
  <li>Tooling such as IDE’s, Servers, auxillary tools</li>
  <li>Longevity of design</li>
  <li>Integration with third parties</li>
  <li>Package Management</li>
  <li>Database tooling and support</li>
  <li>Data Manipulation, analysis, reporting.</li>
</ul>

<h1 id="c-net-6">C# .NET 6</h1>

<ul>
  <li>Static strongly typed compiled language</li>
  <li>Open source cross platform</li>
  <li>Lightweight, highly performant, multithreaded 32/64 bit application runtimes.</li>
</ul>

<h2 id="tooling">Tooling</h2>

<ul>
  <li>Best in class tooling, Visual Studio 2022 is a complete IDE for building web, desktop, mobile, blazor web assembly applications</li>
  <li>LINQPad</li>
</ul>

<h2 id="package-manage">Package Manage</h2>]]></content><author><name>Robin Stemp</name></author><category term="Blog" /><category term=".NET" /><category term="nodejs" /><category term="architecture" /><summary type="html"><![CDATA[Often the decision comes up when starting new software projects, what platform, language to develop with…..]]></summary></entry><entry><title type="html">Some funny code moments</title><link href="https://stemp.dev/blog/some-funny-code/" rel="alternate" type="text/html" title="Some funny code moments" /><published>2023-10-28T00:00:00+10:00</published><updated>2023-10-28T00:00:00+10:00</updated><id>https://stemp.dev/blog/some-funny-code</id><content type="html" xml:base="https://stemp.dev/blog/some-funny-code/"><![CDATA[<p>We have all done it at one point or another, written a piece of code and than just thought… “wtf” or “what was I thinking” or something like that. Those moments in lapses of judgement, low brain juice, lack of oxygen or whatever.</p>

<p>But sometimes there are ones which are well…… damn…. I have seen quite a few interesting pieces of the years. Though ones that stick out.</p>

<h2 id="easy-login">Easy login</h2>

<p>Many years ago when I was brought on to do some PHP maintenance for a high profile telecommunications accessories companies e-commerce website, I found a couple of gotcha’s from the previous developers. One of them was in performing logins, now on this particular website it was using the equivalent of :</p>

<pre><code class="language-mysql">SELECT * FROM users WHERE 'username'='[username-from-form]' and password='[password-from-form]'
</code></pre>

<blockquote>
  <p>Notice the <code class="language-plaintext highlighter-rouge">[password-from-form]</code> . That was literally the value entered directly in the form, no sanitization, or validation was in place at the time.</p>
</blockquote>

<p>Now this was around 2004 so things like SQL injection and the like were not so prevalent. Anyway all it would take to login as any user (including the admin user with admin priviledges) was to enter a nice single asterisk <code class="language-plaintext highlighter-rouge">*</code> in the login form to produce the following.</p>

<pre><code class="language-mysql">SELECT * FROM users WHERE 'username'='[username-from-form]' and password='*'
</code></pre>

<p>Now ‘*’ would mean match anything for that field!.</p>

<p>And voila now you could place nice orders, change orders, view and edit user details, and a variety of other cool things.</p>

<p>I was very suprised to see a high profile company to have severe security issues such as this….. and yet there it was.</p>

<h2 id="novel-database-record-update-process">Novel Database record update process.</h2>

<blockquote>
  <p>WARNING: Example of how NOT to perform updates</p>
</blockquote>

<p>Working on a .NET Core / Blazor Server project and found a novel (by whoever created it) way to update records in a database using EF Core.</p>

<p>Now the client Blazor app was sending up a collection of items to update from a grid edit table. Not just a single row, rather the entire grid of rows. Odd, ok now the database update code went like this.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1. Delete all rows in the table. (yep all rows)
2. And add every single row back in from the collection sent from client, as the client had the entire list of rows from the table.
</code></pre></div></div>

<p>Voila!!!  Database records updated…… lol.</p>]]></content><author><name>Robin Stemp</name></author><category term="Blog" /><category term="Funny Code" /><category term="Disaster Code" /><summary type="html"><![CDATA[We have all done it at one point or another, written a piece of code and than just thought… “wtf” or “what was I thinking” or something like that. Those moments in lapses of judgement, low brain juice, lack of oxygen or whatever.]]></summary></entry><entry><title type="html">Upgrading Large .NET Solutions with lots of projects</title><link href="https://stemp.dev/blog/upgrading-large-dotnet-solution-projects/" rel="alternate" type="text/html" title="Upgrading Large .NET Solutions with lots of projects" /><published>2023-02-18T00:00:00+10:00</published><updated>2023-02-18T00:00:00+10:00</updated><id>https://stemp.dev/blog/upgrading-large-dotnet-solution-projects</id><content type="html" xml:base="https://stemp.dev/blog/upgrading-large-dotnet-solution-projects/"><![CDATA[<style type="text/css">
svg { width: 50%;}
</style>

<script>
document.addEventListener('DOMContentLoaded', e => {
  	// set svg size
	document.querySelectorAll('img[alt=diagram]').forEach((x)=> {
		x.style.width = "60%";
		//x.style.maxWidth = "450px";
	});
});
</script>

<p>12/02/2023</p>

<p>A few days ago, was looking into how to convert a large .NET solution to .NET 7.</p>

<p>So</p>
<ol>
  <li>define the problem</li>
  <li>come up with ideas to solve the problem</li>
  <li>solve the problem</li>
</ol>

<p>Important :</p>
<ul>
  <li>Framework for the most part refers to <code class="language-plaintext highlighter-rouge">TargetFramework</code> spec in <code class="language-plaintext highlighter-rouge">.csproj</code> files. not the actual <code class="language-plaintext highlighter-rouge">.NET Framework</code> from years past before <code class="language-plaintext highlighter-rouge">.NET Core</code> except in the case where a specific <code class="language-plaintext highlighter-rouge">.NET Framework vx.x.x</code> is mentioned.</li>
</ul>

<h2 id="warning">Warning</h2>

<p>This article describes an approach to solve a programming problem, it may seem overly verbose, and is not focused so much around a particular code or language, rather how to approach the <em>problem-solving</em> aspect of it.</p>

<p>In my day to day work for most programming related concerns, I don’t draw up flow-charts and pseudo-code (as it usually fits in the head)  unless it’s quite a complex problem that I believe others may also have difficulty with. Or when doing architectural work related to processes.</p>

<h2 id="update-18022023"><strong>Update: 18/02/2023</strong></h2>

<p>As Of Feb 15th 2023, Microsoft Released a .NET upgrade assistant that can be used inside of Visual Studio to update projects to the latest version of .NET. I haven’t tried this yet, however one of the issues of doing this inside VS is when dealing with large solutions VS can be quite slow, especially with resharper.</p>

<p><a href="https://www.thurrott.com/dev/279377/visual-studio-gets-a-net-upgrade-assistant">Visual Studio Gets a .NET Upgrade Assistant</a></p>

<h2 id="the-problem">The Problem</h2>
<hr />

<p>The goal is to convert all projects within a large solution to .NET 7.</p>

<p>By large, I mean 350 projects in a single solution</p>
<ul>
  <li>32 Azure Functions - 618 source files</li>
  <li>9 Web applications, a couple with react, some with blazor - 667 source files</li>
  <li>28 Console applications - 227 src files</li>
  <li>89 Test projects - 1217 source files</li>
</ul>

<p>With varying versions of .NET and pacakages</p>
<ul>
  <li>.NET Standard2.0/2.1</li>
  <li>.NETCore 2.1/2.2/3.1/5</li>
  <li>Lots of different versions of nuget packages across projects</li>
</ul>

<p>There was previously</p>
<ul>
  <li>.NET Framework 471</li>
</ul>

<p>Some Considerations:</p>
<ul>
  <li>When updating any project, Visual Studio will ask to reload/refresh etc</li>
  <li>When updating framework versions, it’s quite likely that nuget package versions will need to be updated. This is especially true with <code class="language-plaintext highlighter-rouge">Microsoft</code> specific packages that follow the framework version.  And also third-party libs that need updating to support newer framework versions.</li>
</ul>

<p>Now, I have refactored many solutions before, across multiple solutions, upgraded from .NET framework to .net core when it became useful (ie .NET Core 2.1).</p>

<h2 id="the-candidates-for-solutions">The Candidates for solutions</h2>
<hr />

<ol>
  <li>Use visual studio to change targetframeworks</li>
  <li>Use resharper to try and change targetframeworks</li>
  <li>Directly modify .csproj files to change target frameworks with an editor (ie vs code)</li>
</ol>

<h3 id="issues-recognized-with-these-approaches">Issues recognized with these approaches</h3>

<ol>
  <li>Visual studio targetframework
    <ol>
      <li>having to go into every single project at a time</li>
      <li>with every change made to a project file, visual studio refreshes itself, this can be slow across 10’s or in this case hundreds of projects</li>
      <li>Quickly determined this would not work after 30 seconds.</li>
    </ol>
  </li>
  <li>Use resharper
    <ol>
      <li>not sure if resharper has this capability, but even if so, is still affected by VS refresh after update, and resource intensive, slow across the entire solution.</li>
      <li>Deemed same issues as <code class="language-plaintext highlighter-rouge">(1)</code></li>
    </ol>
  </li>
  <li>Directly modify <code class="language-plaintext highlighter-rouge">.csproj</code> files, I’ve done this before multiple times, it seems like the best solution (directly modifying .csproj). Now there are multiple ways to do this.
    <ol>
      <li>Simple find/replace across all <code class="language-plaintext highlighter-rouge">.csproj</code> files. Ie 
    find: <code class="language-plaintext highlighter-rouge">TargetFramework&gt;netstandard2.0&lt;/TargetFramework&gt;</code>
    replace with : <code class="language-plaintext highlighter-rouge">TargetFramework&gt;net7.0&lt;/TargetFramework&gt;</code>
    Repeat with each version….. this however is error-prone and tedious</li>
    </ol>
  </li>
  <li>Use the new Visual Studio .NET Upgrade Assistant from <a href="https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.upgradeassistant">.NET Upgrade Assistant</a></li>
</ol>

<p>(1) and (2) were already out due to being painfully tedious or slow, (4) runs inside VS so will suffer from any VS slow-down. (3) was the closest, so a variation of (3) to reduce human-error (mine or anyone else)</p>

<ol>
  <li>Write scripts, or a console app or similar to automate the process.</li>
</ol>

<p>Ideally (5) is the conclusion to naturally come to, its a desired state for a software dev who likes to create things. However it must make viable sense to apply it. If there is a simpler solution that is much quicker, than that maybe the better approach.</p>

<h2 id="some-pre-requisites---understanding-the-csproj-project-file-sdk-and-targetframework">Some Pre-Requisites - Understanding the .csproj project file sdk and targetframework</h2>
<hr />

<p>Let’s Quickly Analyze what’s in a .NET project file.</p>

<p>Now for this context we are just going to look into .NET Core style projects (Sdk style), .NET framework project files contain a lot more information.</p>

<h4 id="csharp-classlib"><strong>CSharp ClassLib</strong></h4>

<p>Ok lets say we create a new <code class="language-plaintext highlighter-rouge">classlib</code> project using <code class="language-plaintext highlighter-rouge">dotnet new classlib</code> with .NET7.0, here is what we get.</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;Project</span> <span class="na">Sdk=</span><span class="s">"Microsoft.NET.Sdk"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;PropertyGroup&gt;</span>
    <span class="nt">&lt;TargetFramework&gt;</span>net7.0<span class="nt">&lt;/TargetFramework&gt;</span>
    <span class="nt">&lt;RootNamespace&gt;</span>dotnet_proj<span class="nt">&lt;/RootNamespace&gt;</span>
    <span class="nt">&lt;ImplicitUsings&gt;</span>enable<span class="nt">&lt;/ImplicitUsings&gt;</span>
    <span class="nt">&lt;Nullable&gt;</span>enable<span class="nt">&lt;/Nullable&gt;</span>
  <span class="nt">&lt;/PropertyGroup&gt;</span>
<span class="nt">&lt;/Project&gt;</span>
</code></pre></div></div>

<p>Now the key points to look at are the <code class="language-plaintext highlighter-rouge">Sdk</code> and <code class="language-plaintext highlighter-rouge">TargetFramework</code> inside the <code class="language-plaintext highlighter-rouge">PropertyGroup</code> element. Our classlib shows</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;Project</span> <span class="na">Sdk=</span><span class="s">"Microsoft.NET.Sdk"</span><span class="nt">&gt;</span>
</code></pre></div></div>
<p>and framework</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;TargetFramework&gt;</span>net7.0<span class="nt">&lt;/TargetFramework&gt;</span>
</code></pre></div></div>

<p>With <em>web</em> projects (think WebApis, MVC, etc) the Sdk will be</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;Project</span> <span class="na">Sdk=</span><span class="s">"Microsoft.NET.Sdk.Web"</span><span class="nt">&gt;</span>
</code></pre></div></div>

<h4 id="existing-targetframeworks"><strong>Existing TargetFrameworks</strong></h4>

<p>In the <a href="#the-problem">Problem</a> statement above, I mentioned that there were multiple versions of .NET Core to upgrade, they will typically look like the following</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- class libraries --&gt;</span>
<span class="nt">&lt;TargetFramework&gt;</span>netstandard2.0<span class="nt">&lt;/TargetFramework&gt;</span>
<span class="nt">&lt;TargetFramework&gt;</span>netstandard2.1<span class="nt">&lt;/TargetFramework&gt;</span>

<span class="c">&lt;!-- apps of some sort, unit tests etc --&gt;</span>
<span class="nt">&lt;TargetFramework&gt;</span>netcoreapp2.1<span class="nt">&lt;/TargetFramework&gt;</span>
<span class="nt">&lt;TargetFramework&gt;</span>netcoreapp2.2<span class="nt">&lt;/TargetFramework&gt;</span>
<span class="nt">&lt;TargetFramework&gt;</span>netcoreapp3.0<span class="nt">&lt;/TargetFramework&gt;</span>
<span class="nt">&lt;TargetFramework&gt;</span>netcoreapp3.1<span class="nt">&lt;/TargetFramework&gt;</span>

<span class="c">&lt;!-- from net5.0 onwards, can use for any project type,
replaces need for netstandard --&gt;</span>
<span class="nt">&lt;TargetFramework&gt;</span>net5.0<span class="nt">&lt;/TargetFramework&gt;</span>

</code></pre></div></div>

<p>Now that we know that the <code class="language-plaintext highlighter-rouge">TargetFramework</code> is essentially what’s needed to change .NET versions, it becomes much simpler.</p>

<p><strong>Except</strong> for perhaps <em>Azure functions</em>, which also have an additional element, the <code class="language-plaintext highlighter-rouge">AzureFunctionsVersion</code></p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;Project</span> <span class="na">Sdk=</span><span class="s">"Microsoft.NET.Sdk"</span><span class="nt">&gt;</span>
	<span class="nt">&lt;PropertyGroup&gt;</span>
		<span class="nt">&lt;TargetFramework&gt;</span>netcoreapp2.1<span class="nt">&lt;/TargetFramework&gt;</span>
		<span class="nt">&lt;AzureFunctionsVersion&gt;</span>v2<span class="nt">&lt;/AzureFunctionsVersion&gt;</span>
	<span class="nt">&lt;/PropertyGroup&gt;</span>
    ...
<span class="nt">&lt;/Project&gt;</span>
</code></pre></div></div>

<h4 id="packagereferences"><strong>PackageReferences</strong></h4>

<p>Now the next thing is to analyze nuget package references. Remember we are using .NET Core style projects which use PackageReference elements directly in the .csproj, rather than the older <code class="language-plaintext highlighter-rouge">Packages.config</code> file that contained nuget packages and binary dll references in the <code class="language-plaintext highlighter-rouge">.csproj</code> (ie .NET Framework style project file)</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;ItemGroup&gt;</span>
	<span class="nt">&lt;PackageReference</span> <span class="na">Include=</span><span class="s">"Microsoft.ApplicationInsights.AspNetCore"</span> <span class="na">Version=</span><span class="s">"2.20.0"</span> <span class="nt">/&gt;</span>
	<span class="nt">&lt;PackageReference</span> <span class="na">Include=</span><span class="s">"Microsoft.AspNetCore.SpaServices.Extensions"</span> <span class="na">Version=</span><span class="s">"3.1.25"</span> <span class="nt">/&gt;</span>
	<span class="nt">&lt;PackageReference</span> <span class="na">Include=</span><span class="s">"Microsoft.AspNetCore.Authentication.AzureADB2C.UI"</span> <span class="na">Version=</span><span class="s">"2.2.0"</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;/ItemGroup&gt;</span>
</code></pre></div></div>

<p><strong>NOTE: PackageRerences can also include version in an element tag, though is not the default</strong></p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;PackageReference</span> <span class="na">Include=</span><span class="s">"Microsoft.ApplicationInsights.AspNetCore"</span><span class="nt">&gt;</span>
	<span class="nt">&lt;Version&gt;</span>2.20.0<span class="nt">&lt;/Version&gt;</span>
<span class="nt">&lt;/PackageReference&gt;</span>
</code></pre></div></div>

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

<h2 id="creating-a-high-level-design">Creating a high level design</h2>

<p>Ok given the information gathered, we can have a simple process to represent what we need to do at a high level. Eventually we will be able to use A.I to translate high level requirements to code. ChatGPT3 and Github Co-pilot have demonstrated some capability to assist with this, but there is still a way to go for them.</p>

<h4 id="pseudocode">Pseudocode</h4>

<p>Given</p>
<ul>
  <li>Project files have an Sdk element</li>
  <li>TargetFramework is the .NET version</li>
  <li>PackageReferences contain nuget packages and versions</li>
  <li>Azure Functions have an AzureFunctionsVersion element as version number in format <code class="language-plaintext highlighter-rouge">v2</code> etc</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PARSE solutionfile for projects
LOOP through projects
	Open ProjectFile
		Determine ProjectType
			Is it a web project from Sdk
			Does it have AzureFunctionsVersion element
		Update TargetFramework to new version (ie 7.0)
		IF ProjectType IS AzureFunction THEN
			Update AzureFunctionsVersion to latest
		PARSE PackageReferences
		LOOP through PackageReferences
			Get Current Version of Package
			Find Latest Version of Package - from remote nuget repositories
				Cache Latest Version of Package as it may be used in other projects
			Update PackageVersion
		ENDLOOP
	Save and Close ProjectFile
ENDLOOP
</code></pre></div></div>

<p>We can visualize this approach as a series of flowcharts</p>

<p><strong>Process Project Files</strong></p>

<p><img src="/assets/images/2023-02-18-upgrading-large-dotnet-solution-projects-1.svg" alt="diagram" /></p>

<p><strong>Process Package References</strong></p>

<p><img src="/assets/images/2023-02-18-upgrading-large-dotnet-solution-projects-2.svg" alt="diagram" /></p>

<h2 id="now-onto-the-actual-approaches">Now, onto the actual approaches</h2>

<p>Now one of the ways to automate something like this is write a console application, with parameters and so on. We used to do stuff like this decades ago.</p>

<p>Though my first go-to for these types of things is <strong>LinqPad</strong>. I write a little about it <a href="https://stemp.dev/blog/tools-of-the-trade-net-developer/#linqpad">on my .net tools page</a> . The reason for this, is I want to be able to analyze things as I’m going through, dump output results etc without stepping through the debugger…… and without writing unit tests to fulfil each case.</p>

<blockquote>
  <p>Side Note: I’m fully aware of various approaches to testing, TDD and others.</p>
</blockquote>

<p>So in order to update projects en-masse.</p>

<ol>
  <li>Close visual studio solution, otherwise any changes get picked up and refresh vs as it’s happening.</li>
  <li>Open up Visual Studio solution and parse to get list of project files (or get project files from directory path)</li>
</ol>

<p>Now inside LinqPad we could just directly update, but I prefer to analyze what needs changing first, this is something I could present to other(s) aswell to show what will change if needed. There could be oddities found, unexpected results.</p>

<h3 id="step-1-analyze-solution-file-to-build-a-collection-of-project-files-to-update">Step 1. Analyze Solution File to build a collection of project files to update</h3>

<ol>
  <li>define a collection to hold analysis results</li>
  <li>loop through each project file and open
    <ol>
      <li>check if <code class="language-plaintext highlighter-rouge">TargetFramework</code> is in an array of ones to update</li>
      <li>if so, than add to a collection with an object containing filename, currentstate (current framework version), and targetstate (new framework version) - similar to how an event-sourcing operation might look.</li>
    </ol>
  </li>
</ol>

<p><strong>Build Collection of Projects To Update Framework</strong>
<img src="/assets/images/2023-02-18-upgrading-large-dotnet-solution-projects-3.svg" alt="diagram" /></p>

<p>Now we have a collection of items showing what project files need changing to update. Very simple (also do you like <a href="https://mermaid.js.org/">Mermaid</a> ).</p>

<h3 id="step-2-now-lets-execute-it-update-the-project-files">Step 2. Now lets execute it. Update the project files</h3>

<p>So we have a collection of project files spread across many directories that are due for an update from Step1.</p>

<p>Ok so now it’s simply a matter of going through the collection of project files and updating the <code class="language-plaintext highlighter-rouge">TargetFramework</code> property of the <code class="language-plaintext highlighter-rouge">.csproj</code>.</p>

<p>Now a <code class="language-plaintext highlighter-rouge">.csproj</code> is essentially an Xml document. this means we can use <code class="language-plaintext highlighter-rouge">XDocument</code> from <a href="https://learn.microsoft.com/en-us/dotnet/standard/linq/linq-xml-overview">Linq To Xml</a> with relative ease, or the older <a href="https://learn.microsoft.com/en-us/dotnet/api/system.xml.xmldocument?view=net-7.0">XmlDocument DOM</a> to process and update the project file.</p>

<blockquote>
  <p>For Reference: a .NET Project file is described at Microsofts <a href="https://learn.microsoft.com/en-us/aspnet/web-forms/overview/deployment/web-deployment-in-the-enterprise/understanding-the-project-file">Understanding the project file</a></p>
</blockquote>

<p>So in order to load and update a .NET <code class="language-plaintext highlighter-rouge">.csproj</code> file we can:</p>

<ol>
  <li>Load the <code class="language-plaintext highlighter-rouge">.csproj</code> with libaries to manipulate it as XML such as <code class="language-plaintext highlighter-rouge">XDocument</code></li>
  <li>Load some Microsoft Libraries that deal with project files</li>
  <li>Consider simple string replace</li>
</ol>

<p>So, what is the “<em>correct</em>” way to do this?.</p>

<p>Generally we like to find if something exists, and if it does what is required to apply it, how much learning is needed, how simple or complex is it.</p>

<p>We are dealing with a simple text file that happens to be an xml format, however we are just aiming to update a few strings in the file. Nothing more. So with text we can simply use Find/Replace.</p>

<p>If we were doing more manipulation on the project file than using <code class="language-plaintext highlighter-rouge">XDocument</code> may be more suitable or even search for .NET specific libs for managing project files. But in this case, it’s not needed.   Find/Replace aligns with the simple Visual Studio Code approach.</p>

<h4 id="flow-to-update-targetframeworks">flow to update targetframeworks</h4>

<p>So the flow is</p>

<ol>
  <li>Loop through project files
    <ol>
      <li>Open project file into memory (project files are not large, this wont be issue)</li>
      <li>Replace <code class="language-plaintext highlighter-rouge">TargetFramework&gt;{CurrentFrameworkVersion}&lt;/TargetFramework</code> with <code class="language-plaintext highlighter-rouge">TargetFramework&gt;{NewFrameworkVersion}&lt;/TargetFramework</code>. I add the <code class="language-plaintext highlighter-rouge">TargetFramework</code> to be more explicit.</li>
      <li>Check if <code class="language-plaintext highlighter-rouge">AzureFunctionsVersion</code> exists in projectfile and replace the version. Ie replace <code class="language-plaintext highlighter-rouge">AzureFunctionsVersion&gt;v2&lt;/AzureFunctionsVersion</code> with <code class="language-plaintext highlighter-rouge">AzureFunctionsVersion&gt;v4&lt;/AzureFunctionsVersion</code> (which requires .NET6+)</li>
      <li>Save file</li>
    </ol>
  </li>
</ol>

<p><img src="/assets/images/2023-02-18-upgrading-large-dotnet-solution-projects-4.svg" alt="diagram" /></p>

<p>Very simple, now all projects will have <code class="language-plaintext highlighter-rouge">net7.0</code> (or whatever is desired).</p>

<h4 id="wait-a-minute-what-about-nuget-package-references">Wait a minute, what about nuget package references?</h4>

<p>The next thing is to implement the nuget package reference updates. Now this happens on processing each project file. What we want to do is open the project file, collect the package references, and look for the latest stable version of each package, than update the package reference.</p>

<p>Now analyzing package reference updates could have been done in step (1) at the cost of more analysis time (especially fetching remote version info). Though it may have simply been too much information (ie which projects to update). Remember we are dealing with 350 projects.</p>

<p>General flow is like so:</p>

<p>So the new project file update would look like:</p>

<blockquote>
  <p>Note: this is the general success path, obviously have to apply error checking conditions and the like</p>
</blockquote>

<p><img src="/assets/images/2023-02-18-upgrading-large-dotnet-solution-projects-5.svg" alt="diagram" /></p>

<h4 id="wouldnt-fetching-latest-package-version-be-costly-api-calls">Wouldnt fetching latest package version be costly api calls?</h4>

<p>As many projects may share similar package references, we want to cache the latest package versions to reduce need to call a remote resource more than once.</p>

<p><img src="/assets/images/2023-02-18-upgrading-large-dotnet-solution-projects-6.svg" alt="diagram" /></p>

<p>Or alternative caching strategy where we attempt to get item directly from cache without checking if cacheitem exists. Generally simpler, though depends on how cache is implemented.</p>

<p><img src="/assets/images/2023-02-18-upgrading-large-dotnet-solution-projects-7.svg" alt="diagram" /></p>

<h2 id="so-why-the-flowcharts-wheres-the-code">so, why the flowcharts, where’s the code?</h2>

<p>This article was about <em>solving a problem</em>, solving a rather simple problem. refer to the <a href="#warning">Warning</a>.</p>

<p>As programmers, we want to jump into code, get things going as soon as possible. But how do we know if the program is correct if we don’t know what the end result should be. At some point we need to map out the core steps required.</p>

<p>Once flows and logic have been determined, its easy to apply in pretty much any language, be it C#, Java, JavaScript/TS (with nodejs), rust, basic whatever really.</p>

<p>In order to solve any problem, you first need to understand it, otherwise you end up with spaghetti, or complex pathways as your constantly adjusting/hacking code to get it to fit/work as expected. The better you understand what is required, the easier and simpler it will be to both do and explain.</p>

<p>In my early development days, whenever I came across a slightly tricky problem, I would sketch it out on pen/pencil and paper, the flow and logic, eventually it got to a point where I just now do that in my head before starting on something, it makes the development process much smoother. Though diagramming/documenting is important for future reference.</p>

<p><em>Again for a simple problem such as this, it’s not typically required, this is just to demonstrate some of it.</em></p>

<p>Infact with this particular solution, I did the code before writing this article.</p>

<p>If there is enough interest in the code itself, I’ll be happy to share that, just let me know.</p>

<h2 id="ok-so-what-about-linqpad">Ok, so what about LinqPad?</h2>

<p>As mentioned at the beginning of this article, I prefer LinqPad for these types of things, its just fantastic for getting results fast for experimenting and the like. So I initially wrote a collection of linqpad scripts to apply these changes, analyze projects to update, apply changes and the like and dump out results to the linqpad output window which is fantastic.</p>

<h2 id="ok-heres-what-happened">Ok, here’s what happened.</h2>

<p>So after writing some linqpad “scripts” (I call them that because they are not the typical .cs project and execute from LinqPad ). Here is what happened.</p>

<ol>
  <li>Upgraded all .NET projects within a solution with 350 projects to .NET7, including updating all nuget package references to latest. The execution time was about 2-3 minutes first run, I think mainly due to fetching the latest nuget package versions from the remote nuget repo. Still much faster than it would have taken in Visual Studio alone.</li>
  <li>Opened in VS 2022 - Now this is where the real work begins.</li>
  <li>Tried build, expected errors, got thousands, though 90% were due to some libraries could not be built, causing cascading effect of not being able to find dlls.</li>
  <li>major issues encountered
    <ul>
      <li>upgrading .net core 2.1 –&gt; 7 .  Now I have done this in previous  projects, the biggest changes are actually from 2.x to 3.x. So looked up the migration/breaking changes (hint: there’s quite a few)</li>
      <li>found issues with Automapper</li>
      <li>some issues with Entity Framework</li>
    </ul>
  </li>
</ol>]]></content><author><name>Robin Stemp</name></author><category term="Blog" /><category term=".NET" /><category term=".NET 7" /><category term=".NET Upgrade" /><category term=".NET Update" /><category term=".NET Core" /><category term=".NET Solution" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Converting Jekyll to Astro - Lessons Learned Part 2</title><link href="https://stemp.dev/blog/converting-jekyll-to-astro-build-lessons-learned-part2/" rel="alternate" type="text/html" title="Converting Jekyll to Astro - Lessons Learned Part 2" /><published>2022-09-04T00:00:00+10:00</published><updated>2022-09-04T00:00:00+10:00</updated><id>https://stemp.dev/blog/converting-jekyll-to-astro-build-lessons-learned-part2</id><content type="html" xml:base="https://stemp.dev/blog/converting-jekyll-to-astro-build-lessons-learned-part2/"><![CDATA[<h2 id="copying-portfolio--blogs-by-years">Copying Portfolio &amp; Blogs By Years</h2>

<p>This follows on from <a href="./2022-08-27-converting-jekyll-to-astro-build-lessons-learned-part1.md">Part 1</a> of jekyll to astro.build migration.</p>

<p>So now I have a basic astro.build blog site setup with dated blog posts. The next steps were to:</p>

<ul>
  <li>Copy over portfolio pages</li>
  <li>Apply blog by years blog page</li>
</ul>

<h2 id="portfolio">Portfolio</h2>

<p>Now this was rather simple, once I learnt about the astro specifics.</p>

<ol>
  <li>Copy my portfolio folder over which included <code class="language-plaintext highlighter-rouge">.md</code> files to a <code class="language-plaintext highlighter-rouge">/pages/portfolio</code> folder in astro</li>
  <li>Create a <code class="language-plaintext highlighter-rouge">/pages/portfolio.astro</code> view page</li>
</ol>

<p>In the front matter, I put TypeScript to gather the portfolio items sorted by date with</p>

<div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">portfolioItems</span> <span class="o">=</span> <span class="p">(</span><span class="k">await</span> <span class="nx">Astro</span><span class="p">.</span><span class="nx">glob</span><span class="p">(</span><span class="dl">"</span><span class="s2">~/pages/portfolio/**/*.{md,mdx}</span><span class="dl">"</span><span class="p">)).</span><span class="nx">sort</span><span class="p">(</span>
	<span class="p">(</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">(</span><span class="nx">b</span><span class="p">.</span><span class="nx">frontmatter</span><span class="p">.</span><span class="nx">pubDate</span><span class="p">).</span><span class="nx">valueOf</span><span class="p">()</span> <span class="o">-</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">(</span><span class="nx">a</span><span class="p">.</span><span class="nx">frontmatter</span><span class="p">.</span><span class="nx">pubDate</span><span class="p">).</span><span class="nx">valueOf</span><span class="p">()</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Than applied html containers to house the content.</p>

<p>And next up was adding a link to the navigation component.</p>

<p>This all worked rather well, and was quite simple in essence.</p>

<h2 id="add-blog-by-years">Add Blog By Years</h2>

<p>In my legacy (Jeykyll) site, I had a page that displayed blog posts grouped by years. With a multi-column grid for the years.</p>

<p>I wanted to re-create this in astro with some js (typescript). So here I go.</p>

<ol>
  <li>copy the general html layout, and some css styles</li>
  <li>write some javascript to gather blog posts, than group them into years in descending date order</li>
  <li>render out for the arrays of years, with arrays of posts in each.</li>
</ol>

<p>Well this was simpler than I first figured, the main gotcha seems to be the same with any js app, typing, property naming etc. It’s so nice to be able to use simple Javascript/Typescript for this, gives complete flexibility. I will prob clean everything to use typescript a bit later but for now just want to test things out.</p>

<h3 id="writing-some-javascript-to-group-blog-posts-by-year">Writing some Javascript to group blog posts by year</h3>

<p>Now just wrote up some simple js functions to load and group the posts that than get imported into the astro page. The end result is actually a typescript typed definition.</p>

<p><strong>Snippet</strong></p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nx">groupBy</span><span class="p">(</span><span class="nx">arr</span><span class="p">,</span> <span class="nx">prop</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">map</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Map</span><span class="p">(</span><span class="nb">Array</span><span class="p">.</span><span class="k">from</span><span class="p">(</span><span class="nx">arr</span><span class="p">,</span> <span class="nx">obj</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="nx">obj</span><span class="p">[</span><span class="nx">prop</span><span class="p">],</span> <span class="p">[]]));</span>
    <span class="nx">arr</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="nx">obj</span> <span class="o">=&gt;</span> <span class="nx">map</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="nx">obj</span><span class="p">[</span><span class="nx">prop</span><span class="p">]).</span><span class="nx">push</span><span class="p">(</span><span class="nx">obj</span><span class="p">));</span>
    <span class="k">return</span> <span class="nb">Array</span><span class="p">.</span><span class="k">from</span><span class="p">(</span><span class="nx">map</span><span class="p">.</span><span class="nx">values</span><span class="p">());</span>
<span class="p">}</span>

<span class="kd">const</span> <span class="nx">posts</span> <span class="o">=</span> <span class="nx">fetchPosts</span><span class="p">();</span>   <span class="c1">// returns sorted, filtered posts</span>

<span class="kd">const</span> <span class="nx">postYear</span> <span class="o">=</span> <span class="nx">posts</span><span class="p">.</span><span class="nx">map</span><span class="p">((</span><span class="nx">p</span><span class="p">)</span><span class="o">=&gt;</span><span class="p">{</span>
      <span class="k">return</span> <span class="p">{</span> <span class="na">year</span><span class="p">:</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">(</span><span class="nx">p</span><span class="p">.</span><span class="nx">pubDate</span><span class="p">).</span><span class="nx">getFullYear</span><span class="p">(),</span> <span class="na">post</span><span class="p">:</span> <span class="nx">p</span><span class="p">};</span>
    <span class="p">})</span>

<span class="c1">// variable to cache results</span>
<span class="nx">_postByYearGrp</span> <span class="o">=</span> <span class="nx">groupBy</span><span class="p">(</span><span class="nx">postYear</span><span class="p">,</span> <span class="dl">'</span><span class="s1">year</span><span class="dl">'</span><span class="p">).</span><span class="nx">map</span><span class="p">(</span><span class="nx">yrPost</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">{</span> 
      <span class="na">year</span><span class="p">:</span> <span class="nx">yrPost</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">year</span><span class="p">,</span> 
      <span class="na">posts</span><span class="p">:</span> <span class="nx">yrPost</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">p</span> <span class="o">=&gt;</span> <span class="nx">p</span><span class="p">.</span><span class="nx">post</span><span class="p">)</span>
    <span class="p">};</span>
<span class="p">});</span>
</code></pre></div></div>

<h3 id="now-need-taxonomy-for-list-of-years">Now need taxonomy for list of years</h3>

<p>Now to create the taxonomy for list of years</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">export</span> <span class="kd">const</span> <span class="nx">getPostByYearTaxonomy</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nx">_postByYearGrp</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">byYear</span> <span class="o">=&gt;</span> <span class="p">{</span>
          <span class="k">return</span> <span class="p">{</span>
            <span class="na">year</span><span class="p">:</span> <span class="nx">byYear</span><span class="p">.</span><span class="nx">year</span><span class="p">,</span> 
            <span class="na">postCount</span><span class="p">:</span> <span class="nx">byYear</span><span class="p">.</span><span class="nx">posts</span><span class="p">.</span><span class="nx">length</span><span class="p">,</span>
            <span class="na">url</span><span class="p">:</span> <span class="s2">`#</span><span class="p">${</span><span class="nx">byYear</span><span class="p">.</span><span class="nx">year</span><span class="p">}</span><span class="s2">`</span>
          <span class="p">}</span>
      <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>]]></content><author><name>Robin Stemp</name></author><category term="Blog" /><category term="Jekyll" /><category term="Astro" /><category term="npm" /><category term="Javascript" /><category term="TypeScript" /><summary type="html"><![CDATA[Copying Portfolio &amp; Blogs By Years]]></summary></entry><entry><title type="html">Converting Jekyll to Astro - Lessons Learned Part 1</title><link href="https://stemp.dev/blog/converting-jekyll-to-astro-build-lessons-learned-part1/" rel="alternate" type="text/html" title="Converting Jekyll to Astro - Lessons Learned Part 1" /><published>2022-08-27T00:00:00+10:00</published><updated>2022-08-27T00:00:00+10:00</updated><id>https://stemp.dev/blog/converting-jekyll-to-astro-build-lessons-learned-part1</id><content type="html" xml:base="https://stemp.dev/blog/converting-jekyll-to-astro-build-lessons-learned-part1/"><![CDATA[<h2 id="what-is-jekyll-and-astro">What is Jekyll and Astro</h2>

<p>First off, my original website was generated from Jekyll.</p>

<p>Jekyll and Astro are what is known as SSG - Static Site Generators. Essentially they take a variety of file sources such as markdown, and other text sources (potentially scripts) and convert that to a fully fleshed out static HTML/CSS website. Generally with less javascript and bloat so pages remain responsive and fast, with the added benefit of being able to host anywhere… github pages or netlify being a popular choice.</p>

<p>In some ways it is similar to the old web developments we used do 20 years ago with plain HTML/CSS….. with a big difference, these new static sites can call api’s and perform other dynamic actions as they can still have javascript in them, infact with the newer SSG’s you can plug in SPA’s with them, react, vue, svelte etc.</p>

<p>Jekyll was prob one of the first SSG to arrive around 2010 from the github co-founder, and is currently the most popular. However many others have cropped up since than including Hugo, Gatsby, and others.</p>

<p>The thing with Jekyll is it’s built with ruby, and requires ruby libraries etc installed, it’s not too fast at generation, and was designed in an era before JavaScript SPA’s. So I have been looking for a new SSG (Gatsby, Hugo) and so on, however they didn’t seem to fit for one reason or another (build pipelines, platform choice, logic semantics, etc).</p>

<p>Enter Astro.build, simple, works with modern build pipelines for Javascript and it’s platforms, preact, react, svelte etc with Typescript. I believe this will provide flexibilty and better build performance.</p>

<p>So my goal is to convert my current website using Jekyll to Astro.build….at this point I have only started with it for a few days, so will see how it goes…. here is some lessons learned.</p>

<h2 id="converting-jekyll-to-astro">Converting Jekyll to Astro</h2>

<h2 id="1-initial-setup">1. Initial Setup</h2>
<hr />

<p>I head on over to <code class="language-plaintext highlighter-rouge">https://docs.astro.build/en/getting-started/</code> to create a new project.</p>

<p>So simple, just uses standard npm (from Node)</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm create astro@latest
</code></pre></div></div>

<p>I create the <code class="language-plaintext highlighter-rouge">blog</code> template option that comes up, which provides a pre-configured blog structure. I copy my original blog markdown files across into the <code class="language-plaintext highlighter-rouge">pages/blog</code> folder and it all works, a list of blog pages are shown, and can click each one…… this is fantastic, so quick.</p>

<h2 id="2-blog-layouts">2. Blog Layouts</h2>
<hr />

<p>Ok, now in Jekyll there was config that specified layouts for certain types of content, ie blogs, general pages and the like.</p>

<p>With Astro, the documentation demonstrates how to apply a <code class="language-plaintext highlighter-rouge">layout</code> for markdown within the markdowns <code class="language-plaintext highlighter-rouge">frontmatter</code>, this works fine with a few files, but with a lot of pages it could get tedious, also changing layouts means changing in each file… not ideal.</p>

<p>So what I want to do is define a default layout for content within the <code class="language-plaintext highlighter-rouge">pages/blog</code> folders, so they are all consistent.</p>

<p>Fortunately, Astro provides <a href="https://docs.astro.build/en/guides/markdown-content/#markdown-plugins">Markdown plugins</a> that allow you to add remark based plugins. <a href="https://github.com/remarkjs/remark">Remark</a> appears to be a markdown transformer, and looks like the way to accomplish what I’m after.</p>

<h3 id="creating-the-set-blog-layout-functionality">Creating the set blog layout functionality</h3>

<p>After a bit of trial and error. I came up with the following.</p>

<p>So, I create a file <code class="language-plaintext highlighter-rouge">set-blob-layout.mjs</code> and place in the following (also logged out console output of file to debug):</p>

<p>As I only want to apply specific layout for blogs, need the current file path it’s processing, this is in the <code class="language-plaintext highlighter-rouge">file.history</code> array.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nx">remarkSetBlogLayout</span><span class="p">(</span><span class="nx">options</span><span class="p">)</span> <span class="p">{</span> 
    <span class="k">return</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">tree</span><span class="p">,</span> <span class="nx">file</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">//console.log(file);</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">file</span><span class="p">.</span><span class="nx">history</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">includes</span><span class="p">(</span><span class="dl">'</span><span class="s1">pages/blog</span><span class="dl">'</span><span class="p">)){</span>
            <span class="nx">file</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">astro</span><span class="p">.</span><span class="nx">frontmatter</span><span class="p">.</span><span class="nx">layout</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">/src/layouts/BlogPost.astro</span><span class="dl">'</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Now the <code class="language-plaintext highlighter-rouge">astro.config.mjs</code>, I add the <code class="language-plaintext highlighter-rouge">remarkSetBlogLayout</code> function import to the <code class="language-plaintext highlighter-rouge">markdown</code> property to process <code class="language-plaintext highlighter-rouge">.md</code> files and in integrations mdx options to process <code class="language-plaintext highlighter-rouge">.mdx</code> files.</p>

<blockquote>
  <p>NOTE: It’s important to apply <code class="language-plaintext highlighter-rouge">extends</code> for mdx, and <code class="language-plaintext highlighter-rouge">extendDefaultPlugins</code> true for markdown to ensure Astro’s default plugins are enabled.</p>
</blockquote>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="p">{</span> <span class="nx">defineConfig</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">astro/config</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">mdx</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">@astrojs/mdx</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">remarkSetBlogLayout</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">./set-blog-layout.mjs</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">sitemap</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">@astrojs/sitemap</span><span class="dl">'</span><span class="p">;</span>

<span class="c1">// https://astro.build/config</span>
<span class="k">export</span> <span class="k">default</span> <span class="p">{</span>
	<span class="na">site</span><span class="p">:</span> <span class="dl">'</span><span class="s1">https://example.com</span><span class="dl">'</span><span class="p">,</span>
	<span class="na">integrations</span><span class="p">:</span> <span class="p">[</span><span class="nx">mdx</span><span class="p">({</span>
		<span class="na">remarkPlugins</span> <span class="p">:</span> <span class="p">{</span>
			<span class="na">extends</span><span class="p">:</span> <span class="p">[</span><span class="nx">remarkSetBlogLayout</span><span class="p">]</span>
		<span class="p">}</span>	
	<span class="p">}),</span> <span class="nx">sitemap</span><span class="p">()],</span>
	<span class="na">markdown</span><span class="p">:</span> <span class="p">{</span>
		<span class="na">remarkPlugins</span><span class="p">:</span> <span class="p">[</span><span class="nx">remarkSetBlogLayout</span><span class="p">],</span>
		<span class="na">extendDefaultPlugins</span><span class="p">:</span> <span class="kc">true</span>
	<span class="p">}</span>
<span class="p">};</span>

</code></pre></div></div>

<p><strong>SUCCESS !!</strong></p>

<p>And now all the blog posts in markdown files have the default layout I wanted without affecting other pages. This is very nice, it did not take long to figure out once I got the remark config setup correctly with support from the awesome guys at the <a href="https://discord.com/channels/830184174198718474/845451724738265138">Astro Support Thread</a> on discord.</p>

<h2 id="3-set-publish-date-for-blogs-from-the-filename">3. Set publish date for blogs from the filename</h2>
<hr />

<p>So in my Jekyll setup, all my posts are in a single folder and the publish date is inferred from the filename, in the format:</p>

<p><code class="language-plaintext highlighter-rouge">posts/YYYY-MM-DD-post-title.md</code></p>

<blockquote>
  <p>I prefer to have the explicit date in the file name as it makes organization easier at a glance. And reduces need to apply inside each file.</p>
</blockquote>

<p>So there were 2 things to apply:</p>

<ol>
  <li>set blog post date from filename</li>
  <li>being able to organize blog posts, by year into folders</li>
</ol>

<p>So for <em>(1.)</em> I created a remark plugin to apply the <code class="language-plaintext highlighter-rouge">pubDate</code> publishDate.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nx">setPubDateFromFileRemarkPlugin</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">return</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">tree</span><span class="p">,</span> <span class="nx">file</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">file</span><span class="p">.</span><span class="nx">history</span> 
            <span class="o">&amp;&amp;</span> <span class="nx">file</span><span class="p">.</span><span class="nx">history</span><span class="p">.</span><span class="nx">length</span> 
            <span class="o">&amp;&amp;</span> <span class="nx">file</span><span class="p">.</span><span class="nx">history</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">includes</span><span class="p">(</span><span class="dl">'</span><span class="s1">pages/blog</span><span class="dl">'</span><span class="p">)){</span>
            <span class="kd">const</span> <span class="nx">histFile</span> <span class="o">=</span> <span class="nx">file</span><span class="p">.</span><span class="nx">history</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
            <span class="kd">const</span> <span class="nx">fileNameOnly</span> <span class="o">=</span> <span class="nx">getFileName</span><span class="p">(</span><span class="nx">histFile</span><span class="p">);</span>

            <span class="k">try</span> <span class="p">{</span>
                <span class="kd">const</span> <span class="nx">dateStr</span> <span class="o">=</span> <span class="nx">getDateStrFromFile</span><span class="p">(</span><span class="nx">histFile</span><span class="p">);</span>
                <span class="c1">//console.log(`Date-Found-In-FileName: file:${fileNameOnly} Date:${dateStr}`);</span>
                <span class="nx">file</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">astro</span><span class="p">.</span><span class="nx">frontmatter</span><span class="p">.</span><span class="nx">pubDate</span> <span class="o">=</span> <span class="nx">dateStr</span><span class="p">;</span>
            <span class="p">}</span> <span class="k">catch</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
                <span class="c1">//console.log(`Date-Not-Found: ${fileNameOnly} Could be in Meta - Error: ${e.message}`);</span>
            <span class="p">};</span>
        <span class="p">}</span>

    <span class="p">}</span>
  <span class="p">}</span>

</code></pre></div></div>

<p>Once adding this plugin to the config arrays similar to the <code class="language-plaintext highlighter-rouge">set-blog-layout</code>, all the dates were correctly applied to all the markdown posts.</p>

<p>And for <em>(2.)</em> I simply moved the files into suitably organized folders.</p>

<h2 id="conclusion">Conclusion</h2>

<p>Day 1 concluded with an excellent result, and Astro is looking like a winner so far. I am keen to get more moved over. Copying the the markdown files over were literally just a copy, and just a few adjustments to apply the layout and publishing date.</p>]]></content><author><name>Robin Stemp</name></author><category term="Blog" /><category term="Jekyll" /><category term="Astro" /><category term="npm" /><category term="Javascript" /><category term="TypeScript" /><summary type="html"><![CDATA[What is Jekyll and Astro]]></summary></entry><entry><title type="html">Essential Microservice Components</title><link href="https://stemp.dev/blog/essential-microservice-components/" rel="alternate" type="text/html" title="Essential Microservice Components" /><published>2022-05-25T00:00:00+10:00</published><updated>2022-05-25T00:00:00+10:00</updated><id>https://stemp.dev/blog/essential-microservice-components</id><content type="html" xml:base="https://stemp.dev/blog/essential-microservice-components/"><![CDATA[<p>I have spent the last decade or so converting monoliths to microservice based architectures, with the microservices being primarily in .NET (.NET Framework and .NET Core 2-6) with some NodeJs Microservices (for things like puppeteer or javascript specific services) and some python, and compiled a list of items that seem to form Microservice implementations at the microservice level.</p>

<p>Here are some key infrastructural components I have found that apply to microservices (which are essentially mini web backends) with some references to .NET specific tooling, though the concepts can apply to most platforms.</p>

<p>More to be added later.</p>

<ul>
  <li>Apis
    <ul>
      <li>Api Gateways
        <ul>
          <li>proxy</li>
        </ul>
      </li>
      <li>Api Visibility
        <ul>
          <li>publicly accessible</li>
          <li>private</li>
        </ul>
      </li>
      <li>Api routing and route naming, verbs</li>
      <li>Api Style
        <ul>
          <li>RPC Remote Procedure Call style</li>
          <li>REST style</li>
        </ul>
      </li>
      <li>Api Conventions and Standards
        <ul>
          <li>OpenAPI/Swagger</li>
          <li>Serialization (Binary, JSON, MessagePack)
            <ul>
              <li>Json</li>
              <li>MessagePack</li>
            </ul>
          </li>
        </ul>
      </li>
      <li>Api Controllers
        <ul>
          <li>CRUD Verbs, POST, PUT, GET, DELETE, PATCH</li>
          <li>Http Calls
            <ul>
              <li>POST to create often returns 201, 202 with location header set</li>
              <li>GET often returns 200</li>
              <li>DELETE to delete resource with id, often returning 200, 204</li>
            </ul>
          </li>
          <li>Handle errors
            <ul>
              <li>Middleware to handle unhandled exceptions to not duplicate exception handling</li>
              <li>Return client validation errors with 400 with standard data structure providing key error details</li>
              <li>Standardised <a href="https://datatracker.ietf.org/doc/html/rfc7807">ProblemDetails</a> to return 500 and 400 errors</li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
  <li>Microservice event pipeline
    <ul>
      <li>on-demand like call api get response once completed, ideal for simple CRUD</li>
      <li>long-running, post call to api, with 202 accepted return immediately, poll a status uri until completed, get results</li>
      <li>listen to message bus events, queues etc and process message, publish messages (or respond) for event notifications, status updates, etc.</li>
      <li>apply job tracking to track new jobs coming in, processing, completed etc in a database.</li>
    </ul>
  </li>
  <li>HealthChecks
    <ul>
      <li>azure blob storage</li>
      <li>database connections</li>
      <li>service process</li>
    </ul>
  </li>
  <li>Authentication
    <ul>
      <li>Auth Server</li>
      <li>Resource Servers</li>
      <li>JWT tokens</li>
      <li>Auth flows</li>
    </ul>
  </li>
  <li>Authorization
    <ul>
      <li>Roles</li>
      <li>Claims</li>
      <li>Resource Specific Permissions</li>
      <li>Authorization handlers</li>
    </ul>
  </li>
  <li>Messaging
    <ul>
      <li>Message/Event bus
        <ul>
          <li>RabbitMQ</li>
          <li>AzureServiceBus</li>
          <li>EventGrid</li>
          <li>Kafka</li>
        </ul>
      </li>
      <li>Message Abstractions
        <ul>
          <li>MassTransit</li>
          <li>NServiceBus</li>
        </ul>
      </li>
      <li>Message Envelopes</li>
      <li>Message protocols, conventions
        <ul>
          <li>Cloudevents.io</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>DAL (Data Access Layers)
    <ul>
      <li>Sql Server</li>
      <li>Postgressql</li>
      <li>Mysql</li>
      <li>MongoDb</li>
      <li>Cosmos</li>
      <li>Repositories</li>
      <li>Entities</li>
      <li>Mapping Entities with DTO’s/Models</li>
      <li>Migrations (an Example is Entity Framework)
        <ul>
          <li>Adding migrations</li>
          <li>Updating databases
            <ul>
              <li>Sql scripts</li>
              <li>EF Core Bundles</li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
  <li>Services
    <ul>
      <li>Business logic</li>
    </ul>
  </li>
  <li>Configuration
    <ul>
      <li>Json</li>
      <li>Azure Key Vault</li>
      <li>Environment Variables</li>
      <li>Command line</li>
      <li>3rd Party Config providers</li>
    </ul>
  </li>
  <li>Dependency Injection
    <ul>
      <li>Singleton (Application Scoped)</li>
      <li>Scoped (Per Request, or other Scope on demand)</li>
      <li>Transient (per resolution)</li>
    </ul>
  </li>
  <li>Logging and Telemetry
    <ul>
      <li>Logging providers</li>
      <li>Logging Abstractions</li>
      <li>Logging ingestors</li>
    </ul>
  </li>
  <li>Localization
    <ul>
      <li>Language</li>
      <li>Currency</li>
      <li>Culture</li>
      <li>Timezones</li>
    </ul>
  </li>
  <li>Templates
    <ul>
      <li>server side to generate microservice components, base layers</li>
      <li>client side to generate openapi clients, ui components</li>
    </ul>
  </li>
  <li>Docker
    <ul>
      <li>docker files</li>
      <li>docker compose</li>
      <li>docker image builds</li>
      <li>common docker services
        <ul>
          <li>azurite</li>
          <li>sql server</li>
          <li>rabbitmq</li>
          <li>redis</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>DevOps
    <ul>
      <li>Build Versioning
        <ul>
          <li>CI generated versions - Build numbering</li>
          <li>gitversion</li>
          <li>version endpoints
            <ul>
              <li>assembly version</li>
              <li>informational version</li>
            </ul>
          </li>
        </ul>
      </li>
      <li>Build Pipelines
        <ul>
          <li>build</li>
          <li>unit tests</li>
          <li>code coverage</li>
          <li>code syntax formatting / linting</li>
        </ul>
      </li>
      <li>deployment pipelines
        <ul>
          <li>environment setups
            <ul>
              <li>app services / web servers / cloud</li>
              <li>automated testing with tools like newman (Postman collection runner)</li>
            </ul>
          </li>
          <li>hosted</li>
          <li>docker/kubernetes</li>
          <li>per environment configurations
            <ul>
              <li>database connections</li>
              <li>azure/aws storage connections</li>
              <li>message bus connections</li>
              <li>config options</li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
  <li>Hosting
    <ul>
      <li>Cloud</li>
      <li>Scaling
        <ul>
          <li>scale up (vertically)</li>
          <li>scale out (horizontally)</li>
          <li>Autoscale conditions</li>
        </ul>
      </li>
    </ul>
  </li>
</ul>]]></content><author><name>Robin Stemp</name></author><category term="Blog" /><category term="microservice" /><category term="SAAS" /><summary type="html"><![CDATA[I have spent the last decade or so converting monoliths to microservice based architectures, with the microservices being primarily in .NET (.NET Framework and .NET Core 2-6) with some NodeJs Microservices (for things like puppeteer or javascript specific services) and some python, and compiled a list of items that seem to form Microservice implementations at the microservice level.]]></summary></entry><entry><title type="html">A Quick Web API REST Refresher</title><link href="https://stemp.dev/blog/a-quick-api-refresher/" rel="alternate" type="text/html" title="A Quick Web API REST Refresher" /><published>2021-12-16T00:00:00+10:00</published><updated>2021-12-16T00:00:00+10:00</updated><id>https://stemp.dev/blog/a-quick-api-refresher</id><content type="html" xml:base="https://stemp.dev/blog/a-quick-api-refresher/"><![CDATA[<p>So, I have been creating and working with web api’s since the early 2000’s. First with perl cgi-bin requests, PHP simple RPC style POST/GET requests, than SOAP with PHP and .NET, than .NET http handlers with xml, binary, csv, etc…..and over the last decade web apis with .NET MVC, WebApi’s, NodeJs with JSON, and I have seen all arrays and different approaches to implementation.</p>

<p>Ever since we came into the Web Api era around 2009, there was a big shift to using the <code class="language-plaintext highlighter-rouge">REST</code> pattern and terminology with <code class="language-plaintext highlighter-rouge">json</code>, sure we have things like <code class="language-plaintext highlighter-rouge">Graphql</code> now, though for the most part <code class="language-plaintext highlighter-rouge">REST</code> is a fairly simple pattern to use. However it’s often misunderstood even by experienced developers.</p>

<p><code class="language-plaintext highlighter-rouge">REST</code> is really just designed to work the way the stateless <code class="language-plaintext highlighter-rouge">HTTP</code> protocol was designed for. Contrary to popular belief, It doesn’t force certain approaches, rather just uses http the way it was intended. Using verbs, resources, http status codes and the like.</p>

<p>Though some popular patterns have emerged via <code class="language-plaintext highlighter-rouge">REST</code> that make it simple and consistent to apply, irrespective of platform used. Let’s look at some now.</p>

<p>Rest deals with resources, now a resource could represent an entity record in a database, it could represent a process, a job, task, a collection of items. typically a resource refers to a single element. Though a resource, could have sub-resources and the like.</p>

<h3 id="lets-look-at-http-verbs-in-the-rest-context">Let’s look at <code class="language-plaintext highlighter-rouge">HTTP</code> verbs in the REST context:</h3>

<ul>
  <li><code class="language-plaintext highlighter-rouge">POST</code> used for creating resources.</li>
  <li><code class="language-plaintext highlighter-rouge">GET</code> used to query resources, get a collection, get a single item (with an id), with filters and so on.</li>
  <li><code class="language-plaintext highlighter-rouge">PUT</code> for updating a specific resource</li>
  <li><code class="language-plaintext highlighter-rouge">DELETE</code> to delete/remove a specific resource</li>
  <li><code class="language-plaintext highlighter-rouge">PATCH</code> for making amendments, changes to specific parts of a resource</li>
</ul>

<h3 id="now-lets-look-at-the-most-popular-http-status-codes-">Now lets look at the most popular <code class="language-plaintext highlighter-rouge">HTTP Status Codes</code> :</h3>

<p>Anything in <code class="language-plaintext highlighter-rouge">2xx</code> range is a Success status</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">200 OK</code> - everything’s a-ok, request and process is success</li>
  <li><code class="language-plaintext highlighter-rouge">201 Created</code> - ok, we have created a new resource that’s ready, and a link to that resources metadata/status will be in the responses <code class="language-plaintext highlighter-rouge">location</code> header.</li>
  <li><code class="language-plaintext highlighter-rouge">202 Accepted</code> - ok, we acknowledge the request though may not have fulfilled it yet, it could be a long running process, however we have a link in the <code class="language-plaintext highlighter-rouge">location</code> header to obtain completion status, and possible <code class="language-plaintext highlighter-rouge">retry</code> headers.  A client app can potentially poll this <code class="language-plaintext highlighter-rouge">location</code> to see when it’s completed or reached another status ( note: this is http semantics, not talking about event messaging and the like at this point )</li>
  <li><code class="language-plaintext highlighter-rouge">204 No Content</code> - ok success, though we have no content to return..</li>
</ul>

<p>Now <code class="language-plaintext highlighter-rouge">4xx</code> codes represent an issue with the client request</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">400 Bad Request</code> - something in the clients request is malformed, invalid, or simply incorrect, often used for field validation. This means a client should not retry a request without changing something in it.</li>
  <li><code class="language-plaintext highlighter-rouge">401 Unauthorized</code> - the client has not sent up adequate authorization, be it an <code class="language-plaintext highlighter-rouge">Authorization</code> header, or a cookie, or it’s expired, etc. Usually an indication for a client to login.</li>
</ul>

<p>And <code class="language-plaintext highlighter-rouge">5xx</code> indicate a server error of some sort. They may be transient errors, and a retry could potentially work.</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">500 Internal server error</code> - unhandled or unknown server errors, exceptions and the like. (dont use 400’s for these).</li>
  <li><code class="language-plaintext highlighter-rouge">502 Bad Gateway</code> - could be a range of issues, from the web server, to proxies, dns etc.</li>
</ul>

<h3 id="ok-got-it-so-now-look-at-how-they-typically-work">Ok got it, so now look at how they typically work.</h3>

<ul>
  <li><code class="language-plaintext highlighter-rouge">POST</code> is used to create a new resource with data in body, the server returns http <code class="language-plaintext highlighter-rouge">201 Created</code> for a resource that is created and ready, or <code class="language-plaintext highlighter-rouge">202 Accepted</code> to indicate acknoledgement of the request, though resource may be long running. In both instances the url to retrieve the resources metadata/status via a <code class="language-plaintext highlighter-rouge">GET</code> is supplied in the <code class="language-plaintext highlighter-rouge">location</code> header.</li>
  <li><code class="language-plaintext highlighter-rouge">GET</code> is used to query a collection of resource items, or a single item with an id… it typically returns a <code class="language-plaintext highlighter-rouge">200 OK</code>. Now when using <code class="language-plaintext highlighter-rouge">GET</code> with an explicit <code class="language-plaintext highlighter-rouge">id</code> to fetch a single item, this will often (not always) represent the same url route as what the <code class="language-plaintext highlighter-rouge">POST</code> returns in the <code class="language-plaintext highlighter-rouge">location</code> header.</li>
  <li><code class="language-plaintext highlighter-rouge">PUT</code> is used to update an explicit resource. It could return a <code class="language-plaintext highlighter-rouge">200 OK</code> or <code class="language-plaintext highlighter-rouge">204 No Content</code>.</li>
  <li><code class="language-plaintext highlighter-rouge">PATCH</code> is not used as often, however it is similar to a <code class="language-plaintext highlighter-rouge">PUT</code> except where a put is about updating a resource, <code class="language-plaintext highlighter-rouge">PATCH</code> is designed for updating specific parts of a resource, lets say explicit fields, perhaps a status etc.</li>
  <li><code class="language-plaintext highlighter-rouge">DELETE</code> is to delete/remove/cancel an explicit resource. It could return the deleted resource with a <code class="language-plaintext highlighter-rouge">200 OK</code> or just confirmation with a <code class="language-plaintext highlighter-rouge">204 No Content</code>.</li>
</ul>

<blockquote>
  <p>Notice the key point is when using <code class="language-plaintext highlighter-rouge">POST</code>, the webapi should provide the <code class="language-plaintext highlighter-rouge">location</code> header with the url to the resource created/acknoledged</p>
</blockquote>

<h3 id="ahhh-so-what-about-rest-routes">Ahhh so what about REST routes</h3>

<p>Now routing is where things get interesting… often devs will call their API’s <code class="language-plaintext highlighter-rouge">REST</code> based because they use verbs and response codes, however their routing conventions may be more aligned with <code class="language-plaintext highlighter-rouge">RPC</code> (Remote Procedure Call) approaches.</p>

<p>As mentioned before <code class="language-plaintext highlighter-rouge">REST</code> does not enforce particular conventions, however recommends certain concepts. Let’s look at a typical REST convention example.</p>

<p>Let’s say we have a resource called products, in rest we typically use the pluralized form <strong>“products”</strong> to represent a collection of product in a similar way to how database tables are often named (NOTE: remember REST uses resources, does not neccassarily have to tie back to database records.). This way we can apply consistent routing conventions regardless of the resource for most CRUD like operations.</p>

<blockquote>
  <p>NOTE: before you consider that CRUD won’t suit your particular services, and therefore REST wont work. CRUD here is just used as an example for a base set of operations, as it’s familiar for database operations.</p>
</blockquote>

<p><strong>Example REST-like routing style:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>POST /api/products
GET /api/products
GET /api/products/?optionalFilter1=filterValue&amp;limit=10
GET /api/products/{id}
PUT /api/products/{id}
PATCH /api/products/{id}
DELETE /api/products/{id}

</code></pre></div></div>

<p>With this approach in this example there are effectively 2 routes that use different HTTP VERBS to determine the actual operation on the resource. One route defines the resource collection, the other defines an explicit item within that resource collection</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/api/products       - resource collection
/api/products/{id}  - explicit item within resource collection
</code></pre></div></div>

<blockquote>
  <p>REST style API routes define resources, and HTTP Verbs define operations. REST came about as a way to provide consistency and standardization for a web based http environment.</p>
</blockquote>

<p><strong>Now contrast this with an <code class="language-plaintext highlighter-rouge">RPC</code> style api routing</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>POST /api/addproduct
GET /api/getproductslist
GET /api/getproduct/{id}
POST /api/updateproduct
DELETE /api/deleteproduct
</code></pre></div></div>

<p>Now with the <code class="language-plaintext highlighter-rouge">RPC</code> routing, we have 5 routes, indicating the operation, and using potentially any verb, ie <code class="language-plaintext highlighter-rouge">POST</code> is often used instead of <code class="language-plaintext highlighter-rouge">PUT</code>, and even sometimes <code class="language-plaintext highlighter-rouge">DELETE</code>…. the core point being that the route itself defines the operation…. its akin to calling a function, or procedure by name as in <code class="language-plaintext highlighter-rouge">Remote Procedure Call</code>.</p>

<p>Now <code class="language-plaintext highlighter-rouge">RPC</code> is essentially the style many traditional developers have used to call API’s for decades as it translates to older traditional API’s.</p>

<blockquote>
  <p>RPC style API routes define operations, HTTP Verbs are typically POST/GET, though can be any combination.</p>
</blockquote>

<p>Sometimes there is a mix of REST/RPC styles in routing.</p>

<h3 id="recommendation">Recommendation:</h3>

<p>Aim for consistent, and standardized web practices, in essence <code class="language-plaintext highlighter-rouge">REST</code> is very helpful in this regard, especially as API’s grow in scale and functionality. The larger the API the more you need consistency.</p>

<h3 id="references">References:</h3>

<ul>
  <li>For more details on Http status codes, look at the Mozilla <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status">HTTP status page</a>.</li>
  <li>http://apihandyman.io/do-you-really-know-why-you-prefer-rest-over-rpc/</li>
  <li>https://restcookbook.com/</li>
  <li>https://cloud.google.com/blog/products/application-development/rest-vs-rpc-what-problems-are-you-trying-to-solve-with-your-apis</li>
  <li>https://blog.jscrambler.com/rpc-style-vs-rest-web-apis/</li>
</ul>

<h3 id="rest-api-examples">REST Api Examples:</h3>

<ul>
  <li>https://docs.github.com/en/rest</li>
  <li>https://developer.okta.com/docs/reference/core-okta-api/</li>
</ul>]]></content><author><name>Robin Stemp</name></author><category term="Blog" /><category term=".NET Core" /><category term=".NET" /><category term="Web Api" /><category term="Api" /><category term="HTTP" /><category term="Endpoints" /><category term="REST" /><category term="RPC" /><category term="nodejs" /><summary type="html"><![CDATA[So, I have been creating and working with web api’s since the early 2000’s. First with perl cgi-bin requests, PHP simple RPC style POST/GET requests, than SOAP with PHP and .NET, than .NET http handlers with xml, binary, csv, etc…..and over the last decade web apis with .NET MVC, WebApi’s, NodeJs with JSON, and I have seen all arrays and different approaches to implementation.]]></summary></entry><entry><title type="html">Dont return api exceptions as bad requests</title><link href="https://stemp.dev/blog/dont-return-api-exceptions-as-bad-requests/" rel="alternate" type="text/html" title="Dont return api exceptions as bad requests" /><published>2021-12-15T00:00:00+10:00</published><updated>2021-12-15T00:00:00+10:00</updated><id>https://stemp.dev/blog/dont-return-api-exceptions-as-bad-requests</id><content type="html" xml:base="https://stemp.dev/blog/dont-return-api-exceptions-as-bad-requests/"><![CDATA[<p>So recently, when looking at some new projects that have web api or azure function http endpoints, I have noticed a lack of basic understanding of http knowledge that most api developers should have. This is the kind of details that can cause some major debugging and production level issues down the track. One of the subtle but important points is how exceptions are returned to an api client.</p>

<p>For this post, I will use .NET as an example.</p>

<p><strong>AVOID: Sending Bad Request (400) Status codes to a client as a catch-all</strong></p>

<p>Let’s look at a webapi action that does some stuff, and catches exceptions, and returns any exception to the client.</p>

<div class="language-cs highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="nf">HttpPost</span><span class="p">(</span><span class="s">"/route/blah/blah"</span><span class="p">)]</span>
<span class="k">public</span> <span class="n">IActionResult</span> <span class="nf">SomeAwesomeApi</span><span class="p">()</span>
<span class="p">{</span>
     <span class="k">try</span> <span class="p">{</span>
       <span class="c1">// do some stuff</span>
       <span class="p">...</span>
     <span class="p">}</span> <span class="k">catch</span><span class="p">(</span><span class="n">Exception</span> <span class="n">ex</span><span class="p">){</span>
        <span class="n">Return</span> <span class="k">new</span> <span class="nf">BadRequestObjectResult</span><span class="p">(</span><span class="n">ex</span><span class="p">.</span><span class="n">Message</span><span class="p">);</span>    <span class="c1">// returns a 400 bad request regardless of server/client issue</span>
     <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Now, there are a couple of issues with this:</p>

<ol>
  <li><code class="language-plaintext highlighter-rouge">[.NET Specific]</code> The entire try/catch block is unneccassary, as a .NET Core middleware could be written to handle the exception across all actions, rather than repeating it.</li>
  <li><code class="language-plaintext highlighter-rouge">Red Flag</code>: Returning a <code class="language-plaintext highlighter-rouge">BadRequest</code> to the client for exceptions, which is a <code class="language-plaintext highlighter-rouge">HTTP 400</code> status code.</li>
</ol>

<p>With (1) that’s just a good practice for any platform to reduce code duplication.</p>

<p>(2) is the main issue. The reason being is that an <code class="language-plaintext highlighter-rouge">HTTP 400</code> status means that the client request is invalid in some way. <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400">see more about about HTTP 400</a>. This means that the client should modify it’s request before repeating it.  Now in the example above where the <code class="language-plaintext highlighter-rouge">BadRequest</code> is returned on <em>any</em> exception, the exception could be caused from anything, server or client request issue. We don’t know if it’s due to the request, or due to something in the server code path. Perhaps network connectivity is down, there could just be something wrong with the server and nothing to do with the request. In which case we should never just send a 400 badrequest to the client. a <em>400 effectively means a client should not retry without changing the request</em></p>

<blockquote>
  <p>The only time we should send a BadRequest (HTTP 400) status to the client is when we know it’s request related. For example properties don’t validate, or a request header is missing or invalid.  An unknown exception should just return a 500 (Internal server Error)</p>
</blockquote>

<p>Same example as an Azure Function HTTP Trigger Api Endpoint</p>

<div class="language-cs highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="nf">FunctionName</span><span class="p">(</span><span class="s">"SomeFunction"</span><span class="p">)]</span>
<span class="p">[</span><span class="nf">OpenApiOperation</span><span class="p">(</span><span class="n">operationId</span><span class="p">:</span> <span class="s">"SomeFunction"</span><span class="p">,</span> <span class="n">tags</span><span class="p">:</span> <span class="k">new</span><span class="p">[]</span> <span class="p">{</span> <span class="s">"name"</span> <span class="p">})]</span>
<span class="p">[</span><span class="nf">OpenApiParameter</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="s">"id"</span><span class="p">,</span> <span class="n">In</span> <span class="p">=</span> <span class="n">ParameterLocation</span><span class="p">.</span><span class="n">Path</span><span class="p">,</span> <span class="n">Required</span> <span class="p">=</span> <span class="k">true</span><span class="p">,</span> <span class="n">Type</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="n">Int32</span><span class="p">),</span> <span class="n">Description</span> <span class="p">=</span> <span class="s">"an id parameter"</span><span class="p">)]</span>
<span class="p">[</span><span class="nf">OpenApiResponseWithBody</span><span class="p">(</span><span class="n">statusCode</span><span class="p">:</span> <span class="n">HttpStatusCode</span><span class="p">.</span><span class="n">OK</span><span class="p">,</span> <span class="n">contentType</span><span class="p">:</span> <span class="s">"application/json"</span><span class="p">,</span> <span class="n">bodyType</span><span class="p">:</span> <span class="k">typeof</span><span class="p">(</span><span class="n">SomeResponse</span><span class="p">),</span> <span class="n">Description</span> <span class="p">=</span> <span class="s">"Result"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">IActionResult</span><span class="p">&gt;</span> <span class="nf">SomeFunction</span><span class="p">([</span><span class="nf">HttpTrigger</span><span class="p">(</span><span class="n">AuthorizationLevel</span><span class="p">.</span><span class="n">Anonymous</span><span class="p">,</span> <span class="s">"post"</span><span class="p">,</span> <span class="n">Route</span> <span class="p">=</span> <span class="s">"route/blah/{id}"</span><span class="p">)]</span> <span class="n">HttpRequest</span> <span class="n">req</span><span class="p">,</span> <span class="n">ILogger</span> <span class="n">log</span><span class="p">,</span> <span class="kt">int</span> <span class="n">id</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">try</span>
    <span class="p">{</span>
        <span class="c1">// do some stuff</span>
        <span class="p">...</span>
    <span class="p">}</span>
    <span class="k">catch</span><span class="p">(</span><span class="n">Exception</span> <span class="n">ex</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="k">new</span> <span class="nf">BadRequestObjectResult</span><span class="p">(</span><span class="n">ex</span><span class="p">.</span><span class="n">Message</span><span class="p">);</span>
    <span class="p">}</span>

<span class="p">}</span>
</code></pre></div></div>]]></content><author><name>Robin Stemp</name></author><category term="Blog" /><category term=".NET Core" /><category term=".NET" /><category term="Web Api" /><category term="Api" /><summary type="html"><![CDATA[So recently, when looking at some new projects that have web api or azure function http endpoints, I have noticed a lack of basic understanding of http knowledge that most api developers should have. This is the kind of details that can cause some major debugging and production level issues down the track. One of the subtle but important points is how exceptions are returned to an api client.]]></summary></entry><entry><title type="html">What to consider in .NET Core / 5 / 6+ Projects</title><link href="https://stemp.dev/blog/what-to-consider-in-dot-net-core/" rel="alternate" type="text/html" title="What to consider in .NET Core / 5 / 6+ Projects" /><published>2021-10-28T00:00:00+10:00</published><updated>2021-10-28T00:00:00+10:00</updated><id>https://stemp.dev/blog/what-to-consider-in-dot-net-core</id><content type="html" xml:base="https://stemp.dev/blog/what-to-consider-in-dot-net-core/"><![CDATA[<p>Welcome, perhaps your relatively new to .NET Core, you may come from Java, PHP, or even the older .NET Framework.</p>

<p>All too often I see devs, and architects that are not completely familiar with .NET Core implement solutions that are essentially already baked into .NET Core itself. They may have used .NET Framework in the past years ago, and use the same principles applied to .NET Core. This is not a good approach to take, for one it’s reinventing the wheel, usually with code that is less battle tested, and often not as extensible. It also requires extra maintenance and custom documentation, with less support.</p>

<p>Well here I aim to explain the core concepts in .NET Core’s base layers to help you get up to speed quickly. I am assuming you already know C# to some degree, and how it plugs into .NET in general. You also understand design patterns and understand how to write clean maintainable code.</p>

<h2 id="quick-overview-with-net-framework-to-net-core">Quick overview with .NET Framework to .NET Core</h2>

<p>First off <code class="language-plaintext highlighter-rouge">.NET Core != .NET Framework</code> …. that’s right, while they share syntactical similarities, nuget, and tooling and so on, they are essentially completely different platforms.</p>

<ul>
  <li>.NET Framework from .NET Framework 1 - .NET Framework 4.8</li>
  <li>.NET Core 1.0 - .NET Core 3.1 and now just .NET 5 / .NET 6 ….. etc</li>
</ul>

<p><strong>.NET Framework</strong><br />
Designed specifically for Windows OS and released around 2001. Requires Windows tooling such as Visual Studio for editing, and I.I.S for ASP.NET Web Servers, was the .NET ecosystem up until .NET Core come around.</p>
<ul>
  <li>Closed source Proprietary framework</li>
  <li>Windows only development and runtimes (there were spinoffs such as Mono for other platforms, and various other runtimes)</li>
  <li>ASP.NET Minmum memory for a request was approx 26kb</li>
  <li>ASP.NET Extensibility was somewhat complex.</li>
  <li>Suited SOAP, WCF, XML techs</li>
</ul>

<p><strong>.NET Core</strong><br />
Re-architected from the ground up for new open cross platform developments. Released 2014</p>

<ul>
  <li>Cross-platform development and runtimes</li>
  <li>Open source</li>
  <li>Open standards</li>
  <li>Highly configurable and extensible</li>
  <li>Command line tooling infrastructure</li>
  <li>Lighter, significant performance improvements</li>
  <li>Dependency Injection is first class principle</li>
  <li>Web Api minimum request memory ~2kb</li>
  <li>designed for modern development approaches such as Web Api’s, JSON, REST.</li>
  <li>Provided a command line tool <code class="language-plaintext highlighter-rouge">dnx</code> which was later changed to <code class="language-plaintext highlighter-rouge">dotnet</code> in later versions.</li>
</ul>

<p>In essence, .NET 5/6/7+ is the current and future of .NET…… there is no point going back to the older .NET Framework unless legacy projects have no alternative</p>

<h2 id="core-concepts-patterns-considerations-for-net-core5-apps">Core concepts, patterns, considerations for .NET Core/5+ apps</h2>

<table>
  <thead>
    <tr>
      <th>Item</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Abstractions</td>
      <td>Define interfaces</td>
    </tr>
    <tr>
      <td>Builders</td>
      <td>- Define a pattern to build something</td>
    </tr>
    <tr>
      <td> </td>
      <td>- Web Host builders</td>
    </tr>
    <tr>
      <td> </td>
      <td>- Configuration Builders</td>
    </tr>
    <tr>
      <td>Middleware</td>
      <td>Defining Request / Response Pipelines</td>
    </tr>
    <tr>
      <td>Configuration</td>
      <td>Unlike .NET Framework, Configuration in .NET Core is incredibly flexible and simple at the same time. Very simple to extend and create new ConfigurationSource(s) and Providers, you can retrieve config from file(s), databases, environment, command line and access it consistently using <code class="language-plaintext highlighter-rouge">IConfiguration</code> or <code class="language-plaintext highlighter-rouge">IOptions&lt;T&gt;</code> patterns</td>
    </tr>
    <tr>
      <td>Command line tooling</td>
      <td>- <code class="language-plaintext highlighter-rouge">dotnet</code> provides access to built in compilation and runtime tooling, as well as custom built local and global tools</td>
    </tr>
    <tr>
      <td> </td>
      <td>- <code class="language-plaintext highlighter-rouge">dotnet ef</code> provides database migrations, updates and reverse engineering tooling</td>
    </tr>
    <tr>
      <td> </td>
      <td>- <a href="https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-new">dotnet new</a> command for scaffolding new solutions, projects, files. Creating custom templates.</td>
    </tr>
    <tr>
      <td> </td>
      <td>- <a href="https://docs.microsoft.com/en-us/dotnet/core/tools/global-tools">dotnet tools</a> for console based applications</td>
    </tr>
    <tr>
      <td>Dependency Injection</td>
      <td>Now a first class principle. Code by abstraction</td>
    </tr>
    <tr>
      <td>Health Checks</td>
      <td>Health checking multiple services, consider app, db, custom services etc</td>
    </tr>
    <tr>
      <td>Localization</td>
      <td>For localizing content according to a culture, different languages, time zones etc</td>
    </tr>
  </tbody>
</table>

<h2 id="explicit-abstractions">Explicit Abstractions</h2>

<table>
  <thead>
    <tr>
      <th>Item</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">IServiceCollection</code></td>
      <td>- .NET’s Dependency Injection Service registration builder</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">IConfiguration</code></td>
      <td>- .NET flexible overridable configuration system, gather config from multiple sources</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">IOptions&lt;T&gt;</code></td>
      <td>- Strongly typed configuration suitable for injection based on .NET’s flexible configuration system</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">ILogger&lt;T&gt;</code></td>
      <td>- Genericly typed class Logging suitable for class injection</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">ILoggingFactory</code></td>
      <td>- Logging factory to create loggers</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">IDistributedCache</code></td>
      <td>- Distributed caching such as Redis, Sql, Mem, etc</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">IHttpClientFactory</code></td>
      <td>- Injectable factory for creating safe pooled HttpClients</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">IHealthCheck</code></td>
      <td>- For a custom healthcheck to plugin to healthcheck system</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">IStringLocalizer&lt;T&gt;</code></td>
      <td>- Simple string localization with OOTB functionality, and extendable</td>
    </tr>
  </tbody>
</table>]]></content><author><name>Robin Stemp</name></author><category term="Blog" /><category term=".NET Core" /><category term=".NET" /><category term=".NET 5" /><summary type="html"><![CDATA[Welcome, perhaps your relatively new to .NET Core, you may come from Java, PHP, or even the older .NET Framework.]]></summary></entry></feed>