Free book sample

Domain-Centric Architecture with C#

Building Maintainable Applications Using Clean Architecture, SOLID Principles, and Modern Design Patterns

Design applications that stand the test of time by mastering domain-centric architecture patterns in C#.

253 pages14 chaptersOct 31, 2025Software ArchitectureCreated by Kaj

Download sample:

About this book

This comprehensive guide shows you how to structure your code around business logic rather than technical frameworks, creating systems that are easier to test, maintain, and evolve. You'll explore the principles behind Clean Architecture and Onion Architecture, understanding how to organize layers so dependencies flow in one direction—toward your domain. Through practical examples, you'll learn to apply SOLID principles that make your code flexible and resilient to change. You'll discover how to design aggregates that enforce business rules, implement the Repository Pattern to abstract data access, and leverage Dependency Injection to achieve loose coupling. The book covers Entity Framework integration within the infrastructure layer, ensuring your persistence logic doesn't leak into your domain. You'll also see how these architectural patterns apply to modern frameworks like Blazor, enabling you to build full-stack applications with clean separation of concerns. Each concept builds progressively, giving you the knowledge and confidence to architect professional-grade C# applications.

Table of contents

  1. IntroductionWhy Architecture Matters, The Shift to Domain-Centric Thinking, How to Use This BookRead below
  2. Chapter 1: Foundations of Domain-Centric ArchitectureProblems with Traditional Layered Architecture, The Domain-First Approach, Understanding the Dependency Rule, Benefits and Trade-offs
  3. Chapter 2: SOLID Principles in PracticeSingle Responsibility Principle, Open-Closed Principle, Liskov Substitution Principle, Interface Segregation Principle, Dependency Inversion Principle
  4. Chapter 3: Clean Architecture ExplainedThe Four Layers of Clean Architecture, Entities and Use Cases, Interface Adapters and Frameworks, Implementing Clean Architecture in C#
  5. Chapter 4: Onion Architecture Deep DiveUnderstanding Onion Layers, The Domain Core, Application Services Layer, Comparing Onion and Clean Architecture
  6. Chapter 5: Designing the Domain LayerEntities and Value Objects, Domain Services, Domain Events, Avoiding Anemic Domain Models
  7. Chapter 6: Aggregate Design PatternsWhat Are Aggregates, Defining Consistency Boundaries, Aggregate Roots and Invariants, Sizing Aggregates Correctly
  8. Chapter 7: Building the Application LayerImplementing Use Cases, Command and Query Separation, Application Services in Detail, DTOs and Mapping Strategies
  9. Chapter 8: The Repository PatternPurpose and Benefits of Repositories, Designing Repository Interfaces, Generic vs Specific Repositories, Unit of Work Pattern
  10. Chapter 9: Infrastructure Layer ImplementationInfrastructure Layer Responsibilities, Integrating External Services, Configuration and Settings Management
  11. Chapter 10: Entity Framework in Clean ArchitectureSetting Up Entity Framework Core, DbContext Design and Configuration, Mapping Domain Aggregates to Database, Implementing Repositories with EF Core
  12. Chapter 11: Dependency Injection and IoCDependency Injection Fundamentals, IoC Containers in C#, Service Lifetimes and Scopes, Composition Root Pattern
  13. Chapter 12: Presentation Layer with BlazorBlazor in Clean Architecture, Component Design and Separation of Concerns, Dependency Injection in Blazor, State Management Strategies
  14. Chapter 13: Testing Domain-Centric ApplicationsThe Testing Pyramid, Unit Testing the Domain Layer, Integration Testing with Repositories, Mocking and Test Doubles
  15. Chapter 14: Practical Implementation GuideOrganizing Your Solution Structure, Migrating Existing Applications, Common Pitfalls and How to Avoid Them
  16. ConclusionKey Takeaways, Your Next Steps, Continuing Your Architectural Journey

Introduction

Software architecture shapes how applications evolve over time. The decisions you make early in a project determine whether your codebase becomes easier to maintain or gradually transforms into an unmaintainable mess. Many developers have experienced the frustration of working with applications where simple changes require modifications across dozens of files, where business logic hides in controllers or database procedures, and where adding new features feels like navigating a minefield. These problems don't emerge from lack of effort or skill—they result from architectural choices that couple business logic tightly to technical infrastructure.

Domain-centric architecture offers a different path. By placing your business logic at the center of your application and organizing everything else around it, you create systems that reflect how your business actually works. This approach isolates your core domain from external concerns like databases, web frameworks, and third-party services. When your domain logic stands independent of these technical details, your application becomes easier to understand, test, and modify. Changes to your database technology or UI framework no longer require rewriting your business rules.

This book guides you through the principles and practices of building domain-centric applications in C#. You'll learn how Clean Architecture and Onion Architecture organize code into layers with clear dependencies flowing toward the domain. You'll discover how SOLID principles create flexible, maintainable code that adapts to changing requirements. Through practical examples and real-world scenarios, you'll see how to design aggregates that enforce business rules, implement repositories that abstract data access, and leverage dependency injection to achieve loose coupling. Whether you're starting a new project or improving an existing application, these patterns will help you build software that serves your business needs today and adapts to tomorrow's challenges.

Why Architecture Matters

Architecture determines the long-term health of your software. In the early stages of development, architectural differences might seem invisible—features get delivered regardless of how you organize your code. But as applications grow, poor architectural decisions compound. What started as a small application with a few database tables and controllers becomes a tangled web where every change risks breaking existing functionality. Teams slow down, bugs multiply, and developers spend more time fighting the codebase than delivering value.

Consider a typical scenario: your application stores customer data in SQL Server, and your business logic lives in ASP.NET controllers. This works fine initially. Then your company decides to add a mobile app that needs the same business logic. You discover that your logic is tightly coupled to HTTP concerns—it reads directly from Request objects and returns ActionResult instances. You can't reuse it. You face a choice: duplicate the logic in a new API layer, or refactor everything. Both options are expensive and risky.

Good architecture prevents these problems by establishing clear boundaries between different concerns. When your business logic exists independently of delivery mechanisms and data storage, you can:

  • Test business rules without databases or web servers running, making tests fast and reliable
  • Change your database technology from SQL Server to PostgreSQL without touching business logic
  • Add new interfaces like REST APIs, GraphQL endpoints, or message queues without duplicating code
  • Understand the system by reading domain code that expresses business concepts clearly
  • Onboard new developers faster because the architecture guides them toward correct patterns

The cost of poor architecture grows exponentially over time. A study by the Consortium for IT Software Quality found that technical debt costs U.S. companies approximately $2.41 trillion annually[1]. Much of this debt stems from architectural decisions that seemed expedient initially but created maintenance nightmares later. Every shortcut taken, every business rule embedded in a stored procedure, every domain concept scattered across multiple layers adds to this debt.

Domain-centric architecture addresses these challenges by inverting traditional dependencies. Instead of building your business logic on top of frameworks and databases, you build frameworks and databases around your business logic. Your domain becomes the stable center, and everything else becomes a replaceable detail. This inversion requires discipline and upfront thinking, but it pays dividends throughout your application's lifetime. When your business rules change—and they will—you modify domain code without touching infrastructure. When new technologies emerge, you swap out infrastructure without touching domain code.

The benefits extend beyond technical concerns. When your code reflects business concepts clearly, domain experts can read and validate it. Your application becomes a living model of your business, not just a collection of technical artifacts. Conversations with stakeholders improve because you share a common language expressed in code. This alignment between business and technology reduces misunderstandings and helps ensure you're building the right thing, not just building things right.

Architecture also affects team dynamics and productivity. In poorly architected systems, developers fear making changes because they can't predict the consequences. They work around problems instead of fixing them, adding layers of complexity. In well-architected systems, developers understand where different concerns belong. They make changes confidently because the architecture guides them. Code reviews focus on business logic and design rather than untangling dependencies. Teams move faster and deliver more value.

The investment in good architecture pays off most when you need it least obviously—during maintenance and evolution. The majority of software costs occur after initial development[2]. Applications that survive long enough to provide value spend years in maintenance mode, receiving bug fixes, feature additions, and technology updates. Architecture determines whether this maintenance is straightforward or agonizing. Domain-centric architecture makes maintenance manageable by isolating changes and making dependencies explicit.

The Shift to Domain-Centric Thinking

Traditional application development often starts with technical concerns. You choose a framework, design a database schema, create tables, and then add business logic wherever it fits. This database-centric or framework-centric approach feels natural because it follows the tools' conventions. Entity Framework encourages you to think about entities as database rows. ASP.NET MVC encourages you to put logic in controllers. These frameworks provide structure, but they structure your application around technical concerns rather than business concepts.

Domain-centric thinking flips this approach. You start by modeling your business domain—the concepts, rules, and processes that define what your application does. You identify entities like Customer, Order, and Product not as database tables but as business concepts with behaviors and rules. You discover that an Order isn't just a collection of data fields; it's an entity that can be placed, confirmed, shipped, and cancelled, with rules governing each transition. This understanding shapes your code before you consider databases or web frameworks.

The shift requires changing how you think about dependencies. In traditional layered architecture, your business logic depends on data access layers, which depend on databases. Your domain code references Entity Framework classes, calls repository methods that return database entities, and couples itself to persistence concerns. In domain-centric architecture, dependencies flow inward. Your domain defines interfaces for what it needs—perhaps an IOrderRepository—without knowing or caring about implementation details. Infrastructure layers implement these interfaces, depending on the domain rather than the domain depending on infrastructure.

This inversion of dependencies is the Dependency Rule, a core principle of domain-centric architecture. The rule states: source code dependencies must point only inward, toward higher-level policies. Your domain layer sits at the center, containing your business rules and policies. Application services surround the domain, orchestrating use cases. Infrastructure layers sit at the edges, implementing technical details. Dependencies flow from outer layers toward the center, never outward. This means:

  • Domain code never references infrastructure code or frameworks
  • Application services depend on domain interfaces but not infrastructure implementations
  • Infrastructure implementations depend on domain interfaces they implement
  • Presentation layers depend on application services but not directly on domain internals

Consider a concrete example. You're building an e-commerce system, and you need to process orders. In a traditional approach, your OrderController might directly instantiate an OrderService, which directly instantiates an OrderRepository, which directly uses Entity Framework's DbContext. Each layer knows about and depends on the layer below it. If you want to test the order processing logic, you need a database. If you want to change from Entity Framework to Dapper, you modify the repository, which might affect the service, which might affect the controller.

In a domain-centric approach, you start with the domain. You create an Order entity that understands order states and transitions. You define domain services that implement business rules like pricing calculations or inventory checks. You declare an IOrderRepository interface in the domain layer that specifies what operations the domain needs—perhaps GetById, Save, and FindByCustomer. Your domain code uses this interface without knowing about databases.

Your application layer contains use cases like PlaceOrderUseCase that orchestrate domain objects and call repository interfaces. Your infrastructure layer provides an OrderRepository class that implements IOrderRepository using Entity Framework. Your presentation layer calls use cases through application service interfaces. Dependencies flow inward: infrastructure depends on domain interfaces, application services depend on domain entities, and presentation depends on application services. You can test domain logic without databases, swap Entity Framework for another ORM without touching domain code, and add new presentation layers without modifying business rules.

This shift requires discipline. Frameworks and tools encourage you to take shortcuts—to put business logic in controllers because it's convenient, to let Entity Framework entities serve as domain models because it reduces mapping code, to reference infrastructure concerns from domain code because it's faster initially. Domain-centric architecture asks you to resist these shortcuts. The payoff comes later, when your application needs to evolve and you discover that changes are localized and manageable rather than cascading through every layer.

The shift also changes how you communicate about your application. Instead of discussing tables, controllers, and frameworks, you discuss domains, aggregates, and use cases. Your code uses the language of your business—PlaceOrder, CalculateShippingCost, ApplyDiscount—rather than generic CRUD operations. This ubiquitous language, a concept from Domain-Driven Design, bridges the gap between technical and business stakeholders. When everyone uses the same terms with the same meanings, misunderstandings decrease and collaboration improves.

Domain-centric thinking doesn't mean ignoring technical concerns. Databases, frameworks, and infrastructure matter. But they matter as implementation details that serve your domain, not as foundations that constrain it. You still use Entity Framework, ASP.NET, and other tools—you just organize them so they depend on your domain rather than your domain depending on them. This organization gives you flexibility and control, allowing you to make technical decisions based on current needs while preserving the ability to change those decisions later.

How to Use This Book

This book builds progressively from foundational concepts to practical implementation. Each chapter introduces ideas that build on previous chapters, so reading sequentially provides the clearest path. However, if you're already familiar with certain concepts, you can skip ahead to chapters that address your specific interests. The book is organized into three main sections: foundations, core patterns, and practical implementation.

The foundations section (Chapters 1-4) establishes the principles underlying domain-centric architecture. Chapter 1 examines problems with traditional layered architecture and introduces the domain-first approach and the Dependency Rule. Chapter 2 covers SOLID principles in depth, showing how each principle contributes to maintainable code. Chapters 3 and 4 explore Clean Architecture and Onion Architecture respectively, explaining their layers, comparing their approaches, and demonstrating implementation in C#. These chapters provide the conceptual framework for everything that follows.

The core patterns section (Chapters 5-9) dives into specific architectural patterns and layers. Chapter 5 focuses on designing the domain layer, covering entities, value objects, domain services, and domain events. Chapter 6 explores aggregate design patterns, teaching you how to define consistency boundaries and size aggregates correctly. Chapter 7 examines the application layer, showing how to implement use cases and separate commands from queries. Chapter 8 details the Repository Pattern, including when to use generic versus specific repositories. Chapter 9 covers infrastructure layer implementation and integration with external services.

The practical implementation section (Chapters 10-14) applies these patterns to real-world scenarios with specific technologies. Chapter 10 shows how to use Entity Framework Core within clean architecture, including DbContext design and aggregate mapping. Chapter 11 covers dependency injection and IoC containers in depth. Chapter 12 demonstrates building presentation layers with Blazor while maintaining separation of concerns. Chapter 13 addresses testing strategies for domain-centric applications. Chapter 14 provides practical guidance on organizing solution structures and migrating existing applications.

Each chapter follows a consistent structure designed to maximize learning:

  • Concept introduction explains what the pattern or principle is and why it matters
  • Problem scenarios illustrate the issues the pattern solves with concrete examples
  • Implementation guidance shows how to apply the pattern in C# with code examples
  • Best practices highlight common pitfalls and how to avoid them
  • Practical examples demonstrate the pattern in realistic scenarios

Code examples throughout the book use modern C# features including nullable reference types, records, and pattern matching where appropriate. Examples start simple to illustrate core concepts, then grow more sophisticated to show real-world application. You'll see both what to do and what to avoid, with explanations of why certain approaches work better than others. All code examples are complete enough to understand in context but focused enough to highlight specific concepts without overwhelming detail.

The book assumes you have intermediate C# knowledge. You should be comfortable with classes, interfaces, generics, and LINQ. You don't need prior experience with Entity Framework, Blazor, or architectural patterns—the book explains these as needed. If you encounter unfamiliar C# features, the book provides brief explanations, but you may want to consult C# documentation for deeper understanding of language features.

To get the most from this book, consider setting up a practice project where you apply concepts as you learn them. Start with a simple domain—perhaps a library management system, a task tracker, or a simple e-commerce store. As you read each chapter, implement the patterns in your practice project. This hands-on approach reinforces learning and helps you encounter and solve real implementation challenges. The book's examples provide guidance, but applying concepts to your own domain deepens understanding.

You'll notice the book emphasizes principles over prescriptive rules. Domain-centric architecture provides guidelines and patterns, not rigid formulas. Your specific context—team size, project complexity, business domain, and technical constraints—influences how you apply these patterns. The book teaches you to think architecturally so you can make informed decisions rather than blindly following templates. When the book presents multiple approaches, it explains trade-offs so you can choose appropriately for your situation.

Throughout the book, you'll find references to additional resources for deeper exploration. Domain-centric architecture draws from Domain-Driven Design, SOLID principles, and various architectural patterns. While this book provides comprehensive coverage of applying these concepts in C#, the referenced works offer additional perspectives and deeper theoretical foundations. Consider these references as opportunities for continued learning rather than prerequisites.

The book's conclusion synthesizes key takeaways and provides guidance for continuing your architectural journey. Software architecture is a discipline that deepens with experience. This book gives you the knowledge and patterns to start building better applications immediately, but mastery comes from applying these concepts repeatedly, learning from mistakes, and adapting patterns to new contexts. View this book as the beginning of your architectural education, not the end.

As you progress through the book, you'll develop a new perspective on application design. You'll start seeing applications as collections of layers with clear dependencies rather than monolithic codebases. You'll recognize when business logic is leaking into infrastructure and know how to fix it. You'll design classes that have single responsibilities and depend on abstractions rather than concrete implementations. These skills will serve you throughout your career, regardless of which specific frameworks or technologies you use. The principles of domain-centric architecture transcend any particular tool or platform.

Back to contents

Notes

Introduction

  1. 1. Consortium for IT Software Quality, The Cost of Poor Software Quality in the US: A 2022 Report, 2022
  2. 2. Ian Sommerville, Software Engineering, 10th Edition, Pearson, 2015

This is the end of the free sample. The full book has 14 chapters.

Want this book written for you?

Tell us your goals and background, and get your own version of this book, tailored by AI to you.

User avatar
User avatar
User avatar
User avatar
User avatar
9,228 books created by readers like you
As seen on:
Product HuntRedditMediumDEV

Benefits of AI-tailored books

Read one book, not ten:
all the Software Architecture knowledge you need, gathered into a single book.
Save days of learning:
tell us your goals, choose your topics, and the whole book is built around them.
Learn effortlessly:
Software Architecture book written for your specific background and expertise.
Understand at a glance:
includes charts, tables, timelines, checklists, decision trees, and more.
Stay current:
written the day you order it, not years ago.
Trust what you read:
every book is checked for accuracy, with real research when your subject needs it.

Create your unique book in 3 steps

1. Select your focus

Select the focus of your Software Architecture book and share your background

Your Software Architecture book focus
2. Personalize your book

Specify your goals and choose sub-topics to include

3. Get your tailored book

Your book is ready in 10 minutes. Read it online, download as EPUB or PDF, or send to Kindle.

Frequently asked questions

What is TailoredRead?

TailoredRead creates complete, full-length nonfiction ebooks, written specifically for you. Tell us what you want to learn and why, and TailoredRead writes you a complete ebook on it, with charts, tables, and diagrams throughout. Read it online, on Kindle, or on any e-reader, or download it as a PDF or EPUB. Every book is written fresh the day you order it.

How is the book tailored to me?

Before anything is written, you answer a few short questions about your goals, your background, and the topics you care about. Your book is then planned around your answers: written at your level, focused on your goals, and covering the topics you chose, instead of the one-size-fits-all book a store sells everyone.

Will it read like generic AI content?

No. Your book isn't a chat transcript: it's planned chapter by chapter before a single word is written, told in a clear book voice, and explains ideas visually with charts, tables, and diagrams. After writing, every book goes through an editorial pass that polishes chapters so the book reads consistent from start to finish. Judge for yourself: browse thousands of sample books on our Explore Books page.

How accurate is the content?

Our AI first checks whether your subject needs live research. Niche and fast-moving subjects are researched before writing, and the book plan and chapters are grounded in what it finds. After writing, every book goes through a quality pass that checks its facts and consistency, and researched books list their sources in a Notes section at the back.

How long is the book?

You choose the length: Comprehensive (250-300 pages), Detailed (150-200 pages), Essential (70-100 pages), or Short (30-50 pages).

Does the book include visuals?

Yes. Every book includes charts, tables, and diagrams: timelines, checklists, step-by-step guides, decision trees, comparison tables, matrices, and bar charts. A typical book includes dozens of these visual elements.

Can I read it on Kindle? What formats can I download?

Yes. Every book can be read in our online reader or downloaded as a PDF or EPUB. The EPUB can be opened with Kindle, Apple Books, Kobo, and any e-reader. The Commercial and Author licenses also include an editable Word (DOCX) and Markdown download.

How much does it cost?

About the price of a regular ebook. The exact price depends on your book's length and complexity, from $2 for the shortest books to $35 for the most comprehensive, and it's shown when you review your book, before you commit to anything. Each book is a one-time purchase, yours to keep, no subscription. Licenses that let you share, teach, or publish your book range from $35.99 to $49.99.

Can I preview the book before purchasing?

Before you pay, you'll see what your book will cover: the title, a detailed description, the estimated length, and the complete chapter-by-chapter table of contents, so you know what you're getting before you decide. The full text itself is written after you purchase.

How long does it take to create a book?

About 10 minutes. You can start reading the opening chapters while the rest is still being written.

Personalize and buy this book

Get your personalized version, tailored by AI to your goals, background, and interests