Introduction
Domain-Driven Design in ASP.NET Core — Complete Guide is essential for .NET architects building ShopNest Cloud-Native Enterprise Platform — Toolliyo's 120-article microservices master path covering RabbitMQ, Saga, Kubernetes, API Gateway, observability, ASP.NET Core integration, and senior interview preparation. Every article includes minimum 2 detailed production real-world examples (Flipkart, banking, Swiggy, SaaS) in different business domains.
In Indian delivery projects (TCS, Infosys, Wipro), interviewers expect domain-driven design with real Flipkart-scale e-commerce, HDFC-style banking, Swiggy delivery, or SaaS multi-tenant examples — not toy animal demos. This article delivers two mandatory enterprise examples on Inventory Service.
After this article you will
- Explain Domain-Driven Design in plain English and in distributed systems and cloud-native terms
- Implement domain-driven design in ShopNest Cloud-Native Enterprise Platform (Inventory Service)
- Compare the wrong approach vs the production-ready enterprise approach
- Answer fresher, mid-level, and senior microservices and distributed systems interview questions confidently
- Connect this lesson to Article 7 and the 120-article Microservices roadmap
Prerequisites
- Software: .NET 8 SDK, VS 2022 or VS Code, SQL Server Express / LocalDB
- Knowledge: C# basics
- Previous: Article 5 — Clean Architecture in ASP.NET Core Web API — Complete Guide
- Time: 22 min reading + 30–45 min hands-on
Concept deep-dive
Level 1 — Analogy
Domain-Driven Design on ShopNest Cloud-Native extends the distributed platform — each service owns its data and deployment lifecycle.
Level 2 — Technical
Domain-Driven Design integrates with the LINQ query layer: write queries against IEnumerable or IQueryable, understand deferred execution, project to DTOs for ShopNest Cloud-Native reports. On ShopNest Cloud-Native this powers Inventory Service without coupling UI to database internals.
Level 3 — Architecture
[Browser] → [HTTPS/Kestrel] → [Middleware Pipeline]
→ [Routing] → [Controller Action] → [Service Layer]
→ [EF Core / Identity] → [Razor View Engine] → [HTML Response]
Common misconceptions
❌ MYTH: Domain-Driven Design is only needed for large enterprise apps.
✅ TRUTH: ShopNest Cloud-Native starts simple — add complexity when traffic, team size, or compliance demands it.
❌ MYTH: Web API 2 and ASP.NET Core Web API are the same.
✅ TRUTH: Push filtering, sorting, and aggregation to IQueryable so SQL Server does the work — avoid client-side evaluation.
❌ MYTH: You can call .ToList() first and filter in memory — it works for small data.
✅ TRUTH: Never materialize early on large datasets — filter and project in IQueryable, watch for multiple enumeration.
Project structure
ShopNest Cloud-Native/
├── ShopNest.Cloud/
├── src/
│ ├── Gateway/ ← YARP API Gateway (JWT, rate limit)
│ ├── Services/
│ │ ├── Identity.Api/
│ │ ├── User.Api/
│ │ ├── Product.Api/
│ │ ├── Order.Api/
│ │ ├── Payment.Api/
│ │ ├── Inventory.Api/
│ │ ├── Notification.Api/
│ │ └── Analytics.Api/
│ ├── BuildingBlocks/ ← EventBus, Outbox, Polly policies
│ └── docker-compose.yml
├── k8s/ ← Helm charts per service
└── .github/workflows/ ← CI/CD per service
Step-by-Step Implementation — ShopNest (Inventory Service)
Follow the prompt template: create project → core classes → interfaces → pattern implementation → client code → run → enterprise refactor.
Step 1 — The wrong way
// ❌ BAD — fat controller, no ViewModel, sync DB call
public IActionResult Index()
{
return _context.Products.Find(id); // sync, exposes entity, no auth
}
Step 2 — The right way
// ✅ CORRECT — Domain-Driven Design on ShopNest (Inventory Service)
var results = await _context.Products
.Where(p => p.IsPublished && p.CategoryId == categoryId)
.OrderBy(p => p.Name)
.Select(p => new ProductReportDto { Id = p.Id, Name = p.Name, Revenue = p.Orders.Sum(o => o.Total) })
.ToListAsync(ct);
Step 3 — Apply Domain-Driven Design
public IActionResult Details(int id) => View(_products.Find(id));
public IActionResult Create() => View();
[HttpPost] public IActionResult Create(ProductVm m) { /* ... */ }
docker compose up --build
# Verify Domain-Driven Design — check RabbitMQ management UI and kubectl get pods and integration tests pass
Distributed system challenges — Domain-Driven Design
Production microservices fail in predictable ways. ShopNest engineers plan for these explicitly:
- Network failures — Payment service timeout must not hang Order API thread pool; use Polly timeout + async messaging
- Eventual consistency — Inventory may lag 200ms after order; UI shows "confirming stock" not silent wrong state
- Duplicate messages — RabbitMQ redelivery requires idempotent consumers (Idempotency-Key, unique constraints)
- Retry storms — Exponential backoff + jitter; never retry 503s infinitely without circuit breaker
- Cascade failures — Bulkhead isolates Notification failures from blocking Payment path
Real-World Example 1 — Flipkart Big Billion Day E-Commerce
MANDATORY production scenario (Flipkart (India)): how Domain-Driven Design in ASP.NET Core applies in ShopNest Cloud-Native Inventory Service.
Business problem
During Big Billion Day, order traffic spikes 50x in minutes. A monolithic checkout cannot scale independently — payment APIs time out while product catalog stays idle. Microservices let Order, Payment, Inventory, and Notification services scale on separate Kubernetes node pools.
Why Domain-Driven Design in ASP.NET Core matters here
Indian enterprise teams at TCS, Infosys, Wipro, and product companies like Flipkart face this exact distributed systems challenge. Domain-Driven Design in ASP.NET Core is not academic — it directly affects uptime during peak load, deployment frequency, and incident recovery.
Architecture diagram
[Mobile App] → [YARP Gateway :443]
→ [Order.Api] → RabbitMQ → [Payment.Worker] → Razorpay
→ [Inventory.Api] → SQL Server (inventory-db)
→ [Notification.Api] → SMS/Email providers
Redis cache for product catalog; Polly circuit breaker on payment calls.
Production implementation
// ShopNest.Order.Api — PlaceOrderCommandHandler.cs
public sealed class PlaceOrderHandler : IRequestHandler<PlaceOrderCommand, OrderResult>
{
private readonly IOrderRepository _repo;
private readonly IPublishEndpoint _bus; // MassTransit + RabbitMQ
public async Task<OrderResult> Handle(PlaceOrderCommand cmd, CancellationToken ct)
{
var order = Order.Create(cmd.CustomerId, cmd.Items);
await _repo.AddAsync(order, ct);
await _bus.Publish(new OrderPlacedEvent(order.Id, order.Total), ct);
return new OrderResult(order.Id, "PENDING_PAYMENT");
}
}
// docker-compose.yml excerpt
services:
order-api:
build: ./src/Order.Api
environment:
- RabbitMQ__Host=rabbitmq
- ConnectionStrings__OrderDb=Server=order-db;Database=ShopNestOrders;
Production metrics and outcome
P99 checkout latency dropped from 8s to 1.2s after splitting Payment service; independent HPA on order-api (3→40 pods during sale).
Distributed system lessons
- Design for failure — network partitions and partial outages are normal at scale
- Prefer async messaging for cross-service workflows; sync only when latency requires it
- Instrument with OpenTelemetry from day one — you cannot debug what you cannot trace
- Run load tests before Big Billion Day / salary-day / lunch-rush peaks
Real-World Example 2 — HDFC-Style Core Banking Transfers
MANDATORY production scenario (Indian Banking (NEFT/IMPS)): how Domain-Driven Design in ASP.NET Core applies in ShopNest Cloud-Native Inventory Service.
Business problem
Fund transfers must be auditable, idempotent, and eventually consistent across Account, Ledger, Fraud, and Notification services. A shared database caused lock contention — 200ms p99 became 4s under salary-day load.
Why Domain-Driven Design in ASP.NET Core matters here
Indian enterprise teams at TCS, Infosys, Wipro, and product companies like Indian Banking face this exact distributed systems challenge. Domain-Driven Design in ASP.NET Core is not academic — it directly affects uptime during peak load, deployment frequency, and incident recovery.
Architecture diagram
[Mobile Banking] → [API Gateway + mTLS]
→ [Transfer.Api] → Outbox table → [Ledger.Worker]
→ [Fraud.Api] (sync gRPC, 200ms timeout)
→ [Notification.Api] via Kafka topic transfer.completed
Each service owns its DB; Saga compensates if fraud blocks after debit.
Production implementation
// ShopNest.Payment.Api — Idempotent transfer endpoint
[HttpPost("transfers")]
public async Task<IActionResult> Transfer([FromBody] TransferRequest req,
[FromHeader(Name = "Idempotency-Key")] string idempotencyKey)
{
var existing = await _cache.GetAsync<TransferResult>(idempotencyKey);
if (existing != null) return Ok(existing);
var cmd = new InitiateTransferCommand(req.FromAccount, req.ToAccount, req.Amount, idempotencyKey);
var result = await _mediator.Send(cmd);
await _cache.SetAsync(idempotencyKey, result, TimeSpan.FromHours(24));
return Accepted(result);
}
// Saga compensation on fraud failure
public async Task CompensateAsync(Guid transferId) =>
await _bus.Publish(new ReverseTransferCommand(transferId));
Production metrics and outcome
Salary-day throughput: 12,000 TPS with 99.99% success; zero duplicate debits after idempotency keys + outbox.
Distributed system lessons
- Design for failure — network partitions and partial outages are normal at scale
- Prefer async messaging for cross-service workflows; sync only when latency requires it
- Instrument with OpenTelemetry from day one — you cannot debug what you cannot trace
- Run load tests before Big Billion Day / salary-day / lunch-rush peaks
Security checklist (every ShopNest service)
Even non-auth articles must follow: HTTPS only, no secrets in appsettings committed to git, validate JWT on gateway, least-privilege DB users per service, and structured audit logs for Payment/Identity operations.
ASP.NET Core microservices integration — Domain-Driven Design
Register services in Program.cs, configure MassTransit/RabbitMQ, expose health endpoints for Kubernetes, and use IHttpClientFactory with Polly for sync calls between ShopNest services.
Microservices integration patterns & ASP.NET Core integration
Modern C# 12 implementations use primary constructors, records, and DI. Register pattern abstractions in Program.cs with appropriate lifetimes (Singleton for stateless, Scoped for request-bound, Transient for lightweight factories).
Microservices: Apply Domain-Driven Design within bounded contexts — each ShopNest service (Orders, Payments, Inventory) owns its pattern implementation.
Architecture comparison & when NOT to use
Compare Domain-Driven Design with alternative microservices approaches. Avoid overengineering — if a simple function or DI registration suffices, do not force a pattern. Senior architects value judgment over pattern count.
Common errors & fixes
🔴 Mistake 1: Fat controllers with EF Core queries inline
✅ Fix: Move data access to services/repositories; keep controllers thin.
🔴 Mistake 2: Calling .ToList() too early materializing millions of rows into memory
✅ Fix: Defer execution — build IQueryable pipeline, then ToListAsync() once at the end.
🔴 Mistake 3: Filtering in memory after .ToList() instead of in the database query
✅ Fix: Keep filters in IQueryable, use Select projection, paginate with Skip/Take before materialization.
🔴 Mistake 4: Hard-coding connection strings in controllers
✅ Fix: Use appsettings.json + User Secrets locally; Azure Key Vault in production.
Best practices
- 🟢 Use async/await end-to-end for database and I/O calls
- 🟢 Register DbContext as Scoped; avoid capturing it in singletons
- 🟡 Use IQueryable until the last moment; avoid multiple enumeration; project with Select before ToList
- 🟡 Prefer method syntax for complex chains; use query syntax for joins when readability wins
- 🔴 Log structured data with Serilog — include OrderId, UserId, not passwords
- 🔴 Use HTTPS, secure cookies, and authorization policies in production
Interview questions
Fresher level
Q1: What is Domain-Driven Design in ASP.NET Core MVC?
A: Domain-Driven Design is a core MVC capability used in ShopNest Cloud-Native for Inventory Service. Explain in one sentence, then describe controller/view/service placement.
Q2: How would you implement Domain-Driven Design on a TCS-style delivery project?
A: Deferred execution, IQueryable pipelines, Select projection, Skip/Take pagination, and SQL logging in development.
Q3: IEnumerable vs IQueryable — when to use which?
A: IEnumerable for in-memory collections; IQueryable for EF Core database queries that translate to SQL.
Mid / senior level
Q4: Explain LINQ deferred execution and query translation briefly.
A: LINQ → Expression Tree → IQueryProvider → SQL (EF) or Iterator (in-memory) → Results.
Q5: Common production mistake with this topic?
A: Skipping validation, exposing secrets in Git, or untested edge cases (null model, unauthorized user).
Q6: .NET LINQ vs SQL — when to push logic to database?
A: Core is cross-platform, faster, cloud-ready; Framework is maintenance mode on Windows/IIS.
Coding round
Implement Domain-Driven Design for ShopNest Inventory Service: show interface, concrete class, DI registration, and xUnit test with mock.
public class Domain-DrivenDesignPatternTests
{
[Fact]
public async Task ExecuteAsync_ReturnsSuccess()
{
var mock = new Mock();
mock.Setup(s => s.ExecuteAsync(It.IsAny(), default))
.ReturnsAsync(Result.Success("test-id"));
var result = await mock.Object.ExecuteAsync(new Request("test-id"));
Assert.True(result.IsSuccess);
}
}
Summary & next steps
- Article 6: Domain-Driven Design in ASP.NET Core — Complete Guide
- Module: Module 1: Foundations and Fundamentals · Level: BEGINNER
- Applied to ShopNest Cloud-Native — Inventory Service
Previous: Clean Architecture in ASP.NET Core Web API — Complete Guide
Next: Project Setup for Microservices — Complete Guide
Practice: Add one small feature using today's pattern — commit with feat(microservices): article-06.
FAQ
Q1: What is Domain-Driven Design?
Domain-Driven Design helps ShopNest Cloud-Native implement Inventory Service using C# 12 LINQ with EF Core where applicable.
Q2: Do I need Visual Studio?
No — .NET 8 SDK with VS Code + C# Dev Kit works. Visual Studio 2022 Community is recommended for MVC scaffolding.
Q3: Is this asked in Indian IT interviews?
Yes — MVC topics from Modules 1–6 appear in TCS, Infosys, Wipro campus drives; architecture modules in lateral hires.
Q4: Which .NET version?
Examples target .NET 8 LTS and .NET 9 with C# 12+ syntax.
Q5: How does this fit ShopNest Cloud-Native?
Article 6 adds domain-driven design to Inventory Service. By Article 100 you have a portfolio-ready ShopNest Cloud-Native enterprise database layer.