Skip to content

Commit 2774c66

Browse files
nanotaboadaclaude
andcommitted
fix(middleware): move UseCors() before MapControllers(), add inline docs (#451)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 7de7b87 commit 2774c66

3 files changed

Lines changed: 59 additions & 6 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ This project uses famous football stadiums (A-Z) that hosted FIFA World Cup matc
5454

5555
### Changed
5656

57+
- Move `UseCors()` before `MapControllers()` in `Program.cs` to follow the standard ASP.NET Core middleware pipeline order; add an `Infrastructure` service registration section separating cross-cutting concerns (health checks, CORS, rate limiting, Swagger) from the `Controllers` section; add descriptive phrases to top-level section banners; add inline comments explaining the purpose and ordering rationale of each middleware; document the dev-only CORS policy intent in both `Program.cs` and `ServiceCollectionExtensions.AddCorsDefaultPolicy` (#451)
5758
- Replace pre-seeded `storage/players-sqlite3.db` binary blob with EF Core `MigrateAsync()` at startup: schema and seed data are now applied automatically before the first request is served; `STORAGE_PATH` env var controls the database file path (Docker volume path in production, `AppContext.BaseDirectory/storage/` locally); the committed database file, `Dockerfile` db copy step, and `scripts/run-migrations-and-copy-database.sh` have been removed (#459)
5859
- Recreate EF Core migrations using `HasData()` in `OnModelCreating`: three self-contained migrations (`InitialCreate` DDL, `SeedStarting11` DML, `SeedSubstitutes` DML) generated by EF Core with literal `InsertData` values — no migration calls application methods; `NormalizePlayerDataset` patch migration eliminated by folding corrections into seed data from the start (#459)
5960
- Replace `DatabaseFakes.CreateTable()` (placeholder schema) and `DatabaseFakes.Seed()` (manual insert bypassing migrations) with `DatabaseFakes.MigrateAsync()`, which applies the full EF Core migration chain on in-memory SQLite (#459)

src/Dotnet.Samples.AspNetCore.WebApi/Extensions/ServiceCollectionExtensions.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,21 @@ IWebHostEnvironment environment
5454
}
5555

5656
/// <summary>
57-
/// Adds a default CORS policy that allows any origin, method, and header.
57+
/// Adds a default CORS policy that allows any origin, method, and header,
58+
/// restricted to the Development environment.
5859
/// <br />
5960
/// <see href="https://learn.microsoft.com/en-us/aspnet/core/security/cors"/>
6061
/// </summary>
62+
/// <remarks>
63+
/// The permissive wildcard policy (AllowAnyOrigin, AllowAnyMethod, AllowAnyHeader)
64+
/// is intentional for local development, where Swagger UI and local frontends
65+
/// need unrestricted cross-origin access. No CORS policy is registered in
66+
/// Production or other environments, where the API is assumed to be consumed
67+
/// server-to-server or to sit behind a reverse proxy on the same origin, making
68+
/// CORS irrelevant. If a production frontend on a different domain is ever added,
69+
/// replace this with a restrictive named policy that enumerates specific allowed
70+
/// origins instead of using a wildcard.
71+
/// </remarks>
6172
/// <param name="services">The IServiceCollection instance.</param>
6273
/// <param name="environment">The web host environment.</param>
6374
/// <returns>The IServiceCollection for method chaining.</returns>

src/Dotnet.Samples.AspNetCore.WebApi/Program.cs

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55

66
/* -----------------------------------------------------------------------------
77
* Web Application
8+
* Registers all services into the DI container before the application is built.
9+
* Throughout this section, builder.Services refers to the ASP.NET Core
10+
* dependency injection (DI) container — not to be confused with the Services
11+
* subsection below, which registers our own application-level business logic.
812
* https://learn.microsoft.com/en-us/aspnet/core/fundamentals/startup
913
* -------------------------------------------------------------------------- */
1014

@@ -22,11 +26,9 @@
2226
Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(builder.Configuration).CreateLogger();
2327
builder.Host.UseSerilog();
2428

25-
/* Controllers -------------------------------------------------------------- */
29+
/* Infrastructure ----------------------------------------------------------- */
2630

2731
builder.Services.AddHealthChecks();
28-
builder.Services.AddControllers();
29-
builder.Services.AddValidators();
3032
builder.Services.AddCorsDefaultPolicy(builder.Environment);
3133
builder.Services.AddFixedWindowRateLimiter(builder.Configuration);
3234

@@ -35,7 +37,12 @@
3537
builder.Services.AddSwaggerConfiguration(builder.Configuration);
3638
}
3739

38-
/* Services ----------------------------------------------------------------- */
40+
/* Controllers -------------------------------------------------------------- */
41+
42+
builder.Services.AddControllers();
43+
builder.Services.AddValidators();
44+
45+
/* Services (Business Logic) ------------------------------------------------ */
3946

4047
builder.Services.RegisterPlayerService();
4148
builder.Services.AddMemoryCache();
@@ -53,6 +60,7 @@
5360

5461
/* -----------------------------------------------------------------------------
5562
* Database Migration
63+
* Applies pending EF Core migrations at startup, before the app accepts requests.
5664
* https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/applying#apply-migrations-at-runtime
5765
* -------------------------------------------------------------------------- */
5866

@@ -64,21 +72,54 @@
6472

6573
/* -----------------------------------------------------------------------------
6674
* Middlewares
75+
* Defines the order in which middleware components process each HTTP request.
6776
* https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware
77+
* https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware#middleware-order
6878
* -------------------------------------------------------------------------- */
6979

80+
// Replaces the default ASP.NET Core request logging with Serilog's structured
81+
// logging, emitting one log entry per request with timing, status code, and
82+
// other contextual properties.
7083
app.UseSerilogRequestLogging();
84+
85+
// Custom middleware that catches unhandled exceptions and returns a consistent
86+
// RFC 7807 Problem Details response instead of exposing a raw stack trace.
7187
app.UseExceptionHandling();
88+
89+
// Redirects all plain HTTP requests to HTTPS, enforcing transport security.
7290
app.UseHttpsRedirection();
91+
92+
// Intentionally registered before UseRateLimiter so that health check probes
93+
// always succeed regardless of rate-limiting thresholds, allowing monitoring
94+
// and orchestration systems to assess liveness and readiness without being
95+
// throttled.
7396
app.MapHealthChecks("/health");
97+
98+
// Enforces the fixed-window rate limiting policy defined during service
99+
// registration, returning 429 Too Many Requests when the limit is exceeded.
74100
app.UseRateLimiter();
75-
app.MapControllers();
76101

77102
if (app.Environment.IsDevelopment())
78103
{
104+
// Only active in Development, where AddCorsDefaultPolicy registers a
105+
// permissive wildcard policy for Swagger UI and local frontends. No policy
106+
// exists in Production — the API is assumed to be consumed server-to-server
107+
// or behind a reverse proxy on the same origin, where CORS is not needed.
108+
// Must precede MapControllers so CORS headers are applied before any
109+
// endpoint executes, consistent with the standard middleware pipeline order.
79110
app.UseCors();
111+
112+
// Generates the OpenAPI JSON document consumed by Swagger UI.
80113
app.UseSwagger();
114+
115+
// Serves the interactive Swagger UI at /swagger, allowing manual
116+
// exploration and testing of the API endpoints during development.
81117
app.UseSwaggerUI();
82118
}
83119

120+
// Routes incoming HTTP requests to the matching controller actions. Must come
121+
// after all middleware that needs to run before endpoint execution (CORS, rate
122+
// limiting, etc.).
123+
app.MapControllers();
124+
84125
await app.RunAsync();

0 commit comments

Comments
 (0)