RepoPilotOpen in app →

dotnet/eShop

A reference .NET application implementing an eCommerce site

Healthy

Healthy across all four use cases

Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 6d ago
  • 17 active contributors
  • MIT licensed
Show 3 more →
  • CI configured
  • Concentrated ownership — top contributor handles 57% of recent commits
  • No test directory detected

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/dotnet/eshop)](https://repopilot.app/r/dotnet/eshop)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/dotnet/eshop on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: dotnet/eShop

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/dotnet/eShop shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across all four use cases

  • Last commit 6d ago
  • 17 active contributors
  • MIT licensed
  • CI configured
  • ⚠ Concentrated ownership — top contributor handles 57% of recent commits
  • ⚠ No test directory detected

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live dotnet/eShop repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/dotnet/eShop.

What it runs against: a local clone of dotnet/eShop — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in dotnet/eShop | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch main exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 36 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>dotnet/eShop</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of dotnet/eShop. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/dotnet/eShop.git
#   cd eShop
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of dotnet/eShop and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "dotnet/eShop(\\.git)?\\b" \\
  && ok "origin remote is dotnet/eShop" \\
  || miss "origin remote is not dotnet/eShop (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
  && ok "default branch main exists" \\
  || miss "default branch main no longer exists"

# 4. Critical files exist
test -f "eShop.slnx" \\
  && ok "eShop.slnx" \\
  || miss "missing critical file: eShop.slnx"
test -f "src/Basket.API/Program.cs" \\
  && ok "src/Basket.API/Program.cs" \\
  || miss "missing critical file: src/Basket.API/Program.cs"
test -f "src/Catalog.API/Program.cs" \\
  && ok "src/Catalog.API/Program.cs" \\
  || miss "missing critical file: src/Catalog.API/Program.cs"
test -f "src/Basket.API/Repositories/RedisBasketRepository.cs" \\
  && ok "src/Basket.API/Repositories/RedisBasketRepository.cs" \\
  || miss "missing critical file: src/Basket.API/Repositories/RedisBasketRepository.cs"
test -f "src/Catalog.API/Infrastructure/CatalogContext.cs" \\
  && ok "src/Catalog.API/Infrastructure/CatalogContext.cs" \\
  || miss "missing critical file: src/Catalog.API/Infrastructure/CatalogContext.cs"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 36 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~6d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/dotnet/eShop"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

eShop is a reference .NET 9 e-commerce application demonstrating a microservices architecture using .NET Aspire for service orchestration. It implements a complete online store with multiple backing services (Basket.API, Catalog.API, etc.) communicating via gRPC and HTTP, running in containerized environments with Docker. Service-oriented monorepo with src/Basket.API, src/Catalog.API, and other microservices as separate projects under src/. Each service has its own .csproj file. A .aspire/settings.json and .devcenter/ configuration indicate orchestration via .NET Aspire. The Web frontend (eShop.Web.slnf) is a filtered solution exposing only web-layer projects. E2E tests live in e2e/ using Playwright.

👥Who it's for

.NET architects and senior developers building production-grade microservices who need a real-world blueprint for service decomposition, inter-service communication patterns, and cloud-native deployment using .NET Aspire. Also enterprise teams evaluating .NET for distributed e-commerce systems.

🌱Maturity & risk

This is actively maintained and production-ready reference code targeting .NET 9 (released late 2024). It has comprehensive CI/CD via GitHub Actions (playwright.yml, pr-validation.yml), TypeScript end-to-end tests in the e2e/ directory, and follows official Microsoft patterns. The codebase is at 811K lines of C#, indicating substantial, well-structured implementation.

As a reference application rather than a framework, it's not meant for direct fork-and-deploy; you must adapt architectural decisions to your domain. Dependencies are pinned in Directory.Packages.props and nuget.config, but npm dependencies like @playwright/test@^1.42.1 use caret ranges—minor version upgrades could break e2e tests. No evidence of deprecation, but being a moving target for .NET Aspire (still maturing) means future breaking changes are possible.

Active areas of work

The repository recently transitioned to .NET 9 (from prior .NET 8 branch visible in README). Active work includes GitHub Actions validation workflows (pr-validation.yml, playwright.yml), Dependabot security monitoring (.github/dependabot.yml), and TypeScript e2e test expansion (AddItemTest.spec.ts, BrowseItemTest.spec.ts, RemoveItemTest.spec.ts). Multi-architecture Docker builds are being orchestrated (build/multiarch-manifests/).

🚀Get running

git clone https://github.com/dotnet/eShop.git
cd eShop
docker start  # Ensure Docker Desktop is running
dotnet build eShop.slnx
dotnet run --project src/AppHost/AppHost.csproj

On Windows with Visual Studio 2022 17.10+, open eShop.slnx directly and run the AppHost startup project.

Daily commands: Local dev (Visual Studio): Open eShop.slnx → Set AppHost as startup project → F5. CLI: dotnet run --project src/AppHost/AppHost.csproj from repo root. E2E tests: npx playwright test (requires node_modules/ installed via npm install).

🗺️Map of the codebase

  • eShop.slnx — Primary solution file that orchestrates all microservices and defines the project structure.
  • src/Basket.API/Program.cs — Entry point for Basket service; demonstrates dependency injection, gRPC setup, and Redis integration patterns used across all APIs.
  • src/Catalog.API/Program.cs — Entry point for Catalog service; shows Entity Framework Core, database seeding, and integration event publishing setup.
  • src/Basket.API/Repositories/RedisBasketRepository.cs — Core caching implementation for basket state; demonstrates the Redis-backed repository pattern used throughout the application.
  • src/Catalog.API/Infrastructure/CatalogContext.cs — Entity Framework Core DbContext defining domain models and database schema; represents data layer abstraction.
  • Directory.Build.props — Centralized property configuration for all projects; manages versions, dependencies, and build settings across the solution.
  • .aspire/settings.json — Aspire orchestration configuration; defines service discovery, container setup, and inter-service communication.

🛠️How to make changes

Add a new REST API endpoint to Catalog

  1. Define the domain model in src/Catalog.API/Infrastructure/CatalogContext.cs (add DbSet<T>) (src/Catalog.API/Infrastructure/CatalogContext.cs)
  2. Create EntityTypeConfiguration in src/Catalog.API/Infrastructure/EntityConfigurations/ following CatalogItemEntityTypeConfiguration.cs pattern (src/Catalog.API/Infrastructure/EntityConfigurations/CatalogItemEntityTypeConfiguration.cs)
  3. Add migration: dotnet ef migrations add [MigrationName] --project src/Catalog.API (src/Catalog.API/Infrastructure/Migrations/)
  4. Add API endpoint method in src/Catalog.API/Apis/CatalogApi.cs following MapGet/MapPost patterns (src/Catalog.API/Apis/CatalogApi.cs)
  5. Wire endpoint in Program.cs: app.MapCatalogApi() (src/Catalog.API/Program.cs)

Add inter-service communication via integration events

  1. Create event class in src/[Service].API/IntegrationEvents/Events/ extending IntegrationEvent (src/Catalog.API/IntegrationEvents/Events/OrderStatusChangedToPaidIntegrationEvent.cs)
  2. Create event handler in src/[Service].API/IntegrationEvents/EventHandling/ implementing IIntegrationEventHandler<T> (src/Catalog.API/IntegrationEvents/EventHandling/OrderStatusChangedToPaidIntegrationEventHandler.cs)
  3. Publish event in source service using CatalogIntegrationEventService.PublishEventAsync() (src/Catalog.API/IntegrationEvents/CatalogIntegrationEventService.cs)
  4. Subscribe handler in destination Program.cs: .AddIntegrationEventHandler<TEvent, THandler>() (src/Basket.API/Program.cs)

Add a gRPC service for microservice-to-microservice communication

  1. Define proto contract in src/[Service].API/Proto/[service].proto (src/Basket.API/Proto/basket.proto)
  2. Build project to auto-generate C# from proto (src/Basket.API/Basket.API.csproj)
  3. Implement gRPC service class in src/[Service].API/Grpc/ inheriting generated base (src/Basket.API/Grpc/BasketService.cs)
  4. Register gRPC in Program.cs: app.MapGrpcService<BasketService>() (src/Basket.API/Program.cs)
  5. Add gRPC client reference in consuming service Program.cs (src/Catalog.API/Program.cs)

Add an integration event handler in Basket service

  1. Import or create integration event class in src/Basket.API/IntegrationEvents/Events/ (src/Basket.API/IntegrationEvents/Events/OrderStartedIntegrationEvent.cs)
  2. Create handler class in src/Basket.API/IntegrationEvents/EventHandling/ following OrderStartedIntegrationEventHandler pattern (src/Basket.API/IntegrationEvents/EventHandling/OrderStartedIntegrationEventHandler.cs)
  3. Register handler in src/Basket.API/Program.cs using .AddIntegrationEventHandler<TEvent, THandler>() (src/Basket.API/Program.cs)
  4. Ensure message broker is configured in Aspire via .aspire/settings.json (.aspire/settings.json)

🔧Why these technologies

  • .NET 9 with ASP.NET Core — Modern type-safe runtime for building scal

🪤Traps & gotchas

Docker must be running: .NET Aspire will fail to start services if Docker daemon is not active. gRPC requires HTTP/2: Ensure reverse proxy and network allow HTTP/2; some corporate proxies block it. AppHost startup project: Building eShop.slnx alone won't run the app; you must set AppHost as the active startup project in Visual Studio or explicitly invoke it via dotnet run. E2E test auth: Playwright tests require login.setup.ts to authenticate before running (handled in playwright.config.ts projects array). Service port conflicts: Each microservice claims specific ports; if running locally without Aspire orchestration, manually manage port assignments. Aspire version coupling: The codebase targets specific .NET Aspire APIs; updating Aspire SDK may require code changes to Extension methods.

🏗️Architecture

💡Concepts to learn

  • .NET Aspire — This entire project is designed as a reference for Aspire's orchestration model; understanding service discovery, resource binding, and dashboard monitoring is core to running eShop.
  • gRPC and Protocol Buffers — eShop uses gRPC for inter-service communication (evidenced by ServerCallContextIdentityExtensions.cs); understanding .proto contracts and HTTP/2 transport is essential for extending services.
  • Microservices Architecture — eShop demonstrates domain-driven decomposition (Basket, Catalog, Ordering as separate services); architectural patterns like service boundaries, data isolation, and failure handling are implicit in the structure.
  • Entity Framework Core Migrations — Each microservice manages its own database schema via EF Core; understanding migrations, DbContext configuration, and multi-tenancy patterns is critical for data layer modifications.
  • Docker multi-architecture builds — eShop includes build/multiarch-manifests/create-manifests.ps1 for building ARM64 and x86-64 images; critical for cross-platform deployment (e.g., running on Mac M-series or cloud instances).
  • End-to-end testing with Playwright — e2e/ tests validate user workflows across the entire distributed system; Playwright's cross-browser and CI-friendly nature is why it's chosen over Selenium.
  • Centralized NuGet versioning (Directory.Packages.props) — eShop uses MSBuild Central Package Management to avoid version drift across 20+ microservice projects; understanding this pattern prevents transitive dependency conflicts.
  • dotnet/eShopOnContainers — Previous major version of eShop (.NET Framework era), shows the evolution toward .NET Aspire-based orchestration and cloud-native patterns.
  • dotnet/aspire — The .NET Aspire framework that underpins eShop's service orchestration, distributed tracing, and resource management.
  • dotnet/aspire-samples — Official Microsoft samples showing smaller, focused .NET Aspire usage patterns; useful for learning individual Aspire features in isolation.
  • NServiceBus/NServiceBus — Alternative distributed messaging framework often used alongside or instead of gRPC for service communication in .NET microservices.
  • dapr/dapr — Open-source distributed application runtime for service-to-service communication and state management; often compared with Aspire for microservices.

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add E2E tests for Basket.API gRPC service

The repo has Playwright E2E tests (e2e/*.spec.ts) for web flows but lacks tests for the gRPC Basket service. The Basket.API/Grpc/BasketService.cs and Basket.API/Proto/basket.proto are core infrastructure without test coverage. Adding gRPC E2E tests would validate the proto contract and integration with Redis, improving reliability for contributors modifying basket functionality.

  • [ ] Create e2e/BasketGrpcTest.spec.ts for gRPC Basket service operations (add item, get basket, clear basket)
  • [ ] Reference src/Basket.API/Proto/basket.proto to ensure test coverage of all service methods
  • [ ] Update playwright.config.ts if needed to support gRPC testing (grpc-js client library in package.json)
  • [ ] Integrate tests into .github/workflows/playwright.yml pipeline

Add GitHub Actions workflow for .NET code quality (StyleCop/Roslyn analyzers)

The repo has .editorconfig and Directory.Build.props for code standards, plus PR validation workflows (.github/workflows/pr-validation.yml), but lacks automated static analysis. Adding a StyleCop/Roslyn analyzer workflow would catch code style violations early and enforce architectural boundaries (e.g., preventing circular dependencies between microservices like Basket.API and Order.API).

  • [ ] Create .github/workflows/dotnet-analyzers.yml to run dotnet build with TreatWarningsAsErrors enabled
  • [ ] Reference Directory.Build.props to activate existing analyzer rules across all projects
  • [ ] Configure workflow to fail on CA violations and report findings in PR comments
  • [ ] Document analyzer configuration in CONTRIBUTING.md with link to .editorconfig ruleset

Add integration test suite for IntegrationEvents (EventBus patterns)

Basket.API/IntegrationEvents demonstrates event-driven architecture with OrderStartedIntegrationEvent and EventHandling, but no visible tests validate event publishing/subscription flows. This is critical for microservices reliability. Adding tests would catch race conditions and ensure events route correctly across services (especially important when adding new services).

  • [ ] Create tests/Basket.API.Tests/IntegrationEvents/ directory structure (matching src/ layout)
  • [ ] Write tests for src/Basket.API/IntegrationEvents/EventHandling/OrderStartedIntegrationEventHandler.cs validation logic
  • [ ] Add tests for src/Basket.API/IntegrationEvents/Events/OrderStartedIntegrationEvent.cs serialization/deserialization
  • [ ] Reference NuGet test framework (xUnit/NUnit) in Directory.Packages.props and document in CONTRIBUTING.md

🌿Good first issues

  • Add TypeScript-based e2e test for the 'Checkout' flow: Extend e2e/RemoveItemTest.spec.ts to include payment and order confirmation steps, following the existing login.setup.ts pattern. Currently only Add/Browse/Remove item tests exist.
  • Document Basket.API gRPC contract and usage:** Create a markdown guide in docs/ explaining the ServerCallContextIdentityExtensions.cs pattern and how other services should call Basket.API via gRPC with proper authentication headers—currently no service-to-service communication docs exist.
  • Add unit test coverage for src/Basket.API/Extensions/Extensions.cs:** The Extensions.cs file has no corresponding test file. Create Basket.API.Tests project with XUnit tests for extension methods, improving test coverage visible in CI workflows.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 9b4f943 — Update to Asp.Versioning to v10-preview2 (#980) (mikekistler)
  • b81ad95 — Update to Aspire 13.2 (#975) (eerhardt)
  • 5624ad5 — Upgrade to Aspire 13.1 (#939) (joperezr)
  • b832741 — Use latest xUnit, MSTest + move to MTP (#924) (Evangelink)
  • 74f15b1 — Update to Aspire 13 (#916) (eerhardt)
  • 1b2698c — Update to Aspire 9.5 (#900) (eerhardt)
  • 318e037 — Upgrading eshop to .NET 10 and Aspire 9.4.2 (#890) (joperezr)
  • 94e2643 — Inventory drift (#896) (wtgodbe)
  • 0ac6101 — Enable nullable in Catalog.API project (#882) (mikekistler)
  • a13002f — new suppressions (#885) (danmoseley)

🔒Security observations

The eShop reference application demonstrates a reasonable security posture as a well-

  • Medium · Outdated Playwright Dependency — package.json - devDependencies. The package.json specifies @playwright/test at ^1.42.1, which is from early 2024. Playwright releases frequent security updates. Using an outdated version may expose the test infrastructure to known vulnerabilities in the testing framework. Fix: Update @playwright/test to the latest stable version. Run 'npm audit' and 'npm update' to identify and patch vulnerable dependencies.
  • Medium · Potential Credential Exposure via Configuration Files — src/Basket.API/appsettings.json, src/Basket.API/appsettings.Development.json, src/Basket.API/Properties/launchSettings.json, and similar files in other projects. The codebase contains multiple configuration files (appsettings.json, appsettings.Development.json, launchSettings.json) which may contain sensitive data. If not properly managed, these files could expose database connection strings, API keys, or other credentials, especially in the Development variant. Fix: Ensure sensitive configuration values are stored in secure vaults (Azure Key Vault, AWS Secrets Manager) rather than configuration files. Use user secrets for local development. Add *.Development.json to .gitignore if not already present. Never commit credentials to source control.
  • Medium · CredScan Suppressions Present — .config/CredScanSuppressions.json. The presence of .config/CredScanSuppressions.json indicates that credential scanning has identified issues that were suppressed rather than remediated. This may indicate hardcoded secrets or credentials somewhere in the codebase that have been masked rather than removed. Fix: Review all suppressed credential warnings and remediate the root causes by removing hardcoded secrets. Replace with environment variables or secure credential management systems. Re-run credential scanning without suppressions.
  • Low · Dependency Audit Not Configured in CI/CD — .github/workflows/ - all workflow files. While package.json is present, there is no visible evidence of npm audit or automated dependency vulnerability scanning in the CI/CD workflows. The GitHub Actions workflows shown (.github/workflows/) do not explicitly reference npm security scanning. Fix: Add 'npm audit' or 'npm ci --audit' steps to the CI/CD pipeline. Consider integrating Dependabot (already present in dependabot.yml) configuration to automatically check for vulnerable dependencies and create PRs.
  • Low · Missing Security Headers Configuration Visibility — src/Basket.API/Program.cs, src/Catalog.API/Extensions/Extensions.cs and similar startup files. While the file structure shows API projects (Basket.API, Catalog.API), there is no visible configuration for security headers (CSP, HSTS, X-Frame-Options, etc.) in the partial code structure provided. Web applications should explicitly set these headers. Fix: Configure security headers in the ASP.NET Core middleware. Implement CSP, HSTS, X-Content-Type-Options, X-Frame-Options, and other relevant headers in the Program.cs or extension files.
  • Low · Proto Files Require Input Validation Review — src/Basket.API/Proto/basket.proto. The presence of .proto files (gRPC definitions) indicates gRPC services are used. gRPC services must validate all incoming messages to prevent injection attacks and malformed input exploitation. Fix: Ensure all gRPC service implementations (BasketService.cs) validate incoming messages for type, length, and content constraints. Implement proper error handling for invalid inputs.
  • Low · ORM Entity Configuration Requires SQL Injection Review — src/Catalog.API/Infrastructure/CatalogContext.cs, src/Catalog.API/Infrastructure/EntityConfigurations/. The presence of EntityConfigurations and CatalogContext suggests Entity Framework Core usage. While EF Core provides protection against SQL injection by default with parameterized queries, any raw SQL usage needs careful review. Fix: Audit all database access code to ensure no raw SQL queries are used without parameterization. If raw SQL is necessary, use parameterized queries exclusively. Review CatalogContextSeed.cs for any hardcoded test data that should not be in production.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · dotnet/eShop — RepoPilot