<?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: Pouria Ghadiri</title>
    <description>The latest articles on DEV Community by Pouria Ghadiri (@pouria_ghadiri).</description>
    <link>https://dev.to/pouria_ghadiri</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%2F3174277%2F31e7f2d9-2a74-472f-a8ed-af894fbe2e66.jpg</url>
      <title>DEV Community: Pouria Ghadiri</title>
      <link>https://dev.to/pouria_ghadiri</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pouria_ghadiri"/>
    <language>en</language>
    <item>
      <title>Onion Architecture in .NET Core: Keeping Your Core Clean (Part 3)</title>
      <dc:creator>Pouria Ghadiri</dc:creator>
      <pubDate>Thu, 05 Jun 2025 18:08:25 +0000</pubDate>
      <link>https://dev.to/pouria_ghadiri/onion-architecture-in-net-core-keeping-your-core-clean-part-3-5997</link>
      <guid>https://dev.to/pouria_ghadiri/onion-architecture-in-net-core-keeping-your-core-clean-part-3-5997</guid>
      <description>&lt;p&gt;Onion Architecture in .NET Core: Keeping Your Core Clean (Part 3)&lt;/p&gt;

&lt;p&gt;Alright, here we go—part three! If you’ve been following along, you already know &lt;a href="https://dev.to/pouria_ghadiri/why-software-architecture-matters-in-real-net-projects-part-1-nal"&gt;why good architecture matters&lt;/a&gt; and &lt;a href="https://dev.to/pouria_ghadiri/layered-architecture-in-aspnet-core-simple-structured-and-still-relevant-part-2-31m3"&gt;how the old-school layered thing works&lt;/a&gt;. Now let’s talk about Onion Architecture. This one’s a game-changer if you’re sick of spaghetti code or business logic that’s tangled with database weirdness.&lt;/p&gt;

&lt;h3&gt;
  
  
  So, What’s Onion Architecture Anyway?
&lt;/h3&gt;

&lt;p&gt;Picture this: your app is an onion (cue the Shrek jokes). The juicy stuff—your domain, the business rules—sits in the middle. Everything else? Just layers wrapping around, like armor. The golden rule: dependencies only point inwards. That means your core logic couldn’t care less about which database you use, what the UI looks like, or what random third-party library you’ve glued on.&lt;/p&gt;

&lt;p&gt;Why bother? Clean core. If you want to swap out your database, you can. If the latest JavaScript framework drops and everyone loses their minds, your business rules don’t flinch. No more pollution from infrastructure code sneaking into your logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Use It?
&lt;/h3&gt;

&lt;p&gt;Because it keeps your business logic clean and untouched by infrastructure chaos. If you’re switching from SQL Server to PostgreSQL, no problem. Building a new UI? Go for it. The core remains the same.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Principles of Onion Architecture
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The domain (business logic) sits at the center.&lt;/li&gt;
&lt;li&gt;Each layer wraps around the one inside it.&lt;/li&gt;
&lt;li&gt;Outer layers depend on inner ones—not the other way.&lt;/li&gt;
&lt;li&gt;Infrastructure is plugged in via interfaces.&lt;/li&gt;
&lt;li&gt;Code stays clean, testable, and easy to reason about.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How the Layers Stack Up
&lt;/h3&gt;

&lt;p&gt;Here’s a quick look at the architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Center:&lt;/strong&gt; Domain Layer (Entities, Interfaces, Business Rules)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Next Layer:&lt;/strong&gt; Application Layer (Use Cases, Services)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outer Layer:&lt;/strong&gt; Infrastructure Layer (Database, Email, Logging)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outermost:&lt;/strong&gt; Web/API/UI Layer (Controllers, Views, Pages)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each layer only talks to the one just inside it. That’s the key.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Simple .NET Project Structure
&lt;/h3&gt;

&lt;p&gt;Your folders might 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;/MyApp
  /Domain
    Order.cs
    IOrderRepository.cs
  /Application
    OrderService.cs
    IOrderService.cs
  /Infrastructure
    OrderRepository.cs
    EmailSender.cs
  /WebAPI
    OrdersController.cs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Straightforward and clean.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick Code Peek
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Domain Layer&lt;/strong&gt;&lt;br&gt;
Defines your Order entity and a repository interface—no database stuff here.&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;Order&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;Total&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&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="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;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;p&gt;&lt;strong&gt;Application Layer&lt;/strong&gt;&lt;br&gt;
Handles business use cases—like creating an order—but stays blissfully ignorant about where that order gets saved.&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;IOrderService&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;Guid&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;CreateAsync&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;total&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;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="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;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="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;CreateAsync&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;total&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;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;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewGuid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;Total&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="n"&gt;CreatedAt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&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="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;Infrastructure Layer&lt;/strong&gt;&lt;br&gt;
This is where you actually touch the database. It implements those interfaces from the Domain layer.&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;OrderRepository&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;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;_context&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;OrderRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_context&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&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;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;span class="n"&gt;_context&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;_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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Web/API Layer&lt;/strong&gt;&lt;br&gt;
Takes HTTP requests, calls your service, returns IDs. No business logic hiding in here.&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;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"api/[controller]"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrdersController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IOrderService&lt;/span&gt; &lt;span class="n"&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="nf"&gt;OrdersController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IOrderService&lt;/span&gt; &lt;span class="n"&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;_orderService&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;orderService&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;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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&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;decimal&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="kt"&gt;var&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;await&lt;/span&gt; &lt;span class="n"&gt;_orderService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateAsync&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&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;
  
  
  Onion vs Layered Architecture
&lt;/h3&gt;

&lt;p&gt;Here’s a quick comparison:&lt;/p&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;Layered Architecture&lt;/th&gt;
&lt;th&gt;Onion Architecture&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Dependency Direction&lt;/td&gt;
&lt;td&gt;Top-down&lt;/td&gt;
&lt;td&gt;Inward only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Domain Focus&lt;/td&gt;
&lt;td&gt;Not enforced&lt;/td&gt;
&lt;td&gt;Core of everything&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Testability&lt;/td&gt;
&lt;td&gt;Average&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Infra Isolation&lt;/td&gt;
&lt;td&gt;Weak&lt;/td&gt;
&lt;td&gt;Strong&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code Reuse&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  When Should You Use It?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;If your app has more logic than just CRUD.&lt;/li&gt;
&lt;li&gt;If you care about testability and clean architecture.&lt;/li&gt;
&lt;li&gt;If you're building APIs or microservices.&lt;/li&gt;
&lt;li&gt;If you want to avoid vendor lock-in (like a specific DB).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Migrating from Layered to Onion
&lt;/h3&gt;

&lt;p&gt;Already have a layered structure? Here’s how to begin:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Move your business logic into a Domain project.&lt;/li&gt;
&lt;li&gt;Use interfaces to abstract data and external services.&lt;/li&gt;
&lt;li&gt;Use dependency injection to wire it all up.&lt;/li&gt;
&lt;li&gt;Refactor slowly, step-by-step.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;Onion Architecture is like giving your business logic its own safe room. Everything else works around it, but can’t mess with it. If you’re tired of fragile, messy code, this approach might just be what you need.&lt;/p&gt;

&lt;p&gt;Next up in our series: &lt;strong&gt;Clean Architecture&lt;/strong&gt;. Stay tuned!&lt;br&gt;
Have questions or use this in production? Let’s discuss in the comments!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>architecture</category>
      <category>discuss</category>
      <category>learning</category>
    </item>
    <item>
      <title>Layered Architecture in ASP.NET Core: Simple, Structured, and Still Relevant (Part 2)</title>
      <dc:creator>Pouria Ghadiri</dc:creator>
      <pubDate>Thu, 22 May 2025 19:00:26 +0000</pubDate>
      <link>https://dev.to/pouria_ghadiri/layered-architecture-in-aspnet-core-simple-structured-and-still-relevant-part-2-31m3</link>
      <guid>https://dev.to/pouria_ghadiri/layered-architecture-in-aspnet-core-simple-structured-and-still-relevant-part-2-31m3</guid>
      <description>&lt;p&gt;In the &lt;a href="https://dev.to/pouria_ghadiri/why-software-architecture-matters-in-real-net-projects-part-1-nal"&gt;first &lt;/a&gt;part of this series, we explored why software architecture matters—especially in .NET projects that grow beyond simple CRUD applications.&lt;/p&gt;

&lt;p&gt;Today, we’re starting with one of the most familiar patterns: Layered Architecture. It’s often the first structured approach developers learn—and with good reason. It brings clarity and separation of concerns without much overhead.&lt;/p&gt;

&lt;p&gt;Let’s break it down.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Layered Architecture?
&lt;/h2&gt;

&lt;p&gt;Layered Architecture, also known as n-tier architecture, separates your application into logical layers where each layer has a specific responsibility.&lt;/p&gt;

&lt;p&gt;A typical ASP.NET Core project using this pattern includes:&lt;/p&gt;

&lt;p&gt;Presentation Layer (e.g., Controllers, Razor Pages, APIs)&lt;/p&gt;

&lt;p&gt;Application Layer (e.g., Services, Business Logic)&lt;/p&gt;

&lt;p&gt;Data Access Layer (e.g., Repositories, EF Core)&lt;/p&gt;

&lt;p&gt;Domain Layer (optional, for core models and logic)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+-----------------------+
|   Presentation Layer  |
|  (Controllers / API)  |
+-----------------------+
           ↓
+-----------------------+
|   Application Layer   |
| (Services / Use Cases)|
+-----------------------+
           ↓
+-----------------------+
|   Data Access Layer   |
|   (EF Core / DB Code) |
+-----------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each layer only talks to the layer directly below it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use Layered Architecture?
&lt;/h2&gt;

&lt;p&gt;✅ Separation of concerns&lt;br&gt;
✅ Improves maintainability&lt;br&gt;
✅ Simplifies testing (especially service logic)&lt;br&gt;
✅ Well-supported in tutorials, teams, and tooling&lt;/p&gt;

&lt;p&gt;It helps you avoid the "God Controller" or "fat service" problems by pushing logic to the right place.&lt;/p&gt;
&lt;h2&gt;
  
  
  Common Mistakes
&lt;/h2&gt;

&lt;p&gt;Despite its simplicity, developers often misuse this pattern:&lt;/p&gt;

&lt;p&gt;❌ Skipping the application layer, putting logic in controllers&lt;/p&gt;

&lt;p&gt;❌ Services that just forward calls to the database&lt;/p&gt;

&lt;p&gt;❌ Tight coupling between layers&lt;/p&gt;

&lt;p&gt;❌ Ignoring validation and business rules&lt;/p&gt;
&lt;h2&gt;
  
  
  🛠️ A Simple Example in ASP.NET Core
&lt;/h2&gt;

&lt;p&gt;Let’s say we’re building a basic order system.&lt;/p&gt;

&lt;p&gt;1 Domain Models&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Order
{
    public Guid Id { get; set; }
    public DateTime CreatedAt { get; set; }
    public decimal TotalAmount { get; set; }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2 Application Layer&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; public interface IOrderService
{
    Task&amp;lt;Guid&amp;gt; CreateOrderAsync(OrderDto dto);
}
&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;public class OrderService : IOrderService
{
    private readonly IOrderRepository _repository;

    public OrderService(IOrderRepository repository)
    {
        _repository = repository;
    }

    public async Task&amp;lt;Guid&amp;gt; CreateOrderAsync(OrderDto dto)
    {
        var order = new Order
        {
            Id = Guid.NewGuid(),
            CreatedAt = DateTime.UtcNow,
            TotalAmount = dto.Total
        };

        await _repository.AddAsync(order);
        return order.Id;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3 Data Access Layer&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public interface IOrderRepository
{
    Task AddAsync(Order order);
}
&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;public class OrderRepository : IOrderRepository
{
    private readonly AppDbContext _context;

    public OrderRepository(AppDbContext context)
    {
        _context = context;
    }

    public async Task AddAsync(Order order)
    {
        _context.Orders.Add(order);
        await _context.SaveChangesAsync();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4 Presentation Layer (Controller)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
    private readonly IOrderService _orderService;

    public OrdersController(IOrderService orderService)
    {
        _orderService = orderService;
    }

    [HttpPost]
    public async Task&amp;lt;IActionResult&amp;gt; CreateOrder([FromBody] OrderDto dto)
    {
        var id = await _orderService.CreateOrderAsync(dto);
        return Ok(id);
    }
}

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

&lt;/div&gt;



&lt;p&gt;Folder Structure&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/MyApp
  /Controllers
    OrdersController.cs
  /Services
    IOrderService.cs
    OrderService.cs
  /Repositories
    IOrderRepository.cs
    OrderRepository.cs
  /Models
    Order.cs
    OrderDto.cs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Is Layered Architecture Still Relevant?
&lt;/h2&gt;

&lt;p&gt;Yes—but with nuance.&lt;/p&gt;

&lt;p&gt;For small to medium apps, it works great. For complex domains or large teams, it may need enhancements like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;CQRS&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;MediatR&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Onion/Clean Architecture&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key is understanding when it’s enough—and when you need to evolve.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use This Pattern
&lt;/h2&gt;

&lt;p&gt;✅ MVPs or startup products&lt;br&gt;
✅ Internal tools&lt;br&gt;
✅ Projects where complexity is moderate&lt;br&gt;
✅ Teams new to architecture patterns&lt;/p&gt;

&lt;h2&gt;
  
  
  Up Next
&lt;/h2&gt;

&lt;p&gt;In Part 3, we’ll level up to Onion Architecture—a more flexible structure where dependencies flow inward, not outward.&lt;/p&gt;

&lt;p&gt;If Layered Architecture is your first step into designing clean code, Onion Architecture is the next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-Up
&lt;/h2&gt;

&lt;p&gt;Layered Architecture is often underestimated, but when done right, it's clean, simple, and effective. It gives your team a structure without overengineering.&lt;/p&gt;

&lt;p&gt;Thanks for following along!&lt;/p&gt;

&lt;p&gt;Like, comment, or follow for &lt;a href="https://dev.to/pouria_ghadiri/onion-architecture-in-net-core-keeping-your-core-clean-part-3-5997"&gt;Part 3&lt;/a&gt; coming soon.&lt;br&gt;
 Have questions or use this in production? Let’s discuss in the comments!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>discuss</category>
      <category>learning</category>
    </item>
    <item>
      <title>How I Struggled (and Finally Succeeded) Configuring Redis on Oracle Linux</title>
      <dc:creator>Pouria Ghadiri</dc:creator>
      <pubDate>Mon, 19 May 2025 18:18:01 +0000</pubDate>
      <link>https://dev.to/pouria_ghadiri/how-i-struggled-and-finally-succeeded-configuring-redis-on-oracle-linux-2iib</link>
      <guid>https://dev.to/pouria_ghadiri/how-i-struggled-and-finally-succeeded-configuring-redis-on-oracle-linux-2iib</guid>
      <description>&lt;p&gt;Spoiler: It took me 1.5 days to do what could’ve been done in an hour—but that’s how you learn!&lt;/p&gt;

&lt;h3&gt;
  
  
  The Setup
&lt;/h3&gt;

&lt;p&gt;I had two servers:&lt;/p&gt;

&lt;p&gt;🖥️ A Linux server (Oracle Linux) where Redis was installed&lt;/p&gt;

&lt;p&gt;💻 A Windows server running an application that needed to connect to Redis on port 6379&lt;/p&gt;

&lt;p&gt;I thought: "Just install Redis, open port 6379, and boom—it works!"&lt;br&gt;
But no, it wasn't that simple.&lt;/p&gt;

&lt;p&gt;First Mistake: Trusting the Defaults&lt;br&gt;
I installed Redis using &lt;code&gt;dnf&lt;/code&gt;, which was easy enough. The real challenge started when I tried to connect from the Windows server. The connection kept failing—despite Redis running fine locally on the Linux machine.&lt;/p&gt;

&lt;p&gt;I dove into the &lt;code&gt;redis.conf&lt;/code&gt; file (the default config file created during installation), and here’s what I had to change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bind 0.0.0.0
protected-mode no
These two lines are critical:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;bind 0.0.0.0&lt;/code&gt;: Allows connections from any IP, not just localhost.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;protected-mode no&lt;/code&gt;: Disables Redis’s "safe mode" that blocks external access.&lt;/p&gt;

&lt;p&gt;After applying these changes and running &lt;code&gt;redis-server redis.conf&lt;/code&gt;, I connected successfully from the Linux host using &lt;code&gt;redis-cli&lt;/code&gt;. All seemed fine.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Real Error: DENIED by Protected Mode
&lt;/h3&gt;

&lt;p&gt;However, from the Windows server, I still couldn’t connect. A telnet to port &lt;code&gt;6379&lt;/code&gt;returned this error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DENIED Redis is running in protected mode...

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

&lt;/div&gt;



&lt;p&gt;Even though I had disabled protected-mode, Redis still refused the connection.&lt;/p&gt;

&lt;p&gt;The missing piece? Authentication.&lt;/p&gt;

&lt;p&gt;Fixing It with Docker and a Custom &lt;code&gt;redis.conf&lt;/code&gt;&lt;br&gt;
To get more control and test things cleanly, I ran Redis using Docker and created a custom &lt;code&gt;redis.conf&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bind 0.0.0.0
port 6379
daemonize yes
protected-mode no
requirepass MyStrongPassword
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ That last line—&lt;code&gt;requirepass&lt;/code&gt;—was the real key.&lt;/p&gt;

&lt;p&gt;Once Redis had a password, everything worked. My application connected successfully from the Windows server.&lt;/p&gt;

&lt;p&gt;So here’s a quick checklist for allowing remote connections to Redis:&lt;/p&gt;

&lt;p&gt;✅ Edit &lt;code&gt;redis.conf&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;bind 0.0.0.0&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
&lt;code&gt;protected-mode no&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
&lt;code&gt;requirepass your_secure_password&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
✅ Make sure port &lt;code&gt;6379&lt;/code&gt;is open in the firewall&lt;/p&gt;

&lt;p&gt;✅ Restart Redis with the custom config&lt;/p&gt;

&lt;p&gt;✅ Test with &lt;code&gt;redis-cli -a your_password -h your_redis_host&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;What took me 1.5 days could’ve been an hour’s work—but hey, now I really understand Redis’s security model.&lt;/p&gt;

&lt;p&gt;If you're setting up Redis for the first time and wondering why remote clients can't connect—check the config. Don't assume it’s the firewall or Docker networking. It's often just a missing requirepass.&lt;/p&gt;

&lt;h4&gt;
  
  
  Got Tips?
&lt;/h4&gt;

&lt;p&gt;If you have more experience configuring Redis in production or have best practices to share, I’d love to hear from you. This was my first time doing it, and I’m sure there’s room to improve!&lt;/p&gt;

</description>
      <category>redis</category>
      <category>linux</category>
      <category>docker</category>
      <category>beginners</category>
    </item>
    <item>
      <title>I've just started a new article series on software architecture in .NET! My goal is to explain how it works and, more importantly, why it matters. If you're new to concepts like Clean Architecture, DDD, or Onion Architecture—this series is made for you.</title>
      <dc:creator>Pouria Ghadiri</dc:creator>
      <pubDate>Sun, 18 May 2025 17:52:42 +0000</pubDate>
      <link>https://dev.to/pouria_ghadiri/ive-just-started-a-new-article-series-on-software-architecture-in-net-my-goal-is-to-explain-how-3f2f</link>
      <guid>https://dev.to/pouria_ghadiri/ive-just-started-a-new-article-series-on-software-architecture-in-net-my-goal-is-to-explain-how-3f2f</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/pouria_ghadiri/why-software-architecture-matters-in-real-net-projects-part-1-nal" class="crayons-story__hidden-navigation-link"&gt;Why Software Architecture Matters in Real .NET Projects (Part 1)&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/pouria_ghadiri" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3174277%2F31e7f2d9-2a74-472f-a8ed-af894fbe2e66.jpg" alt="pouria_ghadiri profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/pouria_ghadiri" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Pouria Ghadiri
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Pouria Ghadiri
                
              
              &lt;div id="story-author-preview-content-2497586" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/pouria_ghadiri" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3174277%2F31e7f2d9-2a74-472f-a8ed-af894fbe2e66.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Pouria Ghadiri&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/pouria_ghadiri/why-software-architecture-matters-in-real-net-projects-part-1-nal" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;May 17 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/pouria_ghadiri/why-software-architecture-matters-in-real-net-projects-part-1-nal" id="article-link-2497586"&gt;
          Why Software Architecture Matters in Real .NET Projects (Part 1)
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/dotnet"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;dotnet&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/csharp"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;csharp&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/architecture"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;architecture&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/learning"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;learning&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/pouria_ghadiri/why-software-architecture-matters-in-real-net-projects-part-1-nal" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;5&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/pouria_ghadiri/why-software-architecture-matters-in-real-net-projects-part-1-nal#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              2&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>architecture</category>
      <category>learning</category>
    </item>
    <item>
      <title>Why Software Architecture Matters in Real .NET Projects (Part 1)</title>
      <dc:creator>Pouria Ghadiri</dc:creator>
      <pubDate>Sat, 17 May 2025 19:03:02 +0000</pubDate>
      <link>https://dev.to/pouria_ghadiri/why-software-architecture-matters-in-real-net-projects-part-1-nal</link>
      <guid>https://dev.to/pouria_ghadiri/why-software-architecture-matters-in-real-net-projects-part-1-nal</guid>
      <description>&lt;p&gt;When you’re building an app in ASP.NET Core, it’s easy to fall into the trap of just writing code that “works.” Especially when deadlines are tight. But if you’ve ever looked back at your project and thought, “Ugh, this is a mess,” then you know why architecture matters.&lt;br&gt;
Let me break this down from experience — no buzzwords, just what works in real projects.&lt;/p&gt;


&lt;h4&gt;
  
  
  🧱 What Is Software Architecture?
&lt;/h4&gt;

&lt;p&gt;Think of software architecture like the blueprint for a house. You wouldn’t build a house without planning where the walls, plumbing, and electrical systems go — same goes for your code.&lt;br&gt;
In .NET, architecture defines how your application is structured : where your business logic lives, how your components talk to each other, and how your app can grow over time without breaking everything.&lt;br&gt;
It’s not about fancy folders or naming things “Service” or “Manager.” It’s about making sure your code stays clean, testable, and easy to change.&lt;/p&gt;


&lt;h4&gt;
  
  
  👷‍♂️ The Mess We've All Seen
&lt;/h4&gt;

&lt;p&gt;Here’s a common scenario I see all the time:&lt;br&gt;
• Your controller does database calls directly.&lt;br&gt;
• Services just pass data to Entity Framework.&lt;br&gt;
• There’s no clear place for actual business rules.&lt;br&gt;
• Adding a new feature feels risky — like touching one line breaks 10 others.&lt;br&gt;
And here’s what happens as a result:&lt;br&gt;
• Everything is tightly coupled.&lt;br&gt;
• Writing unit tests feels impossible.&lt;br&gt;
• Simple changes take forever.&lt;br&gt;
• New developers struggle to understand the code.&lt;br&gt;
This kind of setup leads to what I call &lt;code&gt;Code Rot&lt;/code&gt; — where the codebase gets harder and harder to work with over time.&lt;br&gt;
💥 Example: &lt;code&gt;The God Controller&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[HttpPost]
public async Task&amp;lt;IActionResult&amp;gt; Create([FromBody] OrderDto dto)
{
    var order = new Order
    {
        CustomerId = dto.CustomerId,
        Total = dto.Total,
        CreatedAt = DateTime.UtcNow
    };

    _context.Orders.Add(order);
    await _context.SaveChangesAsync();

    return Ok(order.Id);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks simple enough, right? But think about what happens when you need:&lt;br&gt;
• Validation (is the customer valid?)&lt;br&gt;
• Business rules (e.g., max 5 orders per day)?&lt;br&gt;
• Event logging?&lt;br&gt;
• Sending a confirmation email?&lt;br&gt;
Now your controller becomes a dumping ground for everything. That’s not scalable.&lt;/p&gt;




&lt;h4&gt;
  
  
  ✅ Goals of Good Architecture
&lt;/h4&gt;

&lt;p&gt;Good architecture gives you practical benefits:&lt;br&gt;
• Separation of concerns – Each part has a clear job.&lt;br&gt;
• Testability – You can write unit tests easily.&lt;br&gt;
• Maintainability – Anyone can read and change the code.&lt;br&gt;
• Flexibility – Want to swap out the database or framework later? Easier said than done without good design.&lt;br&gt;
• Scalability – As the app grows, the code doesn't fall apart.&lt;br&gt;
• Clear domain model – Your business logic is obvious, not hidden in random places.&lt;br&gt;
You don’t need to overengineer. Just be thoughtful. A little planning today saves you hours of refactoring tomorrow.&lt;/p&gt;




&lt;h4&gt;
  
  
  💡 Why This Matters in .NET
&lt;/h4&gt;

&lt;p&gt;Yes, .NET is powerful. Yes, EF Core makes it easy to get started quickly. But most tutorials and templates push you toward patterns like:&lt;br&gt;
• Thin services that just wrap DbContext&lt;br&gt;
• DTOs everywhere with no behavior&lt;br&gt;
• Fat controllers full of logic&lt;br&gt;
These might work for small apps or prototypes, but they don’t scale well. And if your business logic is always changing, or multiple people work on the same code, this approach will slow you down fast.&lt;br&gt;
Architecture becomes even more important when:&lt;br&gt;
• Requirements change often.&lt;br&gt;
• Multiple devs are working on the same project.&lt;br&gt;
• You want a system that’s easy to test and extend.&lt;/p&gt;




&lt;h5&gt;
  
  
  🔮 What’s Coming Next
&lt;/h5&gt;

&lt;p&gt;In this series, we’ll walk through real architectural patterns used in modern .NET applications — not just theory, but examples you can actually use in your next project.&lt;br&gt;
Here’s what I plan to cover (and I’m committed to delivering):&lt;/p&gt;

&lt;p&gt;• Part 2: &lt;a href="https://dev.to/pouria_ghadiri/layered-architecture-in-aspnet-core-simple-structured-and-still-relevant-part-2-31m3"&gt;Layered Architecture – Classic, simple, and still useful.&lt;/a&gt;&lt;br&gt;
• Part 3: &lt;a href="https://dev.to/pouria_ghadiri/onion-architecture-in-net-core-keeping-your-core-clean-part-3-5997"&gt;Onion Architecture – Structure your app so dependencies flow inward.&lt;/a&gt;&lt;br&gt;
• Part 4: Clean Architecture – Inspired by Uncle Bob, adapted for .NET.&lt;br&gt;
• Part 5: Domain-Driven Design in .NET – Building meaningful models.&lt;br&gt;
• Part 6+: CQRS, MediatR, Events, Testing Strategies, and Common Mistakes&lt;/p&gt;




&lt;h5&gt;
  
  
  🚀 Final Thoughts
&lt;/h5&gt;

&lt;p&gt;You don’t have to be at a huge company or working on a massive enterprise system to care about architecture. Even a small app can benefit from a bit of structure.&lt;br&gt;
If you're tired of messy codebases, hard-to-test logic, or struggling to add features without breaking things, this series is for you.&lt;br&gt;
Stick around — we'll turn those spaghetti controllers and thin services into something maintainable, scalable, and enjoyable to work with.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>architecture</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
