الانتقال إلى المحتوى الرئيسي

لوحة الأوامر

ابحث عن أمر لتشغيله...

Store API — E-Commerce Backend

A .NET 10 e-commerce API architected through 10 mentored tasks, evolving from direct DbContext queries to a layered, production-ready system with advanced EF Core performance tuning.

Store API — E-Commerce Backend

Overview

A deliberate learning project that mirrors real production evolution.
Built as a mentored progression through 10 increasingly complex business scenarios — from simple product search to explicit transactions with savepoints — this API demonstrates how architectural decisions compound. Starting score: 3.7/10. Final architecture: 9.3/10.

This is not a tutorial follow-along. Each task was submitted, reviewed, and iterated. The codebase captures the exact journey from "controllers talking directly to the database" to a fully layered system with the Dependency Rule, Result<T> patterns, global exception handling, and automated validation.


Architecture Evolution

The project evolved in two distinct phases, both preserved in the commit history.

Phase 1 — EF Core Mastery (Tasks 01–10)

Controllers called DbContext directly while I learned how EF Core actually translates LINQ to SQL. The focus was query performance, data integrity, and understanding the ORM at the expression-tree level.

  • Deferred execution with conditional IQueryable chaining

  • AsNoTracking() + Select() projection for read-only endpoints (65% fewer columns over the wire vs Include())

  • AsSplitQuery() to eliminate Cartesian explosion on multi-collection loads

  • ExecuteUpdateAsync / ExecuteDeleteAsync for true bulk operations without loading entities

  • Compiled queries (EF.CompileAsyncQuery) to skip LINQ-to-SQL translation on hot paths

  • Savepoints inside explicit transactions to preserve critical work when audit trails fail

Phase 2 — Production Architecture (Direction A)

The same business logic was refactored into a layered architecture to prove the patterns transfer to real systems.

plain

Concern

Before

After

Controller size

50–150 lines

5–15 lines (HTTP only)

Business logic

Scattered in controllers

Service classes

Validation

Manual if checks

FluentValidation (automatic)

Error handling

Try/catch everywhere

One middleware, consistent JSON

Testability

Requires a real database

Fully mockable services

Dependency Rule held throughout:
Store.APIStore.ApplicationStore.DomainStore.Infrastructure


1. The Result<T> Pattern — Replacing Exceptions with Contracts

Services communicate failures without throwing. The controller maps to HTTP in one line.

csharp

Why this matters: Exceptions are expensive and carry no HTTP semantics. Result<T> makes failure a first-class value that is explicit, testable, and cheap.


2. Select() Projection vs Include() — The 65% Reduction

For read scenarios, Select() fetches only the columns you name. Include() loads full entities including every column you never use.

csharp

The rule I now apply in production:

  • Writing dataInclude() → modify entity → SaveChangesAsync()

  • Reading dataSelect() projection → AsNoTracking() → never Include()


3. Explicit Transactions with Savepoints — Protecting Critical Work

When confirming an order, stock reduction is critical. Audit trail creation is recoverable. A savepoint preserves the critical work if the audit fails.

csharp

Why this matters: In high-throughput systems, failing an entire transaction because an audit log insert failed is unacceptable. Savepoints let you define which operations are essential and which are best-effort.


4. Bulk Operations — ExecuteUpdateAsync Without Loading Entities

Applying a discount across an entire category in a single SQL statement. No entities loaded. No SaveChanges. No change tracker.

csharp

The trap I learned to avoid: Pre-computing decimal newPrice = product.Price * 0.9 in C# forces EF to generate one UPDATE per row. Referencing the column inside the lambda (p.Price * (1 - discount)) generates a single bulk UPDATE with SQL arithmetic.


5. FluentValidation — Validation as Infrastructure, Not Code

Validation rules live in dedicated classes and run automatically before the controller action is ever invoked.

csharp

Impact: Services no longer contain defensive if checks against malformed input. The boundary is enforced at the edge, keeping business logic clean and focused.


Key Metrics & Growth

Task

First Attempt

Final Score

Concept

Product Search

3.7

8.7

Deferred execution, pagination

Payment Processing

4.7

8.3

Aggregate validation, balance guards

Bulk Stock Adjustment

6.3

9.3

Batch loading, partial failure

Customer Sales Report

7.0

9.0

Navigation aggregates in SQL

Order Confirmation (Transactions)

7.3

9.3

Savepoints, critical vs recoverable

Architecture Refactor

7.0

9.3

Layered architecture, DI

Total progression: 3.7 → consistent 9.0+ across all new tasks.


What I Would Do Next

This project established the foundation. The next iteration would add:

  • Unit & integration test suite (xUnit + Moq + FluentAssertions) — roadmap already planned

  • Soft-delete safety audit on ExecuteDeleteAsync to prevent accidental hard deletes

  • CQRS split — separate read models with Dapper for report-heavy endpoints

  • Redis caching on compiled query results for hot product/catalog data