<?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: Alimur Razi Rana</title>
    <description>The latest articles on DEV Community by Alimur Razi Rana (@alimurrazi).</description>
    <link>https://dev.to/alimurrazi</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F641420%2F9aff6b3b-2c92-4aa9-a65b-7552c6dda2e3.png</url>
      <title>DEV Community: Alimur Razi Rana</title>
      <link>https://dev.to/alimurrazi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alimurrazi"/>
    <language>en</language>
    <item>
      <title>Reflection in C#: What It Is, Why It Exists</title>
      <dc:creator>Alimur Razi Rana</dc:creator>
      <pubDate>Sun, 12 Jul 2026 04:51:45 +0000</pubDate>
      <link>https://dev.to/alimurrazi/reflection-in-c-what-it-is-why-it-exists-3m90</link>
      <guid>https://dev.to/alimurrazi/reflection-in-c-what-it-is-why-it-exists-3m90</guid>
      <description>&lt;p&gt;Reflection is one of those features every .Net/C# developer has used directly or indirectly. This article walks through — using a dynamic email template engine as the running example — and then tours a few real-life use cases where reflection does real work.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Reflection?
&lt;/h2&gt;

&lt;p&gt;Reflection lets code inspect and interact with types, methods, properties, and assemblies &lt;strong&gt;at runtime&lt;/strong&gt; — even ones it didn't know about at compile time. It lives in the &lt;code&gt;System.Reflection&lt;/code&gt; namespace and has been part of .NET since .NET Framework 1.0 in 2002.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Type&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;someObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetType&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;PropertyInfo&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;properties&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="nf"&gt;GetProperties&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Activator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateInstance&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the mechanism. The &lt;em&gt;value&lt;/em&gt; of reflection only becomes clear once we see the alternative.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: Life Without Reflection
&lt;/h2&gt;

&lt;p&gt;Imagine someone building a system that sends different kinds of emails — order confirmations, password resets, shipping updates — each with its own data merged into a template.&lt;/p&gt;

&lt;p&gt;Without reflection, developers need to write a separate merge method for every email type, manually pulling out each field:&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;OrderConfirmationData&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;CustomerName&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;OrderNumber&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;Total&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;BuildOrderConfirmationEmail&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;template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OrderConfirmationData&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{{CustomerName}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CustomerName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{{OrderNumber}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrderNumber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{{Total}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Total&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"C"&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="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;BuildPasswordResetEmail&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;template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PasswordResetData&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{{UserName}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{{ResetLink}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResetLink&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// ...and one more method for every new email type, forever&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This has three predictable failure modes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Duplication&lt;/strong&gt; — the same merge pattern gets copy-pasted for every model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It doesn't scale&lt;/strong&gt; — add &lt;code&gt;ShippingUpdateData&lt;/code&gt;, &lt;code&gt;InvoiceData&lt;/code&gt;, &lt;code&gt;WelcomeEmailData&lt;/code&gt;, and write three more methods.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Silent bugs&lt;/strong&gt; — add a new field like &lt;code&gt;EstimatedDelivery&lt;/code&gt; to a model and forget to add its &lt;code&gt;.Replace()&lt;/code&gt; call. Nothing fails at compile time; the placeholder just never gets filled in.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Fix: A Reflection-Based Template Engine
&lt;/h2&gt;

&lt;p&gt;Instead of hardcoding which fields exist, the engine asks each object what properties it has and merges them generically:&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;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TemplateEngine&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="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;Render&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;template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Type&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetType&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PropertyInfo&lt;/span&gt; &lt;span class="n"&gt;prop&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetProperties&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;placeholder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"{{"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"}}"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;template&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;FormatValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;FormatValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"C"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MMMM dd, yyyy"&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;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage is now completely generic — &lt;strong&gt;one method handles every email type ever created&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;order&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;OrderConfirmationData&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;CustomerName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Sarah"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;OrderNumber&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ORD-4471"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Total&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;89.99m&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;template&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Hi {{CustomerName}}, your order {{OrderNumber}} totaling {{Total}} has shipped!"&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;email&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TemplateEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// "Hi Sarah, your order ORD-4471 totaling $89.99 has shipped!"&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;reset&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;PasswordResetData&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;UserName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"sarah_k"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ResetLink&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://..."&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;resetEmail&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TemplateEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hi {{UserName}}, click {{ResetLink}} to reset."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What this actually fixed:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One merge engine instead of &lt;em&gt;N&lt;/em&gt; methods. &lt;code&gt;Render()&lt;/code&gt; never changes as new email types are added.&lt;/li&gt;
&lt;li&gt;Adding a field to an email becomes a one-line change: add the property to the model, add the placeholder to the template. No merge code to remember.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is essentially how real templating libraries like &lt;strong&gt;RazorLight&lt;/strong&gt; and &lt;strong&gt;Scriban&lt;/strong&gt; work under the hood: bind a plain object's properties to placeholders without the library ever needing to know specific classes in advance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced Feature: Attribute-Driven Formatting
&lt;/h2&gt;

&lt;p&gt;Once the basic engine works, attributes push formatting rules &lt;em&gt;into the model&lt;/em&gt; instead of hardcoding them in the engine — keeping &lt;code&gt;Render()&lt;/code&gt; generic while still allowing per-field customization:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;AttributeUsage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AttributeTargets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Property&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;DateFormatAttribute&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Attribute&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Format&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;DateFormatAttribute&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;format&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;Format&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;format&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;ShippingUpdateData&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;CustomerName&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;DateFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dddd, MMMM d"&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;DateTime&lt;/span&gt; &lt;span class="n"&gt;EstimatedDelivery&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside &lt;code&gt;Render()&lt;/code&gt;, a quick check against the attribute decides how to format that specific field:&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;dateFormat&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetCustomAttribute&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DateFormatAttribute&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;formatted&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dateFormat&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dateFormat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;FormatValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the same pattern used by &lt;code&gt;[Required]&lt;/code&gt; in ASP.NET Core's &lt;code&gt;DataAnnotations&lt;/code&gt; validation, or &lt;code&gt;[JsonPropertyName]&lt;/code&gt; in &lt;code&gt;System.Text.Json&lt;/code&gt; — metadata lives next to the data it describes, and generic engines read it at runtime instead of needing per-type special-casing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other Places Reflection Does Real Work
&lt;/h2&gt;

&lt;p&gt;The template engine isn't a one-off case — it's an instance of a general pattern: &lt;strong&gt;code that would otherwise need to know about every type in advance gets replaced by code that discovers what it needs at runtime.&lt;/strong&gt; A few other production-grade examples:&lt;/p&gt;

&lt;h3&gt;
  
  
  Dependency Injection Containers
&lt;/h3&gt;

&lt;p&gt;Instead of manually writing &lt;code&gt;new OrderController(new OrderService(new OrderRepository(new DbConnection(...))))&lt;/code&gt;, a DI container reads each class's constructor via &lt;code&gt;GetConstructors()&lt;/code&gt; and &lt;code&gt;GetParameters()&lt;/code&gt;, then recursively resolves and builds the whole graph. This is exactly what &lt;code&gt;builder.Services.AddScoped&amp;lt;IOrderRepository, OrderRepository&amp;gt;()&lt;/code&gt; does under the hood in ASP.NET Core.&lt;/p&gt;

&lt;h3&gt;
  
  
  Validation Frameworks
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;DataAnnotations&lt;/code&gt; and &lt;code&gt;FluentValidation&lt;/code&gt; scan a model's properties for attributes like &lt;code&gt;[Required]&lt;/code&gt; or &lt;code&gt;[Range]&lt;/code&gt; and apply the corresponding rule — one generic validator instead of a hand-written method per class.&lt;/p&gt;

&lt;h3&gt;
  
  
  Serialization
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;System.Text.Json&lt;/code&gt; and &lt;code&gt;Newtonsoft.Json&lt;/code&gt; walk an object's properties via reflection to produce JSON, and walk a JSON document's structure to populate an object — without ever needing hardcoded knowledge of the classes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test Runners
&lt;/h3&gt;

&lt;p&gt;xUnit and NUnit scan the compiled assembly for methods tagged &lt;code&gt;[Fact]&lt;/code&gt; or &lt;code&gt;[Test]&lt;/code&gt; rather than maintaining a manual list of test methods.&lt;/p&gt;

&lt;h3&gt;
  
  
  ORMs
&lt;/h3&gt;

&lt;p&gt;Entity Framework maps class properties to database columns by reflecting over the model classes, matching property names (or &lt;code&gt;[Column]&lt;/code&gt; attributes) to schema columns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reflection is slow
&lt;/h2&gt;

&lt;p&gt;Reflection is slower than direct method calls, but the difference only matters when executed thousands or millions of times. Frameworks like ASP.NET Core, Entity Framework, and System.Text.Json all use reflection where appropriate, then cache metadata so the cost is paid once rather than on every operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;Reflection is powerful, but it isn't a replacement for normal object-oriented code. If types are known at compile time, direct property access is simpler, safer, and faster. Reflection shines while building reusable infrastructure that must work with types it doesn't know in advance.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>From Passwords to Token-based Authentication</title>
      <dc:creator>Alimur Razi Rana</dc:creator>
      <pubDate>Thu, 02 Jul 2026 06:37:42 +0000</pubDate>
      <link>https://dev.to/alimurrazi/from-passwords-to-token-based-authentication-4mmp</link>
      <guid>https://dev.to/alimurrazi/from-passwords-to-token-based-authentication-4mmp</guid>
      <description>&lt;p&gt;Every authentication mechanism in use today emerged to address a specific set of constraints the previous one wasn't designed for. This article walks through that chain — not as a list of definitions, but as a sequence of problems and the constraints that shaped each solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The Problem With Sending Passwords Every Request
&lt;/h2&gt;

&lt;p&gt;The earliest widely used approach, HTTP Basic Authentication, is also the simplest to understand. The client sends the username and password, base64-encoded, on every single request:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GET /api/data&lt;br&gt;
Authorization: Basic dXNlcjpwYXNzd29yZA==&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Base64 is not encryption — it's just a reversible encoding. Anyone who intercepts this header has the raw credentials.&lt;/p&gt;

&lt;p&gt;This approach has three structural problems.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, the password is transmitted on every request, which means every request is a new opportunity for it to leak — through logs, proxies, or a compromised network.&lt;/li&gt;
&lt;li&gt;Second, the server has to validate credentials against the database on every single call, since there's no concept of an established session; that's a database hit for every API request, which doesn't scale.&lt;/li&gt;
&lt;li&gt;Third, there's no way to limit what the credentials can do or for how long. The password grants full access until it's changed, and changing it is the only way to revoke access — there's no way to invalidate just one client's access without affecting every other client using the same password.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Sessions Try to Fix It, But Introduce New Problems
&lt;/h2&gt;

&lt;p&gt;The next evolution moved the credential check to a single moment: login. After verifying the password once, the server creates a session, stores it (in memory or a database), and gives the client a session ID, usually via a cookie. Every subsequent request just sends that ID, not the password.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;The user logs in by submitting their username and password.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Browser ───────────────▶ Server
            Login Request
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The server validates the credentials.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Server ── checks username/password ──▶ Database
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If the credentials are valid, the server creates a new session, stores it in the session store, and generates a unique session ID.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Server ───────────────▶ Session Store
            Create Session
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The server returns the session ID to the browser in a Set-Cookie header.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Server ───────────────▶ Browser
      Set-Cookie: session_id=abc123
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For every subsequent request, the browser automatically includes the session cookie.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Browser ───────────────▶ Server
   Request + session_id cookie
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The server uses the session ID to retrieve the corresponding session from the session store.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Server ───────────────▶ Session Store
          Lookup session_id
   Session Store ─────────▶ Server
          Session data
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If the session exists and is still valid, the server processes the request and returns the requested resource.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Server ───────────────▶ Browser
            Response
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This solves the repeated-password-exposure problem cleanly. But it trades that problem for a different set of issues. The server now has to store and look up a session on every request, which is a form of state that has to live somewhere and be kept in sync if you're running more than one server. Cookies are also sent automatically by the browser, which is exactly what makes them vulnerable to CSRF — a malicious site can trigger a request that carries the user's cookie without their knowledge. And sessions are fundamentally a browser-native concept; they don't map cleanly onto mobile apps, CLI tools, or server-to-server calls, all of which have no natural concept of a cookie jar. For those contexts specifically, sessions weren't a broken solution — they were a solution built for a different problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Bearer Tokens Go Stateless
&lt;/h2&gt;

&lt;p&gt;The fix here was to stop relying on server-side storage altogether and instead issue a self-contained token — most commonly a JWT (JSON Web Token) — that carries its own proof of validity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjapwz5l0aes5bpmxq2fy.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjapwz5l0aes5bpmxq2fy.png" alt=" " width="663" height="159"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The token is called a "bearer" token because possession is the only requirement — whoever holds it can use it, no further proof needed. Crucially, the server doesn't need to look anything up in a database to validate it; it just verifies the signature.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Session-based check:   Request → DB/store lookup → Response   (stateful)&lt;br&gt;
Bearer token check:    Request → verify signature → Response  (stateless)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This single change resolves several of the earlier problems at once. There's no session store to maintain or synchronize across servers. The token can carry scopes, limiting exactly what it's allowed to do, rather than granting blanket access. And because it's just a string in a header, it works identically whether the caller is a browser, a mobile app, a CLI tool, or another backend service — there's no cookie-jar assumption baked in.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. The New Tension Bearer Tokens Introduce
&lt;/h2&gt;

&lt;p&gt;Solving the statelessness problem exposes a different question that sessions never really had to answer cleanly: how long should a token live?&lt;br&gt;
A short-lived token limits the damage if it's ever stolen — an attacker only has a small window before it expires. But it also means the user gets logged out frequently, since there's no way to silently extend access once the token has expired. A long-lived token solves the convenience problem, but now a single stolen token grants extended, possibly indefinite access, which is a much worse outcome if it leaks.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Short-lived token:   safer if stolen, but logs the user out constantly&lt;br&gt;
Long-lived token:    convenient, but dangerous if it's ever compromised&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Picking one or the other means accepting one of these two problems outright. The fix wasn't to pick a side — it was to stop treating this as a single-token problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Refresh Token Flow Resolves the Tension
&lt;/h2&gt;

&lt;p&gt;Instead of one token trying to be both safe and convenient, the solution introduces two tokens, each optimized for a different job. The access token is short-lived and is the one actually sent with every API call. The refresh token is long-lived, but it's used for exactly one purpose: silently obtaining a new access token when the old one expires. It's never sent to the API directly.&lt;/p&gt;

&lt;p&gt;`1. The user logs in by submitting their credentials.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;       Client ───────────────▶ Auth Server
                 Login Request`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;The authentication server verifies the credentials.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  Auth Server ── validates username/password ──▶ User Database
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If authentication succeeds, the server issues two tokens:&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A short-lived access token (e.g., 15 minutes)
A long-lived refresh token (e.g., 30 days)

   Auth Server ───────────────▶ Client
               access_token
               refresh_token
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The client calls protected APIs using the access token.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Client ───────────────▶ API
   Authorization: Bearer access_token
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The API validates the access token. If it's valid, the request&lt;br&gt;
is processed and the response is returned.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   API ── verifies token signature/claims ──▶
   API ───────────────▶ Client
             Response
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After the access token expires, API requests are rejected&lt;br&gt;
with an authentication error (typically 401 Unauthorized).&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Client ───────────────▶ API
   Expired access_token
   ◀─────────────── 401 Unauthorized
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The client sends the refresh token to the authentication server&lt;br&gt;
to obtain a new access token.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Client ───────────────▶ Auth Server
            refresh_token
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The authentication server validates the refresh token and,&lt;br&gt;
if it's still valid, issues a new access token&lt;br&gt;
(and optionally a new refresh token).&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Auth Server ───────────────▶ Client
               new access_token
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The client retries the original request using the new&lt;br&gt;
access token and continues working without requiring&lt;br&gt;
the user to log in again.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Client ───────────────▶ API
   Authorization: Bearer new_access_token
   ◀─────────────── Response`
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This refresh exchange happens silently in the background, invisible to the user — there's no re-login screen, no interruption. The user only has to log in again once the refresh token itself eventually expires, which can be set to a much longer window precisely because the refresh token isn't exposed to the same attack surface as the access token; it's used rarely, against a single dedicated endpoint, rather than being sent on every API call where it would have more chances to leak.&lt;/p&gt;

&lt;p&gt;This two-token model is part of the OAuth 2.0 specification, which formalized exactly this pattern: access tokens for calling resources, refresh tokens for renewing access, and a clear separation of purpose between the two.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. How Access and Refresh Tokens Improve on Earlier Approaches
&lt;/h2&gt;

&lt;p&gt;Looking back at the chain, the access token plus refresh token pair addresses each prior constraint in turn. The password itself is only ever sent once, at login — not on every request, which closes the exposure problem Basic Auth had. There's no server-side session store to maintain, since the access token is self-contained and stateless, removing the scaling constraint that sessions introduce for multi-server deployments. The user isn't forced to log in every few minutes, since the refresh token silently renews access in the background. And if an access token does leak, the damage is bounded by its short expiry, while the refresh token — the more sensitive, longer-lived credential — is never exposed on routine API calls in the first place, limiting its attack surface.&lt;/p&gt;

&lt;p&gt;Each step in this chain didn't make the previous mechanism wrong — it made it insufficient for a different set of requirements: scale, statelessness, portability across client types, and convenience without sacrificing security. The access token and refresh token pair is where that chain currently settles in stateless, API-driven systems, and it's the foundation that more specialized mechanisms later build directly on top of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. When Sessions Are Still the Right Choice
&lt;/h2&gt;

&lt;p&gt;Bearer tokens and refresh tokens address the constraints of stateless, multi-client APIs well — but that doesn't make sessions obsolete. They remain widely used, and in several contexts they're genuinely the better fit.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Immediate revocation is a hard requirement. When a user logs out of a session-based system, the server deletes the session record, and access stops immediately. With bearer tokens, logout on the client side doesn't invalidate the token itself — it just discards it locally. The token remains technically valid until it expires, which is acceptable for most applications but not for systems where instant revocation is non-negotiable, such as banking platforms or enterprise applications managing sensitive data.&lt;/li&gt;
&lt;li&gt;The client is exclusively a browser. Sessions and cookies were designed for exactly this context. If your application is a traditional server-rendered web app with no mobile client, no public API, and no third-party consumers, sessions carry less overhead and are simpler to implement correctly.&lt;/li&gt;
&lt;li&gt;The use case is internal or enterprise-facing. Internal tools, admin panels, and enterprise web applications often prioritize control and auditability over scalability. Session-based auth fits this context well — each active session is visible and individually revocable from the server side, which matters when you need to respond quickly to a compromised account.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In practice, many large systems use both approaches for different layers: session-based auth for first-party browser interfaces where the server needs tight control, and token-based auth for APIs and third-party integrations where statelessness and portability matter more. The two aren't mutually exclusive — they answer different questions.&lt;/p&gt;

</description>
      <category>authentication</category>
      <category>security</category>
    </item>
    <item>
      <title>Singleton, Scoped, and Transient: What They Actually Mean for Your DbContext</title>
      <dc:creator>Alimur Razi Rana</dc:creator>
      <pubDate>Wed, 24 Jun 2026 10:37:18 +0000</pubDate>
      <link>https://dev.to/alimurrazi/singleton-scoped-and-transient-what-they-actually-mean-for-your-dbcontext-271j</link>
      <guid>https://dev.to/alimurrazi/singleton-scoped-and-transient-what-they-actually-mean-for-your-dbcontext-271j</guid>
      <description>&lt;p&gt;Anyone who has worked with dependency injection in .NET, might have registered something like this:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;It works. app runs. But &lt;em&gt;why&lt;/em&gt; does &lt;code&gt;AddDbContext&lt;/code&gt; default to Scoped, and what would break if it didn't?&lt;/p&gt;

&lt;p&gt;Let's find out — by breaking it on purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three lifetimes
&lt;/h2&gt;

&lt;p&gt;Before touching any code, here's what each lifetime actually promises:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Transient&lt;/strong&gt; — A new instance is created &lt;strong&gt;every single time&lt;/strong&gt; it's requested. Ask for it twice in the same method, and get two different instances.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scoped&lt;/strong&gt; — One instance is created &lt;strong&gt;per scope&lt;/strong&gt;, and reused for every request &lt;em&gt;within that scope&lt;/em&gt;. In a web app, a scope is one HTTP request — so everything inside that request shares the same instance. The next request gets a fresh one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Singleton&lt;/strong&gt; — &lt;strong&gt;Exactly one instance&lt;/strong&gt;, ever, for the entire lifetime of the app. Every request, every user, every caller — all sharing that one object, forever, until the app shuts down.&lt;/p&gt;

&lt;p&gt;That's the theory. Now let's watch it actually happen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a DbContext that tells us who it is
&lt;/h2&gt;

&lt;p&gt;The trick to &lt;em&gt;seeing&lt;/em&gt; lifetime behavior instead of just reading about it: give the DbContext a fingerprint.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppDbContext&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DbContext&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;InstanceId&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="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewGuid&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Every time a &lt;em&gt;new&lt;/em&gt; &lt;code&gt;AppDbContext&lt;/code&gt; gets constructed, it stamps itself with a new &lt;code&gt;Guid&lt;/code&gt;. If two services end up holding the same &lt;code&gt;InstanceId&lt;/code&gt;, we know for certain they got handed the same object — not two copies that look alike.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two services that both need a database connection
&lt;/h2&gt;

&lt;p&gt;In any real app, most cases never have just one class touching the database. Let's add two:&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;OrderWriter&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;_db&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;OrderWriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;db&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;_db&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&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;ShowInstance&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;label&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;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"[OrderWriter]     &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; → &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InstanceId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InventoryWriter&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;_db&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;InventoryWriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;db&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;_db&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&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;ShowInstance&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;label&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;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"[InventoryWriter] &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; → &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InstanceId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both just print which &lt;code&gt;AppDbContext&lt;/code&gt; they were handed. Think of these as stand-ins for an &lt;code&gt;OrderRepository&lt;/code&gt; and an &lt;code&gt;InventoryService&lt;/code&gt; in a real order-processing flow — two unrelated classes that both happen to need the same database context.&lt;/p&gt;

&lt;p&gt;We still haven't registered anything with DI yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wiring it up — starting with Singleton
&lt;/h2&gt;

&lt;p&gt;Here's where it gets interesting. Let's register &lt;code&gt;AppDbContext&lt;/code&gt; as a Singleton and see what happens across two separate "requests":&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;services&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;ServiceCollection&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;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="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;options&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;DbContextOptionsBuilder&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseInMemoryDatabase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SingletonTest"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;AppDbContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&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="n"&gt;AddTransient&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderWriter&lt;/span&gt;&lt;span class="p"&gt;&amp;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;AddTransient&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;InventoryWriter&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;provider&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;BuildServiceProvider&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I used an in-memory database here on purpose — no real SQL Server needed, so anyone can copy this straight into a console app and run it.&lt;/p&gt;

&lt;p&gt;Quick note on &lt;code&gt;OrderWriter&lt;/code&gt; and &lt;code&gt;InventoryWriter&lt;/code&gt; being Transient: that's deliberate. We want &lt;em&gt;them&lt;/em&gt; rebuilt fresh every time, so the only thing that can explain a repeated &lt;code&gt;InstanceId&lt;/code&gt; is the DbContext's own lifetime — not some side effect of caching the writer itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simulating two HTTP requests
&lt;/h2&gt;

&lt;p&gt;In a real web app, a "scope" is created automatically for you on every incoming request. In a console app, we have to make that explicit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;requestOne&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateScope&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requestOne&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServiceProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetRequiredService&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderWriter&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;inventory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requestOne&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServiceProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetRequiredService&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;InventoryWriter&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ShowInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Request 1"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ShowInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Request 1"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;using&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;requestTwo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateScope&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requestTwo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServiceProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetRequiredService&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderWriter&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ShowInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Request 2"&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;Each &lt;code&gt;using&lt;/code&gt; block is standing in for one separate incoming HTTP request, completely unrelated to the other.&lt;/p&gt;

&lt;p&gt;Run this with the Singleton registration from above, and here's what prints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[OrderWriter]     Request 1 → 3f1a2b4c-...
[InventoryWriter] Request 1 → 3f1a2b4c-...
[OrderWriter]     Request 2 → 3f1a2b4c-...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same &lt;code&gt;InstanceId&lt;/code&gt;, every single time — even across two completely separate requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why that's actually a problem
&lt;/h2&gt;

&lt;p&gt;In a real app: &lt;strong&gt;two unrelated users, hitting your API at the same time, would be sharing one &lt;code&gt;AppDbContext&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DbContext&lt;/code&gt; isn't thread-safe. If request 1 and request 2 land close enough together, you'll hit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;InvalidOperationException: A second operation was started on this 
context instance before a previous operation completed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And even if you never hit that exact exception, there's a quieter problem: EF Core's change tracker never gets cleared. With Scoped, a new DbContext — and therefore a new empty change tracker — gets created for every request. When the request ends, that DbContext gets disposed, and the tracker (along with everything it was holding onto) gets thrown away with it. But in this case, every entity ever loaded by &lt;em&gt;any&lt;/em&gt; request stays tracked in that one singleton context, forever, growing without bound for as long as the app runs.&lt;/p&gt;

&lt;p&gt;Singleton is wrong here. Let's try the opposite extreme.&lt;/p&gt;

&lt;h2&gt;
  
  
  Swapping in Transient
&lt;/h2&gt;

&lt;p&gt;Same harness — change the registration line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddTransient&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;options&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;DbContextOptionsBuilder&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseInMemoryDatabase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"TransientTest"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;AppDbContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&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;Run the same two-request simulation, and now you get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[OrderWriter]     Request 1 → 9c2e7f10-...
[InventoryWriter] Request 1 → 7b44d821-...
[OrderWriter]     Request 2 → a91f3c05-...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every &lt;code&gt;InstanceId&lt;/code&gt; is different — including &lt;code&gt;OrderWriter&lt;/code&gt; and &lt;code&gt;InventoryWriter&lt;/code&gt;, &lt;em&gt;within the same request&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why that's also a problem —
&lt;/h2&gt;

&lt;p&gt;Picture &lt;code&gt;OrderService&lt;/code&gt; written like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IInventoryService&lt;/span&gt; &lt;span class="n"&gt;_inventory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IOrderRepository&lt;/span&gt; &lt;span class="n"&gt;_repository&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;OrderService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IInventoryService&lt;/span&gt; &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IOrderRepository&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_db&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_inventory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_repository&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;repository&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;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;PlaceOrderAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OrderItem&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_inventory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReserveAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProductId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Quantity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ReserveAsync&lt;/code&gt; and &lt;code&gt;SaveAsync&lt;/code&gt; are written to only &lt;em&gt;stage&lt;/em&gt; their changes — no internal &lt;code&gt;SaveChangesAsync()&lt;/code&gt; calls — trusting that one final commit at the bottom will save everything. That's the correct pattern, &lt;strong&gt;but only if every &lt;code&gt;_db&lt;/code&gt; in this picture is the same object.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What happens with Transient
&lt;/h3&gt;

&lt;p&gt;If &lt;code&gt;AppDbContext&lt;/code&gt; is registered Transient, &lt;code&gt;OrderService&lt;/code&gt;'s own constructor gets handed &lt;em&gt;its own&lt;/em&gt; fresh instance — call it &lt;code&gt;DbContext#3&lt;/code&gt;. That's separate from whatever &lt;code&gt;IInventoryService&lt;/code&gt; was given (&lt;code&gt;DbContext#1&lt;/code&gt;) and whatever &lt;code&gt;IOrderRepository&lt;/code&gt; was given (&lt;code&gt;DbContext#2&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;So:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;_inventory.ReserveAsync&lt;/code&gt; stages its change on &lt;code&gt;DbContext#1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_repository.SaveAsync&lt;/code&gt; stages its change on &lt;code&gt;DbContext#2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_db.SaveChangesAsync()&lt;/code&gt; commits &lt;code&gt;DbContext#3&lt;/code&gt; — which nothing ever touched.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The method runs to completion. No exception. No error. And nothing was saved — because the one context that actually got told to commit was never the one holding any staged changes. The changes inside &lt;code&gt;DbContext#1&lt;/code&gt; and &lt;code&gt;DbContext#2&lt;/code&gt; are simply discarded the moment those objects are disposed, since nobody ever called &lt;code&gt;SaveChangesAsync()&lt;/code&gt; on either of them specifically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Now the one that actually works: Scoped
&lt;/h2&gt;

&lt;p&gt;Last swap:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddScoped&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;options&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;DbContextOptionsBuilder&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseInMemoryDatabase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ScopedTest"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;AppDbContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&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;Run it again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[OrderWriter]     Request 1 → c450e9a2-...
[InventoryWriter] Request 1 → c450e9a2-...
[OrderWriter]     Request 2 → e702b614-...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look at that pattern closely — &lt;code&gt;OrderWriter&lt;/code&gt; and &lt;code&gt;InventoryWriter&lt;/code&gt; share an &lt;code&gt;InstanceId&lt;/code&gt; &lt;em&gt;within&lt;/em&gt; Request 1, but Request 2 gets a completely different one.&lt;/p&gt;

&lt;p&gt;That's exactly the property we need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Within one request&lt;/strong&gt;, every service shares one &lt;code&gt;DbContext&lt;/code&gt; — one change tracker, one real unit of work. &lt;code&gt;OrderWriter&lt;/code&gt; and &lt;code&gt;InventoryWriter&lt;/code&gt; can both stage changes and commit them together.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Across requests&lt;/strong&gt;, nothing leaks. Request 2 starts clean, with no leftover tracked entities from Request 1, and no thread-safety conflict if both requests happen to run at the same time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Putting it side by side
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Lifetime&lt;/th&gt;
&lt;th&gt;Within one request&lt;/th&gt;
&lt;th&gt;Across two requests&lt;/th&gt;
&lt;th&gt;What goes wrong&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Singleton&lt;/td&gt;
&lt;td&gt;Same instance&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Same instance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Thread-safety crashes, unbounded change tracker growth&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transient&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Different instances&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Different instances&lt;/td&gt;
&lt;td&gt;Two services in one request can't share a transaction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scoped&lt;/td&gt;
&lt;td&gt;Same instance&lt;/td&gt;
&lt;td&gt;Different instances&lt;/td&gt;
&lt;td&gt;Nothing — this is the one that fits&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Try it yourself
&lt;/h2&gt;

&lt;p&gt;The full thing runs as a plain console app — no real database required, since we're using EF Core's in-memory provider for the experiment. You'll need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package Microsoft.EntityFrameworkCore.InMemory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then just swap the single registration line between &lt;code&gt;AddSingleton&lt;/code&gt;, &lt;code&gt;AddTransient&lt;/code&gt;, and &lt;code&gt;AddScoped&lt;/code&gt;, rerun, and watch the GUIDs tell the story. &lt;a href="https://gist.github.com/Alimurrazi/1483f404e07b0ec6c3d61f208a5b3abf" rel="noopener noreferrer"&gt;[gist link]&lt;/a&gt; Once you've seen all three side by side like this, the rule stops being something you memorized and starts being something you actually understand: &lt;strong&gt;match the lifetime to how long the state inside the object is supposed to live.&lt;/strong&gt; A &lt;code&gt;DbContext&lt;/code&gt; should live exactly as long as one unit of work — which, in a web app, is exactly one request. That's not a coincidence. That's the entire reason Scoped exists.&lt;/p&gt;

&lt;p&gt;That covers Scoped pretty thoroughly. But Scoped isn't the only lifetime that earns its place — Singleton and Transient each have a scenario where they're not just "safe," they're the &lt;em&gt;better&lt;/em&gt; choice than the other two. Let's look at one real example of each.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Singleton is the right call
&lt;/h2&gt;

&lt;p&gt;Use Singleton for stateless objects, require heavy initialization, or hold global application state. Common examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Caching services&lt;/li&gt;
&lt;li&gt;Configuration providers&lt;/li&gt;
&lt;li&gt;Logging utilities&lt;/li&gt;
&lt;li&gt;Background workers and hosted services&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When to avoid Singleton:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Thread-unsafe state&lt;/strong&gt; — if multiple requests can hit the same instance at the same time, concurrent modifications to mutable data will cause bugs that are hard to reproduce.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Captive dependencies&lt;/strong&gt; — never inject a shorter-lived service (Scoped or Transient) into a Singleton. Doing so forces that shorter-lived service to live far longer than it was designed to, which is exactly the bug our &lt;code&gt;AppDbContext&lt;/code&gt; experiment above demonstrated: a Scoped &lt;code&gt;DbContext&lt;/code&gt; trapped inside something longer-lived stops behaving like a per-request unit of work and starts leaking state across requests instead.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Picture an app-wide pricing settings provider — tax rates, currency exchange rates, feature flags — loaded once from configuration or a slow-changing table, then read over and over by every request that calculates a price.&lt;/p&gt;

&lt;p&gt;If this were Scoped, every single request would re-read config and rebuild that exchange-rate data from scratch — paying the same cost over and over for a result that never changes between requests. Transient would be worse, potentially rebuilding it multiple times &lt;em&gt;within&lt;/em&gt; one request if several services injected it.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Transient is the right call
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use Transient when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The service is stateless&lt;/strong&gt; — the class doesn't hold or track data across multiple calls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You're building lightweight utilities&lt;/strong&gt; — simple validators, formatters, or data mappers are a natural fit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The service isn't thread-safe&lt;/strong&gt; — since you get a fresh instance every time, you sidestep the concurrency issues that come from sharing one object across multiple threads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You need to avoid state contamination&lt;/strong&gt; — you want one operation's execution to never leak data into another operation's execution, even within the same request.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When not to use Transient:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Heavily used dependencies&lt;/strong&gt; — since the container builds a new object every single time, excessive use of Transient services increases allocations and adds pressure on the garbage collector, which can hurt performance at scale.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When sharing context is required&lt;/strong&gt; — if multiple services need to work on the same unit of work at the same time (Entity Framework's &lt;code&gt;DbContext&lt;/code&gt; being the textbook case), Transient breaks that sharing apart. That's exactly what we watched happen in the experiment above — use Scoped instead.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now picture a report builder that accumulates lines as it works — say, one service builds the text for an invoice summary, and a separate, unrelated service builds the text for a shipping label. These aren't two pieces of one shared document; they're two completely independent outputs that just happen to use the same kind of builder. Transient guarantees each service gets its own instance, starting from a clean slate, so the invoice service's lines never show up inside the shipping service's result, and vice versa.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern across all three
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Lifetime&lt;/th&gt;
&lt;th&gt;What actually justifies it&lt;/th&gt;
&lt;th&gt;What goes wrong with the wrong choice&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Singleton&lt;/td&gt;
&lt;td&gt;Holds no per-request data; nothing mutates after construction&lt;/td&gt;
&lt;td&gt;Scoped/Transient would rebuild expensive, identical state on every request for no benefit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scoped&lt;/td&gt;
&lt;td&gt;Wraps a per-request unit of work (like &lt;code&gt;DbContext&lt;/code&gt;) that multiple services need to share&lt;/td&gt;
&lt;td&gt;Singleton leaks state across users; Transient splits one logical operation into disconnected pieces&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transient&lt;/td&gt;
&lt;td&gt;Mutates its own state mid-operation, and that state must never be shared between callers&lt;/td&gt;
&lt;td&gt;Scoped or Singleton would let one caller's leftover state corrupt another's result&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every lifetime decision in this article comes down to the same one question, asked about the specific object in front of you: &lt;strong&gt;what does this object store on itself, who else might be holding the same instance at the same time, and what would happen if they were?&lt;/strong&gt; Answer that honestly for any service in your own app, and the right registration call — &lt;code&gt;AddSingleton&lt;/code&gt;, &lt;code&gt;AddScoped&lt;/code&gt;, or &lt;code&gt;AddTransient&lt;/code&gt; — stops being a guess.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>net</category>
    </item>
    <item>
      <title>React Doesn't Need Node.js — Until It Does</title>
      <dc:creator>Alimur Razi Rana</dc:creator>
      <pubDate>Mon, 08 Jun 2026 16:44:03 +0000</pubDate>
      <link>https://dev.to/alimurrazi/react-doesnt-need-nodejs-until-it-does-59ld</link>
      <guid>https://dev.to/alimurrazi/react-doesnt-need-nodejs-until-it-does-59ld</guid>
      <description>&lt;h2&gt;
  
  
  The Truth Nobody Tells You When You Start React
&lt;/h2&gt;

&lt;p&gt;Most React tutorials for beginners start the same way&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"First, install Node.js..."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And every beginner obeys without question. Most of them never challenge it. It's just accepted as part of the ritual.&lt;/p&gt;

&lt;p&gt;But here's the thing — &lt;strong&gt;React doesn't actually need Node.js to work.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And understanding &lt;em&gt;why&lt;/em&gt; that's true, and &lt;em&gt;where&lt;/em&gt; it stops being true, will completely change how developers think about the entire React ecosystem — including Vite, Next.js, and npm itself.&lt;/p&gt;

&lt;p&gt;Let's start with a proof.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 1: React With Zero Node.js
&lt;/h2&gt;

&lt;p&gt;Create a plain &lt;code&gt;.html&lt;/code&gt; file on your desktop. Paste this in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;React, no Node.js&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"root"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- React from CDN --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/react@18/umd/react.development.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/react-dom@18/umd/react-dom.development.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- Babel to handle JSX in the browser --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/@babel/standalone/babel.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/babel"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Hello&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="o"&gt;!&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Click&lt;/span&gt; &lt;span class="nx"&gt;me&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&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="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Double-click the file. Open it in your browser.&lt;/p&gt;

&lt;p&gt;It works. State works. JSX works. React works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No Node.js. No npm. No terminal. No installation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Just a file and a browser.&lt;/p&gt;

&lt;p&gt;This isn't a trick or a hack. This is how React was used in its early days. React is, at its core, just a JavaScript library — the same as jQuery or Lodash. It can be loaded with a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag like anything else.&lt;/p&gt;

&lt;p&gt;So if that's true... why does every guide tell you to install Node.js?&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 2: Where the CDN Approach Breaks Down
&lt;/h2&gt;

&lt;p&gt;The CDN approach works perfectly for small experiments. But the moment the app grows beyond a single file, it hits its real limitations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First, a common misconception worth clearing up:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Modern browsers actually support ES module imports natively:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Header&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Header.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Footer&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Footer.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So imports themselves aren't the problem. The real limitations are deeper than that.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. JSX Needs Compilation
&lt;/h3&gt;

&lt;p&gt;Browsers understand JavaScript. They do not understand JSX:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ Browser has no idea what this is&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&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;// ✅ Browser only understands this&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello&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;Every JSX file needs to be compiled into plain JavaScript before a browser can run it. Native ES modules don't solve this — the browser still can't parse the JSX syntax itself.&lt;br&gt;
This compilation step is handled by different tools depending on setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Babel — the original JSX compiler, still widely used in plain React projects&lt;/li&gt;
&lt;li&gt;Vite —  the popular choice for modern plain React projects&lt;/li&gt;
&lt;li&gt;Next.js SWC — Next.js ships with its own built-in compiler&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  2. npm Packages Aren't ES Module Compatible Out of the Box
&lt;/h3&gt;

&lt;p&gt;Most npm packages are written in CommonJS format — Node.js's own module system:&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="c1"&gt;// CommonJS — how most npm packages are written&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;something&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is completely different from ES modules:&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="c1"&gt;// ES Modules — what browsers understand&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;something&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Browsers cannot run CommonJS. A bundler is needed to convert and reconcile these formats before they reach the browser.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Dependency Management Becomes a Nightmare
&lt;/h3&gt;

&lt;p&gt;Want to use axios? You'd manually find its CDN link. Then manually find CDN links for all of axios's dependencies. Then &lt;em&gt;their&lt;/em&gt; dependencies. A single real-world package can pull in dozens of sub-dependencies — tracking all of them by hand is completely unworkable.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Performance Suffers With Many Module Files
&lt;/h3&gt;

&lt;p&gt;Even if everything was ES module compatible, loading 200 separate JavaScript files means 200 separate network requests — each with its own overhead. A bundler combines them into one or a few optimized files, which loads faster.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 3: What Node.js Actually Is
&lt;/h2&gt;

&lt;p&gt;Before understanding why Node.js solves these problems, you need to understand what Node.js actually is — because most developers use it for years without knowing this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Operating system cannot run JavaScript.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;OS can run Python (if installed). It can run compiled C++ binaries. But JavaScript? No. Most operating systems don't include a built-in JavaScript runtime that can execute JavaScript files directly.&lt;/p&gt;

&lt;p&gt;Only two environments (currently, there are different alternatives like Deno or Bun, but for simplicity, exclude these environments) have been able to execute JavaScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. The Browser
   → Chrome, Firefox, and Safari all have a built-in JS engine
   → Chrome uses V8 (built by Google)
   → Firefox uses SpiderMonkey

2. Node.js
   → Takes Chrome's V8 engine
   → Strips out the browser parts (DOM, window, etc.)
   → Adds OS-level access (file system, network, processes)
   → Runs as a standalone program on your computer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's literally all Node.js is. It's Chrome's JavaScript engine, liberated from the browser and given the ability to talk to your operating system.&lt;/p&gt;

&lt;p&gt;Ryan Dahl, who created Node.js in 2009, had one core insight:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"JavaScript is already a great language. Why does it only run in browsers? What if it could run anywhere?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So when you install Node.js, you're essentially installing a JavaScript interpreter directly onto your machine — the same engine that powers Chrome, just without the browser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is why npm packages need Node.js.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;npm packages are JavaScript files. OS can store them just fine — it's great at storing files. But it cannot &lt;em&gt;execute&lt;/em&gt; them. It has no JavaScript engine. Node.js provides that engine. Without it, those JavaScript files just sit there on your disk doing nothing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 4: What npm Actually Solves
&lt;/h2&gt;

&lt;p&gt;After Node.js, let's talk about npm — because it's far more than just a package downloader.&lt;/p&gt;

&lt;p&gt;When you run &lt;code&gt;npm install axios&lt;/code&gt;, npm doesn't just download axios. It:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Downloads axios
2. Reads axios's list of dependencies
3. Downloads those dependencies
4. Reads THEIR dependencies
5. Downloads those too
6. Resolves any version conflicts across the whole tree
7. Builds a complete, working dependency graph
8. Stores everything in node_modules
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This process — called dependency resolution — is genuinely complex. Packages depend on other packages, which depend on other packages, which might conflict with each other's version requirements. npm handles all of this automatically.&lt;/p&gt;

&lt;p&gt;Without npm, developers would need to do this by hand. For a real project with dozens of dependencies, each with their own sub-dependencies, that would be thousands of files to track manually. It would be completely unworkable.&lt;/p&gt;

&lt;p&gt;And critically — &lt;strong&gt;npm itself is built on Node.js&lt;/strong&gt;. It needs Node.js to run the resolution logic, download packages, execute install scripts, and manage the entire node_modules directory.&lt;/p&gt;

&lt;p&gt;So the chain is clear:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You need npm
  → npm needs Node.js to run
    → Node.js provides the JS engine
      → JS engine executes npm's logic
        → npm manages your packages
          → packages can now be used in your app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remove Node.js from this chain and the whole thing collapses.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 5: In Production, Node.js Disappears (For Plain React)
&lt;/h2&gt;

&lt;p&gt;Here's something that surprises many developers.&lt;/p&gt;

&lt;p&gt;When you run &lt;code&gt;npm run build&lt;/code&gt; in a plain React + Vite project, Vite does all its work and produces a &lt;code&gt;/dist&lt;/code&gt; folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/dist
  index.html
  assets/
    main.abc123.js     ← plain JavaScript, no JSX
    styles.abc123.css  ← plain CSS
    logo.abc123.png    ← optimized image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are completely static files. Plain HTML, CSS, and JavaScript that any browser understands natively.&lt;/p&gt;

&lt;p&gt;At this point, &lt;strong&gt;Node.js is completely out of the picture.&lt;/strong&gt; You can take this &lt;code&gt;/dist&lt;/code&gt; folder and host it on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS S3&lt;/li&gt;
&lt;li&gt;GitHub Pages&lt;/li&gt;
&lt;li&gt;Netlify&lt;/li&gt;
&lt;li&gt;Cloudflare Pages&lt;/li&gt;
&lt;li&gt;A basic Apache server&lt;/li&gt;
&lt;li&gt;Literally any file hosting service&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No Node.js required. No server running. No ongoing processes. Just files being served.&lt;/p&gt;

&lt;p&gt;Node.js was only needed during &lt;strong&gt;development&lt;/strong&gt; — to run the JSX compiler, manage packages, and transform your code. Once the build is done, it has no role left.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 6: Next.js Changes Everything
&lt;/h2&gt;

&lt;p&gt;Everything we've covered so far describes &lt;strong&gt;plain React&lt;/strong&gt; — a client-side application where the browser does all the rendering work.&lt;/p&gt;

&lt;p&gt;Next.js fundamentally changes this model.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Plain React Renders
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;User visits your site
        ↓
Server sends an almost empty HTML file:

&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"root"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;  ← nothing here
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"bundle.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
        ↓
Browser downloads bundle.js (can be 1-2MB)
        ↓
JavaScript runs, React builds the UI
        ↓
User finally sees content
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server does almost nothing. The browser does all the work. This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users on slow connections wait a long time before seeing anything&lt;/li&gt;
&lt;li&gt;Search engines see an empty page — bad for SEO&lt;/li&gt;
&lt;li&gt;The user's device carries all the rendering cost&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How Next.js Renders
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;User visits react site
        ↓
Request hits the Next.js SERVER (Node.js running live)
        ↓
Server executes React components
        ↓
Produces complete HTML with actual content:

&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"root"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Your Product Name&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;   ← already here
      &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Price: $49&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;            ← already here
      &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;Buy Now&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;     ← already here
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"bundle.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
        ↓
Browser receives full HTML instantly
        ↓
User sees content immediately ✅
        ↓
React "hydrates" — attaches event listeners
        ↓
App becomes interactive ✅
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key difference: &lt;strong&gt;the server does the rendering work before the browser gets involved&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Browser Has No Idea
&lt;/h3&gt;

&lt;p&gt;The browser doesn't know — and doesn't care — whether it received HTML from a Next.js server, a plain React build, a WordPress site, or hand-written HTML. It just renders what it gets.&lt;/p&gt;

&lt;p&gt;The difference is entirely in &lt;strong&gt;what the server sends&lt;/strong&gt;. Next.js sends richer, fuller HTML. Plain React sends almost nothing and lets the browser figure it out.&lt;/p&gt;

&lt;h3&gt;
  
  
  Node.js Stays Alive in Production
&lt;/h3&gt;

&lt;p&gt;This is the critical difference from plain React.&lt;/p&gt;

&lt;p&gt;In a plain React app, Node.js is a development-only tool that disappears after the build.&lt;/p&gt;

&lt;p&gt;In Next.js, &lt;strong&gt;Node.js runs permanently in production&lt;/strong&gt; ( Next.js can also run a project with little or no traditional Node server, depending on how the application is configured ) — processing every user request, rendering components on the server, fetching data from databases, and generating HTML in real time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Plain React:
Node.js role → Development only → Gone after build

Next.js:
Node.js role → Development AND Production → Always running
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is why Next.js cannot be deployed to a static file server (unless exported it as fully static). It needs a live Node.js process running 24/7 to handle incoming requests.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Found this useful? Share it with the developer who just ran &lt;code&gt;npm install&lt;/code&gt; without knowing why.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>node</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Guide to Integrating Cypress and Cucumber with Angular</title>
      <dc:creator>Alimur Razi Rana</dc:creator>
      <pubDate>Sun, 03 Mar 2024 08:57:39 +0000</pubDate>
      <link>https://dev.to/alimurrazi/guide-to-integrating-cypress-and-cucumber-with-angular-4oa6</link>
      <guid>https://dev.to/alimurrazi/guide-to-integrating-cypress-and-cucumber-with-angular-4oa6</guid>
      <description>&lt;p&gt;In software engineering, despite developers' confidence in their code, comprehensive testing is indispensable for determining its efficacy. Developers and QA engineers must navigate through diverse testing phases to ascertain the comprehensive functionality of their applications. Two widely embraced methodologies for this purpose, are End-to-End (E2E) testing and Behavior-Driven Development (BDD) testing.&lt;/p&gt;

&lt;p&gt;While &lt;a href="https://www.cypress.io/"&gt;Cypress &lt;/a&gt;and &lt;a href="https://cucumber.io/"&gt;Cucumber&lt;/a&gt; are favored tools for such testing, integrating them poses challenges due to their differing configurations. If developers try to work with typescript, it creates one extra configuration layer. Cypress’s configuration changed a lot from their pre-10 version. So maybe this blog can help others when they need to work later.&lt;/p&gt;

&lt;p&gt;Numerous tutorials and blogs cover the importance and procedures of E2E testing or BDD testing. However, This article focuses specifically on integration procedures for these testing methodologies.&lt;/p&gt;

&lt;p&gt;Now it's time to make our hands dirty. Cypress and cucumber will be integrated into an angular project which by default maintains typescript. So ensure that you have already installed Node.js, npm, and ng package in your work environment.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Create a new angular project.
&lt;code&gt;ng new angular-cypress-cucumber&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt; E2E testing needs your project running, so you need to run this angular project by
&lt;code&gt;npm start&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt; Install &lt;em&gt;@cypress/schematic&lt;/em&gt; package, this will help the angular project to run with Cypress.
&lt;code&gt;ng add @cypress/schematic&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;During installation, &lt;em&gt;@cypress/schematic&lt;/em&gt; automatically includes necessary npm packages. Additionally, it generates a Cypress configuration file, "&lt;em&gt;cypress.config.ts&lt;/em&gt;" and adjusts the "&lt;em&gt;angular.json&lt;/em&gt;" configuration file accordingly. Furthermore, it establishes a dedicated "&lt;em&gt;cypress&lt;/em&gt;" sub-directory, including sample test files to help the developer get started.&lt;/p&gt;

&lt;p&gt;We will execute test cases on a user list page. On this basic listing page, we can envision below scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Initially, the page will display no users.&lt;/li&gt;
&lt;li&gt;Following the click of the "Get Users" button, an API call will be triggered. If the API returns a valid response, the list will appear.&lt;/li&gt;
&lt;li&gt;In case of an error returned by the API, the page will remain unchanged.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now it is time for BDD &lt;br&gt;
&lt;code&gt;npm i @badeball/cypress-cucumber-preprocessor @cypress/webpack-preprocessor  -d&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Replace the whole &lt;em&gt;cypress.config.ts&lt;/em&gt; with below configuration content&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cypress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;webpack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@cypress/webpack-preprocessor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;preprocessor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@badeball/cypress-cucumber-preprocessor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setupNodeEvents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;preprocessor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addCucumberPreprocessorPlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;file:preprocessor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nf"&gt;webpack&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;webpackOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.js&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;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;rules&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="na"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;feature$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;use&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="na"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@badeball/cypress-cucumber-preprocessor/webpack&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;e2e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;baseUrl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:4200&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// this will be the default page for e2e testing&lt;/span&gt;
    &lt;span class="na"&gt;specPattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;**/e2e/**/*.feature&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// all e2e test file’s name should be in this pattern&lt;/span&gt;
    &lt;span class="nx"&gt;setupNodeEvents&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;devServer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;framework&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;angular&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;bundler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;webpack&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;specPattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;**/*.cy.ts&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;The configuration file facilitates the preprocessing of Cucumber-generated test cases, preparing them for execution by Cypress. Furthermore, it adjusts the spec locations, allowing Cypress to discover &lt;em&gt;.feature&lt;/em&gt; files for test execution. These feature files encapsulate BDD test cases written in the &lt;a href="https://cucumber.io/docs/gherkin/reference/"&gt;Gherkin syntax&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the package.json file add this new property too&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"cypress-cucumber-preprocessor"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"stepDefinitions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cypress/e2e/bdd-cucumber/step-defination/*.step.cy.ts"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Within the existing cypress/e2e directory, create a new folder named &lt;em&gt;bdd-cucumber&lt;/em&gt; and create another folder inside &lt;em&gt;bdd-cucumber&lt;/em&gt; named features. Navigate to the &lt;em&gt;cypress\e2e\bdd-cucumber\features&lt;/em&gt; directory and create a new file named &lt;em&gt;user-page.feature&lt;/em&gt;. As previously noted, Cucumber or BDD operates with the Gherkin language. The features within this folder will adhere to its syntax.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;user-page.feature&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;&lt;span class="kd"&gt;Feature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; User List functionality
  &lt;span class="kn"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; Prepare user page
    &lt;span class="nf"&gt;Given &lt;/span&gt;I am on the user page

  &lt;span class="kn"&gt;Scenario&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; Users appear in UI when API call succeeds
    &lt;span class="nf"&gt;When &lt;/span&gt;I click the &lt;span class="s"&gt;"Get Users"&lt;/span&gt; button
    &lt;span class="nf"&gt;Then &lt;/span&gt;A api call will be requested with valid response
    &lt;span class="nf"&gt;And &lt;/span&gt;user list will be appear on successful api request

  &lt;span class="kn"&gt;Scenario&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; Users do not appear in UI when API call fails
    &lt;span class="nf"&gt;When &lt;/span&gt;I click the &lt;span class="s"&gt;"Get Users"&lt;/span&gt; button to check failed response
    &lt;span class="nf"&gt;Then &lt;/span&gt;A api call will be requested with failed response
    &lt;span class="nf"&gt;And &lt;/span&gt;User list will not appear on failed api request
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also install &lt;em&gt;highlight-cucumber&lt;/em&gt; vscode extension to colorize those features.&lt;/p&gt;

&lt;p&gt;In the bdd-cucumber folder create another folder named &lt;em&gt;step-defination&lt;/em&gt; . Cypress test files will be added to this folder.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;user-page.step.cy.ts&lt;/em&gt;&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Given&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;When&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Then&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@badeball/cypress-cucumber-preprocessor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apiUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://jsonplaceholder.typicode.com/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;Given&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;I am on the user page&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&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="nc"&gt;When&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;I click the "Get Users" button&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;intercept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;apiUrl&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;getUserList&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Get User&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nc"&gt;Then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A api call will be requested with valid response&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@getUserList&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;interception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interception&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;apiUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interception&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&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="nc"&gt;Then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user list will be appear on successful api request&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;span.user-name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;its&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;length&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;should&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;be.greaterThan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nc"&gt;When&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;I click the "Get Users" button to check failed response&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;intercept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;apiUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;forceNetworkError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;getUserList&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Get User&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nc"&gt;Then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A api call will be requested with failed response&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@getUserList&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;interception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interception&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;apiUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interception&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interception&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;forceNetworkError called&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="p"&gt;});&lt;/span&gt;

&lt;span class="nc"&gt;Then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User list will not appear on failed api request&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;span.user-name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;should&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;not.exist&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;As we have already written our test cases, the next step is to implement a user list page. For simplicity, the Angular project comprises solely html and typescript code to retrieve user data via API.&lt;/p&gt;

&lt;p&gt;app.component.ts&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HttpClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/common/http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&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="nx"&gt;string&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="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;templateUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.component.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styleUrls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.component.scss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

 &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;angular-cypress-cucumber&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://jsonplaceholder.typicode.com/users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;httpClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nf"&gt;getUsers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;httpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;err&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Something went wrong!&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;complete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&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="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;app.component.html&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;(click)=&lt;/span&gt;&lt;span class="s"&gt;"getUsers()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Get User&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;*ngFor=&lt;/span&gt;&lt;span class="s"&gt;"let user of users"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"user-name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{user.name}}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now navigate to the project's directory, and run the command &lt;code&gt;npm run cypress:open&lt;/code&gt;. Before that, ensure that the angular project is running in &lt;a href="http://localhost:4200"&gt;http://localhost:4200&lt;/a&gt; which is declared as the base URL in the cypress configuration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Alimurrazi/angular-cypress-cucumber"&gt;Github Link&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cypress</category>
      <category>angular</category>
      <category>cucumber</category>
      <category>bdd</category>
    </item>
  </channel>
</rss>
