<?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: Abdullah D.</title>
    <description>The latest articles on DEV Community by Abdullah D. (@abdecoder).</description>
    <link>https://dev.to/abdecoder</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F546630%2F79234139-b233-49da-8580-583d43d59dc7.png</url>
      <title>DEV Community: Abdullah D.</title>
      <link>https://dev.to/abdecoder</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/abdecoder"/>
    <language>en</language>
    <item>
      <title>The Missing Link: Exposing APIs to AI Agents Without Writing Code</title>
      <dc:creator>Abdullah D.</dc:creator>
      <pubDate>Sat, 27 Dec 2025 14:25:19 +0000</pubDate>
      <link>https://dev.to/abdecoder/the-missing-link-exposing-net-apis-to-ai-agents-without-writing-code-37ii</link>
      <guid>https://dev.to/abdecoder/the-missing-link-exposing-net-apis-to-ai-agents-without-writing-code-37ii</guid>
      <description>&lt;p&gt;If you’ve started building AI agents using the &lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt;, you’ve likely hit a specific wall: &lt;strong&gt;The Boilerplate Wall.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You have a robust (.NET) back-end API with domain logic, validation, and database access all neatly organized. You even have an OpenAPI (Swagger) specification that describes exactly what the API does.&lt;/p&gt;

&lt;p&gt;Yet, to make this accessible to an LLM (like Claude or a local Llama instance), developers often find themselves manually writing "Tool Definitions"—basically re-typing the API schema into a format the AI understands.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/abdebek/MCPify" rel="noopener noreferrer"&gt;MCPify&lt;/a&gt;&lt;/strong&gt; was created to tear down that wall.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: Two Sources of Truth
&lt;/h2&gt;

&lt;p&gt;In the current ecosystem, allowing an AI to interact with a system usually requires:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Defining a Tool (Name, Description, Input Schema).&lt;/li&gt;
&lt;li&gt; Mapping that tool to a C# method.&lt;/li&gt;
&lt;li&gt; Keeping that mapping updated every time the API changes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If a query parameter is added to a controller but the MCP tool definition isn't updated, the AI starts hallucinating arguments or failing silently.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: Swagger &lt;em&gt;Is&lt;/em&gt; The Tool Definition
&lt;/h2&gt;

&lt;p&gt;Since the API already describes itself via OpenAPI/Swagger, that should be treated as the single source of truth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MCPify&lt;/strong&gt; is a library for .NET 8+ that acts as a dynamic bridge. It reads the OpenAPI specification (v2, v3, or v3.1) at runtime and projects it into the MCP Tool format automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;

&lt;p&gt;Instead of hard-coding tools, MCPify injects itself into the Dependency Injection container. It parses the Swagger JSON, resolves the schemas, and automatically hosts the required MCP endpoints (SSE/Stdio).&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started in 3 Steps
&lt;/h2&gt;

&lt;p&gt;It is designed to be "install and forget."&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Installation
&lt;/h3&gt;

&lt;p&gt;Add the package to the ASP.NET Core project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package MCPify

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Configuration
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;Program.cs&lt;/code&gt;, register the service. Provide the URL of the Swagger spec and the Base URL where the API requests should be sent.&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;MCPify.Hosting&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;AddMcpify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;swaggerUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"https://localhost:5001/swagger/v1/swagger.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;apiBaseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"https://localhost:5001"&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="c1"&gt;// Optional: Add a prefix to all tools to avoid naming collisions&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;ToolPrefix&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"myapi_"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Optional: Filter specific endpoints&lt;/span&gt;
        &lt;span class="c1"&gt;// options.Filter = op =&amp;gt; op.Route.Contains("/products");&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. Usage
&lt;/h3&gt;

&lt;p&gt;No custom MCP server implementation is required. Just map the endpoint, and MCPify handles the protocol communication (SSE/Post).&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;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Automatically creates the /sse and /messages endpoints&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;MapMcpifyEndpoint&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;Once running, connect the MCP client (like Claude Desktop) to:&lt;br&gt;
&lt;code&gt;http://localhost:&amp;lt;YOUR_PORT&amp;gt;/sse&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&amp;gt; **Note:&lt;/em&gt;* Ensure you replace &lt;code&gt;&amp;lt;YOUR_PORT&amp;gt;&lt;/code&gt; (e.g., 5000, 5005, 5132, ...) with the actual port number your application is listening on.*&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rapid Prototyping:&lt;/strong&gt; Spin up an agent that controls an entire backend in minutes, not days.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintenance Free:&lt;/strong&gt; If a field is renamed in a DTO, the AI agent knows about the change as soon as the Swagger updates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ecosystem Compatibility:&lt;/strong&gt; It handles the complex work of converting OpenAPI JSON schemas into the specific format MCP expects.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Future updates aim to add support for authentication bridging (passing user tokens through to the tools) and more granular control over operation filtering.&lt;/p&gt;

&lt;p&gt;Developers building Agentic AI with .NET are encouraged to try it out.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/abdebek/MCPify" rel="noopener noreferrer"&gt;github.com/abdebek/MCPify&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NuGet:&lt;/strong&gt; &lt;a href="https://www.nuget.org/packages/MCPify/" rel="noopener noreferrer"&gt;nuget.org/packages/MCPify&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Stop Overwrites with One Attribute: EF Core DbConcurrency Made Simple</title>
      <dc:creator>Abdullah D.</dc:creator>
      <pubDate>Wed, 17 Sep 2025 13:18:54 +0000</pubDate>
      <link>https://dev.to/abdecoder/one-attribute-to-prevent-data-loss-how-ef-cores-timestamp-saves-your-data-34cp</link>
      <guid>https://dev.to/abdecoder/one-attribute-to-prevent-data-loss-how-ef-cores-timestamp-saves-your-data-34cp</guid>
      <description>&lt;h2&gt;
  
  
  The Silent Data Loss Problem Every Multi-User App Faces
&lt;/h2&gt;

&lt;p&gt;Multi-user applications have a dangerous default behavior that many developers don't realize until it's too late. When multiple users modify the same data simultaneously, the last person to save wins, and everyone else's changes disappear without a trace.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Silent data loss.&lt;/strong&gt; No exceptions thrown, no error messages, no warnings - just data quietly vanishing.&lt;/p&gt;

&lt;p&gt;The good news? &lt;strong&gt;EF Core has a built-in solution that requires just one attribute.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: When "Last Write Wins" Becomes "Everyone Loses"
&lt;/h2&gt;

&lt;p&gt;In multi-user applications, the default behavior is deceptively dangerous. When multiple users modify the &lt;strong&gt;same entity&lt;/strong&gt; simultaneously, the last person to save wins, and everyone else's changes disappear without a trace.&lt;/p&gt;

&lt;p&gt;Here's how this common scenario unfolds:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;User A&lt;/strong&gt; loads a product (Stock: 100, Price: $25.99, Name: "Widget")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User B&lt;/strong&gt; loads the same product (Stock: 100, Price: $25.99, Name: "Widget") &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User A&lt;/strong&gt; changes the stock to 1000 (maybe bulk inventory adjustment)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User B&lt;/strong&gt; reduces stock to 75 via raw SQL (direct database update)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User A&lt;/strong&gt; saves their changes ✅&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Result&lt;/strong&gt;: User A's stock value (1000) overwrites User B's stock change (75) 💥&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The key insight&lt;/strong&gt;: Data loss occurs when both users modify the &lt;strong&gt;same field&lt;/strong&gt; concurrently. If User A only changed the name and price (leaving stock untouched), User B's stock change would survive. But when both operations touch the same field, the EF Core save overwrites the direct database change.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: This happens specifically when EF Core's SaveChanges() includes a field that was also modified by raw SQL or another concurrent operation.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hero: One Attribute to Rule Them All
&lt;/h2&gt;

&lt;p&gt;Meet the &lt;code&gt;[Timestamp]&lt;/code&gt; attribute - EF Core's built-in superhero for data integrity:&lt;br&gt;
&lt;/p&gt;

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

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Timestamp&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="n"&gt;RowVersion&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;  &lt;span class="c1"&gt;// 🦸‍♂️ Your data guardian&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. &lt;strong&gt;One attribute. Eight bytes. Zero data loss.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Magic Behind the Scenes
&lt;/h2&gt;

&lt;p&gt;When you add &lt;code&gt;[Timestamp]&lt;/code&gt; to a property, EF Core transforms from a passive bystander into an active protector:&lt;/p&gt;

&lt;h3&gt;
  
  
  Without RowVersion (The Dangerous Way):
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- User B's save overwrites everything&lt;/span&gt;
&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;Products&lt;/span&gt; 
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Original Widget'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Stock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;99&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  With RowVersion (The Safe Way):
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- EF Core includes the version in the WHERE clause&lt;/span&gt;
&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;Products&lt;/span&gt; 
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Premium Widget'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Stock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;99&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;RowVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;x00000000000007D0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If another user changed the data (updating the RowVersion), this query affects &lt;strong&gt;0 rows&lt;/strong&gt;, triggering a &lt;code&gt;DbUpdateConcurrencyException&lt;/code&gt;. No silent data loss. Ever.&lt;/p&gt;

&lt;h2&gt;
  
  
  See It In Action: The Demo That Will Change How You Think About Data
&lt;/h2&gt;

&lt;p&gt;I built a working demo that shows exactly what happens with and without concurrency control. Here's what you can test:&lt;/p&gt;

&lt;h3&gt;
  
  
  🔴 The Dangerous Scenario
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST /demo-concurrency-with-stock-change
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What happens&lt;/strong&gt;: EF Core silently overwrites concurrent changes. Data loss occurs, and nobody knows.&lt;/p&gt;

&lt;h3&gt;
  
  
  🟢 The Protected Scenario
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST /demo-with-rowversion
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What happens&lt;/strong&gt;: &lt;code&gt;DbUpdateConcurrencyException&lt;/code&gt; is thrown. The conflict is detected and must be handled explicitly.&lt;/p&gt;

&lt;h3&gt;
  
  
  🟡 The Edge Case
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST /demo-concurrency-no-stock-change
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What happens&lt;/strong&gt;: When EF Core doesn't modify a field, concurrent raw SQL changes survive. Interesting, but not reliable for production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling Conflicts Like a Pro
&lt;/h2&gt;

&lt;p&gt;When &lt;code&gt;DbUpdateConcurrencyException&lt;/code&gt; occurs, you have three battle-tested strategies:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Store Wins&lt;/strong&gt; (Reload and Show Current Data)
&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;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbUpdateConcurrencyException&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;context&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;product&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ReloadAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// Show user the current database values&lt;/span&gt;
    &lt;span class="c1"&gt;// Let them decide what to do&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. &lt;strong&gt;Client Wins&lt;/strong&gt; (Force the Update)
&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;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbUpdateConcurrencyException&lt;/span&gt; &lt;span class="n"&gt;ex&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;entry&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Entries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Single&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OriginalValues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetDatabaseValues&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;context&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="c1"&gt;// Force save&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. &lt;strong&gt;Smart Merge&lt;/strong&gt; (Best of Both Worlds)
&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;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbUpdateConcurrencyException&lt;/span&gt; &lt;span class="n"&gt;ex&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;entry&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Entries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Single&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;currentValues&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CurrentValues&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;databaseValues&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetDatabaseValues&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Example: Keep user's name/price changes, preserve database stock&lt;/span&gt;
    &lt;span class="n"&gt;currentValues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Stock"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;databaseValues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Stock"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OriginalValues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;databaseValues&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;context&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;h2&gt;
  
  
  The Business Case: Why This Matters
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Cost of Data Loss:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;E-commerce&lt;/strong&gt;: Incorrect inventory leads to overselling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Finance&lt;/strong&gt;: Transaction amounts get corrupted&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Healthcare&lt;/strong&gt;: Patient data becomes inconsistent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Any Business&lt;/strong&gt;: User trust erodes, reputation suffers&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Cost of Implementation:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Development Time&lt;/strong&gt;: 5 minutes to add the attribute&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance Impact&lt;/strong&gt;: ~1ms per operation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage Cost&lt;/strong&gt;: 8 bytes per row&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintenance&lt;/strong&gt;: Zero - it just works&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;ROI&lt;/strong&gt;: Infinite. You can't put a price on data integrity.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Developer's Concurrency Checklist
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✅ Always Use RowVersion For:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Multi-user applications&lt;/li&gt;
&lt;li&gt;Financial transactions
&lt;/li&gt;
&lt;li&gt;Inventory management&lt;/li&gt;
&lt;li&gt;Any critical business data&lt;/li&gt;
&lt;li&gt;Long-running forms&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  📋 Implementation Best Practices:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Create a Base Entity:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

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

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Timestamp&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="n"&gt;RowVersion&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Now all your entities are protected&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;Product&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BaseEntity&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&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;int&lt;/span&gt; &lt;span class="n"&gt;Stock&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;Price&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Test Concurrent Scenarios:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Fact&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;Should_Detect_Concurrent_Updates&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Load same entity in two contexts&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;product1&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;context1&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;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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;product2&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;context2&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;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="c1"&gt;// Modify both&lt;/span&gt;
    &lt;span class="n"&gt;product1&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;"Version 1"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;product2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stock&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="c1"&gt;// First save succeeds&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;context1&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="c1"&gt;// Second save should throw&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ThrowsAsync&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DbUpdateConcurrencyException&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
        &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;context2&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;h2&gt;
  
  
  The Reality Check: Performance vs. Protection
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Without RowVersion&lt;/th&gt;
&lt;th&gt;With RowVersion&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data Loss Risk&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ High&lt;/td&gt;
&lt;td&gt;✅ None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Conflict Detection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ Silent failure&lt;/td&gt;
&lt;td&gt;✅ Explicit exception&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Implementation Effort&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;1 attribute&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Performance Impact&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Baseline&lt;/td&gt;
&lt;td&gt;+8 bytes, +~1ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Peace of Mind&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ Sleepless nights&lt;/td&gt;
&lt;td&gt;✅ Sleep like a baby&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;The complete demo is available on GitHub. Clone it, run it, and see the magic happen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/abdebek/efcore-db-concurrency-demo.git
&lt;span class="nb"&gt;cd &lt;/span&gt;efcore-db-concurrency-demo
dotnet restore
dotnet run

&lt;span class="c"&gt;# Test the scenarios&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://localhost:7112/demo-with-rowversion
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;In a world where data is your most valuable asset, can you afford NOT to protect it?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The &lt;code&gt;[Timestamp]&lt;/code&gt; attribute is:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Built into EF Core&lt;/li&gt;
&lt;li&gt;✅ Automatic and reliable
&lt;/li&gt;
&lt;li&gt;✅ Zero maintenance&lt;/li&gt;
&lt;li&gt;✅ Battle-tested in production&lt;/li&gt;
&lt;li&gt;✅ The difference between data loss and data safety&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;One attribute. Zero data loss. That's the power of &lt;code&gt;[Timestamp]&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Have you experienced silent data loss in your applications? How did you solve it? Share your story in the comments below!&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🔗 Useful Resources:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/ef/core/saving/concurrency" rel="noopener noreferrer"&gt;EF Core Concurrency Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/ef/core/saving/concurrency#handling-concurrency-conflicts" rel="noopener noreferrer"&gt;Handling Concurrency Conflicts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/abdebek/efcore-db-concurrency-demo" rel="noopener noreferrer"&gt;Demo Repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;👏 Found this helpful? Give it a clap and follow for more practical development insights!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>entityframeworkcore</category>
      <category>webdev</category>
      <category>dotnet</category>
      <category>dataintegrity</category>
    </item>
    <item>
      <title>Secure Your .NET 8 APIs in Minutes with OpenIddict: A Minimalist's Guide</title>
      <dc:creator>Abdullah D.</dc:creator>
      <pubDate>Sun, 31 Aug 2025 18:01:37 +0000</pubDate>
      <link>https://dev.to/abdecoder/secure-your-net-8-apis-in-minutes-with-openiddict-a-minimalists-guide-2bog</link>
      <guid>https://dev.to/abdecoder/secure-your-net-8-apis-in-minutes-with-openiddict-a-minimalists-guide-2bog</guid>
      <description>&lt;p&gt;API security is non-negotiable, but implementing OAuth 2.0 and OpenID Connect can often feel like a monumental task, bogged down by complex configurations and boilerplate code. What if you could set up a robust, spec-compliant OIDC server for your .NET API in just a few minutes, with code that fits on a single screen?&lt;/p&gt;

&lt;p&gt;That's exactly what I set out to do. I've created a minimal, self-contained OpenIddict server that provides a rock-solid foundation for token-based authentication, and I've published the complete source code on GitHub.&lt;/p&gt;

&lt;p&gt;This guide will walk you through how it works and how you can get it running in less time than it takes to brew your morning coffee.&lt;/p&gt;

&lt;p&gt;You can find the full, ready-to-run project &lt;a href="https://github.com/abdebek/SecureOpenIddictApi" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why OpenIddict? The Power of "No Magic"
&lt;/h2&gt;

&lt;p&gt;There are many identity solutions for .NET, but OpenIddict stands out for its "no magic" philosophy. It's a low-level, highly configurable framework that gives you full control over the authentication flow. Instead of hiding the implementation behind layers of abstraction, it provides the essential building blocks, allowing you to build a server that is both powerful and transparent.&lt;/p&gt;

&lt;p&gt;This project embraces that philosophy to create an API-first server with key features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OIDC &amp;amp; OAuth 2.0 Compliant&lt;/strong&gt;: No shortcuts, just standard-based security.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Essential Flows Included&lt;/strong&gt;: Supports Password, Client Credentials, and Refresh Token grants out-of-the-box.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimal &amp;amp; Self-Contained&lt;/strong&gt;: The entire configuration is in Program.cs. No hunting through files to understand what's going on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instant Testing&lt;/strong&gt;: Comes with a pre-seeded client and admin user.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Core Configuration: Less Code, More Security
&lt;/h2&gt;

&lt;p&gt;The heart of the server is in the Program.cs file. By chaining a few configuration methods, we can set up the entire OpenID Connect server.&lt;/p&gt;

&lt;p&gt;Here's a look at the core &lt;code&gt;AddOpenIddict()&lt;/code&gt; configuration:&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;AddOpenIddict&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddCore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/*...EF Core setup...*/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddServer&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="c1"&gt;// 1. Set the endpoint URIs&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;SetTokenEndpointUris&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"connect/token"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetUserinfoEndpointUris&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"connect/userinfo"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// 2. Enable the grant types you need&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;AllowPasswordFlow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AllowRefreshTokenFlow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AllowClientCredentialsFlow&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// 3. Explicitly enable the endpoints&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;AllowUserinfoEndpoint&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AllowIntrospectionEndpoint&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AllowRevocationEndpoint&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// 4. Configure certificates and ASP.NET Core integration&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;AddDevelopmentEncryptionCertificate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddDevelopmentSigningCertificate&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;UseAspNetCore&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnableTokenEndpointPassthrough&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;AddValidation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/*...JWT validation setup...*/&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this small block of code, we've configured our endpoints, enabled specific OAuth 2.0 flows, registered scopes, and set up our development certificates. It's clean, readable, and incredibly efficient.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get it Running in Under a Minute
&lt;/h2&gt;

&lt;p&gt;Getting the server running on your machine is a simple two-step process.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Restore Dependencies&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Run the Server&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;/div&gt;



&lt;p&gt;That's it! The first time you run it, an &lt;code&gt;openiddict.db&lt;/code&gt; SQLite file is created, and the database is automatically seeded with a test client (&lt;code&gt;postman&lt;/code&gt;) and an admin user (&lt;code&gt;admin@test.com&lt;/code&gt;). No manual database setup required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Your Secure Endpoints
&lt;/h2&gt;

&lt;p&gt;To make testing easy, the project includes an &lt;code&gt;api.http&lt;/code&gt; file. If you use Visual Studio Code with the REST Client extension, you can immediately start sending requests.&lt;/p&gt;

&lt;p&gt;Here's how you would request a token using the password flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;# From api.http

POST http://localhost:5000/connect/token
Content-Type: application/x-www-form-urlencoded

grant_type=password
&amp;amp;client_id=postman
&amp;amp;client_secret=postman-secret
&amp;amp;username=admin@test.com
&amp;amp;password=AdminPassword123!
&amp;amp;scope=openid profile api
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just click "Send Request," and you'll get back a live access token and refresh token.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Your Foundation for Secure APIs
&lt;/h2&gt;

&lt;p&gt;This minimal server is the perfect starting point. It solves the immediate, and often complex, problem of setting up a secure token service. From here, you can easily extend it to support more flows, integrate it with a frontend application, or deploy it as a central authentication authority for your microservices.&lt;/p&gt;

&lt;p&gt;Building secure APIs doesn't have to be a headache. With the right tools and a clean, minimal approach, you can create a robust and transparent authentication system.&lt;/p&gt;

&lt;p&gt;Check out &lt;a href="https://github.com/abdebek/SecureOpenIddictApi" rel="noopener noreferrer"&gt;the repository&lt;/a&gt; on GitHub, clone the code, and see for yourself!&lt;/p&gt;

</description>
      <category>dotnetcore</category>
      <category>identity</category>
      <category>openiddict</category>
      <category>oauth</category>
    </item>
    <item>
      <title>Building True Micro-Frontends: Beyond iFrames with Module Federation</title>
      <dc:creator>Abdullah D.</dc:creator>
      <pubDate>Sat, 16 Aug 2025 05:56:12 +0000</pubDate>
      <link>https://dev.to/abdecoder/building-true-micro-frontends-beyond-iframes-with-module-federation-3jen</link>
      <guid>https://dev.to/abdecoder/building-true-micro-frontends-beyond-iframes-with-module-federation-3jen</guid>
      <description>&lt;h2&gt;
  
  
  The Evolution of Frontend Architecture
&lt;/h2&gt;

&lt;p&gt;In today's fast-paced development landscape, monolithic frontend applications often become bottlenecks for large teams. Enter &lt;strong&gt;micro-frontends&lt;/strong&gt; – an architectural pattern that brings the benefits of microservices to the frontend world. But not all micro-frontend implementations are created equal.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Makes a "True" Micro-Frontend?
&lt;/h2&gt;

&lt;p&gt;Many developers think micro-frontends are just multiple applications running in iframes. While this approach works, it comes with significant limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Poor User Experience&lt;/strong&gt;: Scrolling issues, navigation problems, and inconsistent styling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limited Communication&lt;/strong&gt;: Complex postMessage APIs for inter-app communication
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SEO Challenges&lt;/strong&gt;: Search engines struggle with iframe-based content&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance Issues&lt;/strong&gt;: Each iframe loads its own resources independently&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Enter Module Federation: The Game Changer
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Webpack Module Federation&lt;/strong&gt; revolutionizes how we build micro-frontends by enabling true runtime integration. Unlike iframe-based solutions, Module Federation allows applications to dynamically load and share code at runtime, creating a seamless user experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Benefits of Module Federation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;🔄 Runtime Code Sharing&lt;/strong&gt;: Applications can share dependencies like React, reducing bundle sizes and improving performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🚀 Independent Deployment&lt;/strong&gt;: Teams can deploy their micro-frontends independently without affecting others.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🛠️ Technology Diversity&lt;/strong&gt;: Different teams can use different tech stacks while maintaining integration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🎯 Seamless Integration&lt;/strong&gt;: No iframe boundaries means natural scrolling, navigation, and styling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Architecture in Action
&lt;/h2&gt;

&lt;p&gt;Let's explore a practical implementation that demonstrates these concepts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Shell App       │ │ Landing MFE     │ │ Dashboard MFE   │
│ (Port 3000)     │◄──►│ (Port 3001)     │ │ (Port 3002)     │
│                 │ │                 │ │                 │
│ • Navigation    │ │ • Marketing     │ │ • Analytics     │
│ • Routing       │ │ • Features      │ │ • Charts        │
│ • Error Bounds  │ │ • Onboarding    │ │ • Real-time     │
└─────────────────┘ └─────────────────┘ └─────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Shell Application: Your Orchestra Conductor
&lt;/h3&gt;

&lt;p&gt;The shell app acts as the main orchestrator, handling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Global Navigation&lt;/strong&gt;: Consistent header and routing across micro-frontends&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Boundaries&lt;/strong&gt;: Graceful failure handling when micro-frontends fail to load&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication&lt;/strong&gt;: Shared user state across all applications&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Theme Management&lt;/strong&gt;: Consistent styling and branding&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Micro-Frontend Components: Independent Yet Connected
&lt;/h3&gt;

&lt;p&gt;Each micro-frontend operates independently but integrates seamlessly:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Landing Micro-Frontend&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Marketing content and feature highlights&lt;/li&gt;
&lt;li&gt;User onboarding flows&lt;/li&gt;
&lt;li&gt;Standalone operation for marketing campaigns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Dashboard Micro-Frontend&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Real-time analytics and data visualization&lt;/li&gt;
&lt;li&gt;Interactive charts and reports&lt;/li&gt;
&lt;li&gt;Independent development and testing cycles&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuration Made Simple
&lt;/h2&gt;

&lt;p&gt;Setting up Module Federation with Vite is surprisingly straightforward:&lt;/p&gt;

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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// vite.config.ts (Shell App)&lt;/span&gt;
&lt;span class="nf"&gt;federation&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;shell&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;remotes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;landing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3001/assets/remoteEntry.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;dashboard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3002/assets/remoteEntry.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Micro-Frontend Configuration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// vite.config.ts (Landing MFE)&lt;/span&gt;
&lt;span class="nf"&gt;federation&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;landing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;remoteEntry.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;exposes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Development Experience That Doesn't Compromise
&lt;/h2&gt;

&lt;p&gt;One of Module Federation's strongest advantages is maintaining an excellent developer experience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hot Reloading&lt;/strong&gt;: Works seamlessly across all micro-frontends&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging&lt;/strong&gt;: Standard browser dev tools work without iframe complications&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TypeScript Support&lt;/strong&gt;: Full type safety across micro-frontend boundaries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Independent Development&lt;/strong&gt;: Teams can work in isolation while testing integration&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Production-Ready Architecture
&lt;/h2&gt;

&lt;p&gt;This isn't just a proof-of-concept – companies like Spotify, ByteDance, and Microsoft use Module Federation in production. The architecture provides:&lt;/p&gt;

&lt;h3&gt;
  
  
  Scalability Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Team Autonomy&lt;/strong&gt;: Different teams can own different parts of the application&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Technology Flexibility&lt;/strong&gt;: Mix React, Vue, Angular, or vanilla JavaScript as needed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment Independence&lt;/strong&gt;: Deploy updates without coordinating with other teams&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failure Isolation&lt;/strong&gt;: One micro-frontend's issues don't crash the entire application&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Performance Optimizations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Shared Dependencies&lt;/strong&gt;: React loaded once, used everywhere&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lazy Loading&lt;/strong&gt;: Micro-frontends load on-demand&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Caching Strategies&lt;/strong&gt;: Individual micro-frontends can be cached independently&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bundle Optimization&lt;/strong&gt;: Only load what's needed when it's needed&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to Choose Module Federation
&lt;/h2&gt;

&lt;p&gt;This architecture shines in several scenarios:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Large Organizations&lt;/strong&gt;: Multiple teams working on different features need coordination without tight coupling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Legacy Migration&lt;/strong&gt;: Gradually modernize monolithic applications by extracting features into micro-frontends.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-Brand Products&lt;/strong&gt;: Different user interfaces sharing common functionality and backend services.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rapid Scaling&lt;/strong&gt;: Independent development and deployment cycles accelerate feature delivery.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started: A Practical Roadmap
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Phase 1: Foundation
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Set up your shell application with basic routing&lt;/li&gt;
&lt;li&gt;Create your first micro-frontend with a simple component&lt;/li&gt;
&lt;li&gt;Configure Module Federation between them&lt;/li&gt;
&lt;li&gt;Implement error boundaries for graceful failures&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Phase 2: Enhancement
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Add shared state management across micro-frontends&lt;/li&gt;
&lt;li&gt;Implement authentication and authorization patterns&lt;/li&gt;
&lt;li&gt;Set up consistent styling and theming&lt;/li&gt;
&lt;li&gt;Add comprehensive error handling and monitoring&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Phase 3: Production
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Configure CI/CD pipelines for independent deployment&lt;/li&gt;
&lt;li&gt;Set up monitoring and performance tracking&lt;/li&gt;
&lt;li&gt;Implement E2E testing strategies&lt;/li&gt;
&lt;li&gt;Document integration patterns for your team&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Technology Stack
&lt;/h2&gt;

&lt;p&gt;A modern implementation typically includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;React 18&lt;/strong&gt; with TypeScript for type safety&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vite&lt;/strong&gt; with Module Federation plugin for fast builds&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailwind CSS&lt;/strong&gt; for consistent, utility-first styling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React Router&lt;/strong&gt; for seamless navigation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Boundaries&lt;/strong&gt; for graceful failure handling&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Beyond the Basics: Advanced Patterns
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Shared Component Libraries
&lt;/h3&gt;

&lt;p&gt;Create a design system that all micro-frontends can consume, ensuring visual consistency while maintaining independence.&lt;/p&gt;

&lt;h3&gt;
  
  
  Event-Driven Communication
&lt;/h3&gt;

&lt;p&gt;Implement pub/sub patterns for loose coupling between micro-frontends, allowing them to communicate without direct dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Progressive Loading
&lt;/h3&gt;

&lt;p&gt;Load micro-frontends progressively based on user interaction, optimizing initial page load times.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: The Future is Modular
&lt;/h2&gt;

&lt;p&gt;Module Federation represents a significant leap forward in frontend architecture. It provides the benefits of micro-frontends – team autonomy, independent deployment, technology diversity – without the drawbacks of iframe-based solutions.&lt;/p&gt;

&lt;p&gt;As applications grow in complexity and teams scale, the ability to develop, deploy, and maintain features independently becomes crucial. Module Federation makes this possible while maintaining the seamless user experience that modern web applications demand.&lt;/p&gt;

&lt;p&gt;The architecture isn't just about technology; it's about enabling teams to work efficiently at scale. By embracing true micro-frontend patterns, organizations can accelerate development, improve maintainability, and create better experiences for both developers and users.&lt;/p&gt;

&lt;p&gt;Ready to explore this architecture hands-on? Check out the &lt;a href="https://github.com/abdebek/slidev-micro-frontend" rel="noopener noreferrer"&gt;complete implementation&lt;/a&gt; that demonstrates these concepts in a production-ready setup. The future of frontend development is modular, independent, and surprisingly elegant.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Want to dive deeper into micro-frontend architecture? The implementation referenced in this article provides a complete, runnable example with TypeScript, modern tooling, and production-ready patterns you can use as a foundation for your own projects.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>microfrontend</category>
      <category>react</category>
      <category>slidev</category>
    </item>
    <item>
      <title>Is Your Code Easy to Read and Maintain? A Deep Dive into Cyclomatic Complexity</title>
      <dc:creator>Abdullah D.</dc:creator>
      <pubDate>Thu, 24 Jul 2025 07:26:18 +0000</pubDate>
      <link>https://dev.to/abdecoder/the-nightmare-of-maintaining-complex-code-444d</link>
      <guid>https://dev.to/abdecoder/the-nightmare-of-maintaining-complex-code-444d</guid>
      <description>&lt;h2&gt;
  
  
  Ever stared down a function with a &lt;strong&gt;Cyclomatic Complexity (CC)&lt;/strong&gt; score over &lt;strong&gt;50&lt;/strong&gt;? You're not alone. That metric isn't just an abstract number; it's a flashing warning sign for a sprawling, untestable, and bug-ridden monster lurking in your codebase.
&lt;/h2&gt;

&lt;h2&gt;
  
  
  What Is Cyclomatic Complexity (CC)?
&lt;/h2&gt;

&lt;p&gt;At its core, &lt;strong&gt;Cyclomatic Complexity&lt;/strong&gt; is a software metric that quantifies the structural complexity of a program.&lt;/p&gt;

&lt;p&gt;Think of your code as a map: CC tells you the number of &lt;strong&gt;independent paths&lt;/strong&gt; (or unique routes) a user's execution could take from start to finish. Essentially, it measures how many different decisions your code makes. The more decisions, the higher the complexity, and the harder the code is to understand and test.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Complexity Scorecard
&lt;/h3&gt;

&lt;p&gt;These are the generally accepted guidelines for interpreting a CC score:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;CC Range&lt;/th&gt;
&lt;th&gt;Interpretation&lt;/th&gt;
&lt;th&gt;Impact &amp;amp; Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1–10&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Excellent&lt;/strong&gt; 🟢&lt;/td&gt;
&lt;td&gt;Simple, clear, and highly testable. Keep it this way!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;11–20&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Moderate&lt;/strong&gt; 🟡&lt;/td&gt;
&lt;td&gt;Manageable, but start being mindful. Consider minor refactoring.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;21–50&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;High&lt;/strong&gt; 🟠&lt;/td&gt;
&lt;td&gt;Difficult to read, test, and maintain. &lt;strong&gt;Needs immediate refactoring&lt;/strong&gt; to break it into smaller functions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&amp;gt; 50&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Danger Zone&lt;/strong&gt; 🔴&lt;/td&gt;
&lt;td&gt;A clear sign of deeply entangled, spaghetti logic. This is an &lt;strong&gt;urgent refactoring priority&lt;/strong&gt; before new bugs appear.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  What Makes CC Skyrocket?
&lt;/h2&gt;

&lt;p&gt;CC increases every time your code introduces a new point of decision or control flow.&lt;/p&gt;

&lt;p&gt;The following structures are the primary contributors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Conditional Statements:&lt;/strong&gt; Each &lt;code&gt;if&lt;/code&gt;/&lt;code&gt;else&lt;/code&gt; branch adds a path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loops:&lt;/strong&gt; &lt;code&gt;for&lt;/code&gt;, &lt;code&gt;while&lt;/code&gt;, and &lt;code&gt;do-while&lt;/code&gt; constructs introduce branching.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Case Statements:&lt;/strong&gt; Every &lt;code&gt;case&lt;/code&gt; within a &lt;code&gt;switch&lt;/code&gt; block is a separate path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logical Operators:&lt;/strong&gt; Using logical &lt;strong&gt;AND&lt;/strong&gt; (&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;) and &lt;strong&gt;OR&lt;/strong&gt; (&lt;code&gt;||&lt;/code&gt;) within a condition effectively adds to the complexity count because they represent multiple conditions that must be checked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ternary Operators:&lt;/strong&gt; The compact &lt;code&gt;? :&lt;/code&gt; operator still adds a decision path.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The True Cost of High Complexity 📉
&lt;/h2&gt;

&lt;p&gt;Why should you, as a developer or a team lead, obsess over this number? Because high complexity directly impacts your team's productivity and sanity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Debugging Hell:&lt;/strong&gt; More paths mean an exponential increase in places for bugs to hide. Tracing execution through tangled logic can turn a 10-minute fix into an all-day ordeal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing Nightmare:&lt;/strong&gt; Achieving full &lt;strong&gt;code coverage&lt;/strong&gt; becomes nearly impossible. You'd need to write an unmanageable number of unit tests just to cover every possible flow, and even then, subtle interactions can be missed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintenance Dread:&lt;/strong&gt; Understanding and safely modifying the code becomes a &lt;strong&gt;Herculean task&lt;/strong&gt;. Developers are hesitant to touch complex modules, leading to &lt;strong&gt;technical debt&lt;/strong&gt; and slower feature development.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Your First Line of Defense: Static Analysis Tools 🛡️
&lt;/h2&gt;

&lt;p&gt;The best way to fight complexity is to catch it early. Don't wait until you're debugging a CC &amp;gt; 50 function at 2 AM.&lt;/p&gt;

&lt;p&gt;Modern &lt;strong&gt;static analysis tools&lt;/strong&gt; are game-changers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Automated Flagging:&lt;/strong&gt; Tools like &lt;strong&gt;CodeMetrics&lt;/strong&gt; (available as extensions for VS Code, Visual Studio, IntelliJ, etc.) proactively calculate CC as you code.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Early Intervention:&lt;/strong&gt; They immediately flag complex code, enabling you to &lt;strong&gt;refactor &lt;em&gt;before&lt;/em&gt; it spirals out of control&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Team Standards:&lt;/strong&gt; They help enforce a consistent complexity limit across your entire team.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Pro Tip:&lt;/strong&gt; Set a firm, automated rule on your CI/CD pipeline to &lt;strong&gt;fail a build&lt;/strong&gt; if the CC of any new or modified function exceeds a threshold, like &lt;strong&gt;20&lt;/strong&gt;. This forces quality up-front.&lt;/p&gt;




&lt;p&gt;Don't let complexity turn your codebase into a nightmare. Embrace static analysis tools, prioritize breaking large functions into smaller, single-responsibility units, and make refactoring for lower complexity a core part of your development process! &lt;strong&gt;Cleaner code is faster code.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>codequality</category>
      <category>refactoring</category>
      <category>coding</category>
      <category>softwareengineering</category>
    </item>
  </channel>
</rss>
