<?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: Chethan Ramaswamy</title>
    <description>The latest articles on DEV Community by Chethan Ramaswamy (@chethanramaswamy).</description>
    <link>https://dev.to/chethanramaswamy</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%2F3854098%2F1084dc39-c5b0-4f76-b77c-c4063d78d3f5.png</url>
      <title>DEV Community: Chethan Ramaswamy</title>
      <link>https://dev.to/chethanramaswamy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chethanramaswamy"/>
    <language>en</language>
    <item>
      <title>OWASP Top 10 for ASP.NET Core Web API: A Practical Security Guide</title>
      <dc:creator>Chethan Ramaswamy</dc:creator>
      <pubDate>Sat, 10 Oct 2026 15:35:01 +0000</pubDate>
      <link>https://dev.to/chethanramaswamy/owasp-top-10-for-aspnet-core-web-api-a-practical-security-guide-cce</link>
      <guid>https://dev.to/chethanramaswamy/owasp-top-10-for-aspnet-core-web-api-a-practical-security-guide-cce</guid>
      <description>&lt;p&gt;&lt;strong&gt;OWASP reference:&lt;/strong&gt; &lt;a href="https://owasp.org/www-project-top-ten/" rel="noopener noreferrer"&gt;OWASP Top&lt;br&gt;
10:2025&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Security note: The OWASP Top 10 is an awareness document, not a&lt;br&gt;
complete security standard or a substitute for threat modeling,&lt;br&gt;
security testing, and your organization's controls. The examples below&lt;br&gt;
are starting points; validate them against your application's&lt;br&gt;
architecture and supported .NET version.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;An ASP.NET Core Web API can have clean code, good test coverage, and a&lt;br&gt;
scalable architecture---and still expose sensitive data or business&lt;br&gt;
operations if its security controls are incomplete.&lt;/p&gt;

&lt;p&gt;Security is not just adding JWT authentication or enabling HTTPS. A&lt;br&gt;
production API must verify who is calling, what that caller is allowed&lt;br&gt;
to do, which inputs are trusted, how secrets are managed, how failures&lt;br&gt;
are handled, and whether suspicious activity can be detected.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;OWASP Top 10:2025&lt;/strong&gt; identifies ten major categories of web&lt;br&gt;
application security risk. This article translates each category into&lt;br&gt;
practical ASP.NET Core Web API guidance, with C# examples and&lt;br&gt;
implementation checks.&lt;/p&gt;
&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; Security foundations for an ASP.NET Core
API
&lt;/li&gt;
&lt;li&gt; A01:2025 --- Broken Access
Control
&lt;/li&gt;
&lt;li&gt; A02:2025 --- Security
Misconfiguration
&lt;/li&gt;
&lt;li&gt; A03:2025 --- Software Supply Chain
Failures
&lt;/li&gt;
&lt;li&gt; A04:2025 --- Cryptographic
Failures
&lt;/li&gt;
&lt;li&gt; A05:2025 --- Injection
&lt;/li&gt;
&lt;li&gt; A06:2025 --- Insecure Design
&lt;/li&gt;
&lt;li&gt; A07:2025 --- Authentication
Failures
&lt;/li&gt;
&lt;li&gt; A08:2025 --- Software or Data Integrity
Failures
&lt;/li&gt;
&lt;li&gt;A09:2025 --- Security Logging and Alerting
Failures&lt;/li&gt;
&lt;li&gt;A10:2025 --- Mishandling of Exceptional
Conditions&lt;/li&gt;
&lt;li&gt;A practical API security
baseline&lt;/li&gt;
&lt;li&gt;Security checklist for code
reviews&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;li&gt;References&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Security foundations for an ASP.NET Core API
&lt;/h2&gt;

&lt;p&gt;Before looking at individual risks, establish a few fundamentals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Authentication&lt;/strong&gt; answers: "Who is calling?"&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Authorization&lt;/strong&gt; answers: "What is this caller allowed to do?"&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Input validation&lt;/strong&gt; checks whether data meets the API's expected
shape and business rules.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Output and error handling&lt;/strong&gt; ensure that responses disclose only
what the caller should see.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Observability&lt;/strong&gt; makes security-relevant events detectable and
actionable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a typical API protected by an identity provider, use a standard&lt;br&gt;
OAuth 2.0/OpenID Connect flow and validate access tokens with ASP.NET&lt;br&gt;
Core authentication middleware. For service-to-service access in Azure,&lt;br&gt;
consider Microsoft Entra ID and managed identities where supported.&lt;/p&gt;

&lt;p&gt;A minimal JWT bearer setup can look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Authentication.JwtBearer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.IdentityModel.Tokens&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAuthentication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JwtBearerDefaults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthenticationScheme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddJwtBearer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Authority&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Identity:Authority"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Audience&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Identity:Audience"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TokenValidationParameters&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;TokenValidationParameters&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;ValidateIssuer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;ValidateAudience&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;ValidateLifetime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;ValidateIssuerSigningKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;ClockSkew&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromMinutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

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

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

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

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

&lt;/div&gt;



&lt;p&gt;Configure the authority and audience for your identity provider. Do not&lt;br&gt;
disable issuer, audience, lifetime, or signing-key validation to "make&lt;br&gt;
tokens work." In production, also confirm signing-key rollover,&lt;br&gt;
scopes/roles, token lifetime, and identity-provider configuration.&lt;/p&gt;
&lt;h2&gt;
  
  
  A01:2025 --- Broken Access Control
&lt;/h2&gt;

&lt;p&gt;Broken access control occurs when an authenticated caller can perform an&lt;br&gt;
operation or access a resource they should not be allowed to access.&lt;br&gt;
This is one of the most important risks for APIs because clients&lt;br&gt;
frequently send object identifiers such as &lt;code&gt;customerId&lt;/code&gt;, &lt;code&gt;orderId&lt;/code&gt;, or&lt;br&gt;
&lt;code&gt;accountId&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Vulnerable pattern
&lt;/h3&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;HttpGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{id:int}"&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;GetOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;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="n"&gt;Orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&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 endpoint verifies neither ownership nor permission. A caller may&lt;br&gt;
change &lt;code&gt;/api/orders/100&lt;/code&gt; to &lt;code&gt;/api/orders/101&lt;/code&gt; and access another&lt;br&gt;
customer's order. This is commonly described as insecure direct object&lt;br&gt;
reference (IDOR), a form of broken access control.&lt;/p&gt;
&lt;h3&gt;
  
  
  Safer approach: enforce access at the resource query
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Authorize&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{id:int}"&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;GetOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;subject&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindFirst&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sub"&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrWhiteSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Forbid&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="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="n"&gt;Orders&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerSubject&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OrderResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;o&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SingleOrDefaultAsync&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;order&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&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;This assumes &lt;code&gt;OwnerSubject&lt;/code&gt; stores a stable subject identifier from the&lt;br&gt;
trusted identity provider. Adapt the claim and ownership model to your&lt;br&gt;
identity design. For multi-tenant systems, include tenant boundaries in&lt;br&gt;
the query and verify that the tenant claim is trusted and correctly&lt;br&gt;
mapped.&lt;/p&gt;
&lt;h3&gt;
  
  
  Practical controls
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Apply &lt;code&gt;[Authorize]&lt;/code&gt; by default to protected controllers or
endpoints.&lt;/li&gt;
&lt;li&gt;  Use policies for roles, scopes, and business permissions.&lt;/li&gt;
&lt;li&gt;  Check &lt;strong&gt;object-level authorization&lt;/strong&gt; on every operation that reads
or changes a resource.&lt;/li&gt;
&lt;li&gt;  Do not trust a tenant ID, owner ID, role, or price supplied by the
client.&lt;/li&gt;
&lt;li&gt;  Restrict mass assignment by using request DTOs instead of binding
persistence entities.&lt;/li&gt;
&lt;li&gt;  Test access using different users, tenants, roles, and resource
owners.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For complex rules, ASP.NET Core resource-based authorization can&lt;br&gt;
centralize policy decisions. A role check alone is not enough if&lt;br&gt;
permission depends on the specific resource.&lt;/p&gt;
&lt;h2&gt;
  
  
  A02:2025 --- Security Misconfiguration
&lt;/h2&gt;

&lt;p&gt;Security misconfiguration includes unsafe defaults, exposed diagnostics,&lt;br&gt;
overly permissive CORS, unnecessary endpoints, and inconsistent security&lt;br&gt;
settings across environments.&lt;/p&gt;
&lt;h3&gt;
  
  
  Common ASP.NET Core pitfalls
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Running a production environment with the Developer Exception Page.&lt;/li&gt;
&lt;li&gt;  Allowing every origin, header, and method through CORS without a
business need.&lt;/li&gt;
&lt;li&gt;  Exposing Swagger/OpenAPI UI publicly when it should be restricted.&lt;/li&gt;
&lt;li&gt;  Forgetting HTTPS redirection or secure proxy configuration.&lt;/li&gt;
&lt;li&gt;  Leaving unused middleware, sample controllers, health details, or
administrative endpoints exposed.&lt;/li&gt;
&lt;li&gt;  Relying on a reverse proxy to enforce controls without confirming
the API's own deployment assumptions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Configure CORS deliberately
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddCors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Frontend"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;policy&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;policy&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithOrigins&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://app.example.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithMethods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"PUT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"DELETE"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithHeaders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Content-Type"&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;Apply the policy explicitly:&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;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseCors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Frontend"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CORS is a browser-enforced cross-origin policy, not authentication or&lt;br&gt;
authorization. Non-browser clients can call an API regardless of CORS&lt;br&gt;
rules. If cookies are used, configure credentials and anti-forgery&lt;br&gt;
protections carefully; never combine credentialed requests with a&lt;br&gt;
wildcard origin.&lt;/p&gt;
&lt;h3&gt;
  
  
  Production configuration checklist
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Use environment-specific configuration and safe defaults.&lt;/li&gt;
&lt;li&gt;  Keep detailed exception pages and developer tools out of production.&lt;/li&gt;
&lt;li&gt;  Restrict API documentation to intended audiences and protect it when
necessary.&lt;/li&gt;
&lt;li&gt;  Trust forwarded headers only from known proxies or networks;
incorrect proxy configuration can affect scheme, host, and client-IP
interpretation.&lt;/li&gt;
&lt;li&gt;  Set request body and upload limits appropriate to the endpoint.&lt;/li&gt;
&lt;li&gt;  Configure security headers at the correct layer for your deployment.&lt;/li&gt;
&lt;li&gt;  Review cloud network access, private endpoints, firewall rules, and
ingress settings.&lt;/li&gt;
&lt;li&gt;  Verify health endpoints disclose no secrets, connection strings, or
internal topology.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  A03:2025 --- Software Supply Chain Failures
&lt;/h2&gt;

&lt;p&gt;Modern .NET applications depend on NuGet packages, SDKs, container base&lt;br&gt;
images, build tasks, GitHub Actions or Azure DevOps tasks, and&lt;br&gt;
deployment artifacts. A vulnerable or compromised dependency or build&lt;br&gt;
pipeline can undermine otherwise secure application code.&lt;/p&gt;
&lt;h3&gt;
  
  
  Reduce dependency risk
&lt;/h3&gt;

&lt;p&gt;Run dependency and vulnerability checks as part of CI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet list package &lt;span class="nt"&gt;--vulnerable&lt;/span&gt; &lt;span class="nt"&gt;--include-transitive&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use this command with a supported SDK and package source configuration.&lt;br&gt;
For automated pipelines, combine it with dependency scanning, repository&lt;br&gt;
alerts, and a policy that fails builds for vulnerabilities that exceed&lt;br&gt;
your organization's risk threshold.&lt;/p&gt;
&lt;h3&gt;
  
  
  Practical controls
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Keep supported .NET SDKs, runtimes, NuGet packages, and container
images patched.&lt;/li&gt;
&lt;li&gt;  Pin or centrally manage dependency versions; review updates rather
than blindly accepting them.&lt;/li&gt;
&lt;li&gt;  Commit and review &lt;code&gt;packages.lock.json&lt;/code&gt; where deterministic package
restore is part of your process.&lt;/li&gt;
&lt;li&gt;  Use trusted package feeds and protect feed credentials.&lt;/li&gt;
&lt;li&gt;  Scan direct and transitive dependencies.&lt;/li&gt;
&lt;li&gt;  Protect CI/CD identities with least privilege and short-lived
credentials where possible.&lt;/li&gt;
&lt;li&gt;  Restrict who can modify pipeline definitions, release environments,
and production approvals.&lt;/li&gt;
&lt;li&gt;  Generate a software bill of materials (SBOM) where required, and
retain provenance for build artifacts.&lt;/li&gt;
&lt;li&gt;  Sign and verify artifacts when supported by your release platform
and threat model.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A clean local build does not prove the supply chain is trustworthy. The&lt;br&gt;
build agent, dependencies, package feed, and artifact promotion path are&lt;br&gt;
part of the security boundary.&lt;/p&gt;
&lt;h2&gt;
  
  
  A04:2025 --- Cryptographic Failures
&lt;/h2&gt;

&lt;p&gt;Cryptographic failures happen when sensitive data is exposed because it&lt;br&gt;
is not protected appropriately, weak algorithms or key handling are&lt;br&gt;
used, or secrets are stored insecurely.&lt;/p&gt;
&lt;h3&gt;
  
  
  Common examples
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Sending credentials or tokens over plain HTTP.&lt;/li&gt;
&lt;li&gt;  Storing passwords in plaintext or using a fast general-purpose hash.&lt;/li&gt;
&lt;li&gt;  Committing database passwords or signing keys to source control.&lt;/li&gt;
&lt;li&gt;  Logging bearer tokens, API keys, or personal data.&lt;/li&gt;
&lt;li&gt;  Using custom encryption instead of established platform libraries.&lt;/li&gt;
&lt;li&gt;  Keeping encryption keys next to the encrypted data without suitable
access controls.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Protect secrets outside source code
&lt;/h3&gt;

&lt;p&gt;For local development, use the .NET Secret Manager for development-only&lt;br&gt;
secrets. It is not an encrypted production secret vault. In Azure,&lt;br&gt;
prefer Key Vault and managed identity rather than storing long-lived&lt;br&gt;
credentials in configuration files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Example: access a secret through configuration.&lt;/span&gt;
&lt;span class="c1"&gt;// The production configuration provider should retrieve it&lt;/span&gt;
&lt;span class="c1"&gt;// from an approved secret store such as Azure Key Vault.&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connectionString&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetConnectionString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"OrdersDatabase"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrWhiteSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InvalidOperationException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"The OrdersDatabase connection string is not configured."&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 example does not itself connect to Key Vault; configure the&lt;br&gt;
appropriate provider and identity for your environment.&lt;/p&gt;
&lt;h3&gt;
  
  
  Practical controls
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Enforce HTTPS and correctly configure TLS at the ingress and
application layers.&lt;/li&gt;
&lt;li&gt;  Use platform password-hashing facilities such as ASP.NET Core
Identity rather than inventing a password hash scheme.&lt;/li&gt;
&lt;li&gt;  Store keys and secrets in a dedicated secret-management service with
access auditing and rotation.&lt;/li&gt;
&lt;li&gt;  Encrypt sensitive data at rest when required by the data
classification and threat model.&lt;/li&gt;
&lt;li&gt;  Minimize the sensitive data you collect, return, and retain.&lt;/li&gt;
&lt;li&gt;  Redact credentials and personal data from logs, traces, and
exception messages.&lt;/li&gt;
&lt;li&gt;  Use cryptographic libraries and algorithms recommended by current
platform guidance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Encryption is not a replacement for authorization. If an attacker can&lt;br&gt;
legitimately retrieve decrypted data through an over-permissive API,&lt;br&gt;
encryption at rest will not solve the access-control problem.&lt;/p&gt;
&lt;h2&gt;
  
  
  A05:2025 --- Injection
&lt;/h2&gt;

&lt;p&gt;Injection occurs when untrusted input is interpreted as executable SQL,&lt;br&gt;
a shell command, a query language expression, or another instruction.&lt;/p&gt;
&lt;h3&gt;
  
  
  SQL injection: unsafe string concatenation
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Do not do this.&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"SELECT * FROM Orders WHERE CustomerId = '&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;customerId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If the input is incorporated into SQL syntax, an attacker may alter the&lt;br&gt;
query's meaning.&lt;/p&gt;
&lt;h3&gt;
  
  
  Prefer parameterized queries
&lt;/h3&gt;

&lt;p&gt;With EF Core, normal LINQ queries are parameterized:&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;orders&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="n"&gt;Orders&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CustomerId&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;customerId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For raw SQL, use parameterized APIs:&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;orders&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="n"&gt;Orders&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromSqlInterpolated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;$"SELECT * FROM Orders WHERE CustomerId = &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;customerId&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="nf"&gt;ToListAsync&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;FromSqlInterpolated&lt;/code&gt; parameterizes interpolated values. Do not replace&lt;br&gt;
it with &lt;code&gt;FromSqlRaw&lt;/code&gt; plus string concatenation. SQL parameters cannot&lt;br&gt;
safely stand in for identifiers such as table names or sort directions;&lt;br&gt;
map those choices to a fixed allowlist.&lt;/p&gt;
&lt;h3&gt;
  
  
  Validate input as well
&lt;/h3&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;sealed&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;CreateOrderRequest&lt;/span&gt;&lt;span class="p"&gt;(&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="n"&gt;Required&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;CustomerReference&lt;/span&gt;&lt;span class="p"&gt;,&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="nf"&gt;Range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Quantity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Use request DTOs and server-side validation, but remember that&lt;br&gt;
validation does not replace parameterized queries. Also:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Avoid building shell commands from request values.&lt;/li&gt;
&lt;li&gt;  Avoid unsafe dynamic expression construction.&lt;/li&gt;
&lt;li&gt;  Treat uploaded files, headers, query parameters, and message-queue
payloads as untrusted.&lt;/li&gt;
&lt;li&gt;  Encode output appropriately when returning data to HTML-rendering
clients.&lt;/li&gt;
&lt;li&gt;  Review XML parsers, template engines, and search/query DSLs for
injection-specific settings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ASP.NET Core APIs often return JSON rather than HTML, so classic&lt;br&gt;
reflected XSS is less common in the API response itself. However, unsafe&lt;br&gt;
content may later be rendered by a browser-based client. JSON does not&lt;br&gt;
make untrusted content safe for every downstream consumer.&lt;/p&gt;
&lt;h2&gt;
  
  
  A06:2025 --- Insecure Design
&lt;/h2&gt;

&lt;p&gt;Insecure design is a weakness in the system's requirements, workflows,&lt;br&gt;
or trust assumptions---not merely a coding defect. A technically correct&lt;br&gt;
endpoint can still implement an unsafe business process.&lt;/p&gt;
&lt;h3&gt;
  
  
  Example: trusting a client-supplied price
&lt;/h3&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;sealed&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;CreateOrderRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ProductId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Quantity&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;UnitPrice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Do not trust this price from the client.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If the API accepts the price as authoritative, a caller may submit a&lt;br&gt;
lower value than the real product price.&lt;/p&gt;

&lt;p&gt;Instead, accept only the data the client is allowed to choose and&lt;br&gt;
calculate authoritative values on the server:&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;sealed&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;CreateOrderRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ProductId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Quantity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Authorize&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HttpPost&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;CreateOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;CreateOrderRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Quantity&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;BadRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Quantity is outside the permitted range."&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;product&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="n"&gt;Products&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SingleOrDefaultAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProductId&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;NotFound&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="k"&gt;new&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;ProductId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Quantity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Quantity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;UnitPrice&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CurrentPrice&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;Orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&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="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;CreatedAtAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GetOrder&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;id&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="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;order&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="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UnitPrice&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;This is illustrative; production code should also validate inventory,&lt;br&gt;
currency, discounts, tax, concurrency, customer eligibility, and&lt;br&gt;
transaction boundaries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Design controls before coding
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Threat-model important flows such as payments, account recovery,
tenant administration, and bulk exports.&lt;/li&gt;
&lt;li&gt;  Define authorization rules for every operation and resource.&lt;/li&gt;
&lt;li&gt;  Set limits for pagination, batch size, file size, request rate, and
expensive queries.&lt;/li&gt;
&lt;li&gt;  Make state transitions explicit and reject invalid transitions.&lt;/li&gt;
&lt;li&gt;  Use idempotency keys for operations where retries could create
duplicate effects.&lt;/li&gt;
&lt;li&gt;  Require additional verification for high-impact actions when
appropriate.&lt;/li&gt;
&lt;li&gt;  Design for abuse cases, not only expected user journeys.&lt;/li&gt;
&lt;li&gt;  Document trust boundaries between the API, identity provider,
database, queues, and external services.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Security requirements should be acceptance criteria, not a last-minute&lt;br&gt;
checklist after the feature is built.&lt;/p&gt;

&lt;h2&gt;
  
  
  A07:2025 --- Authentication Failures
&lt;/h2&gt;

&lt;p&gt;Authentication failures include weak credential handling, incorrect&lt;br&gt;
token validation, insecure authentication flows, and gaps in session or&lt;br&gt;
account lifecycle controls.&lt;/p&gt;

&lt;h3&gt;
  
  
  Validate bearer tokens properly
&lt;/h3&gt;

&lt;p&gt;Use the framework's JWT bearer middleware or a supported&lt;br&gt;
identity-provider integration. Do not manually decode a JWT and treat&lt;br&gt;
its claims as trusted without verifying the signature and relevant&lt;br&gt;
validation rules.&lt;/p&gt;

&lt;p&gt;For access tokens, verify at least:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Signature and signing key.&lt;/li&gt;
&lt;li&gt;  Issuer.&lt;/li&gt;
&lt;li&gt;  Audience.&lt;/li&gt;
&lt;li&gt;  Expiration and not-before timestamps.&lt;/li&gt;
&lt;li&gt;  Required scopes or roles for the API operation.&lt;/li&gt;
&lt;li&gt;  Token type and accepted algorithms as appropriate to the identity
provider.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A valid token proves neither that the caller owns a specific record nor&lt;br&gt;
that every operation is permitted.&lt;/p&gt;

&lt;h3&gt;
  
  
  Practical controls
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  Prefer established identity providers over custom authentication
implementations.&lt;/li&gt;
&lt;li&gt;  Use authorization-code flow with PKCE for appropriate interactive
clients; use client credentials for service-to-service access where
appropriate.&lt;/li&gt;
&lt;li&gt;  Do not use the OAuth resource-owner-password credentials flow for
new designs.&lt;/li&gt;
&lt;li&gt;  Apply rate limits and monitoring to login, password reset, OTP, and
token-related endpoints.&lt;/li&gt;
&lt;li&gt;  Use MFA for privileged and high-risk accounts where applicable.&lt;/li&gt;
&lt;li&gt;  Avoid revealing whether a username or email exists in authentication
and recovery responses.&lt;/li&gt;
&lt;li&gt;  Rotate and revoke credentials when compromise is suspected.&lt;/li&gt;
&lt;li&gt;  Keep access tokens out of URLs, logs, analytics, and error reports.&lt;/li&gt;
&lt;li&gt;  Use managed identities for supported Azure service-to-service access
rather than embedded secrets.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Authorization is still separate
&lt;/h3&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;Authorize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Orders.Read"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{id:int}"&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;Task&lt;/span&gt; &lt;span class="nf"&gt;GetOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// The policy checks a permission; the implementation must still&lt;/span&gt;
    &lt;span class="c1"&gt;// verify that the caller may access this particular order.&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NotImplementedException&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Define the policy in the service configuration and adapt the claim type&lt;br&gt;
to your identity provider:&lt;/p&gt;



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

&lt;/div&gt;

</description>
      <category>api</category>
      <category>backend</category>
      <category>dotnet</category>
      <category>security</category>
    </item>
    <item>
      <title>Abstract Class vs Interface in C#: Demystifying the Difference</title>
      <dc:creator>Chethan Ramaswamy</dc:creator>
      <pubDate>Tue, 06 Oct 2026 16:51:02 +0000</pubDate>
      <link>https://dev.to/chethanramaswamy/abstract-class-vs-interface-in-c-demystifying-the-difference-3ieg</link>
      <guid>https://dev.to/chethanramaswamy/abstract-class-vs-interface-in-c-demystifying-the-difference-3ieg</guid>
      <description>&lt;h1&gt;
  
  
  Abstract Class vs Interface in C#: Demystifying the Difference
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Few C# interview questions create as much confusion as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"What is the difference between an abstract class and an interface,&lt;br&gt;
and when should I use each?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Many developers memorize a comparison table:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Abstract class → can have implementation&lt;/li&gt;
&lt;li&gt;  Interface → defines a contract&lt;/li&gt;
&lt;li&gt;  Abstract class → supports fields&lt;/li&gt;
&lt;li&gt;  Interface → does not&lt;/li&gt;
&lt;li&gt;  Abstract class → single inheritance&lt;/li&gt;
&lt;li&gt;  Interface → multiple inheritance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These statements are useful, but they do not answer the most important&lt;br&gt;
question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why would I choose one over the other when designing a real&lt;br&gt;
application?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This article builds the answer from first principles.&lt;/p&gt;

&lt;p&gt;The simplest way to remember it is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;An interface describes what a type can do. An abstract class&lt;br&gt;
describes what a family of related types fundamentally is, while&lt;br&gt;
allowing shared behavior.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That distinction is much more valuable than memorizing syntax.&lt;/p&gt;


&lt;h1&gt;
  
  
  1. Start With the Real Design Problem
&lt;/h1&gt;

&lt;p&gt;Suppose we are building an application that sends notifications.&lt;/p&gt;

&lt;p&gt;We may have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Email notification&lt;/li&gt;
&lt;li&gt;  SMS notification&lt;/li&gt;
&lt;li&gt;  Push notification&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of them can &lt;strong&gt;send a notification&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That immediately suggests a contract:&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;interface&lt;/span&gt; &lt;span class="nc"&gt;INotificationSender&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;SendAsync&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;message&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;Now imagine that all notification providers also need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Common logging&lt;/li&gt;
&lt;li&gt;  Common validation&lt;/li&gt;
&lt;li&gt;  A provider name&lt;/li&gt;
&lt;li&gt;  Shared retry behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That may suggest an abstract base class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NotificationSender&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ILogger&lt;/span&gt; &lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nf"&gt;NotificationSender&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ILogger&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Logger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logger&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;abstract&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;SendAsync&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;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;LogSending&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;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sending notification: {Message}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="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 two abstractions solve &lt;strong&gt;different design problems&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The interface says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Anything implementing me promises that it can send a notification."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The abstract class says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"These objects belong to the same conceptual family and can share&lt;br&gt;
state and implementation."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is the core distinction.&lt;/p&gt;




&lt;h1&gt;
  
  
  2. What Is an Interface?
&lt;/h1&gt;

&lt;p&gt;An interface is a &lt;strong&gt;contract&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It defines capabilities that a type promises to provide.&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;interface&lt;/span&gt; &lt;span class="nc"&gt;IPaymentProcessor&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ProcessPaymentAsync&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;amount&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;A class implements that contract:&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;StripePaymentProcessor&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IPaymentProcessor&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;ProcessPaymentAsync&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;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Stripe-specific implementation&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;Another implementation can provide a completely different&lt;br&gt;
implementation:&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;RazorpayPaymentProcessor&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IPaymentProcessor&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;ProcessPaymentAsync&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;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Razorpay-specific implementation&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 important point is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The interface does not care how payment is processed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It only defines the capability.&lt;/p&gt;




&lt;h1&gt;
  
  
  3. What Is an Abstract Class?
&lt;/h1&gt;

&lt;p&gt;An abstract class is a &lt;strong&gt;base type that is incomplete by design&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It can contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Abstract methods&lt;/li&gt;
&lt;li&gt;  Concrete methods&lt;/li&gt;
&lt;li&gt;  Fields&lt;/li&gt;
&lt;li&gt;  Properties&lt;/li&gt;
&lt;li&gt;  Constructors&lt;/li&gt;
&lt;li&gt;  Protected members&lt;/li&gt;
&lt;li&gt;  Shared state&lt;/li&gt;
&lt;li&gt;  Static members&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaymentProcessor&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ILogger&lt;/span&gt; &lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nf"&gt;PaymentProcessor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ILogger&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Logger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logger&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;abstract&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ProcessPaymentAsync&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;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;LogPayment&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;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"Processing payment of {Amount}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;amount&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;A derived class must implement the abstract operation:&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;StripePaymentProcessor&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PaymentProcessor&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;StripePaymentProcessor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ILogger&lt;/span&gt; &lt;span class="n"&gt;logger&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;logger&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;override&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;ProcessPaymentAsync&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;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;LogPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Stripe-specific implementation&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here the base class provides &lt;strong&gt;common behavior and state&lt;/strong&gt;, while&lt;br&gt;
subclasses provide specialized behavior.&lt;/p&gt;


&lt;h1&gt;
  
  
  4. The Most Important Difference
&lt;/h1&gt;

&lt;p&gt;The easiest mental model is:&lt;/p&gt;
&lt;h2&gt;
  
  
  Interface = Capability
&lt;/h2&gt;

&lt;p&gt;Ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"What can this object do?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IEnumerable
IDisposable
IComparable
ILogger
IPaymentProcessor
INotificationSender
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A class may support several unrelated capabilities.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight 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="n"&gt;IOrderService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;IDisposable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;IAsyncDisposable&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;These interfaces describe capabilities/contracts.&lt;/p&gt;




&lt;h2&gt;
  
  
  Abstract Class = Family / Common Foundation
&lt;/h2&gt;

&lt;p&gt;Ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"What is this object fundamentally, and what behavior should all&lt;br&gt;
members of this family share?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PaymentProcessor
    ├── StripePaymentProcessor
    ├── RazorpayPaymentProcessor
    └── PayPalPaymentProcessor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They share a common conceptual foundation.&lt;/p&gt;

&lt;p&gt;Therefore an abstract class can make sense.&lt;/p&gt;




&lt;h1&gt;
  
  
  5. A Powerful Interview Rule
&lt;/h1&gt;

&lt;p&gt;When deciding between them, ask two questions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Question 1
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Is this a capability that unrelated classes may need?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If yes, prefer an &lt;strong&gt;interface&lt;/strong&gt;.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IAuditable&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;CreatedAt&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A customer, order, invoice, or product could all be auditable.&lt;/p&gt;

&lt;p&gt;They do not need to belong to the same inheritance hierarchy.&lt;/p&gt;




&lt;h3&gt;
  
  
  Question 2
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Do these classes belong to the same conceptual family and need&lt;br&gt;
shared state or implementation?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If yes, an &lt;strong&gt;abstract class&lt;/strong&gt; may be appropriate.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DocumentProcessor
    ├── PdfProcessor
    ├── WordProcessor
    └── ExcelProcessor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All processors may share:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  File validation&lt;/li&gt;
&lt;li&gt;  Logging&lt;/li&gt;
&lt;li&gt;  Configuration&lt;/li&gt;
&lt;li&gt;  Metrics&lt;/li&gt;
&lt;li&gt;  Common processing workflow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An abstract base class can encapsulate that common behavior.&lt;/p&gt;




&lt;h1&gt;
  
  
  6. Side-by-Side Comparison
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Difference&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Abstract class provides a common foundation. Interface defines a contract or capability.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Implementation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Abstract class can provide shared implementation. Interface can also provide default implementations in modern C#.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;State&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Abstract class can contain instance state. Interface cannot contain instance fields.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Constructors&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Abstract class can have constructors. Interfaces cannot have instance constructors.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Inheritance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A class can inherit only one base class. A class can implement multiple interfaces.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Coupling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Abstract classes create a stronger relationship. Interfaces generally provide looser coupling.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best use&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Use for shared behavior, state, or workflow.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Typical example&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;FileProcessor&lt;/code&gt; → &lt;code&gt;PdfProcessor&lt;/code&gt;, &lt;code&gt;ExcelProcessor&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Interface example&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;INotificationSender&lt;/code&gt; → &lt;code&gt;EmailSender&lt;/code&gt;, &lt;code&gt;SmsSender&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h1&gt;
  
  
  7. Why Does C# Allow Multiple Interfaces but Only One Base Class?
&lt;/h1&gt;

&lt;p&gt;Consider:&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;ReportService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;IReportGenerator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;IAuditable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;IDisposable&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;A class can implement multiple interfaces.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Because these interfaces represent independent capabilities:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ReportService
 ├── IReportGenerator
 ├── IAuditable
 └── IDisposable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But C# allows only one class inheritance chain:&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;ReportService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BaseReportService&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 reason is that inheriting implementation and state creates much&lt;br&gt;
stronger relationships.&lt;/p&gt;

&lt;p&gt;If multiple base classes were allowed, problems such as conflicting&lt;br&gt;
implementations and state become much harder to reason about.&lt;/p&gt;

&lt;p&gt;So C# deliberately separates:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Capability composition&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;from&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation inheritance&lt;/strong&gt;&lt;/p&gt;


&lt;h1&gt;
  
  
  8. Real Example: Interface Is Better
&lt;/h1&gt;

&lt;p&gt;Imagine a logging system.&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;interface&lt;/span&gt; &lt;span class="nc"&gt;INotificationSender&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;SendAsync&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;recipient&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;message&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;Implementations:&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;EmailNotificationSender&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;INotificationSender&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;Task&lt;/span&gt; &lt;span class="nf"&gt;SendAsync&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;recipient&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;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Send email&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedTask&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;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;SmsNotificationSender&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;INotificationSender&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;Task&lt;/span&gt; &lt;span class="nf"&gt;SendAsync&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;recipient&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;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Send SMS&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedTask&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;Why interface?&lt;/p&gt;

&lt;p&gt;Because email and SMS are not necessarily related by inheritance.&lt;/p&gt;

&lt;p&gt;They simply share a capability:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;They can send notifications.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The interface keeps the design loosely coupled.&lt;/p&gt;




&lt;h1&gt;
  
  
  9. Real Example: Abstract Class Is Better
&lt;/h1&gt;

&lt;p&gt;Consider file processors.&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;abstract&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FileProcessor&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;ProcessAsync&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;filePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;ReadAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Validate&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;filePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrWhiteSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ArgumentException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Invalid file path."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ReadAsync&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;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Log&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;filePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Processed &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now:&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;PdfProcessor&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;FileProcessor&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ReadAsync&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;filePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// PDF-specific logic&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedTask&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;And:&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;ExcelProcessor&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;FileProcessor&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ReadAsync&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;filePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Excel-specific logic&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedTask&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;The abstract class provides a common workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Validate
   ↓
Read
   ↓
Log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only the specialized operation changes.&lt;/p&gt;

&lt;p&gt;This is a classic use case for an abstract class.&lt;/p&gt;




&lt;h1&gt;
  
  
  10. Interface Does NOT Mean "No Implementation"
&lt;/h1&gt;

&lt;p&gt;This is an important misconception.&lt;/p&gt;

&lt;p&gt;Modern C# interfaces can contain default implementations.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;ILogger&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Log&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;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;LogError&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;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"ERROR: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&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;So this statement is outdated:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Interfaces cannot contain implementation."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A better statement is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Interfaces primarily define contracts, but modern C# allows them to&lt;br&gt;
provide default implementations as well.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;However, that does not mean interfaces should become replacements for&lt;br&gt;
abstract classes.&lt;/p&gt;

&lt;p&gt;Default interface implementations solve specific versioning and&lt;br&gt;
API-evolution scenarios. They do not provide instance state or turn an&lt;br&gt;
interface into a normal stateful base class.&lt;/p&gt;


&lt;h1&gt;
  
  
  11. Abstract Class vs Interface in Dependency Injection
&lt;/h1&gt;

&lt;p&gt;This is where interfaces are extremely common in .NET applications.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IOrderRepository&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;GetByIdAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Implementation:&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;SqlOrderRepository&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IOrderRepository&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;Task&lt;/span&gt; &lt;span class="nf"&gt;GetByIdAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Database implementation&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NotImplementedException&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Register it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddScoped&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application depends on:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;instead of:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This provides loose coupling.&lt;/p&gt;

&lt;p&gt;It also makes testing easier:&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;FakeOrderRepository&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IOrderRepository&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Test implementation&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 one reason interfaces are heavily used in enterprise .NET&lt;br&gt;
applications.&lt;/p&gt;


&lt;h1&gt;
  
  
  12. Does That Mean We Should Always Use Interfaces?
&lt;/h1&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;p&gt;This is another common mistake.&lt;/p&gt;

&lt;p&gt;Some developers create an interface for every single class:&lt;br&gt;
&lt;/p&gt;

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

OrderService
IOrderService

ProductService
IProductService
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;without any real architectural reason.&lt;/p&gt;

&lt;p&gt;This can produce unnecessary abstraction.&lt;/p&gt;

&lt;p&gt;For example, if a class:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Has one implementation&lt;/li&gt;
&lt;li&gt;  Is internal to a small module&lt;/li&gt;
&lt;li&gt;  Does not need polymorphism&lt;/li&gt;
&lt;li&gt;  Does not represent a meaningful boundary&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;then creating an interface may add complexity without providing much&lt;br&gt;
value.&lt;/p&gt;

&lt;p&gt;The goal is not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Use interfaces everywhere."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The goal is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Use abstraction where it creates a useful boundary.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h1&gt;
  
  
  13. When Should You Use an Interface?
&lt;/h1&gt;

&lt;p&gt;Prefer an interface when:&lt;/p&gt;
&lt;h3&gt;
  
  
  1. You need a contract
&lt;/h3&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;interface&lt;/span&gt; &lt;span class="nc"&gt;IPaymentProcessor&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ProcessAsync&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;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  2. Multiple unrelated classes need the same capability
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Order
Customer
Invoice
Product
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;could all implement:&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;IAuditable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. You need multiple capabilities
&lt;/h3&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;Order&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;IAuditable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;IValidatable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;IExportable&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. You want loose coupling
&lt;/h3&gt;

&lt;p&gt;Especially across application boundaries such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Controller
   ↓
Application Service
   ↓
Interface
   ↓
Implementation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. You expect multiple implementations
&lt;/h3&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IPaymentProcessor
    ├── StripePaymentProcessor
    ├── RazorpayPaymentProcessor
    └── MockPaymentProcessor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  14. When Should You Use an Abstract Class?
&lt;/h1&gt;

&lt;p&gt;Prefer an abstract class when:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. There is a strong "is-a" relationship
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PdfProcessor is a FileProcessor
ExcelProcessor is a FileProcessor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Subclasses need shared implementation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Validate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Subclasses need shared state
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ILogger&lt;/span&gt; &lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. You want to enforce a common workflow
&lt;/h3&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Validate
   ↓
Authenticate
   ↓
Process
   ↓
Audit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is commonly implemented using the Template Method pattern.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. You control the inheritance hierarchy
&lt;/h3&gt;

&lt;p&gt;An abstract base class creates a stronger relationship than an&lt;br&gt;
interface, so it should be used deliberately.&lt;/p&gt;


&lt;h1&gt;
  
  
  15. A Real Enterprise Example
&lt;/h1&gt;

&lt;p&gt;Imagine an order-processing platform.&lt;/p&gt;

&lt;p&gt;We might have:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;as the contract:&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;interface&lt;/span&gt; &lt;span class="nc"&gt;IOrderProcessor&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ProcessAsync&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Different implementations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OnlineOrderProcessor
StoreOrderProcessor
PartnerOrderProcessor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now suppose every processor needs common behavior:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Validate order
Create correlation ID
Start telemetry
Execute processing
Audit result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An abstract class could provide that workflow:&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;abstract&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderProcessorBase&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;ProcessAsync&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="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Validate&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="nf"&gt;ProcessCoreAsync&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="nf"&gt;Audit&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="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;virtual&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Validate&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="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Common validation&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ProcessCoreAsync&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="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;virtual&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Audit&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="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Common audit&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;A concrete processor then implements only the variable portion:&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;OnlineOrderProcessor&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;OrderProcessorBase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ProcessCoreAsync&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="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Online-order-specific logic&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedTask&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;This gives us:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Common workflow
      ↓
Abstract base class
      ↓
Specialized implementations
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If consumers should depend on a stable contract, we can additionally&lt;br&gt;
expose an interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IOrderProcessor
       ↑
OrderProcessorBase
       ↑
OnlineOrderProcessor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The two mechanisms are not competitors.&lt;/p&gt;

&lt;p&gt;They can work together.&lt;/p&gt;




&lt;h1&gt;
  
  
  16. Interface + Abstract Class Together
&lt;/h1&gt;

&lt;p&gt;This is a powerful enterprise pattern.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IFileProcessor&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ProcessAsync&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;filePath&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;Then:&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;abstract&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FileProcessorBase&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IFileProcessor&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;ProcessAsync&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;filePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;ProcessCoreAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nf"&gt;Audit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ProcessCoreAsync&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;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;virtual&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Validate&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;filePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Common validation&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;virtual&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Audit&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;filePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Common auditing&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;Concrete implementation:&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;PdfProcessor&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;FileProcessorBase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ProcessCoreAsync&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;filePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// PDF processing&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedTask&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;Now we have:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interface&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Defines the external contract
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Abstract class&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Provides reusable implementation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Concrete class&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Provides specific behavior
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is often cleaner than trying to force one abstraction to do&lt;br&gt;
everything.&lt;/p&gt;


&lt;h1&gt;
  
  
  17. The "Can Do" vs "Is A" Rule
&lt;/h1&gt;

&lt;p&gt;A classic rule is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Interface = can do&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Abstract class = is a&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

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

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

&lt;/div&gt;



&lt;p&gt;A bird:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;is a Bird
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;means:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;So:&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;abstract&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Bird&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;abstract&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Eat&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and:&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;interface&lt;/span&gt; &lt;span class="nc"&gt;IFlyable&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Fly&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;Then:&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;Eagle&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Bird&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IFlyable&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Eat&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;void&lt;/span&gt; &lt;span class="nf"&gt;Fly&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;But be careful.&lt;/p&gt;

&lt;p&gt;The "is-a / can-do" rule is a useful mental model, not an absolute law.&lt;/p&gt;

&lt;p&gt;Modern software design often focuses more on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Responsibilities&lt;/li&gt;
&lt;li&gt;  Coupling&lt;/li&gt;
&lt;li&gt;  Composition&lt;/li&gt;
&lt;li&gt;  Polymorphism&lt;/li&gt;
&lt;li&gt;  Reuse&lt;/li&gt;
&lt;li&gt;  Changeability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;than on inheritance terminology alone.&lt;/p&gt;




&lt;h1&gt;
  
  
  18. Composition vs Inheritance
&lt;/h1&gt;

&lt;p&gt;One of the most important design l&lt;/p&gt;

</description>
      <category>oops</category>
      <category>interface</category>
      <category>abstractclass</category>
      <category>interviewquestions</category>
    </item>
    <item>
      <title>Agentic AI for Beginners: What Are AI Agents and How Do They Actually Work?</title>
      <dc:creator>Chethan Ramaswamy</dc:creator>
      <pubDate>Wed, 30 Sep 2026 15:27:05 +0000</pubDate>
      <link>https://dev.to/chethanramaswamy/agentic-ai-for-beginners-what-are-ai-agents-and-how-do-they-actually-work-4ih</link>
      <guid>https://dev.to/chethanramaswamy/agentic-ai-for-beginners-what-are-ai-agents-and-how-do-they-actually-work-4ih</guid>
      <description>&lt;h1&gt;
  
  
  Agentic AI for Beginners: What Are AI Agents and How Do They Actually Work?
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;AI agents are not just chatbots with a fancy name. They can use AI models to understand goals, choose actions, use tools, observe results, and continue working until a task is completed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Artificial Intelligence is moving beyond systems that simply generate text.&lt;/p&gt;

&lt;p&gt;Traditional software follows instructions explicitly defined by developers.&lt;/p&gt;

&lt;p&gt;Generative AI can understand natural language and generate text, code, images, and other content.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agentic AI goes one step further: it enables software systems to use AI models to decide what actions should be taken to accomplish a goal.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This creates a new way of building software.&lt;/p&gt;

&lt;p&gt;Instead of telling a system:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Execute these five steps in this exact order."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;we can give it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Achieve this goal."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The system can then determine which steps are necessary, which tools it needs, and when the task is complete.&lt;/p&gt;

&lt;p&gt;However, this does &lt;strong&gt;not&lt;/strong&gt; mean that AI agents should be given unlimited autonomy.&lt;/p&gt;

&lt;p&gt;Production-grade agentic systems require clear boundaries, permissions, security, observability, cost controls, and often human approval.&lt;/p&gt;

&lt;p&gt;This article explains Agentic AI from the ground up.&lt;/p&gt;

&lt;p&gt;No previous AI knowledge is required.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Introduction
&lt;/h2&gt;

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

&lt;p&gt;Imagine you ask an AI assistant:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Find my last three orders and tell me which one was delivered late."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A traditional chatbot may respond:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I don't have access to your order system."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;An AI agent could potentially:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Understand the request.&lt;/li&gt;
&lt;li&gt;Identify that it needs order information.&lt;/li&gt;
&lt;li&gt;Call the order-management API.&lt;/li&gt;
&lt;li&gt;Retrieve the last three orders.&lt;/li&gt;
&lt;li&gt;Analyze delivery dates.&lt;/li&gt;
&lt;li&gt;Determine which order was late.&lt;/li&gt;
&lt;li&gt;Return the result.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The important difference is not simply that the second system uses a more powerful AI model.&lt;/p&gt;

&lt;p&gt;The important difference is that the system can &lt;strong&gt;take actions using tools&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A simplified view looks like this:&lt;br&gt;
&lt;/p&gt;

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

User
  |
  v
LLM
  |
  v
Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An agent looks more like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User
  |
  v
AI Agent
  |
  +----&amp;gt; Reason
  |
  +----&amp;gt; Choose Tool
  |
  +----&amp;gt; Execute Action
  |
  +----&amp;gt; Observe Result
  |
  +----&amp;gt; Reason Again
  |
  v
Final Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ability to move from &lt;strong&gt;generating text to performing authorized actions&lt;/strong&gt; is one of the important ideas behind Agentic AI.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. What Is Generative AI?
&lt;/h2&gt;

&lt;p&gt;Before understanding agents, we need to understand Generative AI.&lt;/p&gt;

&lt;p&gt;Generative AI refers to AI systems that can generate new content based on an input.&lt;/p&gt;

&lt;p&gt;The generated content could be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Text&lt;/li&gt;
&lt;li&gt;Code&lt;/li&gt;
&lt;li&gt;Images&lt;/li&gt;
&lt;li&gt;Audio&lt;/li&gt;
&lt;li&gt;Video&lt;/li&gt;
&lt;li&gt;Structured data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Large Language Models, commonly called &lt;strong&gt;LLMs&lt;/strong&gt;, are a major component of modern Generative AI applications.&lt;/p&gt;

&lt;p&gt;At a simplified level:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Prompt
     |
     v
+-------------+
|     LLM     |
+-------------+
     |
     v
Generated Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

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

Explain dependency injection in .NET.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model can generate an explanation.&lt;/p&gt;

&lt;p&gt;However, there is an important limitation.&lt;/p&gt;

&lt;p&gt;An LLM does not automatically have direct access to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your database&lt;/li&gt;
&lt;li&gt;Your CRM&lt;/li&gt;
&lt;li&gt;Your ERP&lt;/li&gt;
&lt;li&gt;Your internal APIs&lt;/li&gt;
&lt;li&gt;Your payment system&lt;/li&gt;
&lt;li&gt;Your monitoring platform&lt;/li&gt;
&lt;li&gt;Your private documents&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where tools and agentic architectures become important.&lt;/p&gt;

&lt;h3&gt;
  
  
  LLM vs Application
&lt;/h3&gt;

&lt;p&gt;It is useful to separate the AI model from the software application around it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 AI Application
                       |
          +------------+------------+
          |                         |
          v                         v
       AI Model                  Software
          |                         |
          v                         v
    Reasoning/Text            APIs/Database/Tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The LLM provides capabilities such as language understanding and generation.&lt;/p&gt;

&lt;p&gt;The surrounding application provides access to business systems, data, tools, security, and application logic.&lt;/p&gt;

&lt;p&gt;An AI agent is built by combining these capabilities in a controlled way.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. What Is an AI Agent?
&lt;/h2&gt;

&lt;p&gt;An AI agent is a software system that uses an AI model to determine and execute actions toward a goal.&lt;/p&gt;

&lt;p&gt;A simplified conceptual model is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        Goal
          |
          v
      AI Model
          |
          v
       Decision
          |
          v
        Tool
          |
          v
       Result
          |
          v
      AI Model
          |
          v
    Next Decision
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An agent typically combines several capabilities:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;             AI AGENT
                 |
     +-----------+-----------+
     |           |           |
     v           v           v
    LLM        Tools       Memory
     |           |           |
     v           v           v
 Reasoning    Actions      Context
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depending on the architecture, an agent may also have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Planning&lt;/li&gt;
&lt;li&gt;State management&lt;/li&gt;
&lt;li&gt;Retrieval&lt;/li&gt;
&lt;li&gt;Guardrails&lt;/li&gt;
&lt;li&gt;Human approval&lt;/li&gt;
&lt;li&gt;Long-term memory&lt;/li&gt;
&lt;li&gt;Short-term memory&lt;/li&gt;
&lt;li&gt;Multiple specialized agents&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important point is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;An AI agent is not simply an LLM.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The LLM is usually the reasoning component inside a larger software system.&lt;/p&gt;

&lt;h3&gt;
  
  
  A useful mental model
&lt;/h3&gt;

&lt;p&gt;Think of an LLM as a highly capable decision-making component.&lt;/p&gt;

&lt;p&gt;Think of an agent as the &lt;strong&gt;software system that gives that component the ability to interact with the world through controlled interfaces&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LLM
 |
 | decides what may be needed
 v
Agent Runtime
 |
 +---- Tool
 +---- Memory
 +---- Retrieval
 +---- State
 +---- Guardrails
 |
 v
External Systems
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Chatbot vs AI Agent
&lt;/h2&gt;

&lt;p&gt;One of the easiest ways to understand Agentic AI is to compare it with a traditional chatbot.&lt;/p&gt;

&lt;h3&gt;
  
  
  Traditional Chatbot
&lt;/h3&gt;

&lt;p&gt;Suppose you ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"What is the status of order 12345?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A traditional chatbot might search a knowledge base and respond with information.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User
 |
 v
Chatbot
 |
 v
Knowledge Base
 |
 v
Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  AI Agent
&lt;/h3&gt;

&lt;p&gt;An agent could:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User
 |
 v
Agent
 |
 +----&amp;gt; Identify Order
 |
 +----&amp;gt; Call Order API
 |
 +----&amp;gt; Get Delivery Status
 |
 +----&amp;gt; Check Shipping API
 |
 +----&amp;gt; Analyze Result
 |
 v
Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The distinction can be summarized as:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Chatbot&lt;/th&gt;
&lt;th&gt;AI Agent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Understand natural language&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Generate responses&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retrieve information&lt;/td&gt;
&lt;td&gt;Often&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Call tools&lt;/td&gt;
&lt;td&gt;Sometimes&lt;/td&gt;
&lt;td&gt;Common&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Perform actions&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Possible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dynamic decision-making&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Common&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-step tasks&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Common&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;External system interaction&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;td&gt;Common&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;However, these are not strict technical categories.&lt;/p&gt;

&lt;p&gt;A chatbot can use tools.&lt;/p&gt;

&lt;p&gt;An agent can be implemented with a relatively simple workflow.&lt;/p&gt;

&lt;p&gt;The terminology is evolving, so focus on &lt;strong&gt;capabilities and architecture&lt;/strong&gt;, not labels.&lt;/p&gt;

&lt;h3&gt;
  
  
  The key difference
&lt;/h3&gt;

&lt;p&gt;A useful way to think about it is:&lt;br&gt;
&lt;/p&gt;

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

Question
   |
   v
Answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;versus:&lt;br&gt;
&lt;/p&gt;

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

Goal
 |
 v
Understand
 |
 v
Decide
 |
 v
Act
 |
 v
Observe
 |
 v
Decide Again
 |
 v
Complete
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent is oriented around &lt;strong&gt;achieving a goal&lt;/strong&gt;, not merely generating a response.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. The Anatomy of an AI Agent
&lt;/h2&gt;

&lt;p&gt;Let's break an agent into its major components.&lt;/p&gt;

&lt;p&gt;A simplified architecture is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 +----------------+
                 |      User      |
                 +-------+--------+
                         |
                         v
                 +----------------+
                 |   AI Agent     |
                 +----------------+
                         |
          +--------------+--------------+
          |              |              |
          v              v              v
      AI Model         Tools          Memory
          |              |              |
          v              v              v
      Reasoning       Actions        Context
                         |
              +----------+----------+
              |          |          |
              v          v          v
             API       Database    Search
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's understand each component.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.1 AI Model
&lt;/h3&gt;

&lt;p&gt;The AI model provides language understanding and reasoning capabilities.&lt;/p&gt;

&lt;p&gt;It can help determine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What the user wants&lt;/li&gt;
&lt;li&gt;What information is required&lt;/li&gt;
&lt;li&gt;Which tool may be useful&lt;/li&gt;
&lt;li&gt;What parameters should be provided&lt;/li&gt;
&lt;li&gt;Whether another action is necessary&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The model does not necessarily execute the action itself.&lt;/p&gt;

&lt;p&gt;It can instead produce a structured tool request.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tool"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GetOrder"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"arguments"&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;"orderId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"12345"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application can validate that request and execute the corresponding operation.&lt;/p&gt;




&lt;h3&gt;
  
  
  5.2 Tools
&lt;/h3&gt;

&lt;p&gt;Tools allow the agent to interact with the outside world.&lt;/p&gt;

&lt;p&gt;Examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Database
REST API
Search Engine
Calculator
CRM
ERP
Email
Calendar
File Storage
Code Execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent
  |
  +----&amp;gt; Customer API
  |
  +----&amp;gt; Order API
  |
  +----&amp;gt; Payment API
  |
  +----&amp;gt; Notification API
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tools are what allow an agent to move from:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I think this is the answer."&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;blockquote&gt;
&lt;p&gt;"I can retrieve information or perform an authorized operation."&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  5.3 Memory
&lt;/h3&gt;

&lt;p&gt;Memory allows the system to maintain relevant information during or across interactions.&lt;/p&gt;

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

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

My preferred programming language is C#.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Later:&lt;br&gt;
&lt;/p&gt;

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

Show me an example.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A system with appropriate memory may know that the user prefers C#.&lt;/p&gt;

&lt;p&gt;Memory can be divided into different categories.&lt;/p&gt;

&lt;h4&gt;
  
  
  Short-Term Memory
&lt;/h4&gt;

&lt;p&gt;Information needed during the current task.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Current conversation
Current goal
Current tool results
Current state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Long-Term Memory
&lt;/h4&gt;

&lt;p&gt;Information that may be useful across future interactions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Preferences
Historical interactions
Previously stored information
User-specific context
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Memory architecture is an important topic by itself and should not be confused with simply putting more text into a prompt.&lt;/p&gt;




&lt;h3&gt;
  
  
  5.4 State
&lt;/h3&gt;

&lt;p&gt;State represents what the agent currently knows about the task.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Task: Process customer refund

State:
- Customer identified
- Order identified
- Refund eligibility checked
- Refund amount calculated
- Approval required
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;State becomes particularly important for long-running or multi-step agents.&lt;/p&gt;




&lt;h3&gt;
  
  
  5.5 Guardrails
&lt;/h3&gt;

&lt;p&gt;Guardrails define what the agent is allowed and not allowed to do.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent
 |
 +---- Read Customer Data
 |
 +---- Read Order Data
 |
 +---- Create Support Ticket
 |
 X---- Delete Customer
 |
 X---- Issue Unlimited Refund
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Guardrails are critical because an agent that can call tools has real-world capabilities.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. How an Agent Works
&lt;/h2&gt;

&lt;p&gt;Let's walk through a simple example.&lt;/p&gt;

&lt;p&gt;Suppose the user says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Find the weather in Bangalore and suggest whether I should carry an umbrella."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A simplified agent process could be:&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Understand the request
&lt;/h3&gt;

&lt;p&gt;The agent identifies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Location = Bangalore
Task = Get weather
Task = Recommend umbrella
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Identify the required tool
&lt;/h3&gt;

&lt;p&gt;The agent determines that it needs current weather information.&lt;br&gt;
&lt;/p&gt;

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

- Weather API
- Calculator
- Search
- Calendar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It selects:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Call the tool
&lt;/h3&gt;

&lt;p&gt;The agent sends:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bangalore"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to the weather tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Observe the result
&lt;/h3&gt;

&lt;p&gt;The tool may return:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"temperature"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rainProbability"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Rain expected"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5: Reason over the result
&lt;/h3&gt;

&lt;p&gt;The agent interprets the result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Rain probability = 80%

Therefore:
Carry an umbrella.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 6: Generate the final response
&lt;/h3&gt;

&lt;p&gt;The user receives:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Rain is likely today, so carrying an umbrella would be a good idea."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The important part is that the model did not need to know the current weather beforehand.&lt;/p&gt;

&lt;p&gt;It used a tool to retrieve current information.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. The Agent Loop
&lt;/h2&gt;

&lt;p&gt;One of the most important concepts in Agentic AI is the &lt;strong&gt;agent loop&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A simplified agent loop looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;             +----------------+
             |     Goal       |
             +-------+--------+
                     |
                     v
             +----------------+
             |     Reason     |
             +-------+--------+
                     |
                     v
             +----------------+
             |      Act       |
             +-------+--------+
                     |
                     v
             +----------------+
             |    Observe     |
             +-------+--------+
                     |
                     v
             +----------------+
             |     Reason     |
             +-------+--------+
                     |
                     v
                  Complete?
                   /     \
                 No       Yes
                 |         |
                 +---------+
                       |
                       v
                  Final Result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can be summarized as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Reason → Act → Observe → Reason → Act → ...&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The loop continues until the task is complete or another termination condition is reached.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;Suppose an agent is asked:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Find the cheapest flight to London within my budget and book it."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent might:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Goal
 |
 v
Search Flights
 |
 v
Observe Results
 |
 v
Compare Prices
 |
 v
Check Budget
 |
 +---- Budget exceeded ---&amp;gt; Search Again
 |
 v
Select Flight
 |
 v
Ask for Approval
 |
 v
Book Flight
 |
 v
Complete
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that the agent may not know all the required steps before starting.&lt;/p&gt;

&lt;p&gt;The environment can influence what happens next.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why the loop matters
&lt;/h3&gt;

&lt;p&gt;The loop gives agents their dynamic behavior.&lt;/p&gt;

&lt;p&gt;Traditional code often looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Step 1
Step 2
Step 3
Step 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An agent can behave more like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Goal
 |
 v
What should I do next?
 |
 v
Action
 |
 v
What did I learn?
 |
 v
What should I do next?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is powerful, but it also introduces additional risks.&lt;/p&gt;

&lt;p&gt;More autonomy means more opportunities for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Incorrect decisions&lt;/li&gt;
&lt;li&gt;Tool misuse&lt;/li&gt;
&lt;li&gt;Unexpected costs&lt;/li&gt;
&lt;li&gt;Security issues&lt;/li&gt;
&lt;li&gt;Infinite loops&lt;/li&gt;
&lt;li&gt;Incorrect data&lt;/li&gt;
&lt;li&gt;Unintended actions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Therefore, production agents need strong controls.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. What Are Tools?
&lt;/h2&gt;

&lt;p&gt;Tools give an AI agent the ability to interact with external systems.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;REST APIs&lt;/li&gt;
&lt;li&gt;Databases&lt;/li&gt;
&lt;li&gt;Search engines&lt;/li&gt;
&lt;li&gt;Calculators&lt;/li&gt;
&lt;li&gt;CRM systems&lt;/li&gt;
&lt;li&gt;ERP systems&lt;/li&gt;
&lt;li&gt;Email systems&lt;/li&gt;
&lt;li&gt;Calendar systems&lt;/li&gt;
&lt;li&gt;File systems&lt;/li&gt;
&lt;li&gt;Internal enterprise applications&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    AI Agent
                       |
        +--------------+--------------+
        |              |              |
        v              v              v
    Customer API    Order API     Payment API
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tool Calling
&lt;/h3&gt;

&lt;p&gt;Modern AI models can be provided with a list of tools and their descriptions.&lt;/p&gt;

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

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

Description:
Retrieves an order using an order ID.

Parameters:
- orderId: string
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model may determine that this tool is appropriate and produce a structured request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tool"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GetOrder"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"arguments"&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;"orderId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"12345"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application then:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Receives the tool request.&lt;/li&gt;
&lt;li&gt;Validates the arguments.&lt;/li&gt;
&lt;li&gt;Checks authorization.&lt;/li&gt;
&lt;li&gt;Executes the tool.&lt;/li&gt;
&lt;li&gt;Returns the result to the model.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is an important architectural point:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The AI model should not automatically receive unrestricted access to your systems.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The application should remain in control.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tools should be treated as APIs
&lt;/h3&gt;

&lt;p&gt;A good enterprise design treats agent tools similarly to APIs.&lt;/p&gt;

&lt;p&gt;Each tool should have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clear input schema&lt;/li&gt;
&lt;li&gt;Clear output schema&lt;/li&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Authorization&lt;/li&gt;
&lt;li&gt;Validation&lt;/li&gt;
&lt;li&gt;Logging&lt;/li&gt;
&lt;li&gt;Rate limits&lt;/li&gt;
&lt;li&gt;Timeouts&lt;/li&gt;
&lt;li&gt;Error handling&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI Agent
   |
   v
Tool Gateway
   |
   +---- Authorization
   +---- Validation
   +---- Rate Limiting
   +---- Audit Logging
   |
   v
Business API
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  9. What Is Memory?
&lt;/h2&gt;

&lt;p&gt;Memory allows an agent to maintain relevant information during or across interactions.&lt;/p&gt;

&lt;p&gt;There are two common conceptual categories.&lt;/p&gt;

&lt;h3&gt;
  
  
  Short-Term Memory
&lt;/h3&gt;

&lt;p&gt;Information required for the current task.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Current conversation&lt;/li&gt;
&lt;li&gt;Current goal&lt;/li&gt;
&lt;li&gt;Tool results&lt;/li&gt;
&lt;li&gt;Current state&lt;/li&gt;
&lt;li&gt;Intermediate decisions
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Current Task
     |
     v
+--------------------+
| Short-Term Memory  |
+--------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Long-Term Memory
&lt;/h3&gt;

&lt;p&gt;Information that may remain useful across future interactions.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User preferences&lt;/li&gt;
&lt;li&gt;Historical information&lt;/li&gt;
&lt;li&gt;Previously stored context&lt;/li&gt;
&lt;li&gt;Business-specific knowledge
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 Agent
                   |
                   v
            Memory Service
                   |
          +--------+--------+
          |                 |
          v                 v
     Short-Term        Long-Term
       Memory            Memory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Memory is not the same as context
&lt;/h3&gt;

&lt;p&gt;This distinction is important.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context&lt;/strong&gt; is information supplied to the model for the current interaction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory&lt;/strong&gt; is information that the system deliberately stores and retrieves for future or ongoing use.&lt;/p&gt;

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

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

Current conversation
Current tool result
Current task state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;while:&lt;br&gt;
&lt;/p&gt;

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

User preference
Previous interaction
Stored business information
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Memory introduces architectural questions
&lt;/h3&gt;

&lt;p&gt;A production system needs to decide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What should be remembered?&lt;/li&gt;
&lt;li&gt;How long should it be retained?&lt;/li&gt;
&lt;li&gt;Where should it be stored?&lt;/li&gt;
&lt;li&gt;Who can access it?&lt;/li&gt;
&lt;li&gt;How should it be retrieved?&lt;/li&gt;
&lt;li&gt;How can incorrect memories be corrected?&lt;/li&gt;
&lt;li&gt;How should sensitive information be handled?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Memory should therefore be treated as an architectural capability, not simply a feature that is switched on.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. What Is Planning?
&lt;/h2&gt;

&lt;p&gt;Some tasks require multiple steps.&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;"Plan a business trip to London within a budget of ₹2,00,000."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent may need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Search flights.&lt;/li&gt;
&lt;li&gt;Compare prices.&lt;/li&gt;
&lt;li&gt;Search hotels.&lt;/li&gt;
&lt;li&gt;Calculate the total cost.&lt;/li&gt;
&lt;li&gt;Check the budget.&lt;/li&gt;
&lt;li&gt;Find transportation.&lt;/li&gt;
&lt;li&gt;Create an itinerary.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Planning allows an agent to break a high-level goal into smaller actions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Goal
 |
 +---&amp;gt; Find Flights
 |
 +---&amp;gt; Find Hotel
 |
 +---&amp;gt; Calculate Cost
 |
 +---&amp;gt; Check Budget
 |
 +---&amp;gt; Find Transportation
 |
 +---&amp;gt; Create Itinerary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Planning does not always mean creating a perfect plan upfront
&lt;/h3&gt;

&lt;p&gt;A common beginner assumption is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The agent first creates the entire plan and then executes it."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is one possible approach, but agents can also plan dynamically.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Goal
 |
 v
Plan Step 1
 |
 v
Execute
 |
 v
Observe
 |
 v
Update Plan
 |
 v
Execute Next Step
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result of one action can influence the next action.&lt;/p&gt;

&lt;h3&gt;
  
  
  Planning vs deterministic orchestration
&lt;/h3&gt;

&lt;p&gt;This is an important architectural distinction.&lt;/p&gt;

&lt;p&gt;If your business process is known:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Validate
 |
 v
Approve
 |
 v
Create Order
 |
 v
Send Notification
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;you may not need an AI agent.&lt;/p&gt;

&lt;p&gt;A normal workflow may be simpler, cheaper, more predictable, and easier to test.&lt;/p&gt;

&lt;p&gt;Planning becomes more useful when the task is dynamic and the exact sequence cannot easily be predefined.&lt;/p&gt;




&lt;h2&gt;
  
  
  11. A Real-World Example
&lt;/h2&gt;

&lt;p&gt;Consider an enterprise customer-support agent.&lt;/p&gt;

&lt;p&gt;A customer asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"My order hasn't arrived. Can you check what's happening?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent might perform:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Customer
   |
   v
AI Agent
   |
   +----&amp;gt; Customer API
   |
   +----&amp;gt; Order API
   |
   +----&amp;gt; Shipping API
   |
   v
Analyze Information
   |
   v
Generate Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent could discover:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Order Status: Shipped
Expected Delivery: September 30
Current Status: Delayed
Reason: Weather disruption
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It can then explain the situation to the customer.&lt;/p&gt;

&lt;p&gt;With appropriate authorization, the same system could potentially:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a support ticket&lt;/li&gt;
&lt;li&gt;Send an email&lt;/li&gt;
&lt;li&gt;Request a replacement&lt;/li&gt;
&lt;li&gt;Escalate the issue&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Enterprise architecture
&lt;/h3&gt;

&lt;p&gt;A more production-oriented architecture could look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                         Customer
                            |
                            v
                    +---------------+
                    | API Gateway   |
                    +-------+-------+
                            |
                            v
                    +---------------+
                    | AI Agent      |
                    +-------+-------+
                            |
             +--------------+--------------+
             |              |              |
             v              v              v
       Customer Tool   Order Tool    Shipping Tool
             |              |              |
             v              v              v
          CRM/API        Order API      Carrier API
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additional enterprise capabilities would typically include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Authentication
Authorization
Audit Logging
Observability
Rate Limiting
Secrets Management
Guardrails
Human Approval
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Human-in-the-loop
&lt;/h3&gt;

&lt;p&gt;Suppose the customer asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Refund my entire order."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent might determine that a refund is possible, but the actual financial operation may require human approval.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Customer
   |
   v
AI Agent
   |
   v
Check Refund Policy
   |
   v
Refund Amount = ₹50,000
   |
   v
Approval Required
   |
   v
Human Approval
   |
   v
Refund API
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an important pattern for enterprise agentic systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI does not have to mean unrestricted autonomy.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  12. RAG vs Agents
&lt;/h2&gt;

&lt;p&gt;RAG stands for &lt;strong&gt;Retrieval-Augmented Generation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;RAG typically follows this pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Question
      |
      v
Retrieve Relevant Information
      |
      v
LLM
      |
      v
Answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An agent can use RAG as one of its capabilities.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 AI Agent
                     |
       +-------------+-------------+
       |             |             |
       v             v             v
      RAG           API          Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key difference is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;RAG primarily helps an AI system find relevant information, while an agent can use information and tools to accomplish a goal.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;RAG and Agentic AI are therefore not competing concepts.&lt;/p&gt;

&lt;p&gt;RAG can be a component inside an agentic system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;Suppose an employee asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"What is our leave policy and how many days do I have remaining?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent may need two different capabilities.&lt;/p&gt;

&lt;p&gt;First:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RAG
 |
 v
Retrieve Leave Policy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Second:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Employee API
 |
 v
Retrieve Remaining Leave
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the agent combines both results.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    Agent
                      |
             +--------+--------+
             |                 |
             v                 v
            RAG           Employee API
             |                 |
             v                 v
        Leave Policy       Leave Balance
             |                 |
             +--------+--------+
                      |
                      v
                   Answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a good example of why RAG and agents often work together.&lt;/p&gt;




&lt;h2&gt;
  
  
  13. Workflow vs Agent
&lt;/h2&gt;

&lt;p&gt;This is one of the most important architectural decisions.&lt;/p&gt;

&lt;p&gt;A traditional workflow might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Step 1
  |
  v
Step 2
  |
  v
Step 3
  |
  v
Step 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The developer explicitly defines the sequence.&lt;/p&gt;

&lt;p&gt;An agentic system may look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Goal
 |
 v
Agent
 |
 +----&amp;gt; Decide Action
 |
 +----&amp;gt; Execute
 |
 +----&amp;gt; Observe
 |
 +----&amp;gt; Decide Next Action
 |
 +----&amp;gt; Execute
 |
 v
Complete
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  When should you use a workflow?
&lt;/h3&gt;

&lt;p&gt;Use a workflow when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Steps are predictable.&lt;/li&gt;
&lt;li&gt;Business rules are well defined.&lt;/li&gt;
&lt;li&gt;Deterministic execution is important.&lt;/li&gt;
&lt;li&gt;Compliance requires predictable behavior.&lt;/li&gt;
&lt;li&gt;The process is easy to express as a state machine.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Receive Order
      |
      v
Validate Payment
      |
      v
Reserve Inventory
      |
      v
Create Shipment
      |
      v
Send Notification
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is little value in asking an LLM to decide this sequence if the business process is already known.&lt;/p&gt;

&lt;h3&gt;
  
  
  When can an agent help?
&lt;/h3&gt;

&lt;p&gt;Agents can be useful when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The number of steps varies.&lt;/li&gt;
&lt;li&gt;The required tool depends on the situation.&lt;/li&gt;
&lt;li&gt;The task requires interpretation.&lt;/li&gt;
&lt;li&gt;The environment is dynamic.&lt;/li&gt;
&lt;li&gt;The system needs to choose between multiple possible actions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Hybrid architecture
&lt;/h3&gt;

&lt;p&gt;In many enterprise systems, the best architecture may actually be a &lt;strong&gt;hybrid&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    Application
                         |
             +-----------+-----------+
             |                       |
             v                       v
        Deterministic            AI Agent
         Workflow                   |
             |                      Tools
             |                       |
             +-----------+-----------+
                         |
                         v
                   Business Systems
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI Agent
   |
   v
Determine Customer Intent
   |
   v
Deterministic Workflow
   |
   +---- Validate
   +---- Approve
   +---- Execute
   +---- Audit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The AI can handle ambiguity while deterministic code handles critical business operations.&lt;/p&gt;

&lt;p&gt;This combination is often easier to control than giving an agent unrestricted authority.&lt;/p&gt;




&lt;h2&gt;
  
  
  14. Single-Agent vs Multi-Agent
&lt;/h2&gt;

&lt;p&gt;A single-agent system has one primary agent responsible for the task.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User
 |
 v
Agent
 |
 +---&amp;gt; Tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A multi-agent system uses multiple specialized agents.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 Orchestrator
                      |
        +-------------+-------------+
        |             |             |
        v             v             v
   Sales Agent    Finance Agent   Support Agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each agent may have different:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instructions&lt;/li&gt;
&lt;li&gt;Tools&lt;/li&gt;
&lt;li&gt;Permissions&lt;/li&gt;
&lt;li&gt;Knowledge&lt;/li&gt;
&lt;li&gt;Responsibilities&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;Suppose an enterprise wants to build an employee assistant.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    Employee
                        |
                        v
                  Orchestrator
                        |
        +---------------+---------------+
        |               |               |
        v               v               v
   HR Agent        IT Agent        Finance Agent
        |               |               |
        v               v               v
   HR Systems       IT Systems     Finance Systems
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The orchestrator can route a request to the appropriate specialist.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do you always need multiple agents?
&lt;/h3&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;p&gt;A common mistake is to introduce multiple agents simply because the technology allows it.&lt;/p&gt;

&lt;p&gt;If one agent with a few well-designed tools can solve the problem, adding five agents may only introduce:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More complexity&lt;/li&gt;
&lt;li&gt;More latency&lt;/li&gt;
&lt;li&gt;More cost&lt;/li&gt;
&lt;li&gt;More failure points&lt;/li&gt;
&lt;li&gt;More difficult debugging&lt;/li&gt;
&lt;li&gt;More complicated state management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A good architecture starts with the simplest design that satisfies the requirements.&lt;/p&gt;




&lt;h2&gt;
  
  
  15. Simple Agent Architecture
&lt;/h2&gt;

&lt;p&gt;Let's put the concepts together.&lt;/p&gt;

&lt;p&gt;A simple agent architecture can look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                         User
                           |
                           v
                  +----------------+
                  | API / UI Layer |
                  +-------+--------+
                          |
                          v
                  +----------------+
                  |  Agent Runtime |
                  +-------+--------+
                          |
              +-----------+-----------+
              |           |           |
              v           v           v
             LLM        Memory       RAG
              |           |           |
              +-----------+-----------+
                          |
                          v
                       Tools
                          |
          +---------------+---------------+
          |               |               |
          v               v               v
        APIs          Databases        Search
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For an enterprise Azure implementation, the architecture could evolve into:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                         User
                           |
                           v
                  Azure Front Door
                           |
                           v
                   API Management
                           |
                           v
                  ASP.NET Core API
                           |
                           v
                    Agent Runtime
                           |
              +------------+------------+
              |            |            |
              v            v            v
        Azure OpenAI   Azure AI      Memory
                        Search        Store
              |            |            |
              +------------+------------+
                           |
                           v
                    Tool Gateway
                           |
        +------------------+------------------+
        |                  |                  |
        v                  v                  v
     REST APIs         Azure SQL          Service Bus
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Supporting services can include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Microsoft Entra ID
Azure Key Vault
Application Insights
Azure Monitor
OpenTelemetry
Azure Service Bus
Azure Storage
Cosmos DB
Redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact services should depend on the requirements.&lt;/p&gt;

&lt;p&gt;Do not introduce every Azure service simply because it is available.&lt;/p&gt;




&lt;h2&gt;
  
  
  16. Common Misconceptions
&lt;/h2&gt;

&lt;p&gt;Agentic AI is surrounded by a lot of hype.&lt;/p&gt;

&lt;p&gt;Let's address some common misconceptions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Misconception 1: An AI agent is just a chatbot
&lt;/h3&gt;

&lt;p&gt;Not necessarily.&lt;/p&gt;

&lt;p&gt;A chatbot can primarily focus on conversation.&lt;/p&gt;

&lt;p&gt;An agent can combine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reasoning&lt;/li&gt;
&lt;li&gt;Tools&lt;/li&gt;
&lt;li&gt;State&lt;/li&gt;
&lt;li&gt;Memory&lt;/li&gt;
&lt;li&gt;Planning&lt;/li&gt;
&lt;li&gt;Actions&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Misconception 2: Every AI application needs an agent
&lt;/h3&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;p&gt;Many applications are better implemented using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Traditional APIs&lt;/li&gt;
&lt;li&gt;Deterministic workflows&lt;/li&gt;
&lt;li&gt;RAG&lt;/li&gt;
&lt;li&gt;Background jobs&lt;/li&gt;
&lt;li&gt;Event-driven architecture&lt;/li&gt;
&lt;li&gt;Conventional business logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use an agent when dynamic decision-making provides real value.&lt;/p&gt;




&lt;h3&gt;
  
  
  Misconception 3: Agents are completely autonomous
&lt;/h3&gt;

&lt;p&gt;They don't have to be.&lt;/p&gt;

&lt;p&gt;An enterprise agent can operate with strict boundaries.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent
 |
 +---- Read Customer
 |
 +---- Read Order
 |
 +---- Create Ticket
 |
 X---- Delete Customer
 |
 X---- Issue Refund &amp;gt; ₹10,000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The system can require human approval for sensitive actions.&lt;/p&gt;




&lt;h3&gt;
  
  
  Misconception 4: The LLM controls the entire system
&lt;/h3&gt;

&lt;p&gt;A well-designed architecture should not work that way.&lt;/p&gt;

&lt;p&gt;The application should control:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Authorization&lt;/li&gt;
&lt;li&gt;Tool access&lt;/li&gt;
&lt;li&gt;Data access&lt;/li&gt;
&lt;li&gt;Validation&lt;/li&gt;
&lt;li&gt;Business rules&lt;/li&gt;
&lt;li&gt;Audit&lt;/li&gt;
&lt;li&gt;Rate limits&lt;/li&gt;
&lt;li&gt;Approval&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The LLM should operate within those boundaries.&lt;/p&gt;




&lt;h3&gt;
  
  
  Misconception 5: More agents means a better system
&lt;/h3&gt;

&lt;p&gt;Not necessarily.&lt;/p&gt;

&lt;p&gt;Multiple agents can increase:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cost&lt;/li&gt;
&lt;li&gt;Latency&lt;/li&gt;
&lt;li&gt;Complexity&lt;/li&gt;
&lt;li&gt;Debugging difficulty&lt;/li&gt;
&lt;li&gt;Failure modes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start simple.&lt;/p&gt;

&lt;p&gt;Introduce multiple agents only when specialization or isolation provides a real architectural benefit.&lt;/p&gt;




&lt;h3&gt;
  
  
  Misconception 6: Agents always reason perfectly
&lt;/h3&gt;

&lt;p&gt;They don't.&lt;/p&gt;

&lt;p&gt;AI models can produce incorrect decisions or interpretations.&lt;/p&gt;

&lt;p&gt;Therefore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI Decision
     |
     v
Validation
     |
     v
Authorization
     |
     v
Execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is safer than:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI Decision
     |
     v
Execute Anything
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  17. When Should You Use an Agent?
&lt;/h2&gt;

&lt;p&gt;An agent can be a good fit when the problem has several of the following characteristics:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The task is goal-oriented
&lt;/h3&gt;

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

&lt;blockquote&gt;
&lt;p&gt;"Investigate why this customer's order is delayed."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;rather than:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Call API A and then API B."&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  2. The next step depends on the current result
&lt;/h3&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Check Order
    |
    +---- Delivered ---&amp;gt; Close Request
    |
    +---- Delayed -----&amp;gt; Check Shipping
    |
    +---- Cancelled ---&amp;gt; Start Refund
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The path depends on what the system discovers.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Multiple tools may be required
&lt;/h3&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Customer API
Order API
Shipping API
Payment API
Knowledge Base
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  4. Natural language is an important interface
&lt;/h3&gt;

&lt;p&gt;Agents are particularly useful when users express goals rather than structured commands.&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;"Help me resolve this customer complaint."&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  5. The environment changes
&lt;/h3&gt;

&lt;p&gt;The agent may need to adapt based on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tool results&lt;/li&gt;
&lt;li&gt;User responses&lt;/li&gt;
&lt;li&gt;Current data&lt;/li&gt;
&lt;li&gt;External events&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  18. When Should You NOT Use an Agent?
&lt;/h2&gt;

&lt;p&gt;This is just as important as knowing when to use one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do not use an agent simply because it is fashionable.
&lt;/h3&gt;

&lt;p&gt;If a simple API or workflow solves the problem, that may be the better engineering choice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Avoid an agent when the process is completely deterministic
&lt;/h3&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Receive Request
    |
    v
Validate
    |
    v
Save
    |
    v
Publish Event
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There may be no reason to introduce an LLM.&lt;/p&gt;

&lt;h3&gt;
  
  
  Avoid agents for extremely latency-sensitive operations
&lt;/h3&gt;

&lt;p&gt;If the requirement is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Response &amp;lt; 10 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;adding an LLM-based reasoning loop may not be appropriate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Avoid agents when deterministic behavior is mandatory
&lt;/h3&gt;

&lt;p&gt;Some financial, safety-critical, or compliance-sensitive operations may require tightly controlled execution.&lt;/p&gt;

&lt;p&gt;A better pattern can be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI
 |
 v
Recommendation
 |
 v
Deterministic Business Logic
 |
 v
Execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Avoid giving agents unnecessary permissions
&lt;/h3&gt;

&lt;p&gt;The principle should be:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Give an agent the minimum permissions required to accomplish its task.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is similar to the principle of least privilege used in traditional security architecture.&lt;/p&gt;




&lt;h2&gt;
  
  
  19. Beginner Roadmap
&lt;/h2&gt;

&lt;p&gt;If you're new to Agentic AI, don't start by learning ten frameworks.&lt;/p&gt;

&lt;p&gt;Start with the fundamentals.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stage 1: Learn Generative AI
&lt;/h3&gt;

&lt;p&gt;Understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LLMs&lt;/li&gt;
&lt;li&gt;Prompts&lt;/li&gt;
&lt;li&gt;Tokens&lt;/li&gt;
&lt;li&gt;Context windows&lt;/li&gt;
&lt;li&gt;Embeddings&lt;/li&gt;
&lt;li&gt;Model inference
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LLM Fundamentals
        |
        v
Prompting
        |
        v
Context
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Stage 2: Learn Tool Calling
&lt;/h3&gt;

&lt;p&gt;Understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Function calling&lt;/li&gt;
&lt;li&gt;Tool schemas&lt;/li&gt;
&lt;li&gt;Structured outputs&lt;/li&gt;
&lt;li&gt;Tool results
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LLM
 |
 v
Tool Selection
 |
 v
Tool Execution
 |
 v
Result
 |
 v
LLM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Stage 3: Learn RAG
&lt;/h3&gt;

&lt;p&gt;Understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Embeddings&lt;/li&gt;
&lt;li&gt;Vector search&lt;/li&gt;
&lt;li&gt;Retrieval&lt;/li&gt;
&lt;li&gt;Chunking&lt;/li&gt;
&lt;li&gt;Metadata&lt;/li&gt;
&lt;li&gt;Grounding
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Documents
   |
   v
Chunking
   |
   v
Embeddings
   |
   v
Vector Store
   |
   v
Retrieval
   |
   v
LLM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Stage 4: Learn Agent Concepts
&lt;/h3&gt;

&lt;p&gt;Focus on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agent loop&lt;/li&gt;
&lt;li&gt;State&lt;/li&gt;
&lt;li&gt;Memory&lt;/li&gt;
&lt;li&gt;Planning&lt;/li&gt;
&lt;li&gt;Tool selection&lt;/li&gt;
&lt;li&gt;Guardrails&lt;/li&gt;
&lt;li&gt;Human-in-the-loop&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Stage 5: Build a Simple Agent
&lt;/h3&gt;

&lt;p&gt;Start with something small.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User
 |
 v
Agent
 |
 +---- Calculator
 |
 +---- Weather API
 |
 +---- Search
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Stage 6: Learn Agent Frameworks
&lt;/h3&gt;

&lt;p&gt;After understanding the concepts, explore frameworks and SDKs such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Semantic Kernel&lt;/li&gt;
&lt;li&gt;LangChain&lt;/li&gt;
&lt;li&gt;LangGraph&lt;/li&gt;
&lt;li&gt;Microsoft Agent Framework&lt;/li&gt;
&lt;li&gt;Provider-specific agent SDKs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The framework should come &lt;strong&gt;after&lt;/strong&gt; understanding the underlying concepts.&lt;/p&gt;

&lt;p&gt;Otherwise, it is easy to learn framework APIs without understanding what the architecture is actually doing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stage 7: Learn Production Architecture
&lt;/h3&gt;

&lt;p&gt;Then focus on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Security&lt;/li&gt;
&lt;li&gt;Identity&lt;/li&gt;
&lt;li&gt;Authorization&lt;/li&gt;
&lt;li&gt;Observability&lt;/li&gt;
&lt;li&gt;Cost management&lt;/li&gt;
&lt;li&gt;Reliability&lt;/li&gt;
&lt;li&gt;Evaluation&lt;/li&gt;
&lt;li&gt;Prompt injection&lt;/li&gt;
&lt;li&gt;Data protection&lt;/li&gt;
&lt;li&gt;Human approval&lt;/li&gt;
&lt;li&gt;Auditability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A production agent is an &lt;strong&gt;enterprise software system&lt;/strong&gt;, not just a prompt.&lt;/p&gt;




&lt;h2&gt;
  
  
  20. Conclusion
&lt;/h2&gt;

&lt;p&gt;Agentic AI represents a shift from AI systems that primarily &lt;strong&gt;generate responses&lt;/strong&gt; toward systems that can &lt;strong&gt;work toward goals using tools and controlled actions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The simplest mental model is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;              Goal
                |
                v
             Reason
                |
                v
               Act
                |
                v
             Observe
                |
                v
             Reason
                |
                v
            Complete?
             /     \
           No       Yes
           |         |
           +---------+
                |
                v
             Result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The core concepts to remember are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LLM
 |
 +---- Reasoning
 |
 +---- Tools
 |
 +---- Memory
 |
 +---- State
 |
 +---- Planning
 |
 +---- Guardrails
 |
 +---- Human Approval
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But there is an even more important lesson.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Agentic AI is not about giving AI unlimited autonomy. It is about giving AI controlled capabilities to accomplish useful goals.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As an engineer, the question should not simply be:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"How can I build an AI agent?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A better question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Does this problem actually benefit from agentic behavior, and if so, what level of autonomy is appropriate?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That shift in thinking is what separates an interesting AI demo from a production-ready enterprise system.&lt;/p&gt;




&lt;h1&gt;
  
  
  What's Next?
&lt;/h1&gt;

&lt;p&gt;Now that we understand the fundamentals, the next step is to understand the most important building blocks in more detail:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The Agent Loop&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tool Calling&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory and State&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RAG and Agents&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Single-Agent vs Multi-Agent Architecture&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Building an Agent with .NET&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Building an Agent on Azure&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Securing AI Agents&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prompt Injection and Agent Security&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Designing Production-Ready Agentic AI Systems&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Agentic AI is still evolving rapidly.&lt;/p&gt;

&lt;p&gt;The frameworks will change.&lt;/p&gt;

&lt;p&gt;The model providers will change.&lt;/p&gt;

&lt;p&gt;The terminology will change.&lt;/p&gt;

&lt;p&gt;But the fundamental engineering principles will remain:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Clear goals. Controlled tools. Explicit permissions. Observable behavior. Deterministic boundaries. Human oversight where necessary.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is the foundation for building useful and responsible AI agents.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agenticai</category>
      <category>genai</category>
    </item>
    <item>
      <title>Entity Framework Core Performance Optimization: A Practical Guide for .NET Developers</title>
      <dc:creator>Chethan Ramaswamy</dc:creator>
      <pubDate>Sat, 26 Sep 2026 13:55:27 +0000</pubDate>
      <link>https://dev.to/chethanramaswamy/entity-framework-core-performance-optimization-a-practical-guide-for-net-developers-4d35</link>
      <guid>https://dev.to/chethanramaswamy/entity-framework-core-performance-optimization-a-practical-guide-for-net-developers-4d35</guid>
      <description>&lt;h1&gt;
  
  
  Entity Framework Core Performance Optimization: A Practical Guide for .NET Developers
&lt;/h1&gt;

&lt;p&gt;Entity Framework Core (EF Core) simplifies database development by allowing .NET developers to work with strongly typed C# objects and LINQ instead of writing SQL for every database operation.&lt;/p&gt;

&lt;p&gt;However, the convenience of an ORM can sometimes hide expensive operations.&lt;/p&gt;

&lt;p&gt;A LINQ query that looks simple in C# can result in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unnecessary database round trips&lt;/li&gt;
&lt;li&gt;Large result sets&lt;/li&gt;
&lt;li&gt;Excessive change tracking&lt;/li&gt;
&lt;li&gt;N+1 queries&lt;/li&gt;
&lt;li&gt;Expensive joins&lt;/li&gt;
&lt;li&gt;Unnecessary columns being retrieved&lt;/li&gt;
&lt;li&gt;Poor pagination performance&lt;/li&gt;
&lt;li&gt;Excessive memory usage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal of performance optimization is not to avoid EF Core. It is to understand how EF Core translates and executes queries and then design those queries appropriately.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Good EF Core performance comes from minimizing unnecessary database work, data transfer, object materialization, and application-side processing.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This article walks through the most important EF Core performance considerations, from query execution and related-data loading to CRUD operations, &lt;code&gt;DbContext&lt;/code&gt;, diagnostics, and practical optimization patterns.&lt;/p&gt;




&lt;h2&gt;
  
  
  Contents Snapshot
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
1. Understanding Entity Framework Core Performance

&lt;ul&gt;
&lt;li&gt;How EF Core executes queries&lt;/li&gt;
&lt;li&gt;LINQ-to-SQL translation&lt;/li&gt;
&lt;li&gt;Where EF Core performance bottlenecks occur&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
2. Common EF Core Performance Problems

&lt;ul&gt;
&lt;li&gt;Loading unnecessary data&lt;/li&gt;
&lt;li&gt;Excessive entity tracking&lt;/li&gt;
&lt;li&gt;N+1 queries&lt;/li&gt;
&lt;li&gt;Lazy loading&lt;/li&gt;
&lt;li&gt;Excessive &lt;code&gt;Include()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Premature query execution&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
3. Optimizing EF Core Queries

&lt;ul&gt;
&lt;li&gt;Projection with &lt;code&gt;Select()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;DTO-based queries&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AsNoTracking()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Filtering and sorting&lt;/li&gt;
&lt;li&gt;Avoiding client-side processing&lt;/li&gt;
&lt;li&gt;Inspecting generated SQL&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
4. Managing Related Data

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Include()&lt;/code&gt; and &lt;code&gt;ThenInclude()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Eager loading&lt;/li&gt;
&lt;li&gt;Explicit loading&lt;/li&gt;
&lt;li&gt;Lazy loading&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AsSplitQuery()&lt;/code&gt; vs single queries&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
5. Pagination and Large Data Sets

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Skip()&lt;/code&gt; and &lt;code&gt;Take()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Keyset pagination&lt;/li&gt;
&lt;li&gt;Efficient querying of large tables&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
6. Insert, Update, and Delete Performance

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SaveChangesAsync()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Batch operations&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ExecuteUpdateAsync()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ExecuteDeleteAsync()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Handling large data operations&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
7. DbContext Performance

&lt;ul&gt;
&lt;li&gt;DbContext lifetime&lt;/li&gt;
&lt;li&gt;Change tracking&lt;/li&gt;
&lt;li&gt;Connection management&lt;/li&gt;
&lt;li&gt;Async database operations&lt;/li&gt;
&lt;li&gt;Context pooling&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
8. EF Core Performance Patterns and Anti-Patterns

&lt;ul&gt;
&lt;li&gt;Common mistakes&lt;/li&gt;
&lt;li&gt;Recommended patterns&lt;/li&gt;
&lt;li&gt;When to use or avoid specific EF Core features&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
9. Measuring and Diagnosing EF Core Performance

&lt;ul&gt;
&lt;li&gt;Logging&lt;/li&gt;
&lt;li&gt;Generated SQL&lt;/li&gt;
&lt;li&gt;Query timing&lt;/li&gt;
&lt;li&gt;Profiling&lt;/li&gt;
&lt;li&gt;Identifying slow queries&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
10. Practical EF Core Performance Checklist

&lt;ul&gt;
&lt;li&gt;Query checklist&lt;/li&gt;
&lt;li&gt;Tracking checklist&lt;/li&gt;
&lt;li&gt;Loading checklist&lt;/li&gt;
&lt;li&gt;Write-operation checklist&lt;/li&gt;
&lt;li&gt;Production checklist&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;11. Key Takeaways&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  1. Understanding Entity Framework Core Performance
&lt;/h2&gt;

&lt;p&gt;Before optimizing EF Core, it is important to understand what happens when a query is executed.&lt;/p&gt;

&lt;p&gt;Consider this simple query:&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;customers&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At a high level, the execution flow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C# LINQ Query
      |
      v
EF Core
      |
      v
Expression Translation
      |
      v
Generated SQL
      |
      v
Database
      |
      v
Result Set
      |
      v
EF Core Materialization
      |
      v
C# Objects
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Several stages can contribute to the overall execution time.&lt;/p&gt;

&lt;h3&gt;
  
  
  How EF Core Executes Queries
&lt;/h3&gt;

&lt;p&gt;When an &lt;code&gt;IQueryable&lt;/code&gt; is built, EF Core does not immediately execute the query.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;query&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="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OrderBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, the query has been composed but not necessarily executed.&lt;/p&gt;

&lt;p&gt;Execution occurs when a terminal operation is called:&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;customers&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;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other examples include:&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;await&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstAsync&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;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SingleAsync&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;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CountAsync&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;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AnyAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This distinction is important because adding filters and projections before query execution allows EF Core to translate more of the work into SQL.&lt;/p&gt;

&lt;h3&gt;
  
  
  LINQ-to-SQL Translation
&lt;/h3&gt;

&lt;p&gt;Consider:&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;customers&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Conceptually, EF Core translates the LINQ expression into SQL similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Customers&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;IsActive&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact SQL depends on the EF Core version, provider, model configuration, and query.&lt;/p&gt;

&lt;p&gt;This means developers should understand both sides:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LINQ
  |
  v
EF Core Translation
  |
  v
SQL
  |
  v
Database Execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A query that looks efficient in C# is not necessarily efficient after translation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where EF Core Performance Bottlenecks Occur
&lt;/h3&gt;

&lt;p&gt;Potential bottlenecks include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Query translation&lt;/li&gt;
&lt;li&gt;Database execution&lt;/li&gt;
&lt;li&gt;Network transfer&lt;/li&gt;
&lt;li&gt;Entity materialization&lt;/li&gt;
&lt;li&gt;Change tracking&lt;/li&gt;
&lt;li&gt;Application-side processing&lt;/li&gt;
&lt;li&gt;Excessive database round trips&lt;/li&gt;
&lt;li&gt;Large result sets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Therefore:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Do not optimize EF Core based only on how the C# code looks. Measure what the application and database actually do.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h1&gt;
  
  
  2. Common EF Core Performance Problems
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Loading Unnecessary Data
&lt;/h2&gt;

&lt;p&gt;One of the most common problems is retrieving more data than the application needs.&lt;/p&gt;

&lt;p&gt;Consider:&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;customers&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Suppose the &lt;code&gt;Customer&lt;/code&gt; entity contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Id&lt;/li&gt;
&lt;li&gt;Name&lt;/li&gt;
&lt;li&gt;Email&lt;/li&gt;
&lt;li&gt;Phone&lt;/li&gt;
&lt;li&gt;Address&lt;/li&gt;
&lt;li&gt;ProfileImage&lt;/li&gt;
&lt;li&gt;Preferences&lt;/li&gt;
&lt;li&gt;Audit fields&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the API only needs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Id
Name
Email
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;loading the entire entity is unnecessary.&lt;/p&gt;

&lt;p&gt;This can increase:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Database I/O&lt;/li&gt;
&lt;li&gt;Network traffic&lt;/li&gt;
&lt;li&gt;Memory usage&lt;/li&gt;
&lt;li&gt;Entity materialization&lt;/li&gt;
&lt;li&gt;Serialization cost&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Projection is usually a better approach for read-only API scenarios.&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;customers&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;CustomerDto&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&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="n"&gt;Email&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only the required fields are requested by the query.&lt;/p&gt;




&lt;h2&gt;
  
  
  Excessive Entity Tracking
&lt;/h2&gt;

&lt;p&gt;EF Core uses change tracking to detect modifications to entities.&lt;/p&gt;

&lt;p&gt;This is useful when updating data:&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;customer&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;customerId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;customer&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;"John"&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;dbContext&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;EF Core tracks the customer and can determine what changed.&lt;/p&gt;

&lt;p&gt;For read-only scenarios, tracking may not be necessary.&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;customers&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsNoTracking&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&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;AsNoTracking()&lt;/code&gt; tells EF Core not to track the returned entities for changes.&lt;/p&gt;

&lt;p&gt;This can reduce tracking overhead for appropriate read-heavy workloads.&lt;/p&gt;

&lt;p&gt;However, it should not be added blindly everywhere.&lt;/p&gt;

&lt;p&gt;Ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does this query need to modify the returned entities?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If the answer is no, no-tracking may be appropriate.&lt;/p&gt;




&lt;h2&gt;
  
  
  The N+1 Query Problem
&lt;/h2&gt;

&lt;p&gt;The N+1 query problem occurs when an application executes one query to retrieve a collection and then performs additional queries for each item.&lt;/p&gt;

&lt;p&gt;Consider:&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;orders&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depending on the relationship-loading configuration, this can result in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 query  -&amp;gt; Orders

N queries -&amp;gt; Customers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If there are 5,000 orders, the application could potentially perform thousands of additional database operations.&lt;/p&gt;

&lt;p&gt;Even when individual queries are fast, the combined overhead can become significant.&lt;/p&gt;

&lt;h3&gt;
  
  
  Better Approach
&lt;/h3&gt;

&lt;p&gt;Projection can retrieve the required related data as part of the query:&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;orders&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;OrderDto&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Amount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Amount&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="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important principle is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Minimize unnecessary database round trips.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Lazy Loading
&lt;/h2&gt;

&lt;p&gt;Lazy loading retrieves related data when a navigation property is accessed.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight 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;await&lt;/span&gt; &lt;span class="n"&gt;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;orderId&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;customerName&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="n"&gt;Customer&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With lazy loading enabled, accessing &lt;code&gt;Customer&lt;/code&gt; can trigger another database query.&lt;/p&gt;

&lt;p&gt;This can be convenient, but it can also hide database operations inside ordinary property access.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What looks like a simple loop may result in many database calls.&lt;/p&gt;

&lt;h3&gt;
  
  
  Practical Consideration
&lt;/h3&gt;

&lt;p&gt;Lazy loading can be useful in some scenarios, but it should be used carefully in performance-sensitive applications.&lt;/p&gt;

&lt;p&gt;For API workloads, explicit query shaping and projection often make database access easier to understand and control.&lt;/p&gt;




&lt;h2&gt;
  
  
  Excessive &lt;code&gt;Include()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Include()&lt;/code&gt; is useful when related entities are genuinely required.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;orders&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, adding many relationships to a query can result in complex SQL and large result sets.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;orders&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Payments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Shipments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This may result in a large query and repeated data across joined rows.&lt;/p&gt;

&lt;p&gt;If the API only needs selected fields, projection is often clearer:&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;orders&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;OrderSummaryDto&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Amount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Amount&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="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customer&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="n"&gt;ItemCount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Count&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;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;Include()&lt;/code&gt; when you actually need entity graphs.&lt;/p&gt;

&lt;p&gt;Use projection when you need a specific result shape.&lt;/p&gt;




&lt;h2&gt;
  
  
  Premature Query Execution
&lt;/h2&gt;

&lt;p&gt;Consider:&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;customers&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&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;activeCustomers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The entire customer table is loaded into memory before filtering.&lt;/p&gt;

&lt;p&gt;A better approach is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;activeCustomers&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the filtering happens in the database.&lt;/p&gt;

&lt;p&gt;A useful rule is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Keep the query as &lt;code&gt;IQueryable&lt;/code&gt; while composing database operations, and execute it only when you actually need the results.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h1&gt;
  
  
  3. Optimizing EF Core Queries
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Projection with &lt;code&gt;Select()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Projection is one of the most useful EF Core optimization techniques.&lt;/p&gt;

&lt;p&gt;Instead of retrieving complete entities:&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;products&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Products&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;project only the required fields:&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;products&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Products&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ProductDto&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&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="n"&gt;Price&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Price&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This reduces the amount of data transferred from the database.&lt;/p&gt;

&lt;p&gt;It can also reduce application memory consumption and object materialization.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Projection Matters
&lt;/h3&gt;

&lt;p&gt;Consider an entity with 30 columns.&lt;/p&gt;

&lt;p&gt;If an API requires only 4 columns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Entity
  |
  +-- 30 columns
  |
  v
Database
  |
  v
Application
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Projection changes this to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Entity
  |
  +-- 4 required columns
  |
  v
Database
  |
  v
Application
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This becomes increasingly important as data volume grows.&lt;/p&gt;




&lt;h2&gt;
  
  
  DTO-Based Queries
&lt;/h2&gt;

&lt;p&gt;Using DTOs also creates a clear boundary between persistence models and API contracts.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomerDto&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;init&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;init&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="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&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;Email&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;init&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="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&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;Query:&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;customers&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsNoTracking&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;CustomerDto&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&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="n"&gt;Email&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach has several advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explicit data requirements&lt;/li&gt;
&lt;li&gt;Smaller result sets&lt;/li&gt;
&lt;li&gt;Reduced coupling&lt;/li&gt;
&lt;li&gt;Clear API contracts&lt;/li&gt;
&lt;li&gt;Less unnecessary entity materialization&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;code&gt;AsNoTracking()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;For read-only queries:&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;products&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Products&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsNoTracking&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use tracking when you need to modify the entity:&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;product&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Products&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&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;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Price&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;100&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;dbContext&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use no-tracking when the result is simply being read:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET API
  |
  v
Query database
  |
  v
Return response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The choice should be based on the query's behavior, not applied as a blanket rule.&lt;/p&gt;




&lt;h2&gt;
  
  
  Filtering and Sorting
&lt;/h2&gt;

&lt;p&gt;Filtering should generally happen in the database rather than after materialization.&lt;/p&gt;

&lt;p&gt;Avoid:&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;customers&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&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;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Country&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"India"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OrderBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prefer:&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;result&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Country&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"India"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OrderBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows the database to perform the filtering and sorting.&lt;/p&gt;

&lt;p&gt;For large datasets, database-side operations are generally preferable to loading unnecessary rows into application memory.&lt;/p&gt;




&lt;h2&gt;
  
  
  Avoiding Client-Side Processing
&lt;/h2&gt;

&lt;p&gt;A common performance problem occurs when developers unintentionally move processing from the database into application memory.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;customers&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&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;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"A"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead:&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;result&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"A"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The database can process the filtering before returning the result.&lt;/p&gt;

&lt;p&gt;The general pattern is:&lt;br&gt;
&lt;/p&gt;

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

Database
   |
   v
Large result set
   |
   v
Application filtering


Prefer:

Database
   |
   +-- Filter
   +-- Sort
   +-- Project
   |
   v
Small result set
   |
   v
Application
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Inspecting Generated SQL
&lt;/h2&gt;

&lt;p&gt;Do not assume that a LINQ query generates the SQL you expect.&lt;/p&gt;

&lt;p&gt;EF Core provides &lt;code&gt;ToQueryString()&lt;/code&gt; for inspecting the SQL representation of a query.&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;query&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="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;CustomerDto&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToQueryString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sql&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 useful when diagnosing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unexpected joins&lt;/li&gt;
&lt;li&gt;Missing filters&lt;/li&gt;
&lt;li&gt;Excessive columns&lt;/li&gt;
&lt;li&gt;Complex queries&lt;/li&gt;
&lt;li&gt;Unexpected query shapes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For production diagnosis, application logging and database monitoring should also be used rather than relying only on &lt;code&gt;ToQueryString()&lt;/code&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  4. Managing Related Data
&lt;/h1&gt;

&lt;p&gt;Relationships are one of the areas where EF Core can generate unexpected database work.&lt;/p&gt;

&lt;p&gt;Consider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Order
 |
 +-- Customer
 |
 +-- OrderItems
 |
 +-- Payments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The correct loading strategy depends on what the application actually needs.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;code&gt;Include()&lt;/code&gt; and &lt;code&gt;ThenInclude()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Include()&lt;/code&gt; loads related data.&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;orders&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For nested relationships:&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;orders&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ThenInclude&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use this when the related entities are actually required.&lt;/p&gt;

&lt;p&gt;Avoid adding &lt;code&gt;Include()&lt;/code&gt; simply because the relationship exists.&lt;/p&gt;




&lt;h2&gt;
  
  
  Eager Loading
&lt;/h2&gt;

&lt;p&gt;Eager loading retrieves related data as part of the query.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;orders&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explicit&lt;/li&gt;
&lt;li&gt;Easy to understand&lt;/li&gt;
&lt;li&gt;Avoids some hidden database calls&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Potential downside:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Large entity graphs can produce complex queries and large result sets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For read-only APIs, projection can often provide a more precise result shape.&lt;/p&gt;




&lt;h2&gt;
  
  
  Explicit Loading
&lt;/h2&gt;

&lt;p&gt;Explicit loading allows the application to deliberately load related data.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight 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;await&lt;/span&gt; &lt;span class="n"&gt;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;orderId&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Entry&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Reference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives the application explicit control over when related data is loaded.&lt;/p&gt;

&lt;p&gt;It can be useful when the related data is conditionally required.&lt;/p&gt;

&lt;p&gt;However, repeated explicit loading inside loops can still create N+1 behavior.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lazy Loading
&lt;/h2&gt;

&lt;p&gt;Lazy loading loads related entities when they are accessed.&lt;/p&gt;

&lt;p&gt;Although convenient, it can make database activity less visible in application code.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The loop does not visibly contain a database query, but accessing &lt;code&gt;Customer&lt;/code&gt; can trigger one when lazy loading is enabled.&lt;/p&gt;

&lt;p&gt;For performance-sensitive applications, make database access explicit whenever practical.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;code&gt;AsSplitQuery()&lt;/code&gt; vs Single Queries
&lt;/h2&gt;

&lt;p&gt;Consider a query with multiple collection relationships:&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;orders&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Payments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A single-query approach can produce large joins.&lt;/p&gt;

&lt;p&gt;EF Core supports split queries:&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;orders&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Payments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSplitQuery&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

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

Orders
  |
  +-- Items
  |
  +-- Payments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;versus:&lt;br&gt;
&lt;/p&gt;

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

Query 1 -&amp;gt; Orders
Query 2 -&amp;gt; Items
Query 3 -&amp;gt; Payments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Split queries can reduce some join-related duplication, but they also mean multiple database round trips.&lt;/p&gt;

&lt;p&gt;Therefore:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Choose between single and split queries based on the actual query shape and measured performance.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h1&gt;
  
  
  5. Pagination and Large Data Sets
&lt;/h1&gt;

&lt;p&gt;Returning thousands or millions of rows from an API is rarely appropriate.&lt;/p&gt;

&lt;p&gt;Pagination limits the amount of data processed and returned.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;code&gt;Skip()&lt;/code&gt; and &lt;code&gt;Take()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;A common approach is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;customers&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OrderBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pageSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pageSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Page size = 50
Page      = 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The query retrieves the next 50 records after the previous 100 records.&lt;/p&gt;

&lt;p&gt;This approach is simple and useful for many applications.&lt;/p&gt;

&lt;p&gt;However, very large offsets can become increasingly expensive because the database may need to process rows that are skipped.&lt;/p&gt;




&lt;h2&gt;
  
  
  Keyset Pagination
&lt;/h2&gt;

&lt;p&gt;For large datasets, keyset pagination can be an alternative.&lt;/p&gt;

&lt;p&gt;Suppose the last item from the previous page has:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;The next query can be:&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;customers&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;lastCustomerId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OrderBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Previous page
     |
     v
Last Id = 50000
     |
     v
WHERE Id &amp;gt; 50000
     |
     v
Take 50
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach is especially useful for large, sequential datasets.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to Consider Keyset Pagination
&lt;/h3&gt;

&lt;p&gt;Keyset pagination is useful when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The dataset is large&lt;/li&gt;
&lt;li&gt;Users navigate sequentially&lt;/li&gt;
&lt;li&gt;A stable ordering key exists&lt;/li&gt;
&lt;li&gt;Very deep pages are expected&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Offset pagination can still be appropriate when users need direct access to arbitrary pages.&lt;/p&gt;




&lt;h1&gt;
  
  
  6. Insert, Update, and Delete Performance
&lt;/h1&gt;

&lt;p&gt;EF Core performance is not limited to queries.&lt;/p&gt;

&lt;p&gt;Write operations can also become expensive when large numbers of entities are involved.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;code&gt;SaveChangesAsync()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Avoid calling &lt;code&gt;SaveChangesAsync()&lt;/code&gt; inside every iteration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inefficient
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&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;dbContext&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can create many database round trips.&lt;/p&gt;

&lt;h3&gt;
  
  
  Better
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&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;dbContext&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This reduces the number of explicit save operations.&lt;/p&gt;

&lt;p&gt;However, for very large datasets, loading and tracking every entity can still be expensive.&lt;/p&gt;

&lt;p&gt;That is where set-based operations become useful.&lt;/p&gt;




&lt;h2&gt;
  
  
  Batch Operations
&lt;/h2&gt;

&lt;p&gt;When processing large numbers of entities, consider the size of the batch.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1,000,000 records
      |
      v
Process in manageable batches
      |
      +-- Batch 1
      +-- Batch 2
      +-- Batch 3
      +-- ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Batching can help control:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Memory consumption&lt;/li&gt;
&lt;li&gt;Transaction size&lt;/li&gt;
&lt;li&gt;Change tracker size&lt;/li&gt;
&lt;li&gt;Execution time&lt;/li&gt;
&lt;li&gt;Database pressure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The appropriate batch size depends on the workload and should be validated through testing.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;code&gt;ExecuteUpdateAsync()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;For operations that can be expressed as a set-based update, &lt;code&gt;ExecuteUpdateAsync()&lt;/code&gt; can avoid loading entities into memory.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteUpdateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;setters&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;setters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsArchived&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Conceptually, the operation becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application
     |
     v
UPDATE statement
     |
     v
Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;rather than:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Database
     |
     v
Load entities
     |
     v
Application
     |
     v
Track entities
     |
     v
Modify entities
     |
     v
Save changes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For large set-based updates, this can substantially reduce application-side work.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;code&gt;ExecuteDeleteAsync()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Similarly, records can be deleted directly without loading every entity.&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;await&lt;/span&gt; &lt;span class="n"&gt;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsInactive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteDeleteAsync&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 useful when the business operation is simply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Delete all records matching condition
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;rather than:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Load each entity
  |
  v
Run application logic
  |
  v
Delete entities
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before using set-based operations, consider whether entity-level business rules, events, auditing, or other application logic need to run.&lt;/p&gt;




&lt;h2&gt;
  
  
  Handling Large Data Operations
&lt;/h2&gt;

&lt;p&gt;For very large workloads, consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Batching&lt;/li&gt;
&lt;li&gt;Set-based operations&lt;/li&gt;
&lt;li&gt;Appropriate transaction boundaries&lt;/li&gt;
&lt;li&gt;Memory consumption&lt;/li&gt;
&lt;li&gt;Database throughput&lt;/li&gt;
&lt;li&gt;Error recovery&lt;/li&gt;
&lt;li&gt;Idempotency&lt;/li&gt;
&lt;li&gt;Retry behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The right strategy depends on whether the operation is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User-driven&lt;/li&gt;
&lt;li&gt;Scheduled&lt;/li&gt;
&lt;li&gt;Background processing&lt;/li&gt;
&lt;li&gt;Bulk migration&lt;/li&gt;
&lt;li&gt;Data correction&lt;/li&gt;
&lt;li&gt;Real-time processing&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  7. DbContext Performance
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;DbContext&lt;/code&gt; is central to EF Core applications.&lt;/p&gt;

&lt;p&gt;Understanding its lifecycle and behavior is important for performance and correctness.&lt;/p&gt;




&lt;h2&gt;
  
  
  DbContext Lifetime
&lt;/h2&gt;

&lt;p&gt;In ASP.NET Core applications, a common configuration is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="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;This typically creates a scoped &lt;code&gt;DbContext&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The conceptual request lifecycle is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP Request
     |
     v
DbContext
     |
     +-- Query
     +-- Query
     +-- Update
     |
     v
SaveChanges
     |
     v
Request Complete
     |
     v
DbContext Disposed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Avoid using a single &lt;code&gt;DbContext&lt;/code&gt; instance across unrelated concurrent requests.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DbContext&lt;/code&gt; is not designed for concurrent operations on the same instance.&lt;/p&gt;




&lt;h2&gt;
  
  
  Change Tracking
&lt;/h2&gt;

&lt;p&gt;The change tracker maintains information about entities being tracked.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;customer&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;customerId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;customer&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;"Updated Name"&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;dbContext&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;EF Core can determine that &lt;code&gt;Name&lt;/code&gt; changed.&lt;/p&gt;

&lt;p&gt;However, tracking thousands of entities can increase memory and processing overhead.&lt;/p&gt;

&lt;p&gt;For read-heavy workloads, no-tracking queries can reduce this overhead:&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;customers&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsNoTracking&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The right approach depends on the workload.&lt;/p&gt;




&lt;h2&gt;
  
  
  Connection Management
&lt;/h2&gt;

&lt;p&gt;EF Core relies on the underlying database provider for connection management and pooling.&lt;/p&gt;

&lt;p&gt;A simplified flow is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application
     |
     v
EF Core
     |
     v
Connection Pool
     |
     v
Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Potential problems include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connection pool exhaustion&lt;/li&gt;
&lt;li&gt;Long-running database operations&lt;/li&gt;
&lt;li&gt;Excessive concurrency&lt;/li&gt;
&lt;li&gt;Connections held longer than necessary&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If an application experiences database timeouts, investigate whether the problem is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Connection acquisition
        |
        or
        v
Query execution
        |
        or
        v
Database resource contention
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not assume all database timeout problems have the same root cause.&lt;/p&gt;




&lt;h2&gt;
  
  
  Async Database Operations
&lt;/h2&gt;

&lt;p&gt;Use asynchronous database APIs in ASP.NET Core applications:&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;customers&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similarly:&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;await&lt;/span&gt; &lt;span class="n"&gt;dbContext&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Asynchronous I/O allows the application to avoid blocking request threads while waiting for database operations.&lt;/p&gt;

&lt;p&gt;The benefit is particularly relevant for applications handling many concurrent requests.&lt;/p&gt;




&lt;h2&gt;
  
  
  Context Pooling
&lt;/h2&gt;

&lt;p&gt;For some workloads, EF Core supports context pooling.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight 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;AddDbContextPool&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;Pooling allows EF Core to reuse &lt;code&gt;DbContext&lt;/code&gt; instances rather than creating a new instance each time.&lt;/p&gt;

&lt;p&gt;However, pooled contexts require careful consideration of state that might be stored on the context or related services.&lt;/p&gt;

&lt;p&gt;Context pooling is an optimization that should be measured rather than enabled simply because it exists.&lt;/p&gt;




&lt;h1&gt;
  
  
  8. EF Core Performance Patterns and Anti-Patterns
&lt;/h1&gt;

&lt;p&gt;Understanding what not to do is just as important as understanding the recommended patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Loading Everything
&lt;/h3&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;customers&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;followed by application-side filtering.&lt;/p&gt;

&lt;p&gt;Prefer database-side filtering:&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;customers&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Returning Entities Directly From APIs
&lt;/h3&gt;

&lt;p&gt;Returning EF entities directly can expose persistence models to API consumers.&lt;/p&gt;

&lt;p&gt;Prefer DTOs:&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;customers&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;CustomerDto&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Calling &lt;code&gt;SaveChangesAsync()&lt;/code&gt; Repeatedly
&lt;/h3&gt;

&lt;p&gt;Avoid:&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;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&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="nf"&gt;Update&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="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;dbContext&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prefer a suitable batching or set-based strategy.&lt;/p&gt;




&lt;h3&gt;
  
  
  Using Lazy Loading Without Understanding Its Cost
&lt;/h3&gt;

&lt;p&gt;Lazy loading can make database calls invisible in application code.&lt;/p&gt;

&lt;p&gt;Be particularly careful with loops and large collections.&lt;/p&gt;




&lt;h3&gt;
  
  
  Adding &lt;code&gt;Include()&lt;/code&gt; Everywhere
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Include()&lt;/code&gt; is not a replacement for query design.&lt;/p&gt;

&lt;p&gt;Ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do I really need the complete related entity?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If the answer is no, projection may be more appropriate.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recommended Patterns
&lt;/h2&gt;

&lt;p&gt;For read-heavy API endpoints:&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;result&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsNoTracking&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;CustomerDto&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&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="n"&gt;Email&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This combines several useful principles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Database-side filtering&lt;/li&gt;
&lt;li&gt;Projection&lt;/li&gt;
&lt;li&gt;Reduced tracking&lt;/li&gt;
&lt;li&gt;Explicit result shape&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For large updates:&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;await&lt;/span&gt; &lt;span class="n"&gt;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteUpdateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;setters&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;setters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsArchived&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For large result sets:&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;result&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;lastCustomerId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OrderBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  When to Use or Avoid Specific EF Core Features
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Useful When&lt;/th&gt;
&lt;th&gt;Be Careful When&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;AsNoTracking()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read-only queries&lt;/td&gt;
&lt;td&gt;Entities need to be updated through the context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Include()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Related entities are required&lt;/td&gt;
&lt;td&gt;Many large collection relationships are included&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;AsSplitQuery()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Large relationship graphs&lt;/td&gt;
&lt;td&gt;Additional database round trips matter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lazy loading&lt;/td&gt;
&lt;td&gt;Convenience is important&lt;/td&gt;
&lt;td&gt;Query count must be predictable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Projection&lt;/td&gt;
&lt;td&gt;APIs need specific fields&lt;/td&gt;
&lt;td&gt;Complex result shapes require careful testing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ExecuteUpdateAsync()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Large set-based updates&lt;/td&gt;
&lt;td&gt;Entity-level business logic must execute&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ExecuteDeleteAsync()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Large set-based deletes&lt;/td&gt;
&lt;td&gt;Per-entity processing is required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context pooling&lt;/td&gt;
&lt;td&gt;High-throughput workloads&lt;/td&gt;
&lt;td&gt;Context-specific mutable state is used&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The important point is that there is no single EF Core feature that makes every application faster.&lt;/p&gt;




&lt;h1&gt;
  
  
  9. Measuring and Diagnosing EF Core Performance
&lt;/h1&gt;

&lt;p&gt;Performance optimization should start with measurement.&lt;/p&gt;

&lt;p&gt;Do not optimize based solely on assumptions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Logging
&lt;/h2&gt;

&lt;p&gt;EF Core can provide database-related logging that helps identify queries and execution behavior.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight 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="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseSqlServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnableDetailedErrors&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;Be careful when enabling detailed logging in production because sensitive information can potentially appear in logs depending on the configuration.&lt;/p&gt;




&lt;h2&gt;
  
  
  Generated SQL
&lt;/h2&gt;

&lt;p&gt;For a specific query:&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;query&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="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;CustomerDto&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToQueryString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inspecting generated SQL can reveal unexpected behavior.&lt;/p&gt;

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

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

SELECT Id, Name
FROM Customers
WHERE IsActive = 1


Unexpected:

SELECT many columns
FROM Customers
JOIN ...
JOIN ...
JOIN ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can lead to further investigation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Query Timing
&lt;/h2&gt;

&lt;p&gt;Measure actual execution time rather than assuming a query is slow.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;stopwatch&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Stopwatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartNew&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;customers&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;dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsNoTracking&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;stopwatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;$"Query completed in &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;stopwatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ElapsedMilliseconds&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; ms"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For production applications, use structured logging and telemetry instead of ad-hoc console output.&lt;/p&gt;




&lt;h2&gt;
  
  
  Profiling
&lt;/h2&gt;

&lt;p&gt;For a production-grade application, consider observing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP Request
      |
      v
Application Code
      |
      v
EF Core
      |
      v
Database Dependency
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Useful measurements include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API latency&lt;/li&gt;
&lt;li&gt;Database query duration&lt;/li&gt;
&lt;li&gt;Number of database calls&lt;/li&gt;
&lt;li&gt;Result-set size&lt;/li&gt;
&lt;li&gt;Error rate&lt;/li&gt;
&lt;li&gt;Request throughput&lt;/li&gt;
&lt;li&gt;Memory usage&lt;/li&gt;
&lt;li&gt;Connection utilization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The objective is to identify where the time is actually being spent.&lt;/p&gt;




&lt;h2&gt;
  
  
  Identifying Slow Queries
&lt;/h2&gt;

&lt;p&gt;A useful troubleshooting process is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Slow API
   |
   v
Measure API latency
   |
   v
Identify database dependency
   |
   v
Identify slow query
   |
   v
Inspect generated SQL
   |
   v
Analyze execution
   |
   v
Optimize EF Core query
   |
   v
Measure again
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the database query itself is efficient but the API is still slow, investigate other parts of the request pipeline.&lt;/p&gt;




&lt;h1&gt;
  
  
  10. Practical EF Core Performance Checklist
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Query Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Are only required columns being selected?&lt;/li&gt;
&lt;li&gt;[ ] Is filtering performed in the database?&lt;/li&gt;
&lt;li&gt;[ ] Is projection used where appropriate?&lt;/li&gt;
&lt;li&gt;[ ] Are queries executed only when needed?&lt;/li&gt;
&lt;li&gt;[ ] Are N+1 queries eliminated?&lt;/li&gt;
&lt;li&gt;[ ] Is generated SQL understood?&lt;/li&gt;
&lt;li&gt;[ ] Are large result sets paginated?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tracking Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Does the query actually require change tracking?&lt;/li&gt;
&lt;li&gt;[ ] Is &lt;code&gt;AsNoTracking()&lt;/code&gt; used for appropriate read-only queries?&lt;/li&gt;
&lt;li&gt;[ ] Is the number of tracked entities reasonable?&lt;/li&gt;
&lt;li&gt;[ ] Are long-lived &lt;code&gt;DbContext&lt;/code&gt; instances avoided?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Loading Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Is &lt;code&gt;Include()&lt;/code&gt; used only when required?&lt;/li&gt;
&lt;li&gt;[ ] Are large relationship graphs avoided?&lt;/li&gt;
&lt;li&gt;[ ] Is lazy loading being used intentionally?&lt;/li&gt;
&lt;li&gt;[ ] Could projection replace entity loading?&lt;/li&gt;
&lt;li&gt;[ ] Should &lt;code&gt;AsSplitQuery()&lt;/code&gt; be considered for the query shape?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Write-Operation Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Is &lt;code&gt;SaveChangesAsync()&lt;/code&gt; being called unnecessarily inside loops?&lt;/li&gt;
&lt;li&gt;[ ] Can the operation be performed in batches?&lt;/li&gt;
&lt;li&gt;[ ] Can &lt;code&gt;ExecuteUpdateAsync()&lt;/code&gt; be used?&lt;/li&gt;
&lt;li&gt;[ ] Can &lt;code&gt;ExecuteDeleteAsync()&lt;/code&gt; be used?&lt;/li&gt;
&lt;li&gt;[ ] Are transaction boundaries appropriate?&lt;/li&gt;
&lt;li&gt;[ ] Is application-level business logic required for each entity?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Production Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Is query performance measured?&lt;/li&gt;
&lt;li&gt;[ ] Are database calls observable?&lt;/li&gt;
&lt;li&gt;[ ] Are slow queries identifiable?&lt;/li&gt;
&lt;li&gt;[ ] Are application logs configured appropriately?&lt;/li&gt;
&lt;li&gt;[ ] Are connection issues monitored?&lt;/li&gt;
&lt;li&gt;[ ] Are realistic datasets used for performance testing?&lt;/li&gt;
&lt;li&gt;[ ] Are performance changes validated before and after deployment?&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  11. Key Takeaways
&lt;/h1&gt;

&lt;p&gt;Entity Framework Core provides powerful abstractions for working with relational databases, but those abstractions do not remove the need to understand database access patterns.&lt;/p&gt;

&lt;p&gt;The most important principles are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Understand how LINQ becomes SQL.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Retrieve only the data the application actually needs.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use projection for precise read models.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use &lt;code&gt;AsNoTracking()&lt;/code&gt; for appropriate read-only workloads.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Avoid N+1 queries.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use &lt;code&gt;Include()&lt;/code&gt; carefully.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Understand the trade-offs of lazy loading.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keep filtering and sorting in the database where appropriate.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Avoid premature query execution.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use appropriate pagination for large datasets.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Avoid unnecessary &lt;code&gt;SaveChangesAsync()&lt;/code&gt; calls.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consider set-based operations for large updates and deletes.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Manage &lt;code&gt;DbContext&lt;/code&gt; lifetime correctly.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use asynchronous database operations.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Measure performance instead of relying on assumptions.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A useful mental model is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                EF Core Performance
                       |
        +--------------+--------------+
        |              |              |
        v              v              v
      Query          Tracking       Loading
        |              |              |
        v              v              v
   Projection      NoTracking       Include
   Filtering       Context         Lazy Load
   Pagination      Lifetime        Split Query
        |              |              |
        +--------------+--------------+
                       |
                       v
                 Database Work
                       |
                       v
                 Measure &amp;amp; Tune
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;EF Core performance optimization is not about applying every available optimization.&lt;/p&gt;

&lt;p&gt;It is about understanding the workload and choosing the simplest approach that avoids unnecessary work.&lt;/p&gt;

&lt;p&gt;When an EF Core query becomes slow, start with a few fundamental questions:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What data do I actually need?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How many database calls am I making?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is EF Core tracking entities unnecessarily?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What SQL is actually being generated?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can the operation be performed efficiently at the database level?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once these questions become part of the development and code-review process, many EF Core performance issues can be identified before they become production problems.&lt;/p&gt;

&lt;p&gt;The best optimization is often not a complicated EF Core technique. It is simply &lt;strong&gt;doing less unnecessary work&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tags
&lt;/h2&gt;

&lt;h1&gt;
  
  
  dotnet #csharp #efcore #entityframework #aspnetcore #performance #softwarearchitecture #programming
&lt;/h1&gt;

</description>
      <category>dotnet</category>
      <category>efcore</category>
      <category>csharp</category>
      <category>performanceoptimization</category>
    </item>
    <item>
      <title>SOLID Principles in C#: A Practical Guide with Real-World Examples and Design Patterns</title>
      <dc:creator>Chethan Ramaswamy</dc:creator>
      <pubDate>Sat, 26 Sep 2026 09:30:35 +0000</pubDate>
      <link>https://dev.to/chethanramaswamy/solid-principles-in-c-a-practical-guide-with-real-world-examples-and-design-patterns-3lk</link>
      <guid>https://dev.to/chethanramaswamy/solid-principles-in-c-a-practical-guide-with-real-world-examples-and-design-patterns-3lk</guid>
      <description>&lt;h2&gt;
  
  
  📑 Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What Does SOLID Mean?&lt;/li&gt;
&lt;li&gt;SOLID Is Not the Same as Design Patterns&lt;/li&gt;
&lt;li&gt;
1. Single Responsibility Principle — SRP

&lt;ul&gt;
&lt;li&gt;The Simple Explanation&lt;/li&gt;
&lt;li&gt;A Common Problem&lt;/li&gt;
&lt;li&gt;Refactoring the Design&lt;/li&gt;
&lt;li&gt;Design Patterns and Techniques That Can Support SRP&lt;/li&gt;
&lt;li&gt;Common SRP Mistake&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
2. Open/Closed Principle — OCP

&lt;ul&gt;
&lt;li&gt;The Simple Explanation&lt;/li&gt;
&lt;li&gt;A Common Problem&lt;/li&gt;
&lt;li&gt;Applying the Strategy Pattern&lt;/li&gt;
&lt;li&gt;Strategy Pattern and OCP&lt;/li&gt;
&lt;li&gt;Factory Pattern and OCP&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
3. Liskov Substitution Principle — LSP

&lt;ul&gt;
&lt;li&gt;The Simple Explanation&lt;/li&gt;
&lt;li&gt;The Classic Example&lt;/li&gt;
&lt;li&gt;A Better Design&lt;/li&gt;
&lt;li&gt;LSP in Enterprise Applications&lt;/li&gt;
&lt;li&gt;LSP and Composition&lt;/li&gt;
&lt;li&gt;Common LSP Warning Signs&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
4. Interface Segregation Principle — ISP

&lt;ul&gt;
&lt;li&gt;The Simple Explanation&lt;/li&gt;
&lt;li&gt;A Common Problem&lt;/li&gt;
&lt;li&gt;Split the Interface&lt;/li&gt;
&lt;li&gt;ISP in an Enterprise Service&lt;/li&gt;
&lt;li&gt;Patterns That Can Support ISP&lt;/li&gt;
&lt;li&gt;Common ISP Mistake&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
5. Dependency Inversion Principle — DIP

&lt;ul&gt;
&lt;li&gt;The Simple Explanation&lt;/li&gt;
&lt;li&gt;A Common Problem&lt;/li&gt;
&lt;li&gt;Introduce an Abstraction&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Dependency Inversion vs Dependency Injection

&lt;ul&gt;
&lt;li&gt;Dependency Inversion Principle&lt;/li&gt;
&lt;li&gt;Dependency Injection&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SOLID and Design Patterns — The Practical Connection&lt;/li&gt;
&lt;li&gt;SOLID Does Not Mean "More Interfaces"&lt;/li&gt;
&lt;li&gt;SOLID Does Not Mean "Create More Classes"&lt;/li&gt;
&lt;li&gt;SOLID Does Not Mean "Remove Every if/else"&lt;/li&gt;
&lt;li&gt;SOLID Does Not Mean "Use Every Design Pattern"&lt;/li&gt;
&lt;li&gt;
A Real-World Example: Notification System

&lt;ul&gt;
&lt;li&gt;Introduce an Abstraction&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
How to Identify SOLID Issues During Code Review

&lt;ul&gt;
&lt;li&gt;SRP Questions&lt;/li&gt;
&lt;li&gt;OCP Questions&lt;/li&gt;
&lt;li&gt;LSP Questions&lt;/li&gt;
&lt;li&gt;ISP Questions&lt;/li&gt;
&lt;li&gt;DIP Questions&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
A Practical SOLID Refactoring Workflow

&lt;ul&gt;
&lt;li&gt;Step 1 — Identify What Changes&lt;/li&gt;
&lt;li&gt;Step 2 — Identify the Coupling&lt;/li&gt;
&lt;li&gt;Step 3 — Identify the Responsibility&lt;/li&gt;
&lt;li&gt;Step 4 — Introduce an Abstraction When It Adds Value&lt;/li&gt;
&lt;li&gt;Step 5 — Choose a Pattern If It Fits&lt;/li&gt;
&lt;li&gt;Step 6 — Keep the Design Simple&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SOLID in a Typical .NET Application&lt;/li&gt;
&lt;li&gt;SOLID vs Design Patterns&lt;/li&gt;
&lt;li&gt;When Should You Not Apply SOLID Aggressively?&lt;/li&gt;
&lt;li&gt;A Simple SOLID Mental Model&lt;/li&gt;
&lt;li&gt;SOLID Design Pattern Quick Reference&lt;/li&gt;
&lt;li&gt;
Common SOLID Misconceptions

&lt;ul&gt;
&lt;li&gt;Misconception 1: "SOLID means more interfaces."&lt;/li&gt;
&lt;li&gt;Misconception 2: "SOLID means every class should have one method."&lt;/li&gt;
&lt;li&gt;Misconception 3: "SOLID means no if/else statements."&lt;/li&gt;
&lt;li&gt;Misconception 4: "DIP and Dependency Injection are the same."&lt;/li&gt;
&lt;li&gt;Misconception 5: "Every SOLID problem requires a design pattern."&lt;/li&gt;
&lt;li&gt;Misconception 6: "Inheritance is always better than composition."&lt;/li&gt;
&lt;li&gt;Misconception 7: "Following SOLID guarantees good architecture."&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The Most Important Lesson&lt;/li&gt;
&lt;li&gt;Final Takeaways&lt;/li&gt;
&lt;li&gt;Practical SOLID Checklist&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SOLID is one of the most discussed topics in object-oriented programming.&lt;/p&gt;

&lt;p&gt;Most developers have heard of the five principles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;S&lt;/strong&gt; — Single Responsibility Principle&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;O&lt;/strong&gt; — Open/Closed Principle&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L&lt;/strong&gt; — Liskov Substitution Principle&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I&lt;/strong&gt; — Interface Segregation Principle&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;D&lt;/strong&gt; — Dependency Inversion Principle&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But knowing what the letters stand for is very different from knowing how to apply them.&lt;/p&gt;

&lt;p&gt;A developer may remember that SRP means &lt;em&gt;"a class should have one reason to change"&lt;/em&gt; but still struggle to identify an SRP violation in a real application.&lt;/p&gt;

&lt;p&gt;Similarly, developers often learn design patterns such as &lt;strong&gt;Strategy, Factory, Adapter, Decorator, and Repository&lt;/strong&gt;, but may not understand how these patterns relate to SOLID.&lt;/p&gt;

&lt;p&gt;This article takes a practical approach.&lt;/p&gt;

&lt;p&gt;Instead of simply memorizing definitions, we will look at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The problem each SOLID principle tries to solve&lt;/li&gt;
&lt;li&gt;How that problem appears in real applications&lt;/li&gt;
&lt;li&gt;How to recognize the problem&lt;/li&gt;
&lt;li&gt;How to refactor the design&lt;/li&gt;
&lt;li&gt;Which design patterns or techniques can help&lt;/li&gt;
&lt;li&gt;Common misconceptions&lt;/li&gt;
&lt;li&gt;How the principles work together&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The examples use &lt;strong&gt;C# and .NET&lt;/strong&gt;, but the underlying concepts apply to object-oriented software in general.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Does SOLID Mean?
&lt;/h2&gt;

&lt;p&gt;SOLID is an acronym for five object-oriented design principles:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Principle&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Practical Question&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;S&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Single Responsibility Principle&lt;/td&gt;
&lt;td&gt;Does this class have more than one reason to change?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;O&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Open/Closed Principle&lt;/td&gt;
&lt;td&gt;Can I add new behavior without repeatedly modifying stable code?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;L&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Liskov Substitution Principle&lt;/td&gt;
&lt;td&gt;Can a derived type safely replace its base type?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;I&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Interface Segregation Principle&lt;/td&gt;
&lt;td&gt;Are implementations forced to depend on methods they do not need?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;D&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dependency Inversion Principle&lt;/td&gt;
&lt;td&gt;Does my business logic depend directly on implementation details?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A simple way to remember them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;S → Keep responsibilities focused

O → Make changing behavior extensible

L → Make inheritance behaviorally trustworthy

I → Keep interfaces focused

D → Depend on abstractions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SOLID should not be treated as five rules that must be applied mechanically.&lt;/p&gt;

&lt;p&gt;The goal is not to create more interfaces, classes, or abstractions.&lt;/p&gt;

&lt;p&gt;The goal is to create software that is easier to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understand&lt;/li&gt;
&lt;li&gt;Change&lt;/li&gt;
&lt;li&gt;Test&lt;/li&gt;
&lt;li&gt;Extend&lt;/li&gt;
&lt;li&gt;Maintain&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  SOLID Is Not the Same as Design Patterns
&lt;/h2&gt;

&lt;p&gt;This distinction is important.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SOLID principles are design principles.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Design patterns are reusable approaches to recurring software design problems.&lt;/strong&gt;&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Design Problem
      ↓
Identify the underlying design principle
      ↓
Consider possible design approaches
      ↓
Choose a suitable pattern or technique
      ↓
Keep the solution as simple as possible
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A design pattern does not automatically make code SOLID.&lt;/p&gt;

&lt;p&gt;Likewise, SOLID does not require the use of design patterns.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Use SOLID to guide your design decisions. Use a design pattern when it provides a practical solution to the problem you actually have.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Also, not every pattern discussed in this article is a &lt;strong&gt;Gang of Four (GoF)&lt;/strong&gt; design pattern. For example, &lt;strong&gt;Repository&lt;/strong&gt; and &lt;strong&gt;Dependency Injection&lt;/strong&gt; are commonly used design or architectural techniques in modern enterprise applications, but they are not GoF patterns.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Single Responsibility Principle — SRP
&lt;/h2&gt;

&lt;h2&gt;
  
  
  The Simple Explanation
&lt;/h2&gt;

&lt;p&gt;The Single Responsibility Principle states:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A class should have one reason to change.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is often misunderstood as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"A class should contain only one method."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is not what SRP means.&lt;/p&gt;

&lt;p&gt;A class can contain multiple methods and still have a single responsibility.&lt;/p&gt;

&lt;p&gt;The better question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Do the responsibilities in this class change for different reasons?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  A Common Problem
&lt;/h2&gt;

&lt;p&gt;Imagine an e-commerce application with this class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderService&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;CreateOrder&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="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Save order to database&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;ProcessPayment&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="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Process payment&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;SendConfirmationEmail&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="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Send email&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;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;GenerateInvoice&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="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Generate PDF invoice&lt;/span&gt;
        &lt;span class="k"&gt;return&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;At first glance, this may look convenient.&lt;/p&gt;

&lt;p&gt;Everything related to an order is in one place.&lt;/p&gt;

&lt;p&gt;But this class actually contains several responsibilities:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OrderService
    |
    +-- Order persistence
    |
    +-- Payment processing
    |
    +-- Email communication
    |
    +-- Invoice generation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now consider the following changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The database technology changes.&lt;/li&gt;
&lt;li&gt;The payment provider changes.&lt;/li&gt;
&lt;li&gt;The email provider changes.&lt;/li&gt;
&lt;li&gt;The invoice format changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These changes are driven by different concerns.&lt;/p&gt;

&lt;p&gt;If all of them require modifying &lt;code&gt;OrderService&lt;/code&gt;, the class has multiple reasons to change.&lt;/p&gt;

&lt;p&gt;That is a warning sign for SRP.&lt;/p&gt;




&lt;h2&gt;
  
  
  Refactoring the Design
&lt;/h2&gt;

&lt;p&gt;We can separate the responsibilities:&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;interface&lt;/span&gt; &lt;span class="nc"&gt;IOrderRepository&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&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="n"&gt;order&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;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;interface&lt;/span&gt; &lt;span class="nc"&gt;IPaymentService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ProcessAsync&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;INotificationService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;SendOrderConfirmationAsync&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IInvoiceService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;]&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GenerateAsync&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application service can then coordinate the workflow:&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;IOrderRepository&lt;/span&gt; &lt;span class="n"&gt;_orderRepository&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;IPaymentService&lt;/span&gt; &lt;span class="n"&gt;_paymentService&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;INotificationService&lt;/span&gt; &lt;span class="n"&gt;_notificationService&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;IOrderRepository&lt;/span&gt; &lt;span class="n"&gt;orderRepository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;IPaymentService&lt;/span&gt; &lt;span class="n"&gt;paymentService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;INotificationService&lt;/span&gt; &lt;span class="n"&gt;notificationService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_orderRepository&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;orderRepository&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_paymentService&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;paymentService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_notificationService&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;notificationService&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;CreateOrderAsync&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="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_orderRepository&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;_paymentService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ProcessAsync&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;_notificationService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SendOrderConfirmationAsync&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="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;Now the responsibilities are clearer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OrderService
     |
     +── IOrderRepository
     +── IPaymentService
     +── INotificationService
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;OrderService&lt;/code&gt; coordinates the workflow instead of implementing every technical detail itself.&lt;/p&gt;




&lt;h2&gt;
  
  
  Design Patterns and Techniques That Can Support SRP
&lt;/h2&gt;

&lt;p&gt;SRP does not require a particular design pattern.&lt;/p&gt;

&lt;p&gt;However, several patterns or techniques can help separate responsibilities:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern / Technique&lt;/th&gt;
&lt;th&gt;How it can help&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Facade&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Provides a simplified interface over multiple components&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Strategy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Separates interchangeable business algorithms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Command&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Encapsulates an operation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Decorator&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Separates cross-cutting behavior&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mediator&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Separates request handling responsibilities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Repository&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Separates persistence concerns from business logic&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These are not "SRP patterns."&lt;/p&gt;

&lt;p&gt;They are approaches that can help create a design with better separation of responsibilities.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common SRP Mistake
&lt;/h2&gt;

&lt;p&gt;A common misunderstanding is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Every class must do only one thing."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That can lead to unnecessary fragmentation.&lt;/p&gt;

&lt;p&gt;For example, creating a separate class for every small method may produce a system with too many abstractions and dependencies.&lt;/p&gt;

&lt;p&gt;Instead, ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Do these responsibilities change independently?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If they do, separating them may make the design easier to maintain.&lt;/p&gt;

&lt;p&gt;If they do not, keeping them together may be perfectly reasonable.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Open/Closed Principle — OCP
&lt;/h2&gt;

&lt;h2&gt;
  
  
  The Simple Explanation
&lt;/h2&gt;

&lt;p&gt;The Open/Closed Principle states:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Software entities should be open for extension but closed for modification.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A practical interpretation is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Design areas of expected variation so that new behavior can be added without repeatedly changing stable, already-tested code.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This does not mean existing code can never be modified.&lt;/p&gt;

&lt;p&gt;Requirements change, bugs need fixing, and designs evolve.&lt;/p&gt;

&lt;p&gt;The principle is about avoiding unnecessary modification of stable code every time a new variation is introduced.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Common Problem
&lt;/h2&gt;

&lt;p&gt;Consider payment processing:&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;PaymentService&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;Process&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;paymentType&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;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paymentType&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"CreditCard"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Credit card payment&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paymentType&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"PayPal"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// PayPal payment&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paymentType&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"UPI"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// UPI payment&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;Today we support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Credit Card&lt;/li&gt;
&lt;li&gt;PayPal&lt;/li&gt;
&lt;li&gt;UPI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tomorrow we might add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bank Transfer&lt;/li&gt;
&lt;li&gt;Apple Pay&lt;/li&gt;
&lt;li&gt;Google Pay&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the conditional keeps growing, every new payment method requires modifying the same class.&lt;/p&gt;

&lt;p&gt;The problem is not that &lt;code&gt;if&lt;/code&gt; or &lt;code&gt;switch&lt;/code&gt; statements are inherently bad.&lt;/p&gt;

&lt;p&gt;The problem is that independently changing behavior is becoming tightly coupled to one piece of code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Applying the Strategy Pattern
&lt;/h2&gt;

&lt;p&gt;We can introduce an abstraction:&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;interface&lt;/span&gt; &lt;span class="nc"&gt;IPaymentStrategy&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Pay&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;amount&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;Then create separate implementations:&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;CreditCardPayment&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IPaymentStrategy&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;Pay&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;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Process credit card payment&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;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;UpiPayment&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IPaymentStrategy&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;Pay&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;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Process UPI payment&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 service depends on the abstraction:&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;PaymentService&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;IPaymentStrategy&lt;/span&gt; &lt;span class="n"&gt;_paymentStrategy&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;PaymentService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IPaymentStrategy&lt;/span&gt; &lt;span class="n"&gt;paymentStrategy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_paymentStrategy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;paymentStrategy&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;void&lt;/span&gt; &lt;span class="nf"&gt;Process&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;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_paymentStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Pay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&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;Now a new payment method can be introduced:&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;BankTransferPayment&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IPaymentStrategy&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;Pay&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;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Process bank transfer&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 existing payment implementations do not need to change.&lt;/p&gt;




&lt;h2&gt;
  
  
  Strategy Pattern and OCP
&lt;/h2&gt;

&lt;p&gt;This is one of the clearest relationships between SOLID and design patterns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Problem
   ↓
Multiple interchangeable behaviors
   ↓
Identify the variation
   ↓
Encapsulate each behavior
   ↓
Strategy Pattern
   ↓
Add new strategies without changing existing strategies
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Strategy Pattern is particularly useful when several algorithms or business rules implement the same conceptual operation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Factory Pattern and OCP
&lt;/h2&gt;

&lt;p&gt;A Factory can be useful when object creation is itself a concern.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IPaymentProcessor&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Process&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;amount&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;Implementations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IPaymentProcessor
       |
       +---- CreditCardProcessor
       +---- UpiProcessor
       +---- BankTransferProcessor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simple factory might select an implementation:&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;PaymentProcessorFactory&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;IPaymentProcessor&lt;/span&gt; &lt;span class="nf"&gt;Create&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;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"CreditCard"&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;CreditCardProcessor&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="s"&gt;"UPI"&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;UpiProcessor&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="s"&gt;"BankTransfer"&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;BankTransferProcessor&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ArgumentException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Unsupported payment type"&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;However, notice something important.&lt;/p&gt;

&lt;p&gt;The factory itself must change when a new payment type is added.&lt;/p&gt;

&lt;p&gt;Therefore, this factory is not automatically an example of a completely closed-for-modification design.&lt;/p&gt;

&lt;p&gt;It can still be a useful solution if the creation logic is intentionally centralized and the trade-off is acceptable.&lt;/p&gt;

&lt;p&gt;In larger .NET applications, dependency injection, keyed services, configuration-driven registration, or other approaches may sometimes provide a better fit.&lt;/p&gt;

&lt;p&gt;The lesson is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Do not use a pattern simply because its name appears in a SOLID discussion. Evaluate the actual design trade-off.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  3. Liskov Substitution Principle — LSP
&lt;/h2&gt;

&lt;h2&gt;
  
  
  The Simple Explanation
&lt;/h2&gt;

&lt;p&gt;The Liskov Substitution Principle states that:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A derived type should be usable wherever its base type is expected without violating the expectations of the consuming code.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In simpler terms:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If &lt;code&gt;B&lt;/code&gt; is a subtype of &lt;code&gt;A&lt;/code&gt;, replacing an &lt;code&gt;A&lt;/code&gt; with a &lt;code&gt;B&lt;/code&gt; should not unexpectedly break the program's correctness or behavioral assumptions.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;LSP is less about syntax and more about &lt;strong&gt;behavioral contracts&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Classic Example
&lt;/h2&gt;

&lt;p&gt;Consider:&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;Bird&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;virtual&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Fly&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Flying"&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;Now imagine:&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;Penguin&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Bird&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Fly&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NotSupportedException&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;We have created a problem.&lt;/p&gt;

&lt;p&gt;The base class exposes &lt;code&gt;Fly()&lt;/code&gt; as a behavior that consumers can call.&lt;/p&gt;

&lt;p&gt;But &lt;code&gt;Penguin&lt;/code&gt; cannot provide that behavior.&lt;/p&gt;

&lt;p&gt;This code becomes problematic:&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;Bird&lt;/span&gt; &lt;span class="n"&gt;bird&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;Penguin&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The derived type cannot safely satisfy the expectations created by the base abstraction.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Better Design
&lt;/h2&gt;

&lt;p&gt;The problem is the abstraction.&lt;/p&gt;

&lt;p&gt;Not every bird needs to support flying.&lt;/p&gt;

&lt;p&gt;We can separate the concepts:&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;abstract&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Bird&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;abstract&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Move&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;Then define flying separately:&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;interface&lt;/span&gt; &lt;span class="nc"&gt;IFlyingBird&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Fly&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;An eagle can implement it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Eagle&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Bird&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IFlyingBird&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Move&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Fly&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;void&lt;/span&gt; &lt;span class="nf"&gt;Fly&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Eagle is flying"&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;A penguin does not need to implement &lt;code&gt;IFlyingBird&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Penguin&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Bird&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Move&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Penguin is walking"&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;The abstraction now better represents the actual capabilities of the types.&lt;/p&gt;




&lt;h2&gt;
  
  
  LSP in Enterprise Applications
&lt;/h2&gt;

&lt;p&gt;The Bird/Penguin example is useful for understanding the principle, but enterprise applications often encounter LSP problems in more subtle ways.&lt;/p&gt;

&lt;p&gt;Consider a payment processor:&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;abstract&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaymentProcessor&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;abstract&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Process&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;amount&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;abstract&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Refund&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;amount&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;Suppose an implementation does not support refunds:&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;SomePaymentProcessor&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PaymentProcessor&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Process&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;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Process payment&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Refund&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;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NotSupportedException&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;If consumers of &lt;code&gt;PaymentProcessor&lt;/code&gt; reasonably expect every implementation to support refunds, the abstraction is too broad.&lt;/p&gt;

&lt;p&gt;A better design may separate the capabilities:&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;interface&lt;/span&gt; &lt;span class="nc"&gt;IPaymentProcessor&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Process&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;amount&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;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;interface&lt;/span&gt; &lt;span class="nc"&gt;IRefundProcessor&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Refund&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;amount&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;An implementation can then support the capabilities it actually provides.&lt;/p&gt;

&lt;p&gt;This example also connects naturally to the &lt;strong&gt;Interface Segregation Principle&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  LSP and Composition
&lt;/h2&gt;

&lt;p&gt;A useful way to avoid problematic inheritance is to consider composition.&lt;/p&gt;

&lt;p&gt;Instead of creating a complex hierarchy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BaseProcessor
     |
     +-- ProcessorA
     +-- ProcessorB
     +-- ProcessorC
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;consider whether behavior can be composed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Processor
    |
    +-- Strategy
    +-- Validator
    +-- Formatter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Composition is not a replacement for inheritance in every situation, but it can reduce problems caused by incorrect inheritance relationships.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common LSP Warning Signs
&lt;/h2&gt;

&lt;p&gt;Look carefully when you see:&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;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NotSupportedException&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;inside an overridden method.&lt;/p&gt;

&lt;p&gt;This is &lt;strong&gt;not automatically an LSP violation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Sometimes an unsupported operation is legitimate.&lt;/p&gt;

&lt;p&gt;But it should trigger a design question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Does the base abstraction promise behavior that this implementation cannot provide?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Other warning signs include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Derived classes disabling base behavior&lt;/li&gt;
&lt;li&gt;Derived classes significantly changing the meaning of base methods&lt;/li&gt;
&lt;li&gt;Consumers checking concrete subtypes before using them&lt;/li&gt;
&lt;li&gt;Large type-checking blocks&lt;/li&gt;
&lt;li&gt;Frequent &lt;code&gt;is&lt;/code&gt; checks against derived types&lt;/li&gt;
&lt;li&gt;Special-case handling for particular subclasses&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Interface Segregation Principle — ISP
&lt;/h2&gt;

&lt;h2&gt;
  
  
  The Simple Explanation
&lt;/h2&gt;

&lt;p&gt;The Interface Segregation Principle states:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Clients should not be forced to depend on methods they do not use.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In simpler terms:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Prefer focused interfaces that represent meaningful capabilities over large interfaces containing unrelated operations.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  A Common Problem
&lt;/h2&gt;

&lt;p&gt;Consider an employee management system:&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;interface&lt;/span&gt; &lt;span class="nc"&gt;IEmployee&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Work&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Eat&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;AttendMeeting&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;WriteCode&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ManageTeam&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;Now imagine a developer:&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;Developer&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IEmployee&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;Work&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;void&lt;/span&gt; &lt;span class="nf"&gt;Eat&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;void&lt;/span&gt; &lt;span class="nf"&gt;AttendMeeting&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;void&lt;/span&gt; &lt;span class="nf"&gt;WriteCode&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;void&lt;/span&gt; &lt;span class="nf"&gt;ManageTeam&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NotSupportedException&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;The developer is forced to implement &lt;code&gt;ManageTeam()&lt;/code&gt; even though that capability is not part of the developer's responsibility.&lt;/p&gt;

&lt;p&gt;This is a sign of a &lt;strong&gt;fat interface&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Split the Interface
&lt;/h2&gt;

&lt;p&gt;Instead, define smaller, cohesive interfaces:&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;interface&lt;/span&gt; &lt;span class="nc"&gt;IWorker&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Work&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;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;interface&lt;/span&gt; &lt;span class="nc"&gt;IDeveloper&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;WriteCode&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;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;interface&lt;/span&gt; &lt;span class="nc"&gt;IManager&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ManageTeam&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;Now:&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;Developer&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IWorker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IDeveloper&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;Work&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;void&lt;/span&gt; &lt;span class="nf"&gt;WriteCode&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;And:&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;EngineeringManager&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IWorker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IManager&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;Work&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;void&lt;/span&gt; &lt;span class="nf"&gt;ManageTeam&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;Each class depends only on the capabilities it needs.&lt;/p&gt;




&lt;h2&gt;
  
  
  ISP in an Enterprise Service
&lt;/h2&gt;

&lt;p&gt;Imagine a large customer service interface:&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;interface&lt;/span&gt; &lt;span class="nc"&gt;ICustomerService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Customer&lt;/span&gt; &lt;span class="nf"&gt;GetCustomer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;CreateCustomer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Customer&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;UpdateCustomer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Customer&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;DeleteCustomer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;SendMarketingEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ExportCustomers&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;Different consumers may need completely different capabilities.&lt;/p&gt;

&lt;p&gt;Instead, we could separate them:&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;interface&lt;/span&gt; &lt;span class="nc"&gt;ICustomerReader&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Customer&lt;/span&gt; &lt;span class="nf"&gt;GetCustomer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;ICustomerWriter&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;CreateCustomer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Customer&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;UpdateCustomer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Customer&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;DeleteCustomer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;ICustomerExporter&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ExportCustomers&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;This creates smaller contracts that can be consumed independently.&lt;/p&gt;




&lt;h2&gt;
  
  
  Patterns That Can Support ISP
&lt;/h2&gt;

&lt;p&gt;Some patterns can complement interface segregation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Adapter&lt;/strong&gt; — exposes the interface a client actually needs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Facade&lt;/strong&gt; — provides a focused interface over a more complex subsystem&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proxy&lt;/strong&gt; — can provide a focused boundary around another component&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Again, the pattern does not implement ISP automatically.&lt;/p&gt;

&lt;p&gt;The important design decision is to ensure clients are not forced to depend on irrelevant operations.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common ISP Mistake
&lt;/h2&gt;

&lt;p&gt;Do not interpret ISP as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Every interface should contain exactly one method."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is not the principle.&lt;/p&gt;

&lt;p&gt;An interface can contain several methods when they represent one cohesive capability.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IOrderRepository&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetByIdAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;AddAsync&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;Task&lt;/span&gt; &lt;span class="nf"&gt;UpdateAsync&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These operations may form a cohesive persistence contract.&lt;/p&gt;

&lt;p&gt;The goal is &lt;strong&gt;cohesion&lt;/strong&gt;, not an arbitrary number of methods.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Dependency Inversion Principle — DIP
&lt;/h2&gt;

&lt;h2&gt;
  
  
  The Simple Explanation
&lt;/h2&gt;

&lt;p&gt;The Dependency Inversion Principle states:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;High-level modules should not depend on low-level modules. Both should depend on abstractions.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It also states:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Abstractions should not depend on details. Details should depend on abstractions.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In simpler terms:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Business logic should not be tightly coupled to infrastructure details.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  A Common Problem
&lt;/h2&gt;

&lt;p&gt;Consider:&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;SqlOrderRepository&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="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="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SqlOrderRepository&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;void&lt;/span&gt; &lt;span class="nf"&gt;CreateOrder&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="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="nf"&gt;Save&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="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;OrderService&lt;/code&gt; directly creates &lt;code&gt;SqlOrderRepository&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The business service now knows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which persistence implementation is being used&lt;/li&gt;
&lt;li&gt;How the repository is created&lt;/li&gt;
&lt;li&gt;That the repository is backed by SQL Server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This creates tight coupling.&lt;/p&gt;




&lt;h2&gt;
  
  
  Introduce an Abstraction
&lt;/h2&gt;

&lt;p&gt;Define:&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;interface&lt;/span&gt; &lt;span class="nc"&gt;IOrderRepository&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Save&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The infrastructure implementation can be:&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;SqlOrderRepository&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IOrderRepository&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;Save&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="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Save to SQL Server&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;Now the service depends on the abstraction:&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;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;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;_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;void&lt;/span&gt; &lt;span class="nf"&gt;CreateOrder&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="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="nf"&gt;Save&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="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 dependency direction becomes:&lt;br&gt;
&lt;/p&gt;

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

OrderService
     |
     ↓
SqlOrderRepository


After:

OrderService
     |
     ↓
IOrderRepository
     ↑
     |
SqlOrderRepository
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The high-level business logic no longer needs to know the concrete persistence implementation.&lt;/p&gt;




&lt;h1&gt;
  
  
  Dependency Inversion vs Dependency Injection
&lt;/h1&gt;

&lt;p&gt;These concepts are closely related but are not the same thing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dependency Inversion Principle
&lt;/h3&gt;

&lt;p&gt;DIP is a &lt;strong&gt;design principle&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It describes how high-level and low-level components should depend on abstractions.&lt;/p&gt;

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

&lt;p&gt;Dependency Injection is a &lt;strong&gt;technique&lt;/strong&gt; for providing dependencies to a class from outside the class.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&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;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;_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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is constructor injection.&lt;/p&gt;

&lt;p&gt;In ASP.NET Core, the built-in dependency injection container can register the implementation:&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;AddScoped&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IOrderRepository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SqlOrderRepository&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddScoped&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The framework can then provide &lt;code&gt;SqlOrderRepository&lt;/code&gt; when &lt;code&gt;OrderService&lt;/code&gt; is created.&lt;/p&gt;

&lt;p&gt;So the relationship is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DIP
 ↓
Design principle

Dependency Injection
 ↓
Implementation technique
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dependency Injection is one common way to implement a design that follows DIP.&lt;/p&gt;




&lt;h1&gt;
  
  
  SOLID and Design Patterns — The Practical Connection
&lt;/h1&gt;

&lt;p&gt;Now let's connect the principles with patterns and techniques that can help address related design problems.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;SOLID Principle&lt;/th&gt;
&lt;th&gt;Patterns / Techniques That May Help&lt;/th&gt;
&lt;th&gt;Typical Design Problem&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SRP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Command, Strategy, Decorator, Facade, Repository&lt;/td&gt;
&lt;td&gt;Too many independent responsibilities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OCP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Strategy, Decorator, Template Method, Factory&lt;/td&gt;
&lt;td&gt;New behavior repeatedly requires modifying existing code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;LSP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Strategy, Adapter, Composition&lt;/td&gt;
&lt;td&gt;Incorrect or overly restrictive inheritance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ISP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Adapter, Facade, Proxy&lt;/td&gt;
&lt;td&gt;Clients depend on unnecessary operations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DIP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dependency Injection, Adapter, Repository, Factory&lt;/td&gt;
&lt;td&gt;Business logic depends directly on implementation details&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is &lt;strong&gt;not a strict one-to-one mapping&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A pattern can support multiple SOLID principles, and a SOLID principle can be applied without using a design pattern.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Strategy
   ↓
Can support OCP
   ↓
Can also help SRP
   ↓
May also improve testability
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Likewise:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Adapter
   ↓
Can help isolate an external dependency
   ↓
Can support DIP
   ↓
Can expose a focused interface
   ↓
Can support ISP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The correct approach is to start with the design problem, not the pattern name.&lt;/p&gt;




&lt;h1&gt;
  
  
  SOLID Does Not Mean "More Interfaces"
&lt;/h1&gt;

&lt;p&gt;One of the biggest misconceptions about SOLID is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"If I create interfaces everywhere, my code is SOLID."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not necessarily.&lt;/p&gt;

&lt;p&gt;Consider:&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;interface&lt;/span&gt; &lt;span class="nc"&gt;IUserService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;CreateUser&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;UserService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IUserService&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;CreateUser&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;If the interface provides no meaningful abstraction or architectural boundary, it may simply add indirection.&lt;/p&gt;

&lt;p&gt;Instead, ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Where do I actually need an abstraction?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Useful boundaries often include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;External systems&lt;/li&gt;
&lt;li&gt;Infrastructure&lt;/li&gt;
&lt;li&gt;Business strategies&lt;/li&gt;
&lt;li&gt;Multiple implementations&lt;/li&gt;
&lt;li&gt;Testing boundaries&lt;/li&gt;
&lt;li&gt;Plugin-style architectures&lt;/li&gt;
&lt;li&gt;Components that are expected to vary independently&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Abstraction has a cost.&lt;/p&gt;

&lt;p&gt;Use it where it provides a meaningful benefit.&lt;/p&gt;




&lt;h1&gt;
  
  
  SOLID Does Not Mean "Create More Classes"
&lt;/h1&gt;

&lt;p&gt;Another common mistake is over-fragmentation.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OrderService
OrderValidator
OrderCalculator
OrderMapper
OrderLogger
OrderFormatter
OrderHelper
OrderUtility
OrderManager
OrderProcessor
OrderHandler
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Having many classes does not automatically mean the design is better.&lt;/p&gt;

&lt;p&gt;A highly fragmented design can introduce:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More dependencies&lt;/li&gt;
&lt;li&gt;More files&lt;/li&gt;
&lt;li&gt;More abstractions&lt;/li&gt;
&lt;li&gt;More cognitive overhead&lt;/li&gt;
&lt;li&gt;More difficult debugging&lt;/li&gt;
&lt;li&gt;More complex dependency graphs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The objective is &lt;strong&gt;appropriate separation&lt;/strong&gt;, not maximum separation.&lt;/p&gt;




&lt;h1&gt;
  
  
  SOLID Does Not Mean "Remove Every if/else"
&lt;/h1&gt;

&lt;p&gt;Another misconception is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"SOLID means removing every if/else statement."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's not true.&lt;/p&gt;

&lt;p&gt;This can be perfectly reasonable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&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;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;ApplyDiscount&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The question is whether the conditional represents a stable rule or whether it is continuously growing with independently changing behavior.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paymentType&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"CreditCard"&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;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paymentType&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"UPI"&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;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paymentType&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"PayPal"&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;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paymentType&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"BankTransfer"&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;If this list continuously grows and each branch represents an independent behavior, the Strategy Pattern may be worth considering.&lt;/p&gt;

&lt;p&gt;The pattern should be introduced because it improves the design, not simply because an &lt;code&gt;if&lt;/code&gt; statement exists.&lt;/p&gt;




&lt;h1&gt;
  
  
  SOLID Does Not Mean "Use Every Design Pattern"
&lt;/h1&gt;

&lt;p&gt;Design patterns are tools.&lt;/p&gt;

&lt;p&gt;Using them everywhere can create unnecessary complexity.&lt;/p&gt;

&lt;p&gt;For example, a simple calculation does not need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Abstract Factory
      ↓
Factory Method
      ↓
Strategy
      ↓
Decorator
      ↓
Mediator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;when this may be sufficient:&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="kt"&gt;decimal&lt;/span&gt; &lt;span class="nf"&gt;CalculateTax&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;amount&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;amount&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="m"&gt;0.18m&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;A good engineer knows not only how to apply patterns, but also when &lt;strong&gt;not&lt;/strong&gt; to apply them.&lt;/p&gt;




&lt;h1&gt;
  
  
  A Real-World Example: Notification System
&lt;/h1&gt;

&lt;p&gt;Let's bring several SOLID principles together using a notification system.&lt;/p&gt;

&lt;p&gt;Suppose an application needs to send:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Email&lt;/li&gt;
&lt;li&gt;SMS&lt;/li&gt;
&lt;li&gt;Push notifications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A simple implementation might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NotificationService&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;Send&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;type&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;recipient&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;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"Email"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Send email&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"SMS"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Send SMS&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"Push"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Send push notification&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;It works.&lt;/p&gt;

&lt;p&gt;But what happens when we add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WhatsApp&lt;/li&gt;
&lt;li&gt;Microsoft Teams&lt;/li&gt;
&lt;li&gt;Slack&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The class keeps growing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Introduce an Abstraction
&lt;/h2&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;interface&lt;/span&gt; &lt;span class="nc"&gt;INotificationSender&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;SendAsync&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;recipient&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;message&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;Email:&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;EmailNotificationSender&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;INotificationSender&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;Task&lt;/span&gt; &lt;span class="nf"&gt;SendAsync&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;recipient&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;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Send email&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedTask&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;SMS:&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;SmsNotificationSender&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;INotificationSender&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;Task&lt;/span&gt; &lt;span class="nf"&gt;SendAsync&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;recipient&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;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Send SMS&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedTask&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;Push:&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;PushNotificationSender&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;INotificationSender&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;Task&lt;/span&gt; &lt;span class="nf"&gt;SendAsync&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;recipient&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;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Send push notification&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompletedTask&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;The application service can work with the abstraction:&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;NotificationService&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;INotificationSender&lt;/span&gt; &lt;span class="n"&gt;_sender&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;NotificationService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;INotificationSender&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_sender&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;SendAsync&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;recipient&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;message&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;_sender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SendAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="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 resulting design is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NotificationService
        |
        ↓
INotificationSender
        ↑
        |
  +-----+-----+------+
  |           |      |
Email        SMS    Push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Several principles are represented here.&lt;/p&gt;

&lt;h3&gt;
  
  
  SRP
&lt;/h3&gt;

&lt;p&gt;Each sender is responsible for one notification mechanism.&lt;/p&gt;

&lt;h3&gt;
  
  
  OCP
&lt;/h3&gt;

&lt;p&gt;A new notification mechanism can be introduced as another implementation without changing the existing senders.&lt;/p&gt;

&lt;h3&gt;
  
  
  LSP
&lt;/h3&gt;

&lt;p&gt;Each implementation should honor the behavioral contract defined by &lt;code&gt;INotificationSender&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ISP
&lt;/h3&gt;

&lt;p&gt;The interface contains only the operation needed by notification senders.&lt;/p&gt;

&lt;h3&gt;
  
  
  DIP
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;NotificationService&lt;/code&gt; depends on &lt;code&gt;INotificationSender&lt;/code&gt;, not directly on an email, SMS, or push provider.&lt;/p&gt;

&lt;p&gt;This is a good example of how SOLID principles can work together rather than being treated as five isolated rules.&lt;/p&gt;




&lt;h1&gt;
  
  
  How to Identify SOLID Issues During Code Review
&lt;/h1&gt;

&lt;p&gt;Instead of checking the five principles mechanically, ask practical questions.&lt;/p&gt;

&lt;h2&gt;
  
  
  SRP Questions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Does this class have unrelated responsibilities?&lt;/li&gt;
&lt;li&gt;Would different concerns cause different changes to this class?&lt;/li&gt;
&lt;li&gt;Does the class interact with too many unrelated technologies?&lt;/li&gt;
&lt;li&gt;Is the class becoming a "God class"?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  OCP Questions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Does adding a new behavior require modifying existing logic?&lt;/li&gt;
&lt;li&gt;Is a conditional structure continuously growing?&lt;/li&gt;
&lt;li&gt;Are new business rules repeatedly being added to the same class?&lt;/li&gt;
&lt;li&gt;Can the changing behavior be isolated?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  LSP Questions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Does a subclass throw &lt;code&gt;NotSupportedException&lt;/code&gt; for inherited behavior?&lt;/li&gt;
&lt;li&gt;Does a subclass change the expected meaning of a base method?&lt;/li&gt;
&lt;li&gt;Do consumers need to check the concrete subtype before using it?&lt;/li&gt;
&lt;li&gt;Is inheritance actually representing the required behavioral relationship?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ISP Questions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Are implementations forced to implement irrelevant methods?&lt;/li&gt;
&lt;li&gt;Is the interface becoming very large?&lt;/li&gt;
&lt;li&gt;Do different consumers use completely different subsets of the interface?&lt;/li&gt;
&lt;li&gt;Can the contract be divided into meaningful capabilities?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  DIP Questions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Does business logic directly instantiate infrastructure classes?&lt;/li&gt;
&lt;li&gt;Does a service depend directly on a database provider?&lt;/li&gt;
&lt;li&gt;Does business logic know about external SDK implementation details?&lt;/li&gt;
&lt;li&gt;Can an infrastructure implementation be replaced without changing business logic?&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  A Practical SOLID Refactoring Workflow
&lt;/h1&gt;

&lt;p&gt;You do not need to redesign an entire application whenever you discover a SOLID issue.&lt;/p&gt;

&lt;p&gt;A practical workflow is:&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 — Identify What Changes
&lt;/h2&gt;

&lt;p&gt;Ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What is likely to change independently?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Payment provider
Notification channel
Database
Pricing algorithm
Authentication mechanism
File storage provider
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2 — Identify the Coupling
&lt;/h2&gt;

&lt;p&gt;Ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Which component knows too much about this changing behavior?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 3 — Identify the Responsibility
&lt;/h2&gt;

&lt;p&gt;Ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Can this behavior be separated without making the design unnecessarily complex?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 4 — Introduce an Abstraction When It Adds Value
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IPaymentProcessor&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ProcessAsync&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;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5 — Choose a Pattern If It Fits
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Multiple interchangeable algorithms
        ↓
Strategy Pattern
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;External system has an incompatible API
        ↓
Adapter Pattern
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Object creation is complex or needs encapsulation
        ↓
Factory Pattern
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6 — Keep the Design Simple
&lt;/h2&gt;

&lt;p&gt;Do not introduce five abstractions when one abstraction solves the problem.&lt;/p&gt;




&lt;h1&gt;
  
  
  SOLID in a Typical .NET Application
&lt;/h1&gt;

&lt;p&gt;A typical enterprise application may have a structure similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 API Controller
                       |
                       ↓
              Application Service
                       |
          +------------+------------+
          |            |            |
          ↓            ↓            ↓
     Repository     Payment     Notification
          |         Strategy       Service
          ↓            |
      Database      +--+--+
                    |     |
                  Card   UPI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This does not mean every .NET application should have exactly this structure.&lt;/p&gt;

&lt;p&gt;It simply demonstrates how the principles can work together.&lt;/p&gt;

&lt;h3&gt;
  
  
  SRP
&lt;/h3&gt;

&lt;p&gt;Components have focused responsibilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  OCP
&lt;/h3&gt;

&lt;p&gt;New payment strategies can be introduced without modifying existing payment strategies.&lt;/p&gt;

&lt;h3&gt;
  
  
  LSP
&lt;/h3&gt;

&lt;p&gt;Payment implementations should honor the abstraction's behavioral contract.&lt;/p&gt;

&lt;h3&gt;
  
  
  ISP
&lt;/h3&gt;

&lt;p&gt;Consumers can depend on focused interfaces.&lt;/p&gt;

&lt;h3&gt;
  
  
  DIP
&lt;/h3&gt;

&lt;p&gt;Application-level code depends on abstractions rather than infrastructure implementations.&lt;/p&gt;




&lt;h1&gt;
  
  
  SOLID vs Design Patterns
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;SOLID Principles&lt;/th&gt;
&lt;th&gt;Design Patterns&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Design principles&lt;/td&gt;
&lt;td&gt;Reusable design approaches&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Help guide design decisions&lt;/td&gt;
&lt;td&gt;Help solve recurring design problems&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;More abstract&lt;/td&gt;
&lt;td&gt;More concrete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Help identify desirable design characteristics&lt;/td&gt;
&lt;td&gt;Provide implementation techniques&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Can be applied without design patterns&lt;/td&gt;
&lt;td&gt;Can be used independently of SOLID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Focus on maintainability and flexibility&lt;/td&gt;
&lt;td&gt;Focus on recurring structural or behavioral problems&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A useful mental model is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;SOLID tells you what characteristics to aim for. Design patterns provide techniques that may help you achieve those characteristics.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h1&gt;
  
  
  When Should You Not Apply SOLID Aggressively?
&lt;/h1&gt;

&lt;p&gt;SOLID is valuable, but context matters.&lt;/p&gt;

&lt;p&gt;For a small application with a simple and stable requirement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Simple problem
     ↓
Simple implementation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;may be better than:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Simple problem
     ↓
Multiple interfaces
     ↓
Multiple factories
     ↓
Multiple strategies
     ↓
Complex dependency graph
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a larger application with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple teams&lt;/li&gt;
&lt;li&gt;Frequent requirement changes&lt;/li&gt;
&lt;li&gt;External integrations&lt;/li&gt;
&lt;li&gt;Complex business rules&lt;/li&gt;
&lt;li&gt;Long-term maintenance&lt;/li&gt;
&lt;li&gt;Significant automated testing requirements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;appropriate abstractions can provide greater value.&lt;/p&gt;

&lt;p&gt;The right design depends on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complexity&lt;/li&gt;
&lt;li&gt;Change frequency&lt;/li&gt;
&lt;li&gt;Number of implementations&lt;/li&gt;
&lt;li&gt;Team size&lt;/li&gt;
&lt;li&gt;Testing requirements&lt;/li&gt;
&lt;li&gt;Expected lifetime of the software&lt;/li&gt;
&lt;li&gt;Operational requirements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SOLID is a design guide, not a requirement to maximize abstraction.&lt;/p&gt;




&lt;h1&gt;
  
  
  A Simple SOLID Mental Model
&lt;/h1&gt;

&lt;p&gt;When reviewing a class, ask these five questions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. S — Does this class have too many independent reasons to change?

2. O — Do I repeatedly modify this code whenever a new behavior is introduced?

3. L — Can every implementation genuinely honor the behavioral contract
       of its abstraction?

4. I — Is the interface asking implementations to support things they
       don't need?

5. D — Does my business logic depend directly on infrastructure or
       concrete implementations?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These questions are often more useful during code reviews than simply memorizing five definitions.&lt;/p&gt;




&lt;h1&gt;
  
  
  SOLID Design Pattern Quick Reference
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Principle&lt;/th&gt;
&lt;th&gt;Common Design Smell&lt;/th&gt;
&lt;th&gt;Possible Refactoring&lt;/th&gt;
&lt;th&gt;Patterns / Techniques That May Help&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SRP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;One class has unrelated responsibilities&lt;/td&gt;
&lt;td&gt;Extract cohesive responsibilities&lt;/td&gt;
&lt;td&gt;Command, Strategy, Decorator, Facade, Repository&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OCP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;New behavior repeatedly requires modifying existing code&lt;/td&gt;
&lt;td&gt;Encapsulate variation behind abstractions&lt;/td&gt;
&lt;td&gt;Strategy, Decorator, Template Method, Factory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;LSP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Derived type cannot honor the base contract&lt;/td&gt;
&lt;td&gt;Redesign the abstraction or prefer composition&lt;/td&gt;
&lt;td&gt;Strategy, Adapter, Composition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ISP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Large interface with irrelevant methods&lt;/td&gt;
&lt;td&gt;Split into cohesive capabilities&lt;/td&gt;
&lt;td&gt;Adapter, Facade, Proxy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DIP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Business logic directly depends on infrastructure&lt;/td&gt;
&lt;td&gt;Introduce appropriate abstractions&lt;/td&gt;
&lt;td&gt;Dependency Injection, Adapter, Repository, Factory&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This table is a &lt;strong&gt;practical association&lt;/strong&gt;, not a strict rule.&lt;/p&gt;

&lt;p&gt;There is no requirement that a particular SOLID principle must always be implemented using a particular pattern.&lt;/p&gt;




&lt;h1&gt;
  
  
  Common SOLID Misconceptions
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Misconception 1: "SOLID means more interfaces."
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Reality:&lt;/strong&gt; Interfaces are useful when they represent meaningful abstractions or boundaries.&lt;/p&gt;




&lt;h2&gt;
  
  
  Misconception 2: "SOLID means every class should have one method."
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Reality:&lt;/strong&gt; SRP is about reasons to change, not method count.&lt;/p&gt;




&lt;h2&gt;
  
  
  Misconception 3: "SOLID means no if/else statements."
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Reality:&lt;/strong&gt; Conditional logic is perfectly valid. The question is whether independently changing behavior is becoming tightly coupled.&lt;/p&gt;




&lt;h2&gt;
  
  
  Misconception 4: "DIP and Dependency Injection are the same."
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Reality:&lt;/strong&gt; DIP is a design principle. Dependency Injection is one technique that can help implement it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Misconception 5: "Every SOLID problem requires a design pattern."
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Reality:&lt;/strong&gt; Sometimes a simple refactoring is the best solution.&lt;/p&gt;




&lt;h2&gt;
  
  
  Misconception 6: "Inheritance is always better than composition."
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Reality:&lt;/strong&gt; Inheritance is useful when the subtype genuinely satisfies the behavioral contract of the base abstraction. Composition can be preferable when behavior needs to vary independently.&lt;/p&gt;




&lt;h2&gt;
  
  
  Misconception 7: "Following SOLID guarantees good architecture."
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Reality:&lt;/strong&gt; SOLID addresses important object-oriented design concerns, but good architecture also requires consideration of performance, security, reliability, scalability, maintainability, operational complexity, and business requirements.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Most Important Lesson
&lt;/h1&gt;

&lt;p&gt;When developers learn SOLID, it is tempting to memorize statements such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SRP → One responsibility

OCP → Open for extension, closed for modification

LSP → Subtypes must be substitutable

ISP → Small interfaces

DIP → Depend on abstractions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These definitions are useful, but they are only the starting point.&lt;/p&gt;

&lt;p&gt;A more useful engineering mindset is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What is changing?
       ↓
What is coupled to that change?
       ↓
Is the responsibility cohesive?
       ↓
Is the abstraction meaningful?
       ↓
Can the dependency be inverted?
       ↓
Would a design pattern simplify the solution?
       ↓
Is the resulting design actually easier to maintain?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is where SOLID becomes practical.&lt;/p&gt;




&lt;h1&gt;
  
  
  Final Takeaways
&lt;/h1&gt;

&lt;p&gt;SOLID is not about writing more code.&lt;/p&gt;

&lt;p&gt;It is about making change easier to manage.&lt;/p&gt;

&lt;p&gt;The five principles can be summarized as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SRP
→ Keep responsibilities focused.

OCP
→ Isolate expected variation so new behavior can be added with
  minimal modification to stable code.

LSP
→ Make abstractions behaviorally trustworthy.

ISP
→ Keep contracts focused on meaningful capabilities.

DIP
→ Keep high-level business logic independent from implementation details.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Design patterns and techniques can support these principles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SRP → Command, Strategy, Decorator, Facade, Repository

OCP → Strategy, Decorator, Template Method, Factory

LSP → Strategy, Adapter, Composition

ISP → Adapter, Facade, Proxy

DIP → Dependency Injection, Adapter, Repository, Factory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But there is an even more important lesson:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Don't start with a design pattern. Start with the problem.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ask:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;What is changing?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What is tightly coupled to that change?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Can the responsibility be separated?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Is an abstraction actually useful?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Would a design pattern simplify the solution?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Does the resulting design reduce complexity rather than increase it?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Good software design is not about following SOLID mechanically.&lt;/p&gt;

&lt;p&gt;It is about creating a codebase where &lt;strong&gt;responsibilities are clear, dependencies are manageable, expected changes are easier to accommodate, and complexity is kept under control&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The best SOLID design is not the one with the most abstractions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;It is the one that makes the important changes easier without introducing unnecessary complexity.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Practical SOLID Checklist
&lt;/h2&gt;

&lt;p&gt;Before committing a significant design change, ask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;□ Does each component have a clear and cohesive responsibility?

□ Can expected variations be added without repeatedly changing stable code?

□ Can implementations safely honor the contracts of their abstractions?

□ Are interfaces focused on meaningful capabilities?

□ Does business logic avoid unnecessary dependencies on infrastructure details?

□ Am I introducing an abstraction because I need it, rather than because
  SOLID tells me to?

□ Am I using a design pattern because it solves a real problem?

□ Has the solution become simpler or more maintainable?

□ Have I avoided unnecessary layers and abstractions?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the answer to these questions is clear, you are applying SOLID as an &lt;strong&gt;engineering principle&lt;/strong&gt;, rather than simply memorizing its definitions.&lt;/p&gt;




&lt;h1&gt;
  
  
  programming
&lt;/h1&gt;

&lt;h1&gt;
  
  
  csharp
&lt;/h1&gt;

&lt;h1&gt;
  
  
  dotnet
&lt;/h1&gt;

&lt;h1&gt;
  
  
  solid
&lt;/h1&gt;

&lt;h1&gt;
  
  
  designpatterns
&lt;/h1&gt;

&lt;h1&gt;
  
  
  softwarearchitecture
&lt;/h1&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>solid</category>
      <category>designpatterns</category>
    </item>
    <item>
      <title>RAG Explained: A Beginner's Guide to Retrieval-Augmented Generation</title>
      <dc:creator>Chethan Ramaswamy</dc:creator>
      <pubDate>Sat, 26 Sep 2026 06:31:04 +0000</pubDate>
      <link>https://dev.to/chethanramaswamy/rag-explained-a-beginners-guide-to-retrieval-augmented-generation-2dn9</link>
      <guid>https://dev.to/chethanramaswamy/rag-explained-a-beginners-guide-to-retrieval-augmented-generation-2dn9</guid>
      <description>&lt;h2&gt;
  
  
  📑 Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Imagine You Have 10,000 Company Documents&lt;/li&gt;
&lt;li&gt;So, What Is RAG?&lt;/li&gt;
&lt;li&gt;A Simple Real-World Example&lt;/li&gt;
&lt;li&gt;
How Does RAG Actually Work?

&lt;ul&gt;
&lt;li&gt;Stage 1: Prepare the Knowledge&lt;/li&gt;
&lt;li&gt;Step 1: Collect Your Documents&lt;/li&gt;
&lt;li&gt;Step 2: Break Large Documents into Smaller Pieces&lt;/li&gt;
&lt;li&gt;Step 3: Create Embeddings&lt;/li&gt;
&lt;li&gt;Step 4: Store the Information&lt;/li&gt;
&lt;li&gt;Stage 2: Answer the User's Question&lt;/li&gt;
&lt;li&gt;Step 5: The User Asks a Question&lt;/li&gt;
&lt;li&gt;Step 6: Give the Information to the AI&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
The Complete RAG Flow

&lt;ul&gt;
&lt;li&gt;Preparing the knowledge&lt;/li&gt;
&lt;li&gt;Answering a question&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Is RAG Just Search?&lt;/li&gt;
&lt;li&gt;RAG vs Fine-Tuning&lt;/li&gt;
&lt;li&gt;
Where Can We Use RAG?

&lt;ul&gt;
&lt;li&gt;Developer Assistant&lt;/li&gt;
&lt;li&gt;HR Assistant&lt;/li&gt;
&lt;li&gt;Customer Support&lt;/li&gt;
&lt;li&gt;Enterprise Knowledge Assistant&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Does RAG Make AI 100% Accurate?&lt;/li&gt;
&lt;li&gt;What Does RAG Look Like with .NET and Azure?&lt;/li&gt;
&lt;li&gt;The 5 Things You Need to Remember&lt;/li&gt;
&lt;li&gt;Your Turn&lt;/li&gt;
&lt;li&gt;Key Takeaway&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've started learning &lt;strong&gt;Generative AI&lt;/strong&gt;, you've probably come across terms like:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LLM. Embeddings. Vector Search. RAG.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At first, these terms can sound complicated.&lt;/p&gt;

&lt;p&gt;But the basic idea behind &lt;strong&gt;RAG&lt;/strong&gt; is actually quite simple.&lt;/p&gt;

&lt;p&gt;Let's understand it with a real-world example. 👇&lt;/p&gt;




&lt;h2&gt;
  
  
  🤔 Imagine You Have 10,000 Company Documents
&lt;/h2&gt;

&lt;p&gt;Imagine your company has thousands of documents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HR policies&lt;/li&gt;
&lt;li&gt;Travel policies&lt;/li&gt;
&lt;li&gt;Product documentation&lt;/li&gt;
&lt;li&gt;Technical guides&lt;/li&gt;
&lt;li&gt;Customer FAQs&lt;/li&gt;
&lt;li&gt;Security guidelines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now an employee asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"How much can I claim for a hotel during business travel?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Would you expect a general AI model to know your company's specific policy?&lt;/p&gt;

&lt;p&gt;Probably not.&lt;/p&gt;

&lt;p&gt;The information is inside your company's documents.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is where RAG becomes useful.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  💡 So, What Is RAG?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;RAG stands for Retrieval-Augmented Generation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Think of RAG like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Find the right information first, then ask the AI to answer using that information.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's the basic idea.&lt;/p&gt;

&lt;p&gt;A simplified flow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User asks a question
        ↓
Find relevant information
        ↓
Give that information to the AI
        ↓
AI generates an answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's see how this works.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏨 A Simple Real-World Example
&lt;/h2&gt;

&lt;p&gt;Suppose your company's travel policy says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Employees can claim hotel expenses up to ₹5,000 per night when traveling for business.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;An employee asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"What is the hotel reimbursement limit?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A RAG application can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Search the company's travel policy.&lt;/li&gt;
&lt;li&gt;Find the relevant information.&lt;/li&gt;
&lt;li&gt;Provide that information to the AI.&lt;/li&gt;
&lt;li&gt;Generate an answer.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The AI can then respond:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"According to the travel policy, employees can claim hotel expenses up to ₹5,000 per night."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Notice what happened?&lt;/p&gt;

&lt;p&gt;The AI didn't need to already know your company's travel policy.&lt;/p&gt;

&lt;p&gt;The application &lt;strong&gt;retrieved the relevant information first&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That's the basic idea behind RAG.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔍 How Does RAG Actually Work?
&lt;/h2&gt;

&lt;p&gt;Let's break it down into a few simple steps.&lt;/p&gt;

&lt;p&gt;Don't worry — we'll keep the technical jargon to a minimum.&lt;/p&gt;

&lt;p&gt;A basic RAG application can be understood in &lt;strong&gt;two stages&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Prepare the knowledge&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Answer the user's question&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's look at both.&lt;/p&gt;




&lt;h1&gt;
  
  
  📚 Stage 1: Prepare the Knowledge
&lt;/h1&gt;

&lt;p&gt;Before users can ask questions, we need to prepare the documents so that relevant information can be found quickly.&lt;/p&gt;

&lt;h3&gt;
  
  
  📄 Step 1: Collect Your Documents
&lt;/h3&gt;

&lt;p&gt;Your knowledge could come from many places:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📄 PDF files&lt;/li&gt;
&lt;li&gt;📝 Word documents&lt;/li&gt;
&lt;li&gt;🌐 Websites&lt;/li&gt;
&lt;li&gt;🗄️ Databases&lt;/li&gt;
&lt;li&gt;☁️ Cloud storage&lt;/li&gt;
&lt;li&gt;📚 Knowledge bases&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Company Knowledge
       │
       ├── HR Policy.pdf
       ├── Travel Policy.pdf
       ├── Security Policy.pdf
       └── Product Manual.pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These documents become the &lt;strong&gt;knowledge source&lt;/strong&gt; for our AI application.&lt;/p&gt;




&lt;h3&gt;
  
  
  ✂️ Step 2: Break Large Documents into Smaller Pieces
&lt;/h3&gt;

&lt;p&gt;Imagine you have a &lt;strong&gt;100-page travel policy&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We don't want to send all 100 pages to the AI every time someone asks a question.&lt;/p&gt;

&lt;p&gt;Instead, we divide the document into smaller pieces called &lt;strong&gt;chunks&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Travel Policy
      │
      ├── Chunk 1
      ├── Chunk 2
      ├── Chunk 3
      ├── Chunk 4
      └── ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Because when someone asks a question, we usually need only the &lt;strong&gt;small section related to that question&lt;/strong&gt;.&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Question:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
"What is the hotel reimbursement limit?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The system might retrieve:&lt;br&gt;
&lt;/p&gt;

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

"Employees can claim hotel expenses
up to ₹5,000 per night..."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's much more useful than sending the entire document to the AI.&lt;/p&gt;

&lt;h3&gt;
  
  
  💡 Think of it this way
&lt;/h3&gt;

&lt;p&gt;Imagine giving a student a 500-page textbook and asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Find the paragraph about hotel reimbursement."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It would take time to search through the entire book.&lt;/p&gt;

&lt;p&gt;Instead, if we already know the relevant page, we can go directly there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chunking helps us create those smaller searchable pieces of information.&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  🧠 Step 3: Create Embeddings
&lt;/h3&gt;

&lt;p&gt;Here's our first technical concept:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Embeddings.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Embeddings are numerical representations of text that help systems measure semantic similarity.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Embeddings help a system find information based on semantic similarity, rather than only matching exact words.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;&lt;strong&gt;User asks:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"How much can I claim for a hotel?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The document says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Hotel accommodation expenses are limited to ₹5,000 per night."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The words aren't exactly the same.&lt;/p&gt;

&lt;p&gt;But the &lt;strong&gt;meaning is related&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Embeddings help the system identify this semantic similarity.&lt;/p&gt;

&lt;p&gt;You can think of it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Text
 ↓
Embedding Model
 ↓
Numerical Vector
 ↓
Compare with other vectors
 ↓
Find semantically similar content
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You don't need to understand the mathematics behind embeddings to start learning RAG.&lt;/p&gt;

&lt;p&gt;The important thing to remember is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Embeddings help a system find information based on semantic similarity, rather than only matching exact words.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  🗂️ Step 4: Store the Information
&lt;/h3&gt;

&lt;p&gt;Now we need somewhere to store our document chunks and their embeddings.&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;vector databases and vector search systems&lt;/strong&gt; come in.&lt;/p&gt;

&lt;p&gt;Some popular options include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Azure AI Search&lt;/li&gt;
&lt;li&gt;PostgreSQL + pgvector&lt;/li&gt;
&lt;li&gt;Pinecone&lt;/li&gt;
&lt;li&gt;Qdrant&lt;/li&gt;
&lt;li&gt;Weaviate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of this as a &lt;strong&gt;smart search system for your documents&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Document Chunk
      +
Embedding
      +
Metadata
      ↓
Vector Search
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Metadata can contain information such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Document: TravelPolicy.pdf
Department: Finance
Year: 2026
DocumentType: Policy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This additional information can help the application filter and organize the data.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔎 Stage 2: Answer the User's Question
&lt;/h2&gt;

&lt;p&gt;Now our knowledge has been prepared.&lt;/p&gt;

&lt;p&gt;Let's see what happens when a user asks a question.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔎 Step 5: The User Asks a Question
&lt;/h3&gt;

&lt;p&gt;The employee asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"What is the hotel reimbursement limit?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The application converts the question into an embedding and uses it to search the knowledge base.&lt;/p&gt;

&lt;p&gt;The search might return several results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Result 1:
Employees can claim hotel expenses
up to ₹5,000 per night.

Result 2:
Business travel expenses must be
submitted within 30 days.

Result 3:
International travel requires
manager approval.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application identifies the information that is &lt;strong&gt;most relevant to the question&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  🤖 Step 6: Give the Information to the AI
&lt;/h3&gt;

&lt;p&gt;Now we have two important pieces:&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;What is the hotel reimbursement limit?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Relevant information:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Employees can claim hotel expenses up to ₹5,000 per night.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The application provides the question and retrieved context to the LLM.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Question
      +
Retrieved Context
      ↓
Prompt
      ↓
LLM
      ↓
Generated Answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The LLM can then generate:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Employees can claim hotel expenses up to ₹5,000 per night."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And that's the &lt;strong&gt;Generation&lt;/strong&gt; part of &lt;em&gt;Retrieval-Augmented Generation&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧩 The Complete RAG Flow
&lt;/h2&gt;

&lt;p&gt;Now let's separate the process into two simple flows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Preparing the knowledge
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Documents
    ↓
Chunking
    ↓
Embeddings
    ↓
Vector Search Index
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Answering a question
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Question
      ↓
Question Embedding
      ↓
Search the Knowledge Base
      ↓
Relevant Chunks
      ↓
Question + Retrieved Context
      ↓
LLM
      ↓
Final Answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the heart of a RAG application.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Retrieve relevant information → provide it as context → generate an answer.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🔍 Is RAG Just Search?
&lt;/h2&gt;

&lt;p&gt;Not exactly.&lt;/p&gt;

&lt;p&gt;Traditional search might work like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Question
   ↓
Search
   ↓
List of Documents
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You then need to open the documents and find the answer yourself.&lt;/p&gt;

&lt;p&gt;RAG goes one step further:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Question
   ↓
Search Relevant Information
   ↓
Provide Context to AI
   ↓
Generate Answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So you can think of RAG as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Search + AI&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Traditional search helps you &lt;strong&gt;find information&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A RAG application helps an AI system &lt;strong&gt;retrieve relevant information and generate an answer using that information&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🆚 RAG vs Fine-Tuning
&lt;/h2&gt;

&lt;p&gt;This is another question beginners often have:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Why not fine-tune the model instead?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;RAG and fine-tuning solve different problems.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;RAG&lt;/th&gt;
&lt;th&gt;Fine-Tuning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Retrieves external information at query time&lt;/td&gt;
&lt;td&gt;Further trains the model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Useful when knowledge changes frequently&lt;/td&gt;
&lt;td&gt;Useful for specialized behavior or tasks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Documents can be updated independently&lt;/td&gt;
&lt;td&gt;Requires a training process&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commonly used for knowledge-based applications&lt;/td&gt;
&lt;td&gt;Commonly used for specialized model behavior&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A simple way to remember it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;RAG → Give the AI relevant information.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fine-tuning → Adapt the AI for a specific behavior or task.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example, if your company's HR policy changes next month, you can update the knowledge source used by a RAG application without retraining the language model.&lt;/p&gt;




&lt;h2&gt;
  
  
  🌎 Where Can We Use RAG?
&lt;/h2&gt;

&lt;p&gt;RAG isn't limited to company policies.&lt;/p&gt;

&lt;p&gt;It can be used in many real-world applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  👨‍💻 Developer Assistant
&lt;/h3&gt;

&lt;p&gt;A developer asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"How does our authentication service work?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The RAG application searches the company's technical documentation and provides relevant context to the LLM.&lt;/p&gt;




&lt;h3&gt;
  
  
  🏢 HR Assistant
&lt;/h3&gt;

&lt;p&gt;An employee asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"How many vacation days can I carry forward?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The application searches HR policies and generates an answer based on the retrieved information.&lt;/p&gt;




&lt;h3&gt;
  
  
  🛠️ Customer Support
&lt;/h3&gt;

&lt;p&gt;A customer asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"How do I reset my device?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The application can search product documentation and provide step-by-step guidance.&lt;/p&gt;




&lt;h3&gt;
  
  
  📚 Enterprise Knowledge Assistant
&lt;/h3&gt;

&lt;p&gt;An employee asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"What is the process for raising a purchase request?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The application searches company procedures and generates a response.&lt;/p&gt;

&lt;p&gt;The common pattern is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Company Knowledge
       ↓
      RAG
       ↓
      LLM
       ↓
  AI Assistant
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ⚠️ Does RAG Make AI 100% Accurate?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;No.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is important to understand.&lt;/p&gt;

&lt;p&gt;RAG can provide the AI with relevant information, but it does &lt;strong&gt;not guarantee a perfect answer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example, if the retrieval system finds the wrong information, the LLM may generate an incorrect response based on that context.&lt;/p&gt;

&lt;p&gt;There can also be problems if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The source document contains incorrect information.&lt;/li&gt;
&lt;li&gt;Important information was not retrieved.&lt;/li&gt;
&lt;li&gt;The retrieved context is incomplete.&lt;/li&gt;
&lt;li&gt;The prompt doesn't clearly guide the model.&lt;/li&gt;
&lt;li&gt;The model misunderstands the retrieved context.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's why production RAG systems need good:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Document processing&lt;/li&gt;
&lt;li&gt;Search and retrieval&lt;/li&gt;
&lt;li&gt;Security&lt;/li&gt;
&lt;li&gt;Prompt design&lt;/li&gt;
&lt;li&gt;Evaluation&lt;/li&gt;
&lt;li&gt;Monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So don't think of RAG as a magic solution.&lt;/p&gt;

&lt;p&gt;Instead, think of it as a way to &lt;strong&gt;ground an AI application with relevant external information&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  ☁️ What Does RAG Look Like with .NET and Azure?
&lt;/h2&gt;

&lt;p&gt;If you're a .NET developer, a simple enterprise RAG architecture could look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 User
                   ↓
              .NET Web API
                   ↓
             Azure AI Search
                   ↓
             Relevant Chunks
                   ↓
             Prompt + Context
                   ↓
             Azure OpenAI
                   ↓
              AI Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your .NET application can orchestrate the process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Receive the user's question.&lt;/li&gt;
&lt;li&gt;Search for relevant information.&lt;/li&gt;
&lt;li&gt;Retrieve the relevant chunks.&lt;/li&gt;
&lt;li&gt;Build the prompt with the retrieved context.&lt;/li&gt;
&lt;li&gt;Send the request to the AI model.&lt;/li&gt;
&lt;li&gt;Return the response.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This makes RAG particularly interesting for developers working with &lt;strong&gt;.NET and Azure&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 The 5 Things You Need to Remember
&lt;/h2&gt;

&lt;p&gt;If you're completely new to RAG, remember these five concepts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Documents&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Where your knowledge lives.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Chunks&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Smaller pieces of your documents.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Embeddings&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Numerical representations that help systems measure semantic similarity.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Retrieval&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Finding information relevant to the user's question.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Generation&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The LLM uses the retrieved information to generate the answer.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Put them together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Documents
    ↓
Chunks
    ↓
Embeddings
    ↓
Search
    ↓
Relevant Context
    ↓
LLM
    ↓
Answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's &lt;strong&gt;Retrieval-Augmented Generation&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  💬 Your Turn
&lt;/h2&gt;

&lt;p&gt;Have you tried building a RAG application?&lt;/p&gt;

&lt;p&gt;What would you like to build with RAG?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;👨‍💻 Developer assistant&lt;/li&gt;
&lt;li&gt;📄 Document chatbot&lt;/li&gt;
&lt;li&gt;🏢 Enterprise knowledge assistant&lt;/li&gt;
&lt;li&gt;🛠️ Customer support assistant&lt;/li&gt;
&lt;li&gt;🤖 Something else&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Share your idea in the comments. 👇&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  📌 Key Takeaway
&lt;/h2&gt;

&lt;p&gt;If you remember just one sentence from this article, remember this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A RAG application retrieves relevant information from a knowledge source and provides it to an LLM so it can generate a more informed response.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And that's the foundation of many modern &lt;strong&gt;Generative AI applications&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>generativeai</category>
      <category>rag</category>
    </item>
    <item>
      <title>Designing a Scalable Notification System using .NET, Azure Service Bus, MediatR, and SignalR</title>
      <dc:creator>Chethan Ramaswamy</dc:creator>
      <pubDate>Tue, 31 Mar 2026 19:35:49 +0000</pubDate>
      <link>https://dev.to/chethanramaswamy/designing-a-scalable-notification-system-using-net-azure-service-bus-mediatr-and-signalr-5701</link>
      <guid>https://dev.to/chethanramaswamy/designing-a-scalable-notification-system-using-net-azure-service-bus-mediatr-and-signalr-5701</guid>
      <description>&lt;h2&gt;
  
  
  📌 What We'll Cover
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Why I'm Writing This&lt;/li&gt;
&lt;li&gt;The Problem with the "Simple" Approach&lt;/li&gt;
&lt;li&gt;A Better Approach: Event-Driven Notifications&lt;/li&gt;
&lt;li&gt;High-Level Architecture&lt;/li&gt;
&lt;li&gt;Where MediatR Fits&lt;/li&gt;
&lt;li&gt;
Why Azure Service Bus?

&lt;ul&gt;
&lt;li&gt;Loose Coupling&lt;/li&gt;
&lt;li&gt;Retry and Failure Handling&lt;/li&gt;
&lt;li&gt;Independent Scaling&lt;/li&gt;
&lt;li&gt;Future Integrations&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Topics and Subscriptions&lt;/li&gt;
&lt;li&gt;SignalR for Real-Time Notifications&lt;/li&gt;
&lt;li&gt;SignalR at Scale&lt;/li&gt;
&lt;li&gt;
End-to-End Flow

&lt;ul&gt;
&lt;li&gt;Step 1 — User Performs an Action&lt;/li&gt;
&lt;li&gt;Step 2 — API Receives the Request&lt;/li&gt;
&lt;li&gt;Step 3 — Command Handler Processes the Business Operation&lt;/li&gt;
&lt;li&gt;Step 4 — Outbox Processor Publishes the Event&lt;/li&gt;
&lt;li&gt;Step 5 — Consumers Process the Event&lt;/li&gt;
&lt;li&gt;Step 6 — Real-Time Update Reaches the Client&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;One Important Production Consideration: The Outbox Pattern&lt;/li&gt;
&lt;li&gt;Handling Duplicate Messages&lt;/li&gt;
&lt;li&gt;Trade-Offs&lt;/li&gt;
&lt;li&gt;
Where This Architecture Works Well

&lt;ul&gt;
&lt;li&gt;E-commerce&lt;/li&gt;
&lt;li&gt;Banking&lt;/li&gt;
&lt;li&gt;Monitoring Platforms&lt;/li&gt;
&lt;li&gt;Enterprise Applications&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Key Design Principles

&lt;ul&gt;
&lt;li&gt;MediatR&lt;/li&gt;
&lt;li&gt;Azure Service Bus&lt;/li&gt;
&lt;li&gt;Azure Service Bus Topics and Subscriptions&lt;/li&gt;
&lt;li&gt;SignalR&lt;/li&gt;
&lt;li&gt;Azure SignalR Service&lt;/li&gt;
&lt;li&gt;Outbox Pattern&lt;/li&gt;
&lt;li&gt;Idempotent Consumers&lt;/li&gt;
&lt;li&gt;Dead-Letter Handling&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Final Thoughts&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why I'm Writing This
&lt;/h2&gt;

&lt;p&gt;“Send a notification when something happens.”&lt;/p&gt;

&lt;p&gt;It sounds simple.&lt;/p&gt;

&lt;p&gt;But in a real application, notifications can quickly become more complicated than expected.&lt;/p&gt;

&lt;p&gt;You may need to support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Real-time UI notifications&lt;/li&gt;
&lt;li&gt;Email and SMS&lt;/li&gt;
&lt;li&gt;Multiple consumers&lt;/li&gt;
&lt;li&gt;Retries and failure handling&lt;/li&gt;
&lt;li&gt;High traffic&lt;/li&gt;
&lt;li&gt;Future integrations&lt;/li&gt;
&lt;li&gt;Loose coupling between business logic and notification processing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The challenge is not simply &lt;strong&gt;how to send a notification&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The real question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;How do we design notifications so they don't become tightly coupled to the core business flow?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This article walks through one approach using &lt;strong&gt;.NET, MediatR, Azure Service Bus, SignalR, and the Outbox Pattern&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Problem with the "Simple" Approach
&lt;/h1&gt;

&lt;p&gt;A common implementation starts with something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;API
  ↓
Save to Database
  ↓
Send Email
  ↓
Send Notification
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works.&lt;/p&gt;

&lt;p&gt;At least initially.&lt;/p&gt;

&lt;p&gt;But as the application grows, problems start appearing.&lt;/p&gt;

&lt;p&gt;Every feature begins calling notification logic directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OrderService → NotificationService
PaymentService → NotificationService
UserService → NotificationService
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then new requirements arrive:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add SMS&lt;/li&gt;
&lt;li&gt;Add push notifications&lt;/li&gt;
&lt;li&gt;Add in-app notifications&lt;/li&gt;
&lt;li&gt;Add analytics&lt;/li&gt;
&lt;li&gt;Add audit events&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The notification service gradually becomes tightly coupled to multiple parts of the application.&lt;/p&gt;

&lt;p&gt;Another problem is failure handling.&lt;/p&gt;

&lt;p&gt;What happens if the email provider is temporarily unavailable?&lt;/p&gt;

&lt;p&gt;Should the order creation fail?&lt;/p&gt;

&lt;p&gt;Usually, the answer is &lt;strong&gt;no&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The business operation and notification delivery have different reliability requirements.&lt;/p&gt;




&lt;h1&gt;
  
  
  A Better Approach: Event-Driven Notifications
&lt;/h1&gt;

&lt;p&gt;The basic idea is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Business Action
      ↓
Domain/Application Event
      ↓
Outbox
      ↓
Message Broker
      ↓
Notification Consumers
      ↓
Email / UI / SMS / Push / etc.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The business operation completes without waiting for every notification channel to finish.&lt;/p&gt;

&lt;p&gt;This creates a much cleaner boundary between:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Something happened"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;and&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"What should we do because it happened?"&lt;/strong&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  High-Level Architecture
&lt;/h1&gt;

&lt;p&gt;The production-oriented architecture looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                         ┌──────────────────┐
                         │      Client      │
                         └────────┬─────────┘
                                  │
                                  ▼
                         ┌──────────────────┐
                         │   .NET Web API   │
                         └────────┬─────────┘
                                  │
                                  ▼
                         ┌──────────────────┐
                         │     MediatR      │
                         │ Command Handler  │
                         └────────┬─────────┘
                                  │
                                  ▼
                     ┌──────────────────────────┐
                     │    Database Transaction  │
                     │                          │
                     │  ┌────────┐ ┌─────────┐ │
                     │  │ Order  │ │ Outbox  │ │
                     │  └────────┘ └─────────┘ │
                     └────────────┬─────────────┘
                                  │
                                  ▼
                         ┌──────────────────┐
                         │ Outbox Processor │
                         └────────┬─────────┘
                                  │
                                  ▼
                     ┌────────────────────────┐
                     │  Azure Service Bus     │
                     │        Topic           │
                     └────────────┬───────────┘
                                  │
                   ┌──────────────┼──────────────┐
                   │              │              │
                   ▼              ▼              ▼
             ┌──────────┐   ┌───────────┐  ┌──────────┐
             │  Email   │   │  SignalR  │  │  Audit   │
             │ Consumer │   │  Consumer │  │ Consumer │
             └──────────┘   └─────┬─────┘  └──────────┘
                                  │
                                  ▼
                     ┌────────────────────────┐
                     │ Azure SignalR Service  │
                     └────────────┬───────────┘
                                  │
                                  ▼
                           ┌─────────────┐
                           │   Clients   │
                           │Browser/Mobile│
                           └─────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important principle is that each component has a specific responsibility.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The Outbox is part of the primary architecture, not an afterthought.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h1&gt;
  
  
  Where MediatR Fits
&lt;/h1&gt;

&lt;p&gt;MediatR sits primarily inside the application layer.&lt;/p&gt;

&lt;p&gt;Instead of having a controller directly coordinate business operations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Controller
    ↓
Service
    ↓
Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we can use a request/handler model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Controller
    ↓
MediatR
    ↓
Command Handler
    ↓
Business Logic
    ↓
Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;CreateOrderCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;CustomerId&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;Amount&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IRequest&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The handler processes the command:&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;CreateOrderHandler&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IRequestHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CreateOrderCommand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;CreateOrderCommand&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Validate business rules&lt;/span&gt;
        &lt;span class="c1"&gt;// Create order&lt;/span&gt;
        &lt;span class="c1"&gt;// Save order&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;orderId&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;MediatR also provides a clean place for application-level cross-cutting concerns such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Validation&lt;/li&gt;
&lt;li&gt;Logging&lt;/li&gt;
&lt;li&gt;Performance measurement&lt;/li&gt;
&lt;li&gt;Authorization&lt;/li&gt;
&lt;li&gt;Transaction behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important point is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;MediatR is not the message broker.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It helps with &lt;strong&gt;in-process application decoupling&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Azure Service Bus handles &lt;strong&gt;distributed messaging&lt;/strong&gt; between processes or services.&lt;/p&gt;

&lt;p&gt;That distinction becomes important as the system grows.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why Azure Service Bus?
&lt;/h1&gt;

&lt;p&gt;After the business operation is committed, an event such as &lt;code&gt;OrderCreated&lt;/code&gt; needs to be delivered to downstream consumers.&lt;/p&gt;

&lt;p&gt;With the Outbox Pattern, the event is first persisted as part of the same database transaction and is then published asynchronously.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"eventType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"OrderCreated"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"orderId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12345&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"customerId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1001&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The resulting flow becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Order Service
     ↓
Outbox
     ↓
Outbox Processor
     ↓
Azure Service Bus
     ↓
Notification Consumers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Azure Service Bus provides the messaging infrastructure between the producer and consumers.&lt;/p&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Order Service
     ↓
Notification Service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Order Service
     ↓
Outbox
     ↓
Azure Service Bus
     ↓
Notification Consumers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This provides several benefits.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Loose Coupling
&lt;/h2&gt;

&lt;p&gt;The producer doesn't need to know which consumers exist.&lt;/p&gt;

&lt;p&gt;Today:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OrderCreated
    ↓
Email
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tomorrow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OrderCreated
    ↓
Email
SMS
Analytics
Audit
Push Notification
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The order-processing logic doesn't need to change simply because another consumer was added.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Retry and Failure Handling
&lt;/h2&gt;

&lt;p&gt;Azure Service Bus provides messaging and delivery mechanisms, while retry behavior is typically implemented through the Service Bus client and consumer/application logic.&lt;/p&gt;

&lt;p&gt;Transient failures can therefore be handled without making the original business transaction depend on downstream notification delivery.&lt;/p&gt;

&lt;p&gt;Messages that repeatedly fail processing can also be moved to a &lt;strong&gt;dead-letter queue&lt;/strong&gt; for investigation or later recovery.&lt;/p&gt;

&lt;p&gt;The exact retry strategy should be designed at the consumer level based on the type of failure.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Message
   ↓
Consumer
   ↓
Processing succeeds?
   ├── Yes → Complete message
   │
   └── No
       ↓
   Retry / Redelivery
       ↓
   Repeated failure?
       └── Dead-letter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Independent Scaling
&lt;/h2&gt;

&lt;p&gt;The notification consumers can scale independently from the API.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;API instances
     ↓
Outbox Processor
     ↓
Service Bus
     ↓
Notification Workers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If notification volume increases significantly, the consumer side can be scaled independently.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Future Integrations
&lt;/h2&gt;

&lt;p&gt;The same event can potentially be consumed by additional systems without modifying the original producer.&lt;/p&gt;

&lt;p&gt;This is particularly useful in larger enterprise environments.&lt;/p&gt;




&lt;h1&gt;
  
  
  Topics and Subscriptions
&lt;/h1&gt;

&lt;p&gt;For multiple consumers, an Azure Service Bus &lt;strong&gt;Topic&lt;/strong&gt; with multiple &lt;strong&gt;Subscriptions&lt;/strong&gt; is a natural fit.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                  OrderCreated Event
                         │
                         ▼
                ┌─────────────────┐
                │ Azure Service   │
                │ Bus Topic       │
                └────────┬────────┘
                         │
             ┌───────────┼───────────┐
             │           │           │
             ▼           ▼           ▼
        Email Sub    SignalR Sub   Audit Sub
             │           │           │
             ▼           ▼           ▼
          Email       SignalR       Audit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each subscription can receive its own copy of the message.&lt;/p&gt;

&lt;p&gt;This keeps consumers independent.&lt;/p&gt;

&lt;p&gt;It also means that one consumer can fail or be delayed without preventing another subscription from processing its own copy of the event.&lt;/p&gt;




&lt;h1&gt;
  
  
  SignalR for Real-Time Notifications
&lt;/h1&gt;

&lt;p&gt;For browser-based real-time notifications, polling can introduce unnecessary latency and traffic.&lt;/p&gt;

&lt;p&gt;SignalR allows the server to push messages to connected clients.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OrderCreated Event
        ↓
SignalR Consumer
        ↓
SignalR Hub
        ↓
Azure SignalR Service
        ↓
Connected Client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The client can receive something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"Order #12345 has been created successfully."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works particularly well for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dashboards&lt;/li&gt;
&lt;li&gt;Order tracking&lt;/li&gt;
&lt;li&gt;Monitoring systems&lt;/li&gt;
&lt;li&gt;Alerts&lt;/li&gt;
&lt;li&gt;Chat-like applications&lt;/li&gt;
&lt;li&gt;In-app notifications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A SignalR connection can also be associated with a user or group, allowing notifications to be targeted appropriately.&lt;/p&gt;




&lt;h1&gt;
  
  
  SignalR at Scale
&lt;/h1&gt;

&lt;p&gt;A single SignalR server is straightforward.&lt;/p&gt;

&lt;p&gt;The challenge appears when the application is deployed across multiple instances.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                       ┌──────────────────────┐
                       │   Azure SignalR      │
                       │      Service         │
                       └──────────┬───────────┘
                                  │
                    ┌─────────────┼─────────────┐
                    │             │             │
                    ▼             ▼             ▼
               API Instance   API Instance   API Instance
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Azure-hosted applications, &lt;strong&gt;Azure SignalR Service&lt;/strong&gt; can provide the scale-out layer for SignalR connections.&lt;/p&gt;

&lt;p&gt;This allows application instances to remain focused on application processing while Azure SignalR Service manages persistent client connections.&lt;/p&gt;

&lt;p&gt;The exact deployment model depends on application scale, hosting model, and operational requirements.&lt;/p&gt;




&lt;h1&gt;
  
  
  End-to-End Flow
&lt;/h1&gt;

&lt;p&gt;Let's put everything together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 — User performs an action
&lt;/h2&gt;

&lt;p&gt;The user creates an order.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client → POST /orders
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2 — API receives the request
&lt;/h2&gt;

&lt;p&gt;The controller sends a command through MediatR.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Controller
    ↓
CreateOrderCommand
    ↓
MediatR
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3 — Command handler processes the business operation
&lt;/h2&gt;

&lt;p&gt;The handler validates the request and creates the order.&lt;/p&gt;

&lt;p&gt;The order and the corresponding outbox event are persisted in the same database transaction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Database Transaction
       │
       ├── Order
       │
       └── Outbox Event
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is important because it prevents the application from successfully committing the order while completely losing the event because of a separate publish operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 — Outbox processor publishes the event
&lt;/h2&gt;

&lt;p&gt;A background process reads unpublished events from the outbox and publishes them to Azure Service Bus.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Database
   ↓
Outbox Processor
   ↓
Azure Service Bus Topic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The business transaction does not wait for the downstream consumers to finish.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5 — Consumers process the event
&lt;/h2&gt;

&lt;p&gt;Different consumers can react independently.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 OrderCreated
                      ↓
              Azure Service Bus
                 /     |      \
                /      |       \
               ▼       ▼        ▼
            Email   SignalR    Audit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6 — Real-time update reaches the client
&lt;/h2&gt;

&lt;p&gt;The SignalR consumer sends an update to the appropriate connected client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Service Bus
     ↓
SignalR Consumer
     ↓
SignalR Hub
     ↓
Azure SignalR Service
     ↓
Browser / Mobile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key principle is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Order creation should not depend on notification delivery succeeding.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h1&gt;
  
  
  One Important Production Consideration: The Outbox Pattern
&lt;/h1&gt;

&lt;p&gt;There is a subtle issue with a simpler implementation.&lt;/p&gt;

&lt;p&gt;Consider this sequence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Save Order
2. Publish OrderCreated
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happens if step 1 succeeds but step 2 fails?&lt;/p&gt;

&lt;p&gt;The order exists in the database, but the event was never published.&lt;/p&gt;

&lt;p&gt;This is a classic &lt;strong&gt;dual-write problem&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For production systems where reliable event publishing is important, an &lt;strong&gt;Outbox Pattern&lt;/strong&gt; can help.&lt;/p&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Save Order
     ↓
Publish Event
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we persist both the business data and the outgoing event in the same database transaction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Database Transaction
       │
       ├── Order
       │
       └── Outbox Event
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A background worker then reads the outbox and publishes events to Service Bus:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Database
   ↓
Outbox Processor
   ↓
Azure Service Bus
   ↓
Consumers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This separates the critical business transaction from downstream message delivery while preserving the event that needs to be published.&lt;/p&gt;




&lt;h1&gt;
  
  
  Handling Duplicate Messages
&lt;/h1&gt;

&lt;p&gt;Messaging systems should generally be designed with the assumption that a message can potentially be delivered more than once.&lt;/p&gt;

&lt;p&gt;Azure Service Bus commonly uses &lt;strong&gt;at-least-once delivery semantics&lt;/strong&gt; with Peek-Lock processing, so consumers should be designed to handle duplicate delivery safely.&lt;/p&gt;

&lt;p&gt;That means consumers should ideally be &lt;strong&gt;idempotent&lt;/strong&gt;.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Message ID: 8f23...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The consumer can maintain a record of processed message IDs.&lt;/p&gt;

&lt;p&gt;If the same message arrives again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Message
   ↓
Already processed?
   ├── Yes → Ignore / safely return
   └── No  → Process
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This becomes especially important when processing operations such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sending emails&lt;/li&gt;
&lt;li&gt;Updating notification state&lt;/li&gt;
&lt;li&gt;Creating records&lt;/li&gt;
&lt;li&gt;Calling external APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Azure Service Bus also provides &lt;strong&gt;duplicate detection&lt;/strong&gt; capabilities, but duplicate detection should not be treated as a replacement for idempotent consumer design.&lt;/p&gt;




&lt;h1&gt;
  
  
  Trade-Offs
&lt;/h1&gt;

&lt;p&gt;This architecture is not free.&lt;/p&gt;

&lt;p&gt;You are introducing additional infrastructure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Azure Service Bus&lt;/li&gt;
&lt;li&gt;Outbox storage&lt;/li&gt;
&lt;li&gt;Background consumers&lt;/li&gt;
&lt;li&gt;SignalR / Azure SignalR Service&lt;/li&gt;
&lt;li&gt;Monitoring&lt;/li&gt;
&lt;li&gt;Retry handling&lt;/li&gt;
&lt;li&gt;Dead-letter handling&lt;/li&gt;
&lt;li&gt;Distributed tracing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is also eventual consistency.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Order Created
      ↓
Outbox Event
      ↓
Event Published
      ↓
Consumer Processes Event
      ↓
Notification Appears
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The notification might appear milliseconds or seconds after the business operation.&lt;/p&gt;

&lt;p&gt;But that trade-off can be worthwhile when the system needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scalability&lt;/li&gt;
&lt;li&gt;Resilience&lt;/li&gt;
&lt;li&gt;Independent consumers&lt;/li&gt;
&lt;li&gt;Extensibility&lt;/li&gt;
&lt;li&gt;Loose coupling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The architecture should still be evaluated against the actual requirements.&lt;/p&gt;

&lt;p&gt;A small application with one notification channel may not need all of these components.&lt;/p&gt;




&lt;h1&gt;
  
  
  Where This Architecture Works Well
&lt;/h1&gt;

&lt;p&gt;This pattern can be useful in systems such as:&lt;/p&gt;

&lt;h2&gt;
  
  
  E-commerce
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OrderPlaced
    ↓
Email
Inventory
Payment
Shipping
Customer Notification
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Banking
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TransactionCompleted
    ↓
SMS
Email
Mobile Push
Audit
Fraud Monitoring
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Monitoring Platforms
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AlertRaised
    ↓
Dashboard
Email
SMS
Incident Management
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Enterprise Applications
&lt;/h2&gt;

&lt;p&gt;Any system where a business event may need to trigger multiple independent downstream actions can benefit from this approach.&lt;/p&gt;




&lt;h1&gt;
  
  
  Key Design Principles
&lt;/h1&gt;

&lt;p&gt;The technology is important, but the architectural principles matter more.&lt;/p&gt;

&lt;h3&gt;
  
  
  MediatR
&lt;/h3&gt;

&lt;p&gt;Use it for &lt;strong&gt;in-process application decoupling&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Azure Service Bus
&lt;/h3&gt;

&lt;p&gt;Use it for &lt;strong&gt;asynchronous communication between distributed components&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Azure Service Bus Topics and Subscriptions
&lt;/h3&gt;

&lt;p&gt;Use them when multiple independent consumers need to react to the same event.&lt;/p&gt;

&lt;h3&gt;
  
  
  SignalR
&lt;/h3&gt;

&lt;p&gt;Use it for &lt;strong&gt;real-time communication with connected clients&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Azure SignalR Service
&lt;/h3&gt;

&lt;p&gt;Consider it when SignalR needs to scale across multiple application instances in Azure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Outbox Pattern
&lt;/h3&gt;

&lt;p&gt;Use it when you need stronger guarantees between &lt;strong&gt;database state and event publishing&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Idempotent Consumers
&lt;/h3&gt;

&lt;p&gt;Design consumers so duplicate messages don't create unintended side effects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dead-Letter Handling
&lt;/h3&gt;

&lt;p&gt;Treat repeatedly failed messages as operational data that needs monitoring, investigation, and potentially controlled replay.&lt;/p&gt;




&lt;h1&gt;
  
  
  Final Thoughts
&lt;/h1&gt;

&lt;p&gt;Notifications are easy to implement when a system is small.&lt;/p&gt;

&lt;p&gt;They become much more interesting when the application needs to scale, support multiple channels, handle failures, and evolve over time.&lt;/p&gt;

&lt;p&gt;A useful separation is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Business Logic
      ↓
Database Transaction
      ↓
Outbox Event
      ↓
Message Broker
      ↓
Independent Consumers
      ↓
Notification Channels
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this approach, the core business operation doesn't need to know whether the notification is delivered through email, SignalR, SMS, push notifications, or a future integration.&lt;/p&gt;

&lt;p&gt;The result is an architecture that is more &lt;strong&gt;decoupled, scalable, resilient, and easier to evolve&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And perhaps the most important lesson:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Don't let notification delivery become part of your critical business transaction unless it truly needs to be.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you've implemented a similar architecture, I'd be interested in hearing how you handled retries, ordering, duplicate messages, dead-letter queues, and the outbox problem.&lt;/p&gt;




&lt;h1&gt;
  
  
  dotnet #azure #systemdesign #microservices #softwarearchitecture #azureservicebus #signalr #mediatr #eventdrivenarchitecture
&lt;/h1&gt;

</description>
      <category>systemdesign</category>
      <category>dotnet</category>
      <category>azure</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
