<?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: Siddharth</title>
    <description>The latest articles on DEV Community by Siddharth (@xceed).</description>
    <link>https://dev.to/xceed</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%2F760304%2F415f0e9c-ff99-470a-81f5-61583eb03317.jpg</url>
      <title>DEV Community: Siddharth</title>
      <link>https://dev.to/xceed</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/xceed"/>
    <language>en</language>
    <item>
      <title>🧭 Understanding CORS: Preflight vs Actual API Response</title>
      <dc:creator>Siddharth</dc:creator>
      <pubDate>Tue, 11 Nov 2025 06:02:32 +0000</pubDate>
      <link>https://dev.to/xceed/understanding-cors-preflight-vs-actual-api-response-202f</link>
      <guid>https://dev.to/xceed/understanding-cors-preflight-vs-actual-api-response-202f</guid>
      <description>&lt;h2&gt;
  
  
  ⚙️ What is a Preflight Request?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;preflight&lt;/strong&gt; is an automatic &lt;code&gt;OPTIONS&lt;/code&gt; request sent by the &lt;strong&gt;browser&lt;/strong&gt; before the actual API call.&lt;/li&gt;
&lt;li&gt;Purpose: to &lt;strong&gt;ask the server for permission&lt;/strong&gt; to send a non-simple cross-origin request (e.g., one with custom headers like &lt;code&gt;Authorization&lt;/code&gt; or &lt;code&gt;Content-Type&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔁 Preflight vs Actual API Response
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Preflight (&lt;code&gt;OPTIONS&lt;/code&gt;)&lt;/th&gt;
&lt;th&gt;Actual Request (&lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;POST&lt;/code&gt;, etc.)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Who sends it&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Browser (automatically)&lt;/td&gt;
&lt;td&gt;Browser (after preflight passes)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Check if origin, method, and headers are allowed&lt;/td&gt;
&lt;td&gt;Perform the real API action&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Typical Headers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt;, &lt;code&gt;Access-Control-Allow-Methods&lt;/code&gt;, &lt;code&gt;Access-Control-Allow-Headers&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt;, &lt;code&gt;Access-Control-Expose-Headers&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Response Body&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Usually empty (&lt;code&gt;204 No Content&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Contains actual API data or error&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Visible to Frontend JS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No (browser internal)&lt;/td&gt;
&lt;td&gt;Yes (if CORS rules allow)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🧩 Why Preflight is Useful
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🛡️ &lt;strong&gt;Security:&lt;/strong&gt; Prevents unauthorized cross-origin requests.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Negotiation:&lt;/strong&gt; Lets the browser confirm allowed origins, methods, and headers.&lt;/li&gt;
&lt;li&gt;💬 &lt;strong&gt;Safety:&lt;/strong&gt; Ensures your API only accepts intended headers and methods.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  1️⃣ Middleware handles only &lt;code&gt;OPTIONS&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Preflight (success):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;204&lt;/span&gt; &lt;span class="ne"&gt;No Content&lt;/span&gt;
&lt;span class="na"&gt;Access-Control-Allow-Origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;*&lt;/span&gt;
&lt;span class="na"&gt;Access-Control-Allow-Methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GET, POST&lt;/span&gt;
&lt;span class="na"&gt;Access-Control-Allow-Headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Content-Type, Authorization&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Actual request (fails CORS):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt; &lt;span class="ne"&gt;OK&lt;/span&gt;
&lt;span class="na"&gt;Content-Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/json&lt;/span&gt;
&lt;span class="s"&gt;(no Access-Control-Allow-Origin header)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💥 Browser blocks the response because the actual API didn’t include the same CORS header.&lt;/p&gt;




&lt;h3&gt;
  
  
  2️⃣ Error responses skip CORS config
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Preflight (success):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Access-Control-Allow-Origin: https://app.example.com
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Actual (fails due to 500):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt; &lt;span class="ne"&gt;Internal Server Error&lt;/span&gt;
&lt;span class="na"&gt;Content-Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/json&lt;/span&gt;
&lt;span class="s"&gt;(no Access-Control-Allow-Origin header)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💥 Browser treats this as a CORS violation — even though preflight passed.&lt;/p&gt;




&lt;h3&gt;
  
  
  3️⃣ Credentials + Wildcard Origin
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Preflight:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💥 Invalid combo — browsers &lt;strong&gt;block&lt;/strong&gt; if &lt;code&gt;Access-Control-Allow-Credentials: true&lt;/code&gt; is set with &lt;code&gt;*&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You must return the &lt;strong&gt;exact origin&lt;/strong&gt; instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Credentials: true
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  4️⃣ Missing Allowed Headers
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Browser requests:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Access-Control-Request-Headers: Content-Type, Authorization
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Server responds (missing Authorization):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Access-Control-Allow-Headers: Content-Type
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💥 Browser rejects the request:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response.”&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  💡 Developer Recommendations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Apply CORS consistently&lt;/strong&gt; on &lt;strong&gt;all responses&lt;/strong&gt; — success or error.&lt;/li&gt;
&lt;li&gt;⚙️ &lt;strong&gt;Use middleware per route&lt;/strong&gt; if different APIs need different origins.&lt;/li&gt;
&lt;li&gt;🧱 &lt;strong&gt;Include &lt;code&gt;Authorization&lt;/code&gt; and &lt;code&gt;Content-Type&lt;/code&gt;&lt;/strong&gt; in &lt;code&gt;allowedHeaders&lt;/code&gt; if you use tokens or JSON.&lt;/li&gt;
&lt;li&gt;🔐 &lt;strong&gt;Be explicit&lt;/strong&gt; — don’t rely on defaults.&lt;/li&gt;
&lt;li&gt;🧪 &lt;strong&gt;Test in DevTools&lt;/strong&gt; — verify that both &lt;code&gt;OPTIONS&lt;/code&gt; and the actual request return matching &lt;code&gt;Access-Control-Allow-*&lt;/code&gt; headers.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🧭 TL;DR
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Preflight = browser asking for permission&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Actual request = performing the action&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Preflight can pass while the actual request fails if headers, origins, or credentials aren’t consistent.&lt;/p&gt;

&lt;p&gt;🔧 &lt;strong&gt;Fix:&lt;/strong&gt; Apply the same &lt;code&gt;Access-Control-Allow-*&lt;/code&gt; headers to &lt;em&gt;every&lt;/em&gt; response — including errors — and explicitly list headers like &lt;code&gt;Authorization&lt;/code&gt; and &lt;code&gt;Content-Type&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>networking</category>
      <category>api</category>
      <category>webdev</category>
      <category>security</category>
    </item>
    <item>
      <title>HTTP GET vs POST vs PUT vs PATCH vs DELETE</title>
      <dc:creator>Siddharth</dc:creator>
      <pubDate>Tue, 11 Nov 2025 06:02:16 +0000</pubDate>
      <link>https://dev.to/xceed/http-get-vs-post-vs-put-vs-patch-vs-delete-hnj</link>
      <guid>https://dev.to/xceed/http-get-vs-post-vs-put-vs-patch-vs-delete-hnj</guid>
      <description>&lt;h3&gt;
  
  
  &lt;strong&gt;1. GET&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Purpose:&lt;/strong&gt; Retrieve data from a server.&lt;br&gt;
&lt;strong&gt;Characteristics:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Safe &amp;amp; idempotent:&lt;/strong&gt; It doesn’t modify data on the server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cacheable:&lt;/strong&gt; Responses can be cached by browsers or CDNs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No body:&lt;/strong&gt; Parameters go in the &lt;strong&gt;URL query string&lt;/strong&gt; (&lt;code&gt;/users?id=123&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /users/123
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📦 Retrieves the user with ID 123.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;2. POST&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Purpose:&lt;/strong&gt; Create a new resource on the server.&lt;br&gt;
&lt;strong&gt;Characteristics:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Not idempotent:&lt;/strong&gt; Multiple identical requests may create multiple resources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Has a body:&lt;/strong&gt; Data (usually JSON) is sent in the request body.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Common for:&lt;/strong&gt; Creating items, submitting forms, authentication, uploads.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST /users
Content-Type: application/json

{
  "name": "Alice",
  "email": "alice@example.com"
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📦 Creates a new user record.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;3. PUT&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Purpose:&lt;/strong&gt; Replace an existing resource entirely.&lt;br&gt;
&lt;strong&gt;Characteristics:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Idempotent:&lt;/strong&gt; Sending the same request repeatedly results in the same outcome.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Requires full resource representation&lt;/strong&gt; — all fields, not just the ones you’re updating.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;PUT /users/123
Content-Type: application/json

{
  "name": "Alice Updated",
  "email": "alice@newdomain.com"
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📦 Replaces the entire user record for ID 123.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;4. PATCH&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Purpose:&lt;/strong&gt; Partially update a resource.&lt;br&gt;
&lt;strong&gt;Characteristics:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Idempotent (in theory):&lt;/strong&gt; Usually behaves as such if properly implemented.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Only includes the fields to change&lt;/strong&gt; in the request body.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;PATCH /users/123
Content-Type: application/json

{
  "email": "alice@newdomain.com"
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📦 Updates only the &lt;code&gt;email&lt;/code&gt; field for user 123.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;5. DELETE&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Purpose:&lt;/strong&gt; Remove a resource from the server.&lt;br&gt;
&lt;strong&gt;Characteristics:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Idempotent:&lt;/strong&gt; Repeated DELETEs have the same effect.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Usually no body.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;DELETE /users/123
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📦 Deletes the user with ID 123.&lt;/p&gt;




&lt;h3&gt;
  
  
  🧭 Summary Table
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Idempotent&lt;/th&gt;
&lt;th&gt;Safe&lt;/th&gt;
&lt;th&gt;Request Body&lt;/th&gt;
&lt;th&gt;Typical Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GET&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Retrieve&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;Fetch data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;POST&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Create&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Add new resource&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PUT&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Replace&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Full update&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PATCH&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Update&lt;/td&gt;
&lt;td&gt;✅ (mostly)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Partial update&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DELETE&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Remove&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌ (usually)&lt;/td&gt;
&lt;td&gt;Delete data&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🧭 Why HTTP verbs matter, why do I care (even if the SQL looks the same)?
&lt;/h2&gt;

&lt;p&gt;When building REST APIs in .NET, it might feel like &lt;code&gt;POST&lt;/code&gt;, &lt;code&gt;PUT&lt;/code&gt;, or &lt;code&gt;PATCH&lt;/code&gt; all do the same thing — after all, they can each trigger the same SQL &lt;code&gt;UPDATE&lt;/code&gt; statement.&lt;/p&gt;

&lt;p&gt;But the &lt;strong&gt;true power&lt;/strong&gt; of HTTP verbs isn’t about your SQL logic — it’s about how &lt;strong&gt;clients&lt;/strong&gt;, &lt;strong&gt;caches&lt;/strong&gt;, &lt;strong&gt;load balancers&lt;/strong&gt;, and &lt;strong&gt;tools&lt;/strong&gt; interpret your API’s &lt;em&gt;intent&lt;/em&gt;.  &lt;/p&gt;

&lt;p&gt;HTTP verbs define a &lt;strong&gt;contract&lt;/strong&gt; for how requests behave in terms of caching, retries, idempotency, and security. Think of HTTP verbs as &lt;strong&gt;contracts&lt;/strong&gt; between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clients&lt;/strong&gt; (browsers, mobile apps, other services),&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Servers&lt;/strong&gt; (your .NET API),&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intermediaries&lt;/strong&gt; (load balancers, caches, proxies, frameworks, monitoring tools).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They communicate &lt;strong&gt;intent&lt;/strong&gt;, not implementation.&lt;/p&gt;

&lt;p&gt;So while these verbs &lt;em&gt;can&lt;/em&gt; all trigger an &lt;code&gt;UPDATE&lt;/code&gt; in SQL, their &lt;strong&gt;meaning&lt;/strong&gt; in HTTP defines how the system behaves around that request — caching, retries, idempotency, logging, security, etc.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Example Scenario
&lt;/h2&gt;

&lt;p&gt;You have a SQL Server &lt;code&gt;Users&lt;/code&gt; table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;Email&lt;/span&gt; &lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fetch a user&lt;/li&gt;
&lt;li&gt;Create a user&lt;/li&gt;
&lt;li&gt;Replace a user&lt;/li&gt;
&lt;li&gt;Partially update a user’s email&lt;/li&gt;
&lt;li&gt;Delete a user&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🚀 RESTful API Design
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;HTTP Verb&lt;/th&gt;
&lt;th&gt;Endpoint&lt;/th&gt;
&lt;th&gt;Request Body&lt;/th&gt;
&lt;th&gt;Behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Fetch user&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/api/users/123&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;td&gt;Returns JSON for user 123&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Create new user&lt;/td&gt;
&lt;td&gt;&lt;code&gt;POST&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/api/users&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ "name": "Alice", "email": "a@b.com" }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Creates new user (auto-generated ID)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Replace entire user&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PUT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/api/users/123&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ "name": "Alice", "email": "new@b.com" }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Replaces user 123’s record entirely&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Update only email&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PATCH&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/api/users/123&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ "email": "new@b.com" }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Updates just the email&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delete user&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DELETE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/api/users/123&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;td&gt;Deletes user 123&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  ⚡ When the Difference Matters
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Why Verb Matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Retry Logic&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;PUT&lt;/code&gt; and &lt;code&gt;DELETE&lt;/code&gt; are idempotent — safe to retry after a timeout. &lt;code&gt;POST&lt;/code&gt; might create duplicates.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Caching&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;GET&lt;/code&gt; responses can be cached. &lt;code&gt;POST&lt;/code&gt; and &lt;code&gt;PATCH&lt;/code&gt; cannot.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Proxy/CDN Behavior&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;CDNs can cache &lt;code&gt;GET&lt;/code&gt; and invalidate caches after &lt;code&gt;PUT&lt;/code&gt;, &lt;code&gt;PATCH&lt;/code&gt;, or &lt;code&gt;DELETE&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Documentation &amp;amp; SDKs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Tools like Swagger/OpenAPI generate correct docs and client SDKs when verbs are semantically correct.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You can enforce different permissions (e.g., &lt;code&gt;GET&lt;/code&gt; public, &lt;code&gt;PUT&lt;/code&gt; requires &lt;code&gt;Admin&lt;/code&gt;).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Monitoring&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Logs make more sense (&lt;code&gt;DELETE /users&lt;/code&gt; → “user deletions”) when verbs match actions.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🧩 Example: Retrying Requests
&lt;/h2&gt;

&lt;p&gt;If a frontend app calls:&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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/users/123&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="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PUT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a@b.com&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the request times out, the client can safely retry because &lt;strong&gt;PUT is idempotent&lt;/strong&gt; — sending it twice has the same effect.&lt;/p&gt;

&lt;p&gt;If it were a &lt;strong&gt;POST&lt;/strong&gt;, two requests might create &lt;strong&gt;duplicate users&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ Summary
&lt;/h2&gt;

&lt;p&gt;Even though the internal logic (e.g., SQL &lt;code&gt;UPDATE&lt;/code&gt;) might be identical:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;POST&lt;/code&gt; → &lt;em&gt;create new resource&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PUT&lt;/code&gt; → &lt;em&gt;replace resource entirely&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PATCH&lt;/code&gt; → &lt;em&gt;partially update resource&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DELETE&lt;/code&gt; → &lt;em&gt;remove resource&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET&lt;/code&gt; → &lt;em&gt;retrieve resource&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using the correct HTTP verbs gives your API:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Predictable behavior&lt;/li&gt;
&lt;li&gt;Correct retry &amp;amp; caching semantics&lt;/li&gt;
&lt;li&gt;Better documentation and tooling&lt;/li&gt;
&lt;li&gt;Compatibility with clients, proxies, and REST conventions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🧠 Tip
&lt;/h2&gt;

&lt;p&gt;You can combine this with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model validation&lt;/strong&gt; (to verify email format)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ETags or RowVersion&lt;/strong&gt; for concurrency control&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Global exception filters&lt;/strong&gt; for consistent responses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where REST verbs and database logic truly complement each other.&lt;/p&gt;

</description>
      <category>api</category>
      <category>beginners</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Writing XUnit Tests without Object Arrays</title>
      <dc:creator>Siddharth</dc:creator>
      <pubDate>Sat, 12 Oct 2024 14:30:17 +0000</pubDate>
      <link>https://dev.to/xceed/writing-xunit-tests-without-object-arrays-clean-and-scalable-test-data-jk</link>
      <guid>https://dev.to/xceed/writing-xunit-tests-without-object-arrays-clean-and-scalable-test-data-jk</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;In unit testing with XUnit, we often use object arrays for test data. However, managing complex test data can quickly become cumbersome and hard to read. In this post, we’ll explore how to write cleaner and more scalable XUnit tests using &lt;code&gt;TheoryData&amp;lt;T&amp;gt;&lt;/code&gt; without relying on &lt;code&gt;object[]&lt;/code&gt; arrays.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example Scenario: Retrieving Food by Type
&lt;/h3&gt;

&lt;p&gt;Let's implement a &lt;code&gt;FoodService&lt;/code&gt; class with a method that retrieves food items by type.&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;FoodType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Fruit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Fast&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;IFoodService&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;IEnumerable&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="nf"&gt;GetByType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FoodType&lt;/span&gt; &lt;span class="n"&gt;type&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="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FoodService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IFoodService&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;IEnumerable&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="nf"&gt;GetByType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FoodType&lt;/span&gt; &lt;span class="n"&gt;type&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;type&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;FoodType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fruit&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Apple"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Banana"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;FoodType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fast&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Pizza"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Burger"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&amp;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;NotImplementedException&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;Here, we use &lt;code&gt;TheoryData&amp;lt;T&amp;gt;&lt;/code&gt; to hold our test cases, defining a &lt;code&gt;FoodTestData&lt;/code&gt; record that includes input parameters, expected results, and a custom name for each test case:&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;FoodTests&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// override ToString method allow us to specify name for individual tests in TheoryData&amp;lt;T&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;FoodTestData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FoodType&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&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;Expected&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;TestName&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="k"&gt;override&lt;/span&gt; &lt;span class="kt"&gt;string&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;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;TestName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// this method has the input parameters and expected values. we can scale this method with more tests without changes the test itself.&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;TheoryData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FoodTestData&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetFoodTestData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&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;Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;FoodType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fruit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Expected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Apple"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"Banana"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;TestName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Test should return expected fruits"&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;Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;FoodType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fast&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Expected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Pizza"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"Burger"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;TestName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Test should return expected fast food"&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="n"&gt;Theory&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;MemberData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GetFoodTestData&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;void&lt;/span&gt; &lt;span class="nf"&gt;ShouldReturnExpectedFood&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FoodTestData&lt;/span&gt; &lt;span class="n"&gt;foodTestData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Arrange&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;mockFoodService&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;Mock&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IFoodService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
        &lt;span class="n"&gt;mockFoodService&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetByType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FoodType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fruit&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Returns&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s"&gt;"Apple"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Banana"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="c1"&gt;// Act&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;food&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;FoodService&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;GetByType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;foodTestData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Assert&lt;/span&gt;
        &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;foodTestData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;food&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;
  
  
  Output
&lt;/h3&gt;

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

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

&lt;p&gt;Using &lt;code&gt;TheoryData&amp;lt;T&amp;gt;&lt;/code&gt; with a named record keeps our tests clean, easy to read, and scalable for future test cases. &lt;/p&gt;

&lt;p&gt;Thank you for reading.&lt;/p&gt;

</description>
      <category>unittest</category>
      <category>xunit</category>
    </item>
    <item>
      <title>.NET Configuration</title>
      <dc:creator>Siddharth</dc:creator>
      <pubDate>Thu, 26 Jan 2023 08:39:29 +0000</pubDate>
      <link>https://dev.to/xceed/simplified-net-core-basics-configurations-579c</link>
      <guid>https://dev.to/xceed/simplified-net-core-basics-configurations-579c</guid>
      <description>&lt;p&gt;Configuring .NET apps can be confusing with all the different options available. We have different types of apps like Web APIs, Background Service and Console app etc. which can run on different .NET versions or environments and setting them up with correct configurations can be overwhelming.&lt;/p&gt;

&lt;p&gt;I want to share what I learned that helped me understand how all the different configurations fit together and make sense of it all. &lt;/p&gt;

&lt;p&gt;Before we start let's first understand .NET project SDK which is a base for different types of configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  .NET project SDK
&lt;/h3&gt;

&lt;p&gt;.NET Core, .NET 5 and later projects are associated with a SDK (Software Development Kit). It is responsible for compiling, packing and publishing code. SDK contains .NET CLI, runtime and libraries.&lt;/p&gt;

&lt;p&gt;We can target SDK in project file to configure different types of .NET apps.&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;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Project&lt;/span&gt; &lt;span class="n"&gt;Sdk&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.NET.Sdk"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;Project&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Available SDKs
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ID&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Microsoft.NET.Sdk&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The .NET SDK. This is the base SDK for all other SDKs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Microsoft.NET.Sdk.Web&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The .NET &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/razor-pages/web-sdk" rel="noopener noreferrer"&gt;Web SDK&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Microsoft.NET.Sdk.BlazorWebAssembly&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The .NET &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/blazor#blazor-webassembly" rel="noopener noreferrer"&gt;Blazor WebAssembly&lt;/a&gt; SDK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Microsoft.NET.Sdk.Razor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The .NET &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/razor-pages/sdk" rel="noopener noreferrer"&gt;Razor SDK&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Microsoft.NET.Sdk.Worker&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The .NET &lt;a href="https://learn.microsoft.com/en-us/dotnet/core/extensions/workers" rel="noopener noreferrer"&gt;Worker Service&lt;/a&gt; SDK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Microsoft.NET.Sdk.WindowsDesktop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The .NET &lt;a href="https://learn.microsoft.com/en-us/dotnet/core/project-sdk/msbuild-props-desktop" rel="noopener noreferrer"&gt;Desktop SDK&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  ASP.NET Core apps
&lt;/h2&gt;

&lt;p&gt;ASP.NET Core is composed of several building blocks. These blocks can be configured to suit the requirements and shape the overall configuration of the application. We are going to look at some of the important blocks.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Host&lt;/li&gt;
&lt;li&gt;Dependency Injection&lt;/li&gt;
&lt;li&gt;Middlewares&lt;/li&gt;
&lt;li&gt;Configuration&lt;/li&gt;
&lt;li&gt;Environments&lt;/li&gt;
&lt;li&gt;Logging&lt;/li&gt;
&lt;li&gt;HttpContext&lt;/li&gt;
&lt;li&gt;Routing&lt;/li&gt;
&lt;li&gt;Server&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Host
&lt;/h3&gt;

&lt;p&gt;The Host, also referred as Host builder or builder, is the first step in configuration. It is used to configure app and its services. Host contains all resources of an app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An HTTP server implementation&lt;/li&gt;
&lt;li&gt;Middleware components&lt;/li&gt;
&lt;li&gt;Logging&lt;/li&gt;
&lt;li&gt;Dependency injection (DI) services&lt;/li&gt;
&lt;li&gt;Configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are three types of hosts you can choose which depends on the .NET project SDK:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ASP.NET Core Web Host&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Exists only for backward compatibility&lt;/li&gt;
&lt;li&gt;Supports .NET Core 2.x Apps&lt;/li&gt;
&lt;li&gt;Uses &lt;code&gt;WebHost.CreateDefaultBuilder()&lt;/code&gt; to create builder&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;.NET Generic Host&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Available in all .NET SDKs&lt;/li&gt;
&lt;li&gt;Supports ASP.NET Core 3.x and .NET 5 Apps&lt;/li&gt;
&lt;li&gt;Uses &lt;code&gt;Host.CreateDefaultBuilder()&lt;/code&gt; to create builder&lt;/li&gt;
&lt;li&gt;More info: &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/web-host?view=aspnetcore-7.0#set-up-a-host" rel="noopener noreferrer"&gt;.NET Generic Host&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;.NET WebApplication Host&lt;/strong&gt; also known as Minimal Host

&lt;ul&gt;
&lt;li&gt;Simplified version of .NET Generic Host&lt;/li&gt;
&lt;li&gt;It provides some of the default configuration and hence significantly reduces the number of files and lines of code to configure an app. &lt;/li&gt;
&lt;li&gt;Available only in &lt;code&gt;Microsoft.NET.Sdk.Web&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Supports .NET 6 Apps &lt;/li&gt;
&lt;li&gt;Uses &lt;code&gt;WebApplication.CreateBuilder()&lt;/code&gt; to create builder&lt;/li&gt;
&lt;li&gt;More info: &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/web-host?view=aspnetcore-7.0" rel="noopener noreferrer"&gt;.NET Web Host&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The following example configures apps and services using .NET Generic host:&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;Program&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;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="c1"&gt;// create host and run app&lt;/span&gt;
        &lt;span class="nf"&gt;CreateHostBuilder&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="nf"&gt;ConfigureHostConfiguration&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;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetBasePath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Directory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetCurrentDirectory&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&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="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;IHostBuilder&lt;/span&gt; &lt;span class="nf"&gt;CreateHostBuilder&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;=&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateDefaultBuilder&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="nf"&gt;ConfigureWebHostDefaults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;webBuilder&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;webBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseStartup&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Startup&lt;/span&gt;&lt;span class="p"&gt;&amp;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;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Startup&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;IConfiguration&lt;/span&gt; &lt;span class="n"&gt;Configuration&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="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Startup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IConfiguration&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;)&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="n"&gt;configuration&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 services&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ConfigureServices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IServiceCollection&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;)&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;AddScoped&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IGitHubService&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GitHubService&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;AddScoped&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ISlackService&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SlackService&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 app&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Configure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IApplicationBuilder&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;IWebHostEnvironment&lt;/span&gt; &lt;span class="n"&gt;env&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;UseRouting&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;UseAuthentication&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="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;Same configuration but with WebApplication host:&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;// create host&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;// configure services&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;AddScoped&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IGitHubService&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GitHubService&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;AddScoped&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ISlackService&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SlackService&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;// configure app&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;UseRouting&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;UseAuthentication&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="c1"&gt;// runs app after configuration&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;RunAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Dependency Injection (services)
&lt;/h3&gt;

&lt;p&gt;ASP.NET Core includes dependency injection (DI) that makes configured services available throughout an app. Services are added to the DI container using WebApplicationBuilder.Services (builder.Services). When the builder is instantiated, many &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-7.0#framework-provided-services" rel="noopener noreferrer"&gt;framework-provided services&lt;/a&gt; are added by default.&lt;/p&gt;

&lt;p&gt;Example&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="nf"&gt;AddRazorPages&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;AddControllersWithViews&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;AddScoped&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IContactRepository&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ContactRepository&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As services are add to DI container, we can resolve these services using constructor.&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;Contact&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;readonly&lt;/span&gt; &lt;span class="n"&gt;IContactRepository&lt;/span&gt; &lt;span class="n"&gt;_contactRepository&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;Contact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IContactRepository&lt;/span&gt; &lt;span class="n"&gt;contactRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_contactRepository&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;contactRepository&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="n"&gt;Contact&lt;/span&gt; &lt;span class="nf"&gt;Get&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;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_contactRepository&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="n"&gt;id&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;
  
  
  Middleware
&lt;/h3&gt;

&lt;p&gt;In simple terms, middleware is a set of tools that connects different parts of an application and allows them to work together. When the application gets a request, the middleware receives it first and directs it to the right place in the application.&lt;/p&gt;

&lt;p&gt;In the configuration, we can add series of middleware in request pipeline. These middleware are chained together. In even of an incoming request, each middleware in sequence - &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chooses whether to pass the request to the next middleware.&lt;/li&gt;
&lt;li&gt;It can perform its operation before and after the next middleware.&lt;/li&gt;
&lt;/ul&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%2Fnt7sfjrjs4rwezfb544n.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%2Fnt7sfjrjs4rwezfb544n.png" alt="How middleware works" width="600" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By convention, a middleware is invoked by an extension method starts with "Use" keyword. Sequence is the order middleware are defined. "Run" or "RunAsync" method in the last terminates the request.&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;// create host&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;// configure services&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;AddScoped&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IContactRepository&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ContactRepository&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// configure app&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;UseExceptionHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/Error"&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="c1"&gt;// custom middleware&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;Use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Do work that can write to the Response.&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Invoke&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// Do logging or other work that doesn't write to the Response.&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// terminates the request&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;From here on things are easy if you understand SDKs, Hosts, DI &amp;amp; Middleware. Let's check rest of the building blocks quickly -&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;

&lt;p&gt;ASP.NET Core apps provides configuration framework. It get settings in key-value pairs. It has many built-in configuration providers which gets settings/configurations from different sources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Settings files, such as &lt;code&gt;appsettings.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Environment variables&lt;/li&gt;
&lt;li&gt;Azure Key Vault&lt;/li&gt;
&lt;li&gt;Azure App Configuration&lt;/li&gt;
&lt;li&gt;Command-line arguments&lt;/li&gt;
&lt;li&gt;Custom providers, installed or created&lt;/li&gt;
&lt;li&gt;Directory files&lt;/li&gt;
&lt;li&gt;In-memory .NET objects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can use host/builder to configuration from multiple sources.&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;// Services&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;settings&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;GetSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Settings"&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;Configure&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Settings&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;settings&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&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;UseRouting&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;UseAuthentication&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="c1"&gt;// Terminates request&lt;/span&gt;
&lt;span class="k"&gt;await&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;RunAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Environments
&lt;/h3&gt;

&lt;p&gt;Set the &lt;code&gt;ASPNETCORE_ENVIRONMENT&lt;/code&gt; environment variable to your environment name and access it using Host Builder. By default &lt;code&gt;Development&lt;/code&gt;, &lt;code&gt;Staging&lt;/code&gt; and &lt;code&gt;Production&lt;/code&gt; values are supported .NET configuration.&lt;/p&gt;

&lt;p&gt;ASP.NET Core reads that environment variable at app startup and stores the value in an &lt;code&gt;IWebHostEnvironment&lt;/code&gt; implementation. This implementation is available anywhere in an app via dependency injection (DI).&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="nf"&gt;AddRazorPages&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;AddControllersWithViews&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;UseExceptionHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/Error"&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;UseHsts&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;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Logging
&lt;/h3&gt;

&lt;p&gt;ASP.NET Core supports variety of &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-7.0#bilp" rel="noopener noreferrer"&gt;built-in&lt;/a&gt; and &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-7.0#third-party-logging-providers" rel="noopener noreferrer"&gt;third-party&lt;/a&gt; logging providers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Console&lt;/li&gt;
&lt;li&gt;Debug&lt;/li&gt;
&lt;li&gt;Event Tracing on Windows&lt;/li&gt;
&lt;li&gt;Windows Event Log&lt;/li&gt;
&lt;li&gt;TraceSource&lt;/li&gt;
&lt;li&gt;Azure App Service&lt;/li&gt;
&lt;li&gt;Azure Application Insights&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you create a building using &lt;code&gt;WebApplication.CreateBuilder&lt;/code&gt; it adds Console, Debug, EventSource and EventLog by default. You can reconfigure logging providers using Host builder.&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;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;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Final thoughts
&lt;/h3&gt;

&lt;p&gt;If we rethink the structure of the ASP.NET core building blocks it looks something like this -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- .NET project SDK
  - Host (builder)
    - Dependency Injection (builder.Services)
    - Configuration (builder.Configuration)
    - Logging (builder.Logging)
    - App (builder.Build())
      - Middlewares (app.Use{ExtensionMethod})
      - Environments (app.Environment)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope this helps to clear confusion. Thanks for reading!&lt;/p&gt;




&lt;h4&gt;
  
  
  References
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/?view=aspnetcore-7.0&amp;amp;tabs=windows" rel="noopener noreferrer"&gt;ASP.NET Core fundamentals overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/core/project-sdk/overview" rel="noopener noreferrer"&gt;.NET project SDKs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://andrewlock.net/exploring-dotnet-6-part-2-comparing-webapplicationbuilder-to-the-generic-host/" rel="noopener noreferrer"&gt;Comparing WebApplicationBuilder to the Generic Host&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>Understanding Git Rebase</title>
      <dc:creator>Siddharth</dc:creator>
      <pubDate>Fri, 25 Nov 2022 17:21:17 +0000</pubDate>
      <link>https://dev.to/xceed/git-rebase-3emg</link>
      <guid>https://dev.to/xceed/git-rebase-3emg</guid>
      <description>&lt;p&gt;Understanding git rebase is confusing when you start working with it. Here's how I understand Git Rebase.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Rebase
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Git Merge and Git Rebase does the same thing - both can pull changes from other branches. But Rebase works little different from Merge.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  ELI5 version
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;h4&gt;
  
  
  Git Rebase
&lt;/h4&gt;

&lt;p&gt;You are about to travel for few days so you start packing bags. You put your t-shirts, charger, headphones, toothbrush etc. Your friend is about to come at your place to drop you at railway station. Your friend bought a gift for you - a new shiny jeans. You want to put the jeans below all of your cloths therefore you pull all your cloths from bag/suitcase, put jeans and put back your cloths. This is basically rebase.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;items in bag is your feature branch&lt;/li&gt;
&lt;li&gt;new blue jeans is your master branch&lt;/li&gt;
&lt;li&gt;when you reshuffle cloths to put new jeans below other cloths is git rebase&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Git Rebase Vs Git Merge
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;in &lt;code&gt;git rebase&lt;/code&gt; you add more cloths to your base as you receive them. so it is properly organized and easy to pull cloths, easy to manage.&lt;/li&gt;
&lt;li&gt;in &lt;code&gt;git merge&lt;/code&gt; you are lazy - you put that jeans and any other item on top of your bag as you receive them. This is hard to pull specific things when you need them, results merge conflicts often complex one and overall hard to manage.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  How Rebase works
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Let's say you create a new branch &lt;code&gt;feature/contact-us-page&lt;/code&gt; from &lt;code&gt;master&lt;/code&gt; branch. While you are working on your feature the master branch gets updated with new features.&lt;/p&gt;

&lt;p&gt;Consider following history of feature and master branch&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;feature/contact-us-page&lt;/th&gt;
&lt;th&gt;master&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;commit 102&lt;/td&gt;
&lt;td&gt;commit 106 Merge branch home-page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;commit 101&lt;/td&gt;
&lt;td&gt;commit 105 Merge branch about-us-page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;commit 100&lt;/td&gt;
&lt;td&gt;commit 104 Merge branch login-page&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;When you run &lt;code&gt;git rebase master&lt;/code&gt; on your branch, it pulls changes from master and move them below your current branch changes. Here's how your feature branch commit will look&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;feature/contact-us-page&lt;/th&gt;
&lt;th&gt;master&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;commit 102&lt;/td&gt;
&lt;td&gt;commit 106 Merge branch home-page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;commit 101&lt;/td&gt;
&lt;td&gt;commit 105 Merge branch about-us-page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;commit 100&lt;/td&gt;
&lt;td&gt;commit 104 Merge branch login-page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;commit 106 Merge branch home-page&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;commit 105 Merge branch about-us-page&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;commit 104 Merge branch login-page&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Master branch history when you merge your branch into master using merge strategy&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;master&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;commit 102&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;commit 101&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;commit 100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;commit 106 Merge branch home-page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;commit 105 Merge branch about-us-page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;commit 104 Merge branch login-page&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  VS how Merge works
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;When you run &lt;code&gt;git merge master&lt;/code&gt; on your branch, it pulls changes from master and move them into a new commit. This new commit is on top of your changes. Here's how your feature branch commit will look after git merge -&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;feature/contact-us-page&lt;/th&gt;
&lt;th&gt;master&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;commit 107 Merge branch master&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;commit 102&lt;/td&gt;
&lt;td&gt;commit 106 Merge branch home-page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;commit 101&lt;/td&gt;
&lt;td&gt;commit 105 Merge branch about-us-page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;commit 100&lt;/td&gt;
&lt;td&gt;commit 104 Merge branch login-page&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Important thing to note here is &lt;code&gt;commit 106 feature/home-page&lt;/code&gt;, &lt;code&gt;commit 105 feature/about-us-page&lt;/code&gt; and &lt;code&gt;commit 104 feature/login-page&lt;/code&gt; are still present in &lt;code&gt;commit 107 merge commit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Master branch history when you merge your branch into master using merge strategy&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;master&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;commit 107 Merge branch master&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;commit 106 Merge branch home-page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;commit 105 Merge branch about-us-page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;commit 104 Merge branch login-page&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Rules for Rebasing
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;When not to do Rebase - Always rebase on your own branch. Never use it on public branches&lt;/li&gt;
&lt;li&gt;Force Push with Caution - When you rebase, git pulls latest changes and move it below your changes. It basically rewrites your history. To push changes to origin you need to do force push - &lt;code&gt;git push --force&lt;/code&gt;. &lt;strong&gt;Please be very careful&lt;/strong&gt;, if you push on some other branch, it will rewrite history of that branch and there is no way to revert it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Benefits of Rebasing over Merge
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;You will get much cleaner history&lt;/li&gt;
&lt;li&gt;Reverting changes or whole branch is a lot easier because you are always dealing with simple commits. In Merge you deal with merge commits which has other commits.&lt;/li&gt;
&lt;li&gt;You won't get bigger merge conflicts&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;




&lt;h4&gt;
  
  
  Finally, thank you for reading. I hope it helps you with Rebase.
&lt;/h4&gt;

</description>
      <category>git</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Delegates - Behind The Scenes</title>
      <dc:creator>Siddharth</dc:creator>
      <pubDate>Sun, 22 May 2022 05:53:35 +0000</pubDate>
      <link>https://dev.to/xceed/delegates-behind-the-scenes-5ail</link>
      <guid>https://dev.to/xceed/delegates-behind-the-scenes-5ail</guid>
      <description>&lt;p&gt;Let's say we want to filter even numbers. In C#, we usually do it using LINQ's &lt;code&gt;Where&lt;/code&gt; extension -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var numbers = Enumerable.Range(1, 100);
var evenNumbers = numbers.Where(n =&amp;gt; n % 2 == 0);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The signature of &lt;code&gt;Where&lt;/code&gt; takes &lt;code&gt;Func&amp;lt;int, bool&amp;gt;&lt;/code&gt; as parameter&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--51R4fxtI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yej2us7p9r4kx16azrei.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--51R4fxtI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yej2us7p9r4kx16azrei.png" alt="Signature of LINQ's Where extension method" width="749" height="168"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The syntactic sugar, behind the scenes, is basically doing&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var evenNumbers = numbers.Where(new Func&amp;lt;int, bool&amp;gt;(n =&amp;gt; n % 2 == 0));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Func is a delegate which has &lt;code&gt;int&lt;/code&gt; as input and &lt;code&gt;bool&lt;/code&gt; as output. We can write it as -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var evenNumbers = numbers.Where(delegate(int n)
{
    return n % 2 == 0;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means we can do -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public static bool IsEven(int number)
{
    return number % 2 == 0;
}
var evenNumbers = numbers.Where(IsEven);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>csharp</category>
    </item>
    <item>
      <title>AdGuard Home as Private DNS Server on Raspberry Pi</title>
      <dc:creator>Siddharth</dc:creator>
      <pubDate>Wed, 26 Jan 2022 07:14:29 +0000</pubDate>
      <link>https://dev.to/xceed/accessing-agh-outside-network-g97</link>
      <guid>https://dev.to/xceed/accessing-agh-outside-network-g97</guid>
      <description>&lt;p&gt;To access AGH outside network and to use it as a private DNS server, we need 3 things -&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Domain&lt;/li&gt;
&lt;li&gt;TLS Certificate&lt;/li&gt;
&lt;li&gt;Port forwarding&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Registering Domain
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You can register domain from any website, however, one of the free option is to use duckdns.org. Create account, add a sub-domain to your account.&lt;/li&gt;
&lt;li&gt;You need to attach your public IP address to the domain you have created. You can use whatismyip.com to find your public IP address.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Obtaining TLS Certificate
&lt;/h3&gt;

&lt;p&gt;Encryption is based on TLS certificate and it is needed to use AGH as a private DNS server which is accessible outside your home network. We can obtain TLS certificate for free using letsencrypt.org.&lt;/p&gt;

&lt;h4&gt;
  
  
  Install Certbot
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt update
sudo apt install certbot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Get a certificate using DNS challenge
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Start issuing certificate&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo certbot certonly --manual --preferred-challenges=dns -- preferred-chain="ISRG Root X1"
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enter the domain you've registered on DuckDns.org. After this step -- DO NOT press continue until you add DNS challenge record to your domain.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add DNS challenge to your domain by visiting the following URL -&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://www.duckdns.org/update?domains={DOMAIN}&amp;amp;token={TOKEN}&amp;amp;txt={TXT_VALUE}
&lt;/code&gt;&lt;/pre&gt;

&lt;h6&gt;
  
  
  Here, DOMAIN is your domain.duckdns.org. TOKEN you can find in home page of DuckDns. TXT_VALUE is the verification string in terminal generated using certbot command.
&lt;/h6&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Press enter to continue and verify the ownership of the domain.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After successful verification, &lt;code&gt;fullchain.pem&lt;/code&gt; and &lt;code&gt;privkey.pem&lt;/code&gt; files will be generated for your domain. Please note down the path of both of these files.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Enable Encryption in AdGuard Home
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to AGH &amp;gt; Settings &amp;gt; Encryption Settings&lt;/li&gt;
&lt;li&gt;Enable Encryption checkbox&lt;/li&gt;
&lt;li&gt;Enter your duckdns domain in Server Name&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;fullchain.pem&lt;/code&gt; file path in Certificate section. After adding status should be "Certificate chain is valid"&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;privkey.pem&lt;/code&gt; file path in Private key section. After adding status should be "This is a valid RSA private key"&lt;/li&gt;
&lt;li&gt;Save Configuration&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Port Forwarding
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Encrypted traffic needs reaches to AGH server and for that port needs to be forwarded. I recommend to forward all ports but you can forward the port based on your need. Forwarding different ports enables different "feature". Here's quick summary -

&lt;ul&gt;
&lt;li&gt;HTTPS port (443) - When you forward HTTPS port, you can access AGH Dashboard using &lt;code&gt;https://{your-domain}.duckdns.org&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;DNS-over-TLS port (853) - Forwarding this port enables you to use AGH as private DNS service in mobile devices outside your home network.&lt;/li&gt;
&lt;li&gt;DNS-over-QUIC port (784) - Forwarding this port enables the devices to use DNS-over-QUIC as private DNS server.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Forwarding port on Router

&lt;ul&gt;
&lt;li&gt;Login to router and find port forward / virtual servers settings&lt;/li&gt;
&lt;li&gt;Depending on your router you will have combination of these probably with different names for External IP, External Port, Internal IP and Internal Port.&lt;/li&gt;
&lt;li&gt;External IP is your public IP address, Internal IP is your Raspberry Pi address and internal/external port will be (443, 853 or 784). Save settings for each port to enable port forwarding.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Use as private DNS
&lt;/h3&gt;

&lt;p&gt;If all steps are successful, you can use &lt;code&gt;https://{your-domain}.duckdns.org&lt;/code&gt; to visit AGH server from any network. You can also configure &lt;code&gt;{your-domain}.duckdns.org&lt;/code&gt; as private DNS on various devices.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Configure AdGuard Home with Raspberry Pi</title>
      <dc:creator>Siddharth</dc:creator>
      <pubDate>Wed, 26 Jan 2022 07:14:07 +0000</pubDate>
      <link>https://dev.to/xceed/configure-adguard-home-with-raspberry-pi-jpj</link>
      <guid>https://dev.to/xceed/configure-adguard-home-with-raspberry-pi-jpj</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4qTrSkkN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r5aqdwol7d817gnm15q3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4qTrSkkN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r5aqdwol7d817gnm15q3.png" alt="AdGuard Home" width="880" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Intro
&lt;/h3&gt;

&lt;p&gt;I was using &lt;a href="https://dev.to/xceed/taking-control-of-privacy-using-nextdns-1gde"&gt;NextDNS&lt;/a&gt; for couple months and recently switched to AdGaurd Home as it is more advanced. It's bit more complex to setup as compare to NextDNS. I have faced many challenges while configuring with Raspberry Pi, however, struggling for a day or two I am finally able to configure it. Hence, thought to create a step-by-step guide hoping this might help someone facing similar issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  AdGuard Home (AGH)
&lt;/h3&gt;

&lt;p&gt;It's a free and open source, network-wide software for blocking ads &amp;amp; tracking. After you set up, it'll cover all your devices without needing any client-side software. You can read more about AdGuard Home at &lt;a href="https://adguard.com/en/adguard-home/overview.html"&gt;https://adguard.com/en/adguard-home/overview.html&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Go to &lt;a href="https://github.com/AdguardTeam/AdGuardHome/releases"&gt;release page&lt;/a&gt;, download and unpack binaries on your pi using following command -&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wget 'https://static.adguard.com/adguardhome/release/AdGuardHome_linux_armv6.tar.gz'
tar -f AdGuardHome_linux_armv6.tar.gz -x -v
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;blockquote&gt;
&lt;p&gt;Below commands will install AGH as a service so if your pi restart it will start automatically.&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ./AdGuardHome/
sudo ./AdGuardHome -s install
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;blockquote&gt;
&lt;p&gt;Here are the other commands you might need to control the service:&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AdGuardHome -s uninstall: uninstall the AdGuard Home service.
AdGuardHome -s start: start the service.
AdGuardHome -s stop: stop the service.
AdGuardHome -s restart: restart the service.
AdGuardHome -s status: show the current service status.
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Initial Setup
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;By default AGH runs on port 53, hence you can start initial setup by visiting &lt;code&gt;{raspberrypi-ip-address}:53&lt;/code&gt; from any device in your network. Once you complete the initial setup you will be redirected to Dashboard.&lt;/p&gt;

&lt;p&gt;You can test your setup by visiting some website or running following command to test and dashboard on AGH will show data -&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nslookup github.com {raspberrypi-ip-address}
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Configure AGH on Router
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Get the AGH listening IP address (usually device IP where AGH is running) from Setup Guide tab&lt;/li&gt;
&lt;li&gt;Login to your router and add your Raspberry-Pi IP address as primary DNS server. If your router, doesn't allow you to add IP from same subnet, you can add Primary DNS in DHCP Server settings and it should work.&lt;/li&gt;
&lt;li&gt;That's it. Traffic from devices in your network should appear in AGH Dashboard.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Upstream &amp;amp; Bootstrap DNS
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;AGH works as a proxy, therefore, you can redirect unblocked traffic to your favorite DNS servers. Upstream DNS providers will handle your traffic and Bootstrap DNS will be used to resolve upstream DNS providers. &lt;/p&gt;

&lt;p&gt;It's super easy to configure Upstream and Bootstrap DNS servers. Pick one or more &lt;a href="https://kb.adguard.com/general/dns-providers"&gt;DNS server providers&lt;/a&gt; and add them to ADH &amp;gt; Settings &amp;gt; DNS Settings &amp;gt; Upstream and Bootstrap DNS section. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  DNS Blocklist
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Now you can go to Filter &amp;gt; DNS Blocklist and select predefined blocklists to add them and AGH will start blocking ads and tracking domain.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
    </item>
    <item>
      <title>How I send a gift coupon to my nerdy friend </title>
      <dc:creator>Siddharth</dc:creator>
      <pubDate>Fri, 26 Nov 2021 21:49:53 +0000</pubDate>
      <link>https://dev.to/xceed/how-i-send-a-gift-coupon-to-my-nerdy-friend-11b2</link>
      <guid>https://dev.to/xceed/how-i-send-a-gift-coupon-to-my-nerdy-friend-11b2</guid>
      <description>&lt;h3&gt;
  
  
  Context
&lt;/h3&gt;

&lt;p&gt;Our company has organized "Secret Santa", pre-covid times. I got the name of a nerdy colleague and a friend. I decided to gift him Amazon gift coupon. Like people usually do - hiding gift somewhere in desk, I instead created an online puzzle like a treasure hunt using some automation. If he solves he will receive gift on his email.&lt;/p&gt;

&lt;h3&gt;
  
  
  Starting Point
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Printed a bar code on a paper and put it on my friend's workstation desk. Upon scanning, it redirects to a simple website I've created using wixsite.com.
Here's the picture of printed barcode along with other gifts -
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uy2Zd1qA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5wpvr5si0a63vaula843.jpg" alt="gifts" width="880" height="660"&gt;
&lt;/li&gt;
&lt;li&gt;The landing page shows following instruction -
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--amOaOTiB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k4i4vqic0edw0pytki5v.png" alt="landing-page" width="597" height="280"&gt; &lt;/li&gt;
&lt;li&gt;To get your gift all you need is an email address.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Don't scroll! Take the challenge
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Before I tell you more, why don't you give a try yourself to find the email address? Here's the link after scanning barcode - &lt;a href="https://turantsephele.wixsite.com/giftgenerator"&gt;https://turantsephele.wixsite.com/giftgenerator&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;S&lt;br&gt;
C&lt;br&gt;
R&lt;br&gt;
O&lt;br&gt;
L&lt;br&gt;
L&lt;/p&gt;

&lt;p&gt;T&lt;br&gt;
O&lt;/p&gt;

&lt;p&gt;S&lt;br&gt;
E&lt;br&gt;
E&lt;/p&gt;

&lt;p&gt;N&lt;br&gt;
E&lt;br&gt;
X&lt;br&gt;
T&lt;/p&gt;

&lt;p&gt;S&lt;br&gt;
T&lt;br&gt;
E&lt;br&gt;
P&lt;br&gt;
S&lt;/p&gt;

&lt;h3&gt;
  
  
  Finding hints to find the email address
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Once you click "Get email address", it redirects you to another page which shows a timer and nothing else. And with a small hidden button somewhere in page.&lt;/li&gt;
&lt;li&gt;If you are able to find the button and click, it redirects you to &lt;a href="http://fatiherikli.github.io/brainfuck-visualizer/#KysrKysrKysrKwpbCj4rKysrKwo+KysrKysrCj4rKysrKysrCj4rKysrKysrKysrCj4rKysrKysrKysrKwo8PDw8PC0KXQo+Pj4tLS4+Ky4tLS4+Ky48Ky4rLjw8PCsrKysrKysrLi0tLS4tLS0uKysrLi0tLisrLgotLS0tLS4rKysrLi0tLS0tLisrKysrLj4+Pi48PDwrLgotLS0uKysrLi0tLS0uKysrLi0uKysuLS0tLS0tLS4rKysrKysuCisrLi0tLi0uKy4+Pj4tLS48PDwuLS4tLi0tLS0uKysrKysrLisuLS4+Pj4rLjw8PC4tLS0tLS4rKysrKy4rKysuCi0tLS4+Pj4tLjw8PC0tLS0uPj4+KysuPDw8KysrKy4tLS0uKysrLj4+PisuPDw8Lj4+Pi0tLgoK"&gt;brainfuck visualizer&lt;/a&gt; with some pre-populated code. &lt;/li&gt;
&lt;li&gt;I've written this code in brainfuck and when you run it outputs next hint.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Final Hint
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;That brainfuck code outputs a simple string -
&lt;code&gt;Decode:747572616e7473657068656c6540676d61696c2e636f6d&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;After decoding, it gives you the email address.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Automation for sending gift coupon
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;I have created a IFTTT flow which triggers when there is an incoming email with subject "HOG RIEEDERRRRR" and it is from my friend's email address.&lt;/li&gt;
&lt;li&gt;Once this condition matches, IFTTT sends an email back with gift coupon details.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  To make sure friend don't stuck
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Once timer ran out it reveals a link to brainfuck visualizer code.&lt;/li&gt;
&lt;li&gt;If he can't solve the puzzle in 3 days, an email triggers and sent gift coupon details to friend's email address. Again using IFTTT.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's all folks!&lt;/p&gt;

&lt;p&gt;If you did something similar or have some idea like this, drop it in comments :)&lt;/p&gt;

</description>
      <category>wixsite</category>
      <category>ifttt</category>
      <category>automation</category>
    </item>
    <item>
      <title>Taking control of privacy using NextDns</title>
      <dc:creator>Siddharth</dc:creator>
      <pubDate>Tue, 23 Nov 2021 10:16:27 +0000</pubDate>
      <link>https://dev.to/xceed/taking-control-of-privacy-using-nextdns-1gde</link>
      <guid>https://dev.to/xceed/taking-control-of-privacy-using-nextdns-1gde</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oMbfj1IK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pebn4vuu0k1p3jqfftpp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oMbfj1IK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pebn4vuu0k1p3jqfftpp.png" alt="NextDNS" width="781" height="269"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem
&lt;/h3&gt;

&lt;p&gt;We use a lot of apps and websites everyday on different devices and operating systems. We don't have control on what data is being send to these services. OfCourse, in Android and iPhone we can have some permissions in place but it is very limited. &lt;/p&gt;

&lt;p&gt;There is no way you can control privacy for all of your devices from a central place.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is NextDNS
&lt;/h3&gt;

&lt;p&gt;It is a firewall which can be setup at network (router) level or at individual devices. It protects you from all kinds of security threats, blocks ads and trackers on websites and in apps and provides a safe and supervised Internet for kids — on all devices and on all networks. It gives you full control of the your privacy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features
&lt;/h3&gt;

&lt;p&gt;All of the features are optional and can be enabled or disabled based on needs.&lt;/p&gt;

&lt;h4&gt;
  
  
  Configuration Features
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Multiple configuration - you can have one or more configurations which can be used for each or group of devices.&lt;/li&gt;
&lt;li&gt;Works using DNS - All you need is to configure a DNS provide by the configuration to have blocking in place. Once you configure DNS on device, blocking works regardless of network.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Security Features
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Google Safe Browsing - Block malware and phishing domains&lt;/li&gt;
&lt;li&gt;Cryptojacking Protection - Prevent the unauthorized use of your devices to mine cryptocurrency.&lt;/li&gt;
&lt;li&gt;DNS Rebinding Protection - Prevent attackers from taking control of your local devices through the Internet.&lt;/li&gt;
&lt;li&gt;Typosquatting Protection - Block domains registered by malicious actors that target users who incorrectly type a website address.&lt;/li&gt;
&lt;li&gt;and a lot more&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Privacy Features
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Blocklists - Block ads &amp;amp; trackers using the most popular blocklists using pre-configured open source blocklists can be enabled/disabled.&lt;/li&gt;
&lt;li&gt;Native Tracking Protection - Blocks wide spectrum trackers at operating system level.&lt;/li&gt;
&lt;li&gt;Affiliate &amp;amp; Tracking Links - Blocks affiliate &amp;amp; tracking domains common on deals websites, in emails or in search results.&lt;/li&gt;
&lt;li&gt;and a lot more
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FO-GACqZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b39oawz93n4h5yg5ap8c.png" alt="Blocklists" width="880" height="339"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Parental Controls
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Block websites, apps and games. &lt;/li&gt;
&lt;li&gt;Block based on categories&lt;/li&gt;
&lt;li&gt;Block based on day and time of the day&lt;/li&gt;
&lt;li&gt;Enforce safe search&lt;/li&gt;
&lt;li&gt;YouTube restricted mode&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Optional Logs &amp;amp; Analytics
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;When enabled, it gives complete picture of the network and devices including resolved queries, blocked queries, block reason, traffic destination by countries, % of encrypted DNS queries etc.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--B6YyDApI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5h57a6n0fbaaps8rz7ej.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B6YyDApI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5h57a6n0fbaaps8rz7ej.png" alt="Query Insights" width="880" height="621"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Pricing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Sandbox - This is free environment for 7 days to try NextDNS.&lt;/li&gt;
&lt;li&gt;Free - Once you signup, you can save settings. This tier is limited to 300,000 queries per month for all devices under the account.&lt;/li&gt;
&lt;li&gt;Paid - Gives you unlimited queries per month for $2/month.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Getting Started
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://my.nextdns.io/start"&gt;Sandbox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nextdns.io/?from=bq3pk9f5"&gt;Free&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>privacy</category>
      <category>dns</category>
      <category>nextdns</category>
    </item>
  </channel>
</rss>
