<?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: Roel</title>
    <description>The latest articles on DEV Community by Roel (@roelvs).</description>
    <link>https://dev.to/roelvs</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%2F831500%2Fbef192a8-ee0a-457f-a20a-664996543aa8.png</url>
      <title>DEV Community: Roel</title>
      <link>https://dev.to/roelvs</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/roelvs"/>
    <language>en</language>
    <item>
      <title>Analyze Your MTG Deck in Seconds with MTGDeckTag.com</title>
      <dc:creator>Roel</dc:creator>
      <pubDate>Mon, 09 Mar 2026 09:34:56 +0000</pubDate>
      <link>https://dev.to/roelvs/analyze-your-mtg-deck-in-seconds-with-mtgdecktagcom-2eaj</link>
      <guid>https://dev.to/roelvs/analyze-your-mtg-deck-in-seconds-with-mtgdecktagcom-2eaj</guid>
      <description>&lt;p&gt;I’ve been building a small MTG/EDH side project called mtgdecktag.com, a clean, focused tool for analyzing and understanding your decks. I love putting my decks into Moxfield, but what frustrated me most is that I have to manually tag all the cards and what they do. Especially for ramp and removal this can be tedious. &lt;/p&gt;

&lt;p&gt;So that's why i created MTGDECKTAG.&lt;/p&gt;

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

&lt;p&gt;Paste your list, hit “Analyze,” and you get a fast, structured breakdown of all the required items you want in a commander deck.&lt;/p&gt;

&lt;p&gt;The UI is simple, readable, and built to get out of your way so you can focus on the game.&lt;/p&gt;

&lt;p&gt;It can even list brackets, combo's and do a small EDHRec analysis.&lt;/p&gt;

&lt;p&gt;If you want to try it or give feedback, it’s live here: &lt;a href="https://mtgdecktag.com" rel="noopener noreferrer"&gt;https://mtgdecktag.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>mtg</category>
      <category>edh</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>How to Vue.js: Create Your First Project Quickly (using Vite)</title>
      <dc:creator>Roel</dc:creator>
      <pubDate>Mon, 15 Dec 2025 13:24:28 +0000</pubDate>
      <link>https://dev.to/roelvs/how-to-vuejs-create-your-first-project-using-vite-5fie</link>
      <guid>https://dev.to/roelvs/how-to-vuejs-create-your-first-project-using-vite-5fie</guid>
      <description>&lt;p&gt;In this guide, we will set up a brand new Vue.js 3 project using the standard build tool, Vite.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Vite?
&lt;/h2&gt;

&lt;p&gt;If you are coming from older Vue tutorials, you might be used to the "Vue CLI" (Webpack). That is now legacy. We use Vite (French for "quick") because it significantly improves the development experience:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Instant Startup: It uses Native ES Modules (ESM) to serve files on demand, rather than bundling the entire app before starting.&lt;/li&gt;
&lt;li&gt;Performance: Hot Module Replacement (HMR) stays fast regardless of how large your app grows.&lt;/li&gt;
&lt;li&gt;Configuration: You will now use vite.config.js for your settings instead of the old vue.config.js.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/en/download" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; version 18.3 or higher.&lt;/li&gt;
&lt;li&gt;A terminal (PowerShell, Bash, or cmd).&lt;/li&gt;
&lt;li&gt;Visual Studio Code (recommended).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Initialize the Project
&lt;/h2&gt;

&lt;p&gt;Open your terminal and navigate to your projects folder. Run the following command to initialize the official Vue scaffolder. This command explicitly sets up a Vite-based project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm create vue@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Configure the Project
&lt;/h2&gt;

&lt;p&gt;The command line will prompt you for a project name and several optional features. For a clean start, use the following configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Project name: my-first-vue-app&lt;/li&gt;
&lt;li&gt;Add TypeScript? No (keep it simple for now)&lt;/li&gt;
&lt;li&gt;Add JSX Support? No&lt;/li&gt;
&lt;li&gt;Add Vue Router? No&lt;/li&gt;
&lt;li&gt;Add Pinia for state management? No&lt;/li&gt;
&lt;li&gt;Add Vitest for Unit Testing? No&lt;/li&gt;
&lt;li&gt;Add ESLint for code quality? Yes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 3: Install Dependencies
&lt;/h2&gt;

&lt;p&gt;Navigate into your new project folder and install the NPM packages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;my-first-vue-app
npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Run the Development Server
&lt;/h2&gt;

&lt;p&gt;Start the local development server. Because of Vite, this should be nearly instant.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see the output pointing to &lt;code&gt;http://localhost:5173/&lt;/code&gt;. Open this URL to see the default Vue welcome page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Clean up the boilerplate
&lt;/h2&gt;

&lt;p&gt;Open the project in VS Code. To start with a blank slate, open src/App.vue and replace the contents with this basic structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello World!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;{{ message }}&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;style &lt;/span&gt;&lt;span class="na"&gt;scoped&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#42b883&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the file. Your browser will automatically reload to show your changes.&lt;/p&gt;

&lt;p&gt;You now have a running Vue 3 application powered by Vite. From here, you can start building custom components in the &lt;code&gt;src/components&lt;/code&gt; folder and importing them into &lt;code&gt;App.vue&lt;/code&gt;. This can be advanced and tricky, but we will leave that up for another tutorial.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>tutorial</category>
      <category>vue</category>
      <category>vite</category>
    </item>
    <item>
      <title>How to: Using a clever way to store multiple values in a single enum using bitmask</title>
      <dc:creator>Roel</dc:creator>
      <pubDate>Tue, 07 Oct 2025 08:19:59 +0000</pubDate>
      <link>https://dev.to/roelvs/how-to-use-a-bitmask-based-rights-system-for-cookie-consent-38pb</link>
      <guid>https://dev.to/roelvs/how-to-use-a-bitmask-based-rights-system-for-cookie-consent-38pb</guid>
      <description>&lt;p&gt;Have you ever been in a position where you need to track multiple choices of a user and want to avoid having to create a new seperate variable for each of those choices? That is where Bitmask can be your hero!&lt;/p&gt;

&lt;p&gt;In the following example we will set up user cookie consent using bitmask to have a real-world example.&lt;/p&gt;

&lt;p&gt;Managing user consent for cookies can get messy when dealing with multiple categories. A bitmask-based rights system offers a compact and efficient way to store and evaluate consent using binary flags.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Define Categories as Powers of 2
&lt;/h2&gt;

&lt;p&gt;Assign each cookie category a unique power-of-2 value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Flags&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;CookieConsent&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;None&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Necessary&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;// 2^0&lt;/span&gt;
    &lt;span class="n"&gt;Preferences&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;// 2^1&lt;/span&gt;
    &lt;span class="n"&gt;Statistics&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;// 2^2&lt;/span&gt;
    &lt;span class="n"&gt;Marketing&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt;       &lt;span class="c1"&gt;// 2^3&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows combinations to be stored as a single integer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Store Combined Consent as an Integer
&lt;/h2&gt;

&lt;p&gt;If a user consents to Necessary, Statistics, and Marketing, the combined value is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;consent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CookieConsent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Necessary&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;CookieConsent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Statistics&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;CookieConsent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marketing&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can store 13 in a cookie or database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Check Consent Using Bitwise Operations
&lt;/h2&gt;

&lt;p&gt;To check if a user has consented to a specific category:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;hasMarketing&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;consent&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;CookieConsent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marketing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;hasPreferences&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;consent&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;CookieConsent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Preferences&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works even if multiple flags are combined.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Deserialize from Stored Value
&lt;/h2&gt;

&lt;p&gt;When reading the stored value (e.g. from a cookie):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;storedValue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;13&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;userConsent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CookieConsent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;storedValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userConsent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasFlag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CookieConsent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marketing&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Load marketing scripts&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The value 13 in binary is 1101, which corresponds to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="nf"&gt;Necessary&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;Statistics&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;Marketing&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So userConsent will contain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;CookieConsent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Necessary&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;CookieConsent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Statistics&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;CookieConsent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marketing&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can check individual flags 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;if (userConsent.HasFlag(CookieConsent.Marketing))
{
    // Load marketing scripts
}

if (userConsent.HasFlag(CookieConsent.Preferences))
{
    // Will return false, since Preferences (2) is not included in 13
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Extend with New Categories
&lt;/h2&gt;

&lt;p&gt;Add new categories by continuing the power-of-2 pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;CookieConsent&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;None&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Necessary&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Preferences&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Statistics&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Marketing&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Analytics&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;16&lt;/span&gt;      &lt;span class="c1"&gt;// 2^4&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps the system scalable and backward-compatible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Store and Retrieve Consent in Cookies
&lt;/h2&gt;

&lt;p&gt;You can store the combined consent value as an integer in a cookie:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cookies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CookieConsent"&lt;/span&gt;&lt;span class="p"&gt;,((&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;consent&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To retrieve and parse it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;storedValue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cookies&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"CookieConsent"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;userConsent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CookieConsent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;storedValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 7: Use Consent Flags in Middleware or Services
&lt;/h2&gt;

&lt;p&gt;Use the flags to conditionally load services or scripts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userConsent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasFlag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CookieConsent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marketing&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Load marketing scripts&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userConsent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasFlag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CookieConsent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Analytics&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Enable analytics tracking&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 8: Optional – Serialize to Frontend
&lt;/h2&gt;

&lt;p&gt;If you need to pass consent flags to JavaScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;consentFlags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Necessary&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userConsent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasFlag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CookieConsent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Necessary&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;Preferences&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userConsent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasFlag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CookieConsent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Preferences&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;Statistics&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userConsent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasFlag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CookieConsent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Statistics&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;Marketing&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userConsent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasFlag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CookieConsent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marketing&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;Analytics&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userConsent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasFlag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CookieConsent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Analytics&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;consentFlags&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows the frontend to react accordingly. &lt;/p&gt;

&lt;p&gt;This system can be applied to even more scenario's if you feel like it. Examples can be user permissions/access control, file system attributes like hidden, readonly etc, or even log levels.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>bitmask</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to C#: Building a .NET 9 API with SQL Server and Entity Framework Core</title>
      <dc:creator>Roel</dc:creator>
      <pubDate>Fri, 28 Mar 2025 12:46:39 +0000</pubDate>
      <link>https://dev.to/roelvs/how-to-c-building-a-net-9-api-with-sql-server-and-entity-framework-core-2lji</link>
      <guid>https://dev.to/roelvs/how-to-c-building-a-net-9-api-with-sql-server-and-entity-framework-core-2lji</guid>
      <description>&lt;p&gt;In this tutorial, we will create a new project with a database using Entity Framework Core in .NET 9. For this example, we will build a simple blog API using SQL Server. Entity Framework Core is a powerful ORM that allows you to create and manage databases using C#.&lt;/p&gt;

&lt;p&gt;There are different packages available depending on the database provider you need. For this tutorial, we will use SQL Server, which requires the package &lt;code&gt;Microsoft.EntityFrameworkCore.SqlServer&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Visual Studio 2022 (latest update)&lt;/li&gt;
&lt;li&gt;.NET version 9&lt;/li&gt;
&lt;li&gt;NuGet: &lt;code&gt;Microsoft.EntityFrameworkCore.SqlServer&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;NuGet: &lt;code&gt;Microsoft.EntityFrameworkCore.Tools&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Creating a New Project
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open Visual Studio and create a new solution.&lt;/li&gt;
&lt;li&gt;Add a new project using the &lt;strong&gt;ASP.NET Core Web API&lt;/strong&gt; template.&lt;/li&gt;
&lt;li&gt;Name the project &lt;code&gt;EntityFrameworkCoreDemo&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Adding the Required Packages
&lt;/h2&gt;

&lt;p&gt;To add Entity Framework Core, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Right-click on your project and select &lt;code&gt;Manage NuGet Packages&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Navigate to the &lt;code&gt;Browse&lt;/code&gt; tab and search for &lt;code&gt;Microsoft.EntityFrameworkCore.SqlServer&lt;/code&gt;. Select the latest stable version and install it.&lt;/li&gt;
&lt;li&gt;Install &lt;code&gt;Microsoft.EntityFrameworkCore.Tools&lt;/code&gt; similarly.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Creating the Database
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Defining the Model
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create a new folder called &lt;code&gt;Models&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Inside the &lt;code&gt;Models&lt;/code&gt; folder, create a new file called &lt;code&gt;Post.cs&lt;/code&gt; and define the following model:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.ComponentModel.DataAnnotations&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Content&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating the Database Context
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create another file named &lt;code&gt;BloggingContext.cs&lt;/code&gt; inside the &lt;code&gt;Models&lt;/code&gt; folder:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.EntityFrameworkCore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BloggingContext&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DbContext&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DbSet&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Posts&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnConfiguring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbContextOptionsBuilder&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connectionString&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"BLOGGING_DB_CONNECTION"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InvalidOperationException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Database connection string is not set."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseSqlServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Applying Migrations
&lt;/h3&gt;

&lt;p&gt;Before applying migrations, ensure error handling and rollback strategies are in place to maintain database integrity. Run the following commands in the &lt;strong&gt;Package Manager Console&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Add-Migration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;InitialCreate&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Update-Database&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If an error occurs, use &lt;code&gt;Remove-Migration&lt;/code&gt; to undo changes before they are applied.&lt;br&gt;
Before applying migrations, ensure error handling and rollback strategies are in place to maintain database integrity. Run the following commands in the &lt;strong&gt;Package Manager Console&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Add-Migration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;InitialCreate&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Update-Database&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If an error occurs, use &lt;code&gt;Remove-Migration&lt;/code&gt; to undo changes before they are applied. Model&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new folder called &lt;code&gt;Models&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Inside the &lt;code&gt;Models&lt;/code&gt; folder, create a new file called &lt;code&gt;Post.cs&lt;/code&gt; and define the following model:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.ComponentModel.DataAnnotations&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Content&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create another file named &lt;code&gt;BloggingContext.cs&lt;/code&gt; inside the &lt;code&gt;Models&lt;/code&gt; folder:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.EntityFrameworkCore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BloggingContext&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DbContext&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DbSet&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Posts&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnConfiguring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbContextOptionsBuilder&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connectionString&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"BLOGGING_DB_CONNECTION"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InvalidOperationException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Database connection string is not set."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseSqlServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuring the Connection String
&lt;/h2&gt;

&lt;p&gt;Instead of hardcoding the connection string, we store it as an environment variable. For production environments, consider using Azure Key Vault, AWS Secrets Manager, or a similar secrets management service.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set the environment variable in your development environment:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nv"&gt;$env&lt;/span&gt;:BLOGGING_DB_CONNECTION &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Server=localhost;Database=BloggingDB;User Id=sa;Password=yourpassword;TrustServerCertificate=True;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;In production, set the environment variable securely using the hosting server’s configuration system.&lt;br&gt;
Instead of hardcoding the connection string, we store it as an environment variable. For production environments, consider using Azure Key Vault, AWS Secrets Manager, or a similar secrets management service.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set the environment variable in your development environment:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nv"&gt;$env&lt;/span&gt;:BLOGGING_DB_CONNECTION &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Server=localhost;Database=BloggingDB;User Id=sa;Password=yourpassword;TrustServerCertificate=True;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;In production, set the environment variable securely using the hosting server’s configuration system.
Instead of hardcoding the connection string, we store it as an environment variable.&lt;/li&gt;
&lt;li&gt;Set the environment variable in your development environment by using the environment variables or using a .env file:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nv"&gt;$env&lt;/span&gt;:BLOGGING_DB_CONNECTION &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Server=localhost;Database=BloggingDB;User Id=sa;Password=yourpassword;TrustServerCertificate=True;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or create a .env file in the root of your project.&lt;/p&gt;

&lt;h3&gt;
  
  
  !!!   MAKE SURE TO INCLUDE THE .ENV INTO YOUR .GITIGNORE. NEVER PUSH THIS TO SOURCE CONTROL/GIT. !!!
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;In production, set the environment variable on the hosting server.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Creating the Database
&lt;/h2&gt;

&lt;p&gt;Run the following commands in the &lt;strong&gt;Package Manager Console&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Add-Migration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;InitialCreate&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Update-Database&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuring the Application
&lt;/h2&gt;

&lt;p&gt;Open &lt;code&gt;Program.cs&lt;/code&gt; and modify the &lt;code&gt;ConfigureServices&lt;/code&gt; section to register &lt;code&gt;BloggingContext&lt;/code&gt;. Additionally, configure logging and monitoring for better observability.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BloggingContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddControllers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddEndpointsApiExplorer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSwaggerGen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Configure logging&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ClearProviders&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddConsole&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseSwagger&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseSwaggerUI&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAuthorization&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapControllers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;Program.cs&lt;/code&gt; and modify the &lt;code&gt;ConfigureServices&lt;/code&gt; section to register &lt;code&gt;BloggingContext&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BloggingContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddControllers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddEndpointsApiExplorer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSwaggerGen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseSwagger&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseSwaggerUI&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAuthorization&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapControllers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating a Controller
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Right-click the &lt;code&gt;Controllers&lt;/code&gt; folder and select &lt;code&gt;Add -&amp;gt; Controller&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Choose &lt;code&gt;API Controller with actions, using Entity Framework&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;code&gt;Post&lt;/code&gt; as the model and &lt;code&gt;BloggingContext&lt;/code&gt; as the data context.&lt;/li&gt;
&lt;li&gt;Name the controller &lt;code&gt;PostController.cs&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Running the Application
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Start the application by pressing &lt;code&gt;F5&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Open the browser and navigate to &lt;code&gt;https://localhost:&amp;lt;port&amp;gt;/swagger&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Test your API using Swagger.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You have successfully created a blog API using Entity Framework Core with .NET 9 and SQL Server. The database connection is now managed via an environment variable, making it more secure and flexible for different environments.&lt;/p&gt;

&lt;p&gt;To optimize performance in production, consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enabling caching mechanisms to reduce database load.&lt;/li&gt;
&lt;li&gt;Optimizing SQL queries and indexing frequently accessed columns.&lt;/li&gt;
&lt;li&gt;Implementing monitoring tools like Application Insights or Prometheus.&lt;/li&gt;
&lt;li&gt;Using connection pooling to manage multiple database requests efficiently.&lt;/li&gt;
&lt;li&gt;Handling database migrations carefully to prevent downtime during deployments.
You have successfully created a blog API using Entity Framework Core with .NET 9 and SQL Server. The database connection is now managed via an environment variable, making it more secure and flexible for different environments.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To optimize performance in production, consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enabling caching mechanisms to reduce database load.&lt;/li&gt;
&lt;li&gt;Optimizing SQL queries and indexing frequently accessed columns.&lt;/li&gt;
&lt;li&gt;Implementing monitoring tools like Application Insights or Prometheus.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  - Using connection pooling to manage multiple database requests efficiently.
&lt;/h2&gt;

&lt;p&gt;You have successfully created a blog API using Entity Framework Core with .NET 9 and SQL Server. The database connection is now managed via an environment variable, making it more secure and flexible for different environments.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>csharp</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to C#: Add Configuration to your .NET 8 Web API Application</title>
      <dc:creator>Roel</dc:creator>
      <pubDate>Wed, 27 Nov 2024 10:09:24 +0000</pubDate>
      <link>https://dev.to/roelvs/how-to-c-add-configuration-to-your-net-8-web-api-application-4cjf</link>
      <guid>https://dev.to/roelvs/how-to-c-add-configuration-to-your-net-8-web-api-application-4cjf</guid>
      <description>&lt;p&gt;Managing configuration settings is crucial for any application, including Web APIs. Separating configuration from code allows for cleaner codebases, easier maintenance, and flexibility to change settings without redeploying your application. This guide will walk you through adding custom configuration to a .NET 8 Web API application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;.NET 8 SDK&lt;/strong&gt; installed on your machine.&lt;/li&gt;
&lt;li&gt;A basic &lt;strong&gt;.NET 8 Web API Application&lt;/strong&gt;. You can create one using the command:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  dotnet new webapi &lt;span class="nt"&gt;-o&lt;/span&gt; MyWebApiApp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 1: Understanding the Default Configuration
&lt;/h2&gt;

&lt;p&gt;When you create a new Web API project, &lt;code&gt;appsettings.json&lt;/code&gt; and &lt;code&gt;appsettings.Development.json&lt;/code&gt; files are included by default. The &lt;code&gt;appsettings.json&lt;/code&gt; file is used to store configuration settings in JSON format, which the application reads at runtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Adding Custom Configuration Sections
&lt;/h2&gt;

&lt;p&gt;Let's add a custom configuration section to the &lt;code&gt;appsettings.json&lt;/code&gt; file. Open &lt;code&gt;appsettings.json&lt;/code&gt; and add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Logging"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"LogLevel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Information"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Microsoft.AspNetCore"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Warning"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"AllowedHosts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ApiSettings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"TwitterApiKey"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-api-key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"TwitterApiSecret"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-api-secret"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"BearerToken"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-bearer-token"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This adds a new section called &lt;code&gt;ApiSettings&lt;/code&gt; where you can store your API credentials.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Create a Strongly-Typed Configuration Class
&lt;/h2&gt;

&lt;p&gt;To access the &lt;code&gt;ApiSettings&lt;/code&gt; section in a strongly-typed manner, create a new class that matches the structure of the configuration section.&lt;/p&gt;

&lt;p&gt;Create a new file &lt;code&gt;ApiSettings.cs&lt;/code&gt; in your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyWebApiApp&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApiSettings&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;TwitterApiKey&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;TwitterApiSecret&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;BearerToken&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Register the Configuration in &lt;code&gt;Program.cs&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;In .NET 8, the &lt;code&gt;Program.cs&lt;/code&gt; file uses the minimal hosting model. You'll need to modify it to register your configuration class.&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;Program.cs&lt;/code&gt; and modify it as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Bind ApiSettings and add it to the services collection&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configure&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApiSettings&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ApiSettings"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.Configuration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;MyWebApiApp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Add services to the container.&lt;/span&gt;

&lt;span class="c1"&gt;// Bind ApiSettings and add it to the services collection&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configure&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApiSettings&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ApiSettings"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddControllers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddEndpointsApiExplorer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSwaggerGen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Configure the HTTP request pipeline.&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsDevelopment&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseSwagger&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseSwaggerUI&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAuthorization&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapControllers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code binds the &lt;code&gt;ApiSettings&lt;/code&gt; section of the configuration to the &lt;code&gt;ApiSettings&lt;/code&gt; class and registers it with the dependency injection (DI) container.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Access Configuration in Controllers or Services
&lt;/h2&gt;

&lt;p&gt;Now that the configuration is registered, you can inject it into your controllers or services.&lt;/p&gt;

&lt;h3&gt;
  
  
  Injecting into a Controller
&lt;/h3&gt;

&lt;p&gt;Open the &lt;code&gt;WeatherForecastController.cs&lt;/code&gt; (or create a new controller) and modify it to use &lt;code&gt;IOptions&amp;lt;ApiSettings&amp;gt;&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Mvc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.Options&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyWebApiApp.Controllers&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[controller]"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TwitterController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ApiSettings&lt;/span&gt; &lt;span class="n"&gt;_apiSettings&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;TwitterController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IOptions&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApiSettings&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;apiSettings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_apiSettings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;apiSettings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"apikey"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;GetApiKey&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;TwitterApiKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_apiSettings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TwitterApiKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;TwitterApiSecret&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_apiSettings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TwitterApiSecret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;BearerToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_apiSettings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BearerToken&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Injecting into a Service
&lt;/h3&gt;

&lt;p&gt;If you prefer to keep your controllers thin, you can create a service class:&lt;/p&gt;

&lt;h4&gt;
  
  
  Create a Service Interface and Class
&lt;/h4&gt;

&lt;p&gt;Create a new interface &lt;code&gt;ITwitterService.cs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyWebApiApp.Services&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;ITwitterService&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;GetApiKey&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;GetApiSecret&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;GetBearerToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the implementation &lt;code&gt;TwitterService.cs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.Options&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyWebApiApp.Services&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TwitterService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ITwitterService&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ApiSettings&lt;/span&gt; &lt;span class="n"&gt;_apiSettings&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;TwitterService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IOptions&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApiSettings&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;apiSettings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_apiSettings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;apiSettings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;GetApiKey&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_apiSettings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TwitterApiKey&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;GetApiSecret&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_apiSettings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TwitterApiSecret&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;GetBearerToken&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_apiSettings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BearerToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Register the Service in &lt;code&gt;Program.cs&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Add the service to the DI container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ITwitterService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TwitterService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Modify the Controller to Use the Service
&lt;/h4&gt;

&lt;p&gt;Update &lt;code&gt;TwitterController.cs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Mvc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;MyWebApiApp.Services&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyWebApiApp.Controllers&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[controller]"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TwitterController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ITwitterService&lt;/span&gt; &lt;span class="n"&gt;_twitterService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;TwitterController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ITwitterService&lt;/span&gt; &lt;span class="n"&gt;twitterService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_twitterService&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;twitterService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"apikey"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;GetApiKey&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;TwitterApiKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_twitterService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetApiKey&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="n"&gt;TwitterApiSecret&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_twitterService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetApiSecret&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="n"&gt;BearerToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_twitterService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetBearerToken&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6: Run and Test the Application
&lt;/h2&gt;

&lt;p&gt;Run your application using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Navigate to &lt;code&gt;https://localhost:&amp;lt;port&amp;gt;/swagger&lt;/code&gt; to access the Swagger UI. You should see your &lt;code&gt;TwitterController&lt;/code&gt; and the &lt;code&gt;GetApiKey&lt;/code&gt; endpoint.&lt;/p&gt;

&lt;p&gt;Try executing the &lt;code&gt;GetApiKey&lt;/code&gt; endpoint to see your configuration values returned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: Secure Your Sensitive Data
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Never store sensitive information like API keys or secrets in plain text within &lt;code&gt;appsettings.json&lt;/code&gt;, especially in production environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using User Secrets for Development
&lt;/h3&gt;

&lt;p&gt;For development, you can use the &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets" rel="noopener noreferrer"&gt;Secret Manager&lt;/a&gt; to store sensitive data.&lt;/p&gt;

&lt;p&gt;Run the following command in your project directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet user-secrets init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add secrets using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet user-secrets &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="s2"&gt;"ApiSettings:TwitterApiKey"&lt;/span&gt; &lt;span class="s2"&gt;"your-api-key"&lt;/span&gt;
dotnet user-secrets &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="s2"&gt;"ApiSettings:TwitterApiSecret"&lt;/span&gt; &lt;span class="s2"&gt;"your-api-secret"&lt;/span&gt;
dotnet user-secrets &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="s2"&gt;"ApiSettings:BearerToken"&lt;/span&gt; &lt;span class="s2"&gt;"your-bearer-token"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These secrets will be stored securely on your machine and won't be checked into source control.&lt;/p&gt;

&lt;h3&gt;
  
  
  Modifying &lt;code&gt;Program.cs&lt;/code&gt; to Include User Secrets
&lt;/h3&gt;

&lt;p&gt;When in development mode, the configuration builder automatically includes user secrets. Ensure your &lt;code&gt;Program.cs&lt;/code&gt; includes &lt;code&gt;builder.Configuration&lt;/code&gt; as shown:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Add services to the container.&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configure&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApiSettings&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ApiSettings"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By following these steps, you've successfully added custom configuration to your .NET 8 Web API application. This setup allows you to manage your application settings efficiently while keeping your code clean and maintainable. Remember to secure sensitive information appropriately, especially in production environments.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;References:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration" rel="noopener noreferrer"&gt;Configuration in ASP.NET Core&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets" rel="noopener noreferrer"&gt;Safe storage of app secrets in development in ASP.NET Core&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a continuation from:&lt;br&gt;
&lt;a href="https://dev.to/iamrule/add-your-appsettingsjson-to-a-c-console-application-5gd6"&gt;https://dev.to/iamrule/add-your-appsettingsjson-to-a-c-console-application-5gd6&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>dotnet</category>
      <category>tutorial</category>
      <category>csharp</category>
    </item>
    <item>
      <title>How to C#: Creating a simple CRUD page with Blazor and EntityFrameworkCore</title>
      <dc:creator>Roel</dc:creator>
      <pubDate>Fri, 22 Nov 2024 13:28:47 +0000</pubDate>
      <link>https://dev.to/roelvs/how-to-c-creating-a-simple-crud-page-with-blazor-and-entityframeworkcore-1j9o</link>
      <guid>https://dev.to/roelvs/how-to-c-creating-a-simple-crud-page-with-blazor-and-entityframeworkcore-1j9o</guid>
      <description>&lt;p&gt;Blazor, part of the .NET ecosystem, enables developers to build interactive web applications using C#. In this guide, we'll create a simple CRUD (Create, Read, Update, Delete) application using Blazor and Entity Framework Core in .NET 8.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Prerequisites&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;.NET 8 SDK&lt;/strong&gt;: Ensure you have the latest .NET 8 SDK installed. You can download it from the official .NET website. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Blazor Project&lt;/strong&gt;: Create a new Blazor Server or WebAssembly project.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;NuGet Packages&lt;/strong&gt;: Add the following packages to your project:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;  &lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.EntityFrameworkCore"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"8.0.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.EntityFrameworkCore.SqlServer"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"8.0.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.EntityFrameworkCore.Tools"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"8.0.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1: Set Up the Data Model&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Define a simple data model, for example, a &lt;code&gt;Product&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;Price&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a &lt;code&gt;DbContext&lt;/code&gt; to manage the database operations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppDbContext&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DbContext&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DbSet&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Products&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;AppDbContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbContextOptions&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;base&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2: Configure the Database Connection&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In your &lt;code&gt;appsettings.json&lt;/code&gt;, add the connection string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ConnectionStrings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"DefaultConnection"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Server=(localdb)&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;mssqllocaldb;Database=BlazorCrudDb;Trusted_Connection=True;"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;Program.cs&lt;/code&gt;, register the &lt;code&gt;AppDbContext&lt;/code&gt; with the dependency injection container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseSqlServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetConnectionString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DefaultConnection"&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3: Create the Database&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Use Entity Framework Core tools to create the database:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the Package Manager Console.&lt;/li&gt;
&lt;li&gt;Run the following commands:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;Add-Migration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;InitialCreate&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="n"&gt;Update-Database&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;Step 4: Build the Blazor Components&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Create a Blazor component, e.g., &lt;code&gt;ProductList.razor&lt;/code&gt;, to handle CRUD operations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@page "/products"
@inject AppDbContext Context

&amp;lt;h3&amp;gt;Product List&amp;lt;/h3&amp;gt;

&amp;lt;table&amp;gt;
    &amp;lt;thead&amp;gt;
        &amp;lt;tr&amp;gt;
            &amp;lt;th&amp;gt;Name&amp;lt;/th&amp;gt;
            &amp;lt;th&amp;gt;Price&amp;lt;/th&amp;gt;
            &amp;lt;th&amp;gt;Actions&amp;lt;/th&amp;gt;
        &amp;lt;/tr&amp;gt;
    &amp;lt;/thead&amp;gt;
    &amp;lt;tbody&amp;gt;
        @foreach (var product in products)
        {
            &amp;lt;tr&amp;gt;
                &amp;lt;td&amp;gt;@product.Name&amp;lt;/td&amp;gt;
                &amp;lt;td&amp;gt;@product.Price&amp;lt;/td&amp;gt;
                &amp;lt;td&amp;gt;
                    &amp;lt;button @onclick="() =&amp;gt; EditProduct(product.Id)"&amp;gt;Edit&amp;lt;/button&amp;gt;
                    &amp;lt;button @onclick="() =&amp;gt; DeleteProduct(product.Id)"&amp;gt;Delete&amp;lt;/button&amp;gt;
                &amp;lt;/td&amp;gt;
            &amp;lt;/tr&amp;gt;
        }
    &amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;

&amp;lt;h3&amp;gt;Add/Edit Product&amp;lt;/h3&amp;gt;
&amp;lt;input @bind="currentProduct.Name" placeholder="Name" /&amp;gt;
&amp;lt;input @bind="currentProduct.Price" placeholder="Price" /&amp;gt;
&amp;lt;button @onclick="SaveProduct"&amp;gt;Save&amp;lt;/button&amp;gt;

@code {
    private List&amp;lt;Product&amp;gt; products;
    private Product currentProduct = new Product();

    protected override async Task OnInitializedAsync()
    {
        products = await Context.Products.ToListAsync();
    }

    private async Task SaveProduct()
    {
        if (currentProduct.Id == 0)
        {
            Context.Products.Add(currentProduct);
        }
        else
        {
            Context.Products.Update(currentProduct);
        }
        await Context.SaveChangesAsync();
        products = await Context.Products.ToListAsync();
        currentProduct = new Product();
    }

    private void EditProduct(int id)
    {
        currentProduct = products.FirstOrDefault(p =&amp;gt; p.Id == id);
    }

    private async Task DeleteProduct(int id)
    {
        var product = await Context.Products.FindAsync(id);
        if (product != null)
        {
            Context.Products.Remove(product);
            await Context.SaveChangesAsync();
            products = await Context.Products.ToListAsync();
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;Step 5: Run and Test the Application&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Run your Blazor application and navigate to &lt;code&gt;/products&lt;/code&gt;. You should be able to add, edit, and delete products, with changes reflected in the database.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You've now created a basic CRUD application using Blazor and Entity Framework Core in .NET 8. This setup provides a solid foundation for building more complex applications. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Azure: Host a Selenium JavaScript Node Application in Azure and Send Email Notifications on Failures</title>
      <dc:creator>Roel</dc:creator>
      <pubDate>Wed, 28 Aug 2024 08:25:54 +0000</pubDate>
      <link>https://dev.to/roelvs/how-to-azure-host-a-selenium-javascript-node-application-in-azure-and-send-email-notifications-on-failures-2aio</link>
      <guid>https://dev.to/roelvs/how-to-azure-host-a-selenium-javascript-node-application-in-azure-and-send-email-notifications-on-failures-2aio</guid>
      <description>&lt;h3&gt;
  
  
  How to Host a Selenium JavaScript Node Application in Azure and Send Email Notifications on Failures
&lt;/h3&gt;

&lt;p&gt;Automated browser testing is essential for maintaining web application quality. Selenium is a powerful tool for automating browsers, and in this guide, we'll walk through hosting a Selenium JavaScript Node application on Azure App Service and setting up email notifications if the tests fail three times in a row. This approach ensures you are immediately aware of any repeated failures in your web application's functionality.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;To follow this tutorial, you’ll need:&lt;br&gt;
(For more in depth about this process visit: &lt;a href="https://dev.to/iamrule/how-to-js-automate-testing-with-selenium-46j4"&gt;https://dev.to/iamrule/how-to-js-automate-testing-with-selenium-46j4&lt;/a&gt; )&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Node.js&lt;/strong&gt; and &lt;strong&gt;npm&lt;/strong&gt; installed on your local machine.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Selenium JavaScript&lt;/strong&gt; script ready for deployment.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;Azure account&lt;/strong&gt; with access to Azure App Services.&lt;/li&gt;
&lt;li&gt;Basic understanding of using the &lt;strong&gt;Azure Portal&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Step-by-Step Instructions
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Step 1: Prepare Your Selenium Script
&lt;/h4&gt;

&lt;p&gt;Ensure your Selenium script is ready for deployment. Below is an example of a simple script that opens a webpage and checks for an element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;By&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;until&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;selenium-webdriver&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chrome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;selenium-webdriver/chrome&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Utility function to pause execution&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;runTest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addArguments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--no-sandbox&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--headless&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--disable-gpu&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forBrowser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chrome&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setChromeOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Replace with your target URL&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;until&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;elementLocated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test-element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Element found and page loaded successfully.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error during test:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;runTest&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ensure that the script runs in &lt;strong&gt;headless mode&lt;/strong&gt;, as this is required for running Selenium scripts in a server environment like Azure App Services.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2: Create an Azure Web App Using the Azure Portal
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Log in to the Azure Portal&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to &lt;a href="https://portal.azure.com" rel="noopener noreferrer"&gt;portal.azure.com&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create a Resource Group&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the left-hand menu, click on &lt;strong&gt;Resource groups&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;+ Create&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Fill in the &lt;strong&gt;Resource group name&lt;/strong&gt; (e.g., &lt;code&gt;SeleniumTestingRG&lt;/code&gt;) and select your &lt;strong&gt;Region&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Review + create&lt;/strong&gt; and then &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create an Azure App Service&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Navigate back to the &lt;strong&gt;Home&lt;/strong&gt; screen and select &lt;strong&gt;App Services&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;+ Create&lt;/strong&gt; and choose &lt;strong&gt;Web App&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Fill in the &lt;strong&gt;Basics&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Subscription&lt;/strong&gt;: Choose your Azure subscription.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource Group&lt;/strong&gt;: Select the resource group you just created (&lt;code&gt;SeleniumTestingRG&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt;: Enter a unique name for your web app (e.g., &lt;code&gt;selenium-tests-app&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publish&lt;/strong&gt;: Select &lt;strong&gt;Code&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runtime stack&lt;/strong&gt;: Choose &lt;strong&gt;Node 14 LTS&lt;/strong&gt; or the version matching your script.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operating System&lt;/strong&gt;: Select &lt;strong&gt;Windows&lt;/strong&gt; or &lt;strong&gt;Linux&lt;/strong&gt; (Linux is preferred for headless browser tests).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Region&lt;/strong&gt;: Choose the same region as your resource group.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Next: Monitoring&lt;/strong&gt;, then &lt;strong&gt;Review + create&lt;/strong&gt; and &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Deploy Your Selenium Script to the Web App&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After the deployment is complete, navigate to your Web App resource in the Azure Portal.&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;Deployment&lt;/strong&gt; section, click on &lt;strong&gt;Deployment Center&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Local Git&lt;/strong&gt; or &lt;strong&gt;GitHub&lt;/strong&gt; (if you want to connect to a repository).&lt;/li&gt;
&lt;li&gt;Follow the steps to set up deployment from your local machine or GitHub repository.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Step 3: Configure the Application Settings
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Add Application Settings&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the Web App resource, go to &lt;strong&gt;Configuration&lt;/strong&gt; under the &lt;strong&gt;Settings&lt;/strong&gt; section.&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Application settings&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Ensure that you add any necessary environment variables or settings needed for your Selenium script to run.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Install Chrome and Chromedriver&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You will need to ensure that the Chrome browser and ChromeDriver are available on the server. This can be managed by adding startup commands or scripts to download and install Chrome and ChromeDriver on the server, but for simplicity, ensure your deployment package includes these if needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Step 4: Set Up Azure Monitor and Alerts
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Enable Logging and Monitoring&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to the &lt;strong&gt;Monitoring&lt;/strong&gt; section in your Web App and select &lt;strong&gt;App Service logs&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;Application Logging (Filesystem)&lt;/strong&gt; to &lt;strong&gt;On&lt;/strong&gt; and select a log level (e.g., &lt;strong&gt;Error&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;Save the settings.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create an Alert Rule&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to &lt;strong&gt;Azure Monitor&lt;/strong&gt; in the Azure Portal.&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Alerts&lt;/strong&gt; &amp;gt; &lt;strong&gt;+ New alert rule&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Set the &lt;strong&gt;Scope&lt;/strong&gt; to your Web App.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Condition&lt;/strong&gt;, choose &lt;strong&gt;Custom log search&lt;/strong&gt; or &lt;strong&gt;Failed request&lt;/strong&gt; depending on your script’s logging strategy.&lt;/li&gt;
&lt;li&gt;Set up the query to detect three consecutive errors or failures.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Actions&lt;/strong&gt;, click &lt;strong&gt;Add action group&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Fill in the details and add an &lt;strong&gt;Email/SMS/Push/Voice&lt;/strong&gt; action.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Review + create&lt;/strong&gt; and then &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Step 5: Test Your Setup
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Run a Test Deployment&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deploy the Selenium script to the Azure Web App following the same steps as above.&lt;/li&gt;
&lt;li&gt;Check the logs in the Azure Portal to ensure the script runs successfully.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Trigger a Failure and Verify Alerts&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modify your Selenium script to cause a deliberate failure (e.g., by changing the element ID).&lt;/li&gt;
&lt;li&gt;Redeploy the script and monitor the logs for errors.&lt;/li&gt;
&lt;li&gt;Ensure that after three consecutive failures, an email notification is sent to your configured address.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Common Issues/Troubleshooting
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deployment Errors&lt;/strong&gt;: Make sure your &lt;code&gt;package.json&lt;/code&gt; is correctly set up and all dependencies are installed before deploying.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment Issues&lt;/strong&gt;: If the browser does not open, check if the headless mode is enabled and ensure that Chrome and ChromeDriver are installed on the server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timeouts and Failures&lt;/strong&gt;: Adjust the Selenium script to increase the wait time if elements take longer to load.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;By following these steps, you have successfully hosted a Selenium JavaScript Node application on Azure and configured it to send email notifications if the test fails three times in a row. This setup helps automate your testing process and keeps you informed of any critical issues without constant manual checking.&lt;/p&gt;

&lt;p&gt;Remember to keep monitoring your Azure services and update your Selenium scripts as your web application evolves.&lt;/p&gt;

&lt;p&gt;Happy testing! 🚀&lt;/p&gt;

</description>
      <category>azure</category>
      <category>node</category>
      <category>selenium</category>
    </item>
    <item>
      <title>How to JS: Automate testing with Selenium</title>
      <dc:creator>Roel</dc:creator>
      <pubDate>Wed, 28 Aug 2024 08:23:07 +0000</pubDate>
      <link>https://dev.to/roelvs/how-to-js-automate-testing-with-selenium-46j4</link>
      <guid>https://dev.to/roelvs/how-to-js-automate-testing-with-selenium-46j4</guid>
      <description>&lt;h3&gt;
  
  
  How to Automate Browser Testing with Selenium in JavaScript
&lt;/h3&gt;

&lt;p&gt;Automated browser testing is a must for any web developer to ensure their applications function correctly. In this post, we'll walk through setting up Selenium with JavaScript to automate a simple browser task: opening a webpage and clicking a button.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;To follow along, you’ll need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Node.js&lt;/strong&gt; and &lt;strong&gt;npm&lt;/strong&gt; installed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Chrome&lt;/strong&gt; and &lt;strong&gt;ChromeDriver&lt;/strong&gt; installed (or another browser and its respective driver).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1: Set Up Your Project
&lt;/h3&gt;

&lt;p&gt;First, create a new folder for your project. Open your terminal and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;selenium-test
&lt;span class="nb"&gt;cd &lt;/span&gt;selenium-test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, initialize a new Node.js project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command generates a &lt;code&gt;package.json&lt;/code&gt; file that keeps track of your project’s dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Install Selenium WebDriver
&lt;/h3&gt;

&lt;p&gt;We’ll use &lt;code&gt;npm&lt;/code&gt; to install Selenium WebDriver and ChromeDriver:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;selenium-webdriver chromedriver &lt;span class="nt"&gt;--save&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These packages provide the necessary libraries and tools to automate Chrome with Selenium.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Write Your Selenium Script
&lt;/h3&gt;

&lt;p&gt;Create a new file named &lt;code&gt;test.js&lt;/code&gt; in your project folder. This script will open a webpage, wait for a button to become clickable, and then click it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;By&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;until&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;selenium-webdriver&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chrome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;selenium-webdriver/chrome&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Helper function to pause the script&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;runTest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Configure Chrome to suppress unwanted prompts&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addArguments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--no-default-browser-check&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--no-first-run&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--disable-default-apps&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--disable-infobars&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forBrowser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chrome&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setChromeOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Open the target webpage&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Change this URL to the site you want to test&lt;/span&gt;

    &lt;span class="c1"&gt;// Wait for an element to load&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;until&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;elementLocated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;className&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sample-class&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Found element with class "sample-class".&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Generic wait for 6 seconds to handle any dynamic content&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Wait for the button to be clickable&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;until&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;elementLocated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sample-button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Re-locate the button to ensure it’s still in the DOM&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sample-button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Button located:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Click the button&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Button clicked successfully.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Wait for the next page or action to load&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;until&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlContains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;new-page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Navigation to new page was successful.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error during the test:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Always close the browser&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;runTest&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Run the Script
&lt;/h3&gt;

&lt;p&gt;To execute your script, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node test.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Chrome will open and perform the actions defined in your script. Watch the console for logs indicating each step's progress.&lt;/p&gt;

&lt;h3&gt;
  
  
  Troubleshooting
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;StaleElementReferenceError&lt;/strong&gt;: This happens when the DOM changes after finding an element. To avoid this, always re-locate elements right before interacting with them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timeouts&lt;/strong&gt;: If an element takes longer to load, increase the timeout in &lt;code&gt;driver.wait()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;You now have a basic setup for automated browser testing using Selenium and JavaScript. This setup can be easily expanded to include more complex interactions, checks, and validation steps.&lt;/p&gt;

&lt;p&gt;Remember to keep your drivers updated to match your browser versions and consider using a headless mode for CI/CD environments.&lt;/p&gt;

&lt;p&gt;If you want to host it in Azure check out my other post: &lt;a href="https://dev.to/iamrule/how-to-azure-host-a-selenium-javascript-node-application-in-azure-and-send-email-notifications-on-failures-2aio"&gt;https://dev.to/iamrule/how-to-azure-host-a-selenium-javascript-node-application-in-azure-and-send-email-notifications-on-failures-2aio&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy testing!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>selenium</category>
      <category>node</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to C#: Validating a JSON to a JSON Schema</title>
      <dc:creator>Roel</dc:creator>
      <pubDate>Tue, 20 Aug 2024 10:00:49 +0000</pubDate>
      <link>https://dev.to/roelvs/how-to-c-validating-a-json-to-a-json-schema-3mle</link>
      <guid>https://dev.to/roelvs/how-to-c-validating-a-json-to-a-json-schema-3mle</guid>
      <description>&lt;p&gt;Validating JSON against a JSON schema is crucial when ensuring the data your application consumes meets the expected structure. Here's how you can quickly set this up in a C# console application.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Set Up Your Project
&lt;/h2&gt;

&lt;p&gt;Start by creating a new C# Console Application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet new console &lt;span class="nt"&gt;-n&lt;/span&gt; JsonValidationDemo
&lt;span class="nb"&gt;cd &lt;/span&gt;JsonValidationDemo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Install Required Packages
&lt;/h2&gt;

&lt;p&gt;To validate JSON against a schema, you'll need to install the &lt;code&gt;Newtonsoft.Json&lt;/code&gt; and &lt;code&gt;Newtonsoft.Json.Schema&lt;/code&gt; packages. Use the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package Newtonsoft.Json
dotnet add package Newtonsoft.Json.Schema
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Add Your JSON and Schema
&lt;/h2&gt;

&lt;p&gt;For this example, let's assume you have a &lt;code&gt;sample.json&lt;/code&gt; and &lt;code&gt;schema.json&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sample.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;schema.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"integer"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"age"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Write the Validation Code
&lt;/h2&gt;

&lt;p&gt;In &lt;code&gt;Program.cs&lt;/code&gt;, add the following code to read the JSON and schema, then validate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Newtonsoft.Json&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Newtonsoft.Json.Linq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Newtonsoft.Json.Schema&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.IO&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;jsonData&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAllText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sample.json"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;schemaData&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAllText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"schema.json"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;JSchema&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schemaData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;JObject&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsValid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;IList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"JSON is valid."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"JSON is invalid. Errors:"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"- &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Run the Application
&lt;/h2&gt;

&lt;p&gt;Execute the program using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will tell you if your JSON matches the schema, providing detailed errors if not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extras: Advanced Tips for JSON Schema Validation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Strict Validation with &lt;code&gt;additionalProperties&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;To ensure that your JSON object does not contain any properties not defined in the schema, use the &lt;code&gt;additionalProperties&lt;/code&gt; keyword in your schema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"integer"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"age"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"additionalProperties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;additionalProperties: false&lt;/code&gt;, any extra properties in your JSON will cause validation to fail, enforcing a strict schema.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Best Practice: Validate Required Fields
&lt;/h3&gt;

&lt;p&gt;Always specify the required fields in the &lt;code&gt;required&lt;/code&gt; array to prevent accidental omission. For example:&lt;/p&gt;

&lt;h4&gt;
  
  
  Updated &lt;code&gt;schema.json&lt;/code&gt;:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"integer"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"age"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the &lt;code&gt;email&lt;/code&gt; field is optional, but &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;age&lt;/code&gt; are required. If the JSON does not include &lt;code&gt;name&lt;/code&gt; or &lt;code&gt;age&lt;/code&gt;, validation will fail.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Best Practice: Use Version Control for Schemas
&lt;/h3&gt;

&lt;p&gt;Keep your JSON schemas in version control, just like your code. This allows you to track changes over time and ensures consistency. Here’s a basic example of how you might organize your schemas:&lt;/p&gt;

&lt;h4&gt;
  
  
  Project Structure:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/JsonValidationDemo
  /Schemas
    - v1.schema.json
    - v2.schema.json
  Program.cs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this setup, you might start with &lt;code&gt;v1.schema.json&lt;/code&gt; and evolve to &lt;code&gt;v2.schema.json&lt;/code&gt; as your application grows, ensuring that you can always refer back to or validate against older schemas if needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Validating JSON against a schema is a straightforward process with C#. By leveraging &lt;code&gt;Newtonsoft.Json&lt;/code&gt; and &lt;code&gt;Newtonsoft.Json.Schema&lt;/code&gt;, you can easily ensure your data adheres to the expected format. Implementing strict validation with &lt;code&gt;additionalProperties&lt;/code&gt;, carefully managing required fields, and versioning your schemas are key practices to make your application more robust and reliable.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>json</category>
      <category>validation</category>
    </item>
    <item>
      <title>How to C#: Using the JObject Class</title>
      <dc:creator>Roel</dc:creator>
      <pubDate>Mon, 01 Jul 2024 13:26:30 +0000</pubDate>
      <link>https://dev.to/roelvs/how-to-c-using-the-jobject-class-47e2</link>
      <guid>https://dev.to/roelvs/how-to-c-using-the-jobject-class-47e2</guid>
      <description>&lt;p&gt;Working with JSON is essential in many C# applications. The &lt;code&gt;JObject&lt;/code&gt; class from the Newtonsoft.Json library makes it easy to manipulate JSON data. Here’s a quick guide with practical tips and a real-world example to help you get the most out of &lt;code&gt;JObject&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing Newtonsoft.Json
&lt;/h3&gt;

&lt;p&gt;Make sure you have the Newtonsoft.Json package installed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package Newtonsoft.Json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating and Parsing JSON
&lt;/h3&gt;

&lt;p&gt;Creating a &lt;code&gt;JObject&lt;/code&gt; from a JSON string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Newtonsoft.Json.Linq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;jsonString&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;@"{ 'name': 'John', 'age': 30 }"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;JObject&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creating a &lt;code&gt;JObject&lt;/code&gt; programmatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;JObject&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;JObject&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"John"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Accessing Data
&lt;/h3&gt;

&lt;p&gt;Access properties using indexers or the &lt;code&gt;Value&amp;lt;T&amp;gt;&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Name: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, Age: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Modifying JObject
&lt;/h3&gt;

&lt;p&gt;Add or update properties:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Jane"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"jane@example.com"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remove properties:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Traversing JObject
&lt;/h3&gt;

&lt;p&gt;For nested JSON structures, use &lt;code&gt;SelectToken&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;JObject&lt;/span&gt; &lt;span class="n"&gt;nestedObject&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;@"{ 'person': { 'name': 'John', 'age': 30 } }"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;JToken&lt;/span&gt; &lt;span class="n"&gt;nameToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nestedObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SelectToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$.person.name"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nameToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// Output: John&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real-World Example: Configuring API Settings
&lt;/h3&gt;

&lt;p&gt;Let's look at a practical example where we manage API settings using &lt;code&gt;JObject&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;appsettings.json:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ApiSettings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"TwitterApiKey"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-api-key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"TwitterApiSecret"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-api-secret"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"BearerToken"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-bearer-token"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Loading and Using API Settings:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.IO&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Newtonsoft.Json.Linq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAllText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"appsettings.json"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;JObject&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;apiSettings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"ApiSettings"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;apiSettings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"TwitterApiKey"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;apiSecret&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;apiSettings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"TwitterApiSecret"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;bearerToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;apiSettings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"BearerToken"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"API Key: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"API Secret: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;apiSecret&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Bearer Token: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;bearerToken&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tips and Best Practices
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Validate JSON Structure:&lt;/strong&gt; Always validate your JSON structure before parsing to avoid runtime errors.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"ApiSettings"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ApiSettings section is missing in appsettings.json"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Handle Null Values:&lt;/strong&gt; Ensure you handle potential null values to prevent &lt;code&gt;NullReferenceException&lt;/code&gt;.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;   &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;apiSettings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"TwitterApiKey"&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="s"&gt;"default-api-key"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Use Strongly Typed Classes:&lt;/strong&gt; For complex configurations, consider deserializing JSON into strongly-typed classes for better maintainability.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;   &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;apiSettings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"ApiSettings"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;ToObject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApiSettings&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApiSettings&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;TwitterApiKey&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;TwitterApiSecret&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;BearerToken&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Leverage LINQ to JSON:&lt;/strong&gt; Use LINQ queries to filter and select JSON data.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;   &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;keys&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"ApiSettings"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Children&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;JProperty&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

   &lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ForEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;JObject&lt;/code&gt; class in Newtonsoft.Json is a powerful tool for working with JSON in C#. From basic parsing and manipulation to advanced usage and best practices, this guide provides a solid foundation. Keep experimenting and applying these techniques in your projects to handle JSON data efficiently. Happy coding!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fut9319lu32oh3llyebgw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fut9319lu32oh3llyebgw.gif" alt="All Done!" width="480" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>json</category>
      <category>howto</category>
    </item>
    <item>
      <title>How to configure API Versioning in .NET 8</title>
      <dc:creator>Roel</dc:creator>
      <pubDate>Sat, 29 Jun 2024 22:11:44 +0000</pubDate>
      <link>https://dev.to/roelvs/comprehensive-guide-to-api-versioning-in-net-8-1i9j</link>
      <guid>https://dev.to/roelvs/comprehensive-guide-to-api-versioning-in-net-8-1i9j</guid>
      <description>&lt;h3&gt;
  
  
  Implementing API Versioning in .NET 8 with Evolving Models
&lt;/h3&gt;

&lt;p&gt;What if you want to create a robust API and need to manage different versions to ensure backward compatibility, especially when models evolve over time? The default .NET application template doesn’t provide this out of the box, so here's a guide to make this process simpler.&lt;/p&gt;

&lt;h3&gt;
  
  
  Requirements
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;.NET 8 Web API project&lt;/li&gt;
&lt;li&gt;The following packages:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Asp.Versioning.Http"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"8.0.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Asp.Versioning.Mvc.ApiExplorer"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"8.0.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Guide
&lt;/h3&gt;

&lt;p&gt;Follow these steps to implement versioning in your .NET 8 Web API project, including handling evolving models.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Add the references above to the project&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Configure Services in &lt;code&gt;Program.cs&lt;/code&gt;&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;   &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddApiVersioning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultApiVersion&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ApiVersion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AssumeDefaultVersionWhenUnspecified&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReportApiVersions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ApiVersionReader&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ApiVersionReader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
           &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;UrlSegmentApiVersionReader&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
           &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HeaderApiVersionReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"X-Api-Version"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;AddApiExplorer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GroupNameFormat&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"'v'VVV"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SubstituteApiVersionInUrl&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;

   &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddControllers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddEndpointsApiExplorer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSwaggerGen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SwaggerDoc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"v1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;OpenApiInfo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"My API - V1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"v1.0"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
       &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SwaggerDoc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"v2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;OpenApiInfo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"My API - V2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"v2.0"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;

   &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsDevelopment&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseSwagger&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
       &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseSwaggerUI&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseHttpsRedirection&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAuthorization&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapControllers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Implement Versioned Controllers&lt;/strong&gt;:
Create versioned controllers by decorating them with the &lt;code&gt;ApiVersion&lt;/code&gt; attribute:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;   &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyApp.Controllers.v1&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;ApiVersion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1.0"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
       &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"api/v{version:apiVersion}/[controller]"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
       &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
       &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WorkoutsController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
       &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;MapToApiVersion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1.0"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
           &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{id}"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
           &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;GetV1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"This is version 1.0"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyApp.Controllers.v2&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;ApiVersion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2.0"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
       &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"api/v{version:apiVersion}/[controller]"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
       &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
       &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WorkoutsController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
       &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;MapToApiVersion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2.0"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
           &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{id}"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
           &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;GetV2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"This is version 2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NewField&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"New data"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Handling Evolving Models&lt;/strong&gt;:
When models evolve, create separate model classes for each version to maintain backward compatibility.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Version 1 Model:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WorkoutV1&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Version 2 Model with Additional Fields:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WorkoutV2&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Description&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="c1"&gt;// New field&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update the controller methods to use the appropriate models:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;   &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyApp.Controllers.v1&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;ApiVersion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1.0"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
       &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"api/v{version:apiVersion}/[controller]"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
       &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
       &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WorkoutsController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
       &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;MapToApiVersion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1.0"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
           &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{id}"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
           &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;GetV1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;workout&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;WorkoutV1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Workout V1"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
               &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;workout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyApp.Controllers.v2&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;ApiVersion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2.0"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
       &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"api/v{version:apiVersion}/[controller]"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
       &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
       &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WorkoutsController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
       &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;MapToApiVersion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2.0"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
           &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{id}"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
           &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;GetV2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;workout&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;WorkoutV2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Workout V2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"This is a description."&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
               &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;workout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Configure Swagger Documentation&lt;/strong&gt;:
Ensure each API version has its own Swagger documentation:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;   &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSwaggerGen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SwaggerDoc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"v1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;OpenApiInfo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"My API - V1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"v1.0"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
       &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SwaggerDoc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"v2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;OpenApiInfo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"My API - V2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"v2.0"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Run Your Application&lt;/strong&gt;:
Build and run your application to see the versioned API in action:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   dotnet run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Access Different API Versions&lt;/strong&gt;:
Use the URL to access different versions of your API:

&lt;ul&gt;
&lt;li&gt;Version 1.0: &lt;code&gt;https://localhost:5001/api/v1/workouts/{id}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Version 2.0: &lt;code&gt;https://localhost:5001/api/v2/workouts/{id}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Deprecating API Versions
&lt;/h3&gt;

&lt;p&gt;To deprecate an old API version, set the &lt;code&gt;Deprecated&lt;/code&gt; property on the &lt;code&gt;ApiVersion&lt;/code&gt; attribute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;ApiVersion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Deprecated&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"api/v{version:apiVersion}/[controller]"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DeprecatedController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{id}"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;GetV1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"This version is deprecated."&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Organizing Versioned Controllers and Models in Solution Explorer
&lt;/h3&gt;

&lt;p&gt;To keep your project organized, especially as you add more versions, follow these tips:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create a Folder Structure&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Create a main folder called &lt;code&gt;Controllers&lt;/code&gt; and subfolders for each version, e.g., &lt;code&gt;v1&lt;/code&gt;, &lt;code&gt;v2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Place each version of your controllers in the respective folder.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   - Controllers
     - v1
       - WorkoutsController.cs
     - v2
       - WorkoutsController.cs
   - Models
     - v1
       - WorkoutV1.cs
     - v2
       - WorkoutV2.cs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Naming Conventions&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use clear and consistent naming conventions to differentiate between versions.&lt;/li&gt;
&lt;li&gt;Include the version number in the model and controller class names if needed for clarity, e.g., &lt;code&gt;WorkoutV1&lt;/code&gt;, &lt;code&gt;WorkoutV2&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Updating Namespaces&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensure the namespaces reflect the folder structure to avoid conflicts.&lt;/li&gt;
&lt;li&gt;Example:
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt; &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyApp.Models.v1&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WorkoutV1&lt;/span&gt;
     &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
         &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;

 &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyApp.Models.v2&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WorkoutV2&lt;/span&gt;
     &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
         &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
         &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Description&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="c1"&gt;// New field&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Consistent Routing&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensure your routing attributes are consistent and clear to indicate the version in the URL path.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  All Done!
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/VIjf1GqRSbf0OsNG0H/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/VIjf1GqRSbf0OsNG0H/giphy.gif" width="480" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you have a versioned API that can evolve smoothly while maintaining backward compatibility. Don’t forget to document and communicate breaking or big changes! Feel free to experiment and make it even more advanced!&lt;/p&gt;

</description>
      <category>api</category>
      <category>dotnet</category>
      <category>versioning</category>
    </item>
    <item>
      <title>The best webtools I can find for you to use</title>
      <dc:creator>Roel</dc:creator>
      <pubDate>Mon, 17 Jun 2024 17:25:53 +0000</pubDate>
      <link>https://dev.to/roelvs/the-best-webtools-i-can-find-for-you-to-use-2i6d</link>
      <guid>https://dev.to/roelvs/the-best-webtools-i-can-find-for-you-to-use-2i6d</guid>
      <description>&lt;p&gt;Some of the best tools I can find on the web that I frequently use. This list will always be under construction. Feel free to comment with your tips!&lt;/p&gt;

&lt;h3&gt;
  
  
  Productivity and Utilities
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://ninite.com" rel="noopener noreferrer"&gt;Ninite&lt;/a&gt; - Bulk install multiple applications.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.ccleaner.com" rel="noopener noreferrer"&gt;CCleaner&lt;/a&gt; - System optimization and cleaning.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://chocolatey.org" rel="noopener noreferrer"&gt;Chocolatey&lt;/a&gt; - Windows package manager.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.voidtools.com" rel="noopener noreferrer"&gt;Everything&lt;/a&gt; - Fast file search.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.autohotkey.com" rel="noopener noreferrer"&gt;AutoHotkey&lt;/a&gt; - Automation scripting language.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://getgreenshot.org" rel="noopener noreferrer"&gt;Greenshot&lt;/a&gt; - Screenshot tool.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.jam-software.com/treesize_free" rel="noopener noreferrer"&gt;TreeSize&lt;/a&gt; - Disk space management.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.irfanview.com" rel="noopener noreferrer"&gt;IrfanView&lt;/a&gt; - Image viewer and editor.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.ccleaner.com/recuva" rel="noopener noreferrer"&gt;Recuva&lt;/a&gt; - File recovery.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.ccleaner.com/speccy" rel="noopener noreferrer"&gt;Speccy&lt;/a&gt; - System information.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ditto-cp.sourceforge.io" rel="noopener noreferrer"&gt;Ditto&lt;/a&gt; - Clipboard manager.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://justgetflux.com" rel="noopener noreferrer"&gt;F.lux&lt;/a&gt; - Screen color adjustment.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.rainmeter.net" rel="noopener noreferrer"&gt;Rainmeter&lt;/a&gt; - Desktop customization.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.stardock.com/products/fences" rel="noopener noreferrer"&gt;Stardock Fences&lt;/a&gt; - Desktop organization.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sumatrapdfreader.org/free-pdf-reader.html" rel="noopener noreferrer"&gt;SumatraPDF&lt;/a&gt; - PDF reader.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.7-zip.org" rel="noopener noreferrer"&gt;7-Zip&lt;/a&gt; - File archiver.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.win-rar.com" rel="noopener noreferrer"&gt;WinRAR&lt;/a&gt; - File archiver.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.peazip.org" rel="noopener noreferrer"&gt;PeaZip&lt;/a&gt; - File archiver.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://keepass.info" rel="noopener noreferrer"&gt;KeePass&lt;/a&gt; - Password manager.&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.launchy.net" rel="noopener noreferrer"&gt;Launchy&lt;/a&gt; - Application launcher.&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.executor.dk" rel="noopener noreferrer"&gt;Executor&lt;/a&gt; - Application launcher.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://en.ejie.me" rel="noopener noreferrer"&gt;Clover&lt;/a&gt; - Windows Explorer tabs.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.listary.com" rel="noopener noreferrer"&gt;Listary&lt;/a&gt; - Search utility.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://wiztreefree.com" rel="noopener noreferrer"&gt;WizTree&lt;/a&gt; - Disk space management.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.belarc.com/products_belarc_advisor" rel="noopener noreferrer"&gt;Belarc Advisor&lt;/a&gt; - System information.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Development
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://code.visualstudio.com" rel="noopener noreferrer"&gt;Visual Studio Code&lt;/a&gt; - Code editor.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sublimetext.com" rel="noopener noreferrer"&gt;Sublime Text&lt;/a&gt; - Code editor.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://atom.io" rel="noopener noreferrer"&gt;Atom&lt;/a&gt; - Code editor.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.jetbrains.com/idea" rel="noopener noreferrer"&gt;JetBrains IntelliJ IDEA&lt;/a&gt; - Java IDE.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.postman.com" rel="noopener noreferrer"&gt;Postman&lt;/a&gt; - API development.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://insomnia.rest" rel="noopener noreferrer"&gt;Insomnia&lt;/a&gt; - API client.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.docker.com" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; - Containerization.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://git-scm.com" rel="noopener noreferrer"&gt;Git&lt;/a&gt; - Version control.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://desktop.github.com" rel="noopener noreferrer"&gt;GitHub Desktop&lt;/a&gt; - Git client.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sourcetreeapp.com" rel="noopener noreferrer"&gt;SourceTree&lt;/a&gt; - Git client.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ngrok.com" rel="noopener noreferrer"&gt;ngrok&lt;/a&gt; - Secure introspectable tunnels.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pinggy.io" rel="noopener noreferrer"&gt;Pinggy&lt;/a&gt; - Secure tunnels to localhost.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.apachefriends.org/index.html" rel="noopener noreferrer"&gt;XAMPP&lt;/a&gt; - Local server environment.&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.wampserver.com/en" rel="noopener noreferrer"&gt;WAMP&lt;/a&gt; - Windows server environment.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://laragon.org" rel="noopener noreferrer"&gt;Laragon&lt;/a&gt; - Lightweight server environment.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.vagrantup.com" rel="noopener noreferrer"&gt;Vagrant&lt;/a&gt; - Development environments.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.anaconda.com" rel="noopener noreferrer"&gt;Anaconda&lt;/a&gt; - Data science and machine learning.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://jupyter.org" rel="noopener noreferrer"&gt;Jupyter&lt;/a&gt; - Interactive notebooks.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://visualstudio.microsoft.com" rel="noopener noreferrer"&gt;Visual Studio&lt;/a&gt; - IDE for various languages.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.jetbrains.com/pycharm" rel="noopener noreferrer"&gt;PyCharm&lt;/a&gt; - Python IDE.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.eclipse.org" rel="noopener noreferrer"&gt;Eclipse&lt;/a&gt; - IDE for Java and other languages.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://netbeans.apache.org" rel="noopener noreferrer"&gt;NetBeans&lt;/a&gt; - IDE for Java and other languages.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.jetbrains.com/phpstorm" rel="noopener noreferrer"&gt;PhpStorm&lt;/a&gt; - IDE for PHP.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.jetbrains.com/webstorm" rel="noopener noreferrer"&gt;WebStorm&lt;/a&gt; - IDE for JavaScript.&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://brackets.io" rel="noopener noreferrer"&gt;Brackets&lt;/a&gt; - Code editor for web development.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Design and Multimedia
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://www.photopea.com" rel="noopener noreferrer"&gt;Photopea&lt;/a&gt; - Online image editor.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.gimp.org" rel="noopener noreferrer"&gt;GIMP&lt;/a&gt; - Image editor.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://inkscape.org" rel="noopener noreferrer"&gt;Inkscape&lt;/a&gt; - Vector graphics editor.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.blender.org" rel="noopener noreferrer"&gt;Blender&lt;/a&gt; - 3D modeling and animation.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://krita.org" rel="noopener noreferrer"&gt;Krita&lt;/a&gt; - Digital painting.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.audacityteam.org" rel="noopener noreferrer"&gt;Audacity&lt;/a&gt; - Audio editing.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://obsproject.com" rel="noopener noreferrer"&gt;OBS Studio&lt;/a&gt; - Screen recording and streaming.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://handbrake.fr" rel="noopener noreferrer"&gt;HandBrake&lt;/a&gt; - Video conversion.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.blackmagicdesign.com/products/davinciresolve" rel="noopener noreferrer"&gt;DaVinci Resolve&lt;/a&gt; - Video editing.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.lwks.com" rel="noopener noreferrer"&gt;Lightworks&lt;/a&gt; - Video editing.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://affinity.serif.com/en-us/photo" rel="noopener noreferrer"&gt;Affinity Photo&lt;/a&gt; - Image editor.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://affinity.serif.com/en-us/designer" rel="noopener noreferrer"&gt;Affinity Designer&lt;/a&gt; - Vector graphics editor.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sketch.com" rel="noopener noreferrer"&gt;Sketch&lt;/a&gt; - Design tool.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.figma.com" rel="noopener noreferrer"&gt;Figma&lt;/a&gt; - Design collaboration.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.milanote.com" rel="noopener noreferrer"&gt;Milanote&lt;/a&gt; - Visual organization.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.canva.com" rel="noopener noreferrer"&gt;Canva&lt;/a&gt; - Online design tool.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pixlr.com" rel="noopener noreferrer"&gt;Pixlr&lt;/a&gt; - Online photo editor.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://vectr.com" rel="noopener noreferrer"&gt;Vectr&lt;/a&gt; - Vector graphics editor.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.designer.io" rel="noopener noreferrer"&gt;Gravit Designer&lt;/a&gt; - Vector design app.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.coreldraw.com" rel="noopener noreferrer"&gt;CorelDRAW&lt;/a&gt; - Vector graphics editor.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.aseprite.org" rel="noopener noreferrer"&gt;Aseprite&lt;/a&gt; - Pixel art tool.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://procreate.art" rel="noopener noreferrer"&gt;Procreate&lt;/a&gt; - Digital painting (iPad).&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.artrage.com" rel="noopener noreferrer"&gt;ArtRage&lt;/a&gt; - Digital painting.&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://pixologic.com/zbrush" rel="noopener noreferrer"&gt;ZBrush&lt;/a&gt; - 3D sculpting.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.maxon.net/en/cinema-4d" rel="noopener noreferrer"&gt;Cinema 4D&lt;/a&gt; - 3D modeling and animation.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Communication and Collaboration
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://slack.com" rel="noopener noreferrer"&gt;Slack&lt;/a&gt; - Team communication.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://discord.com" rel="noopener noreferrer"&gt;Discord&lt;/a&gt; - Voice, video, and text chat.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://zoom.us" rel="noopener noreferrer"&gt;Zoom&lt;/a&gt; - Video conferencing.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.microsoft.com/en/microsoft-teams/group-chat-software" rel="noopener noreferrer"&gt;Microsoft Teams&lt;/a&gt; - Collaboration and communication.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://trello.com" rel="noopener noreferrer"&gt;Trello&lt;/a&gt; - Project management.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://asana.com" rel="noopener noreferrer"&gt;Asana&lt;/a&gt; - Project management.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.notion.so" rel="noopener noreferrer"&gt;Notion&lt;/a&gt; - All-in-one workspace.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://miro.com" rel="noopener noreferrer"&gt;Miro&lt;/a&gt; - Online whiteboard.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.figma.com" rel="noopener noreferrer"&gt;Figma&lt;/a&gt; - Design collaboration.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.milanote.com" rel="noopener noreferrer"&gt;Milanote&lt;/a&gt; - Visual organization.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://basecamp.com" rel="noopener noreferrer"&gt;Basecamp&lt;/a&gt; - Project management.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://monday.com" rel="noopener noreferrer"&gt;Monday.com&lt;/a&gt; - Project management.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://clickup.com" rel="noopener noreferrer"&gt;ClickUp&lt;/a&gt; - Project management.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://airtable.com" rel="noopener noreferrer"&gt;Airtable&lt;/a&gt; - Project management and database.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.wrike.com" rel="noopener noreferrer"&gt;Wrike&lt;/a&gt; - Project management.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://meet.google.com" rel="noopener noreferrer"&gt;Google Meet&lt;/a&gt; - Video conferencing.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.gotomeeting.com" rel="noopener noreferrer"&gt;GoToMeeting&lt;/a&gt; - Video conferencing.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.skype.com" rel="noopener noreferrer"&gt;Skype&lt;/a&gt; - Voice, video, and text chat.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.webex.com" rel="noopener noreferrer"&gt;Cisco Webex&lt;/a&gt; - Video conferencing.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.teamviewer.com" rel="noopener noreferrer"&gt;TeamViewer&lt;/a&gt; - Remote access and support.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.yammer.com" rel="noopener noreferrer"&gt;Yammer&lt;/a&gt; - Enterprise social network.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.chanty.com" rel="noopener noreferrer"&gt;Chanty&lt;/a&gt; - Team communication.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://flock.com" rel="noopener noreferrer"&gt;Flock&lt;/a&gt; - Team communication.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Web Development
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://getbootstrap.com" rel="noopener noreferrer"&gt;Bootstrap&lt;/a&gt; - Front-end framework.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tailwindcss.com" rel="noopener noreferrer"&gt;Tailwind CSS&lt;/a&gt; - Utility-first CSS framework.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://jquery.com" rel="noopener noreferrer"&gt;jQuery&lt;/a&gt; - JavaScript library.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://reactjs.org" rel="noopener noreferrer"&gt;React&lt;/a&gt; - JavaScript library for building user interfaces.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://vuejs.org" rel="noopener noreferrer"&gt;Vue.js&lt;/a&gt; - JavaScript framework.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://angular.io" rel="noopener noreferrer"&gt;Angular&lt;/a&gt; - JavaScript framework.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nextjs.org" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; - React framework.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nuxtjs.org" rel="noopener noreferrer"&gt;Nuxt.js&lt;/a&gt; - Vue.js framework.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://svelte.dev" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt; - JavaScript framework.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.djangoproject.com" rel="noopener noreferrer"&gt;Django&lt;/a&gt; - Python web framework.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://flask.palletsprojects.com" rel="noopener noreferrer"&gt;Flask&lt;/a&gt; - Python web framework.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://rubyonrails.org" rel="noopener noreferrer"&gt;Ruby on Rails&lt;/a&gt; - Ruby web framework.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://laravel.com" rel="noopener noreferrer"&gt;Laravel&lt;/a&gt; - PHP web framework.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://symfony.com" rel="noopener noreferrer"&gt;Symfony&lt;/a&gt; - PHP web framework.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dotnet.microsoft.com/apps/aspnet" rel="noopener noreferrer"&gt;ASP.NET&lt;/a&gt; - Web framework for .NET.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://spring.io" rel="noopener noreferrer"&gt;Spring&lt;/a&gt; - Java web framework.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.gatsbyjs.com" rel="noopener noreferrer"&gt;Gatsby&lt;/a&gt; - React-based static site generator.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://gohugo.io" rel="noopener noreferrer"&gt;Hugo&lt;/a&gt; - Static site generator.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://jekyllrb.com" rel="noopener noreferrer"&gt;Jekyll&lt;/a&gt; - Static site generator.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://wordpress.org" rel="noopener noreferrer"&gt;WordPress&lt;/a&gt; - Content management system.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.drupal.org" rel="noopener noreferrer"&gt;Drupal&lt;/a&gt; - Content management system.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://magento.com" rel="noopener noreferrer"&gt;Magento&lt;/a&gt; - E-commerce platform.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.shopify.com" rel="noopener noreferrer"&gt;Shopify&lt;/a&gt; - E-commerce platform.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://woocommerce.com" rel="noopener noreferrer"&gt;WooCommerce&lt;/a&gt; - E-commerce plugin for WordPress.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ghost.org" rel="noopener noreferrer"&gt;Ghost&lt;/a&gt; - Publishing platform.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Security and Privacy
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://www.lastpass.com" rel="noopener noreferrer"&gt;LastPass&lt;/a&gt; - Password manager.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://1password.com" rel="noopener noreferrer"&gt;1Password&lt;/a&gt; - Password manager.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://bitwarden.com" rel="noopener noreferrer"&gt;Bitwarden&lt;/a&gt; - Password manager.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nordvpn.com" rel="noopener noreferrer"&gt;NordVPN&lt;/a&gt; - VPN service.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.expressvpn.com" rel="noopener noreferrer"&gt;ExpressVPN&lt;/a&gt; - VPN service.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.malwarebytes.com" rel="noopener noreferrer"&gt;Malwarebytes&lt;/a&gt; - Anti-malware.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.avast.com" rel="noopener noreferrer"&gt;Avast&lt;/a&gt; - Antivirus.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.kaspersky.com" rel="noopener noreferrer"&gt;Kaspersky&lt;/a&gt; - Antivirus.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.veracrypt.fr" rel="noopener noreferrer"&gt;VeraCrypt&lt;/a&gt; - Disk encryption.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://privacybadger.org" rel="noopener noreferrer"&gt;Privacy Badger&lt;/a&gt; - Browser privacy.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://adblockplus.org" rel="noopener noreferrer"&gt;Adblock Plus&lt;/a&gt; - Ad blocker.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/gorhill/uBlock" rel="noopener noreferrer"&gt;uBlock Origin&lt;/a&gt; - Ad blocker.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://protonmail.com" rel="noopener noreferrer"&gt;ProtonMail&lt;/a&gt; - Encrypted email.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tutanota.com" rel="noopener noreferrer"&gt;Tutanota&lt;/a&gt; - Encrypted email.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://signal.org" rel="noopener noreferrer"&gt;Signal&lt;/a&gt; - Encrypted messaging.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.torproject.org" rel="noopener noreferrer"&gt;Tor Browser&lt;/a&gt; - Anonymous browsing.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://duckduckgo.com" rel="noopener noreferrer"&gt;DuckDuckGo&lt;/a&gt; - Private search engine.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://brave.com" rel="noopener noreferrer"&gt;Brave&lt;/a&gt; - Privacy-focused browser.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.glasswire.com" rel="noopener noreferrer"&gt;GlassWire&lt;/a&gt; - Network monitoring.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.zonealarm.com" rel="noopener noreferrer"&gt;ZoneAlarm&lt;/a&gt; - Firewall.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.emsisoft.com" rel="noopener noreferrer"&gt;Emsisoft&lt;/a&gt; - Anti-malware.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.superantispyware.com" rel="noopener noreferrer"&gt;SuperAntiSpyware&lt;/a&gt; - Anti-spyware.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.hitmanpro.com" rel="noopener noreferrer"&gt;HitmanPro&lt;/a&gt; - Malware removal.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.adlice.com/download/roguekiller" rel="noopener noreferrer"&gt;RogueKiller&lt;/a&gt; - Malware removal.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.safer-networking.org" rel="noopener noreferrer"&gt;Spybot&lt;/a&gt; - Anti-spyware.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Cloud Storage and Backup
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://www.google.com/drive" rel="noopener noreferrer"&gt;Google Drive&lt;/a&gt; - Cloud storage.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.dropbox.com" rel="noopener noreferrer"&gt;Dropbox&lt;/a&gt; - Cloud storage.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.microsoft.com/en/microsoft-365/onedrive/online-cloud-storage" rel="noopener noreferrer"&gt;OneDrive&lt;/a&gt; - Cloud storage.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.icloud.com" rel="noopener noreferrer"&gt;iCloud&lt;/a&gt; - Cloud storage.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.pcloud.com" rel="noopener noreferrer"&gt;pCloud&lt;/a&gt; - Cloud storage.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sync.com" rel="noopener noreferrer"&gt;Sync.com&lt;/a&gt; - Cloud storage.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.backblaze.com" rel="noopener noreferrer"&gt;Backblaze&lt;/a&gt; - Backup service.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.crashplan.com" rel="noopener noreferrer"&gt;CrashPlan&lt;/a&gt; - Backup service.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.acronis.com/en-us/personal/computer-backup" rel="noopener noreferrer"&gt;Acronis True Image&lt;/a&gt; - Backup software.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.carbonite.com" rel="noopener noreferrer"&gt;Carbonite&lt;/a&gt; - Backup service.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.idrive.com" rel="noopener noreferrer"&gt;IDrive&lt;/a&gt; - Backup service.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://spideroak.com" rel="noopener noreferrer"&gt;SpiderOak&lt;/a&gt; - Cloud storage.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.zoolz.com" rel="noopener noreferrer"&gt;Zoolz&lt;/a&gt; - Cloud backup.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www2.livedrive.com" rel="noopener noreferrer"&gt;Livedrive&lt;/a&gt; - Cloud backup.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://degoo.com" rel="noopener noreferrer"&gt;Degoo&lt;/a&gt; - Cloud storage.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://mega.nz" rel="noopener noreferrer"&gt;Mega&lt;/a&gt; - Cloud storage.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tresorit.com" rel="noopener noreferrer"&gt;Tresorit&lt;/a&gt; - Cloud storage.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.box.com" rel="noopener noreferrer"&gt;Box&lt;/a&gt; - Cloud storage.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.amazon.com/clouddrive" rel="noopener noreferrer"&gt;Amazon Drive&lt;/a&gt; - Cloud storage.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://hubic.com/en" rel="noopener noreferrer"&gt;HubiC&lt;/a&gt; - Cloud storage.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://internxt.com" rel="noopener noreferrer"&gt;Internxt&lt;/a&gt; - Cloud storage.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.jottacloud.com/en" rel="noopener noreferrer"&gt;Jottacloud&lt;/a&gt; - Cloud storage.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.elephantdrive.com" rel="noopener noreferrer"&gt;ElephantDrive&lt;/a&gt; - Cloud backup.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.msp360.com" rel="noopener noreferrer"&gt;MSP360&lt;/a&gt; - Backup software.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.duplicati.com" rel="noopener noreferrer"&gt;Duplicati&lt;/a&gt; - Backup software.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://www.rainmeter.net" rel="noopener noreferrer"&gt;Rainmeter&lt;/a&gt; - Desktop customization.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.stardock.com/products/fences" rel="noopener noreferrer"&gt;Stardock Fences&lt;/a&gt; - Desktop organization.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://getsharex.com" rel="noopener noreferrer"&gt;ShareX&lt;/a&gt; - Screen capture and file sharing.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.libreoffice.org" rel="noopener noreferrer"&gt;LibreOffice&lt;/a&gt; - Office suite.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.openoffice.org" rel="noopener noreferrer"&gt;OpenOffice&lt;/a&gt; - Office suite.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sumatrapdfreader.org/free-pdf-reader.html" rel="noopener noreferrer"&gt;SumatraPDF&lt;/a&gt; - PDF reader.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.7-zip.org" rel="noopener noreferrer"&gt;7-Zip&lt;/a&gt; - File archiver.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.win-rar.com" rel="noopener noreferrer"&gt;WinRAR&lt;/a&gt; - File archiver.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.peazip.org" rel="noopener noreferrer"&gt;PeaZip&lt;/a&gt; - File archiver.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://keepass.info" rel="noopener noreferrer"&gt;KeePass&lt;/a&gt; - Password manager.&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.launchy.net" rel="noopener noreferrer"&gt;Launchy&lt;/a&gt; - Application launcher.&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.executor.dk" rel="noopener noreferrer"&gt;Executor&lt;/a&gt; - Application launcher.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://en.ejie.me" rel="noopener noreferrer"&gt;Clover&lt;/a&gt; - Windows Explorer tabs.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.listary.com" rel="noopener noreferrer"&gt;Listary&lt;/a&gt; - Search utility.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://wiztreefree.com" rel="noopener noreferrer"&gt;WizTree&lt;/a&gt; - Disk space management.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.belarc.com/products_belarc_advisor" rel="noopener noreferrer"&gt;Belarc Advisor&lt;/a&gt; - System information.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://justgetflux.com" rel="noopener noreferrer"&gt;F.lux&lt;/a&gt; - Screen color adjustment.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ditto-cp.sourceforge.io" rel="noopener noreferrer"&gt;Ditto&lt;/a&gt; - Clipboard manager.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.rescuetime.com" rel="noopener noreferrer"&gt;RescueTime&lt;/a&gt; - Time management.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://toggl.com" rel="noopener noreferrer"&gt;Toggl&lt;/a&gt; - Time tracking.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pomodoneapp.com" rel="noopener noreferrer"&gt;Pomodone&lt;/a&gt; - Pomodoro timer.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.focusatwill.com" rel="noopener noreferrer"&gt;Focus@Will&lt;/a&gt; - Productivity music.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.noisli.com" rel="noopener noreferrer"&gt;Noisli&lt;/a&gt; - Background noise generator.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://getcoldturkey.com" rel="noopener noreferrer"&gt;Cold Turkey&lt;/a&gt; - Distraction blocker.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://freedom.to" rel="noopener noreferrer"&gt;Freedom&lt;/a&gt; - Distraction blocker.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is just the first draft and will be expanded upon soon! If you have more tools we can add feel free to comment!&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
