You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
REST API for managing football players built with ASP.NET Core 10. Implements CRUD operations with a layered architecture, EF Core + SQLite persistence, FluentValidation, AutoMapper, and in-memory caching. Part of a cross-language comparison study (Go, Java, Python, Rust, TypeScript).
5
+
REST API for managing football players built with ASP.NET Core 10. Implements CRUD operations with a layered architecture, EF Core + SQLite persistence, FluentValidation, AutoMapper, and in-memory caching. Part of a cross-language comparison study (Go, Java, Python, Rust, TypeScript). Primarily a learning and reference project — clarity and educational value take precedence over brevity.
├── Configurations/ — Options classes bound from appsettings.json
36
+
├── Middlewares/ — Custom ASP.NET Core middleware
37
+
├── Data/ — DbContext + DbInitializer (seed data)
38
+
└── Storage/ — SQLite database file (players.db)
33
39
34
40
test/Dotnet.Samples.AspNetCore.WebApi.Tests/
35
-
├── ControllersTests/
36
-
└── ServicesTests/
41
+
├── Unit/ — Unit tests (controllers, services, validators)
42
+
└── Utilities/ — Shared test helpers: PlayerFakes, PlayerMocks, PlayerStubs
37
43
```
38
44
39
45
**Layer rule**: `Controller → Service → Repository → Database`. Controllers must not access repositories directly. Business logic must not live in controllers.
40
46
47
+
**Cross-cutting**: `Program.cs` wires health checks (`GET /health`), rate limiting, CORS (dev only), and Swagger UI (dev only). Serilog is configured at host level. All validators are registered via `AddValidatorsFromAssemblyContaining<PlayerRequestModelValidator>()`.
| Service / Validator |`{MethodName}_{StateUnderTest}_{ExpectedBehavior}`|`RetrieveAsync_CacheMiss_QueriesRepositoryAndCachesResult`|
67
+
68
+
Each pattern has exactly three underscore-delimited segments. Do not add a fourth segment.
69
+
70
+
### FluentValidation rule sets
71
+
72
+
Validators use CRUD-named rule sets to make intent explicit. Use `RuleSet("Create", ...)` and `RuleSet("Update", ...)` — never anonymous / default rules.
73
+
74
+
```csharp
75
+
// "Create" rule set — POST /players
76
+
// Includes BeUniqueSquadNumber to prevent duplicate squad numbers on insert.
77
+
RuleSet("Create", () => {
78
+
RuleFor(p=>p.SquadNumber)
79
+
.MustAsync(BeUniqueSquadNumber).WithMessage("SquadNumber must be unique.");
80
+
// ... other rules
81
+
});
82
+
83
+
// "Update" rule set — PUT /players/squadNumber/{n}
84
+
// BeUniqueSquadNumber intentionally omitted: the player already exists in DB.
85
+
RuleSet("Update", () => {
86
+
// ... same structural rules, no uniqueness check
87
+
});
88
+
```
89
+
90
+
Controllers must call the appropriate rule set explicitly:
`ValidateAsync(T, Action<ValidationStrategy<T>>)` is a FluentValidation extension method. Internally it calls `ValidateAsync(IValidationContext, CancellationToken)`. Moq must target the **interface overload**, not the generic one:
102
+
103
+
```csharp
104
+
// ✅ Correct — matches the overload actually called at runtime
- FluentValidation rule set structure (adding or removing rule sets affects controller callers and tests)
101
177
102
178
### Never modify
103
179
104
180
- Production configurations or deployment secrets
105
181
-`.runsettings` coverage thresholds
106
182
- Port configuration (9000)
107
183
- Database type (SQLite — demo/dev only)
184
+
- CD pipeline tag format (`vX.Y.Z-stadium`) or the stadium name sequence — names are assigned sequentially A→Z from the list in `CHANGELOG.md`; the next name is always the next unused letter
108
185
109
186
### Key workflows
110
187
111
-
**Add an endpoint**: Add DTO in `Models/` → update `PlayerMappingProfile` in `Mappings/`(AutoMapper) → add repository method(s) in `Repositories/` → add service method in `Services/` → add controller action in `Controllers/` → add validator in `Validators/` → add tests → run pre-commit checks.
188
+
**Add an endpoint**: Add DTO in `Models/` → update `PlayerMappingProfile` in `Mappings/` → add repository method(s) in `Repositories/` → add service method in `Services/` → add controller action in `Controllers/` → add/update validator rule set in `Validators/` → add tests in `test/.../Unit/` → run pre-commit checks.
0 commit comments