Skip to content

Commit 9631511

Browse files
authored
Merge pull request #462 from nanotaboada/fix/cors-middleware-order
fix(middleware): move `UseCors()` before `MapControllers()`, add inline docs (#451)
2 parents 7de7b87 + 4e2283b commit 9631511

File tree

3 files changed

+60
-7
lines changed

3 files changed

+60
-7
lines changed

CHANGELOG.md

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

5555
### Changed
5656

57+
- Call `.DisableRateLimiting()` on `MapHealthChecks("/health")` to enforce the exemption from the global rate limiter at the endpoint level, ensuring health check probes are never throttled (#451)
58+
- 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)
5759
- 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)
5860
- 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)
5961
- 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 & 6 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,53 @@
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();
73-
app.MapHealthChecks("/health");
91+
92+
// DisableRateLimiting() exempts the health check endpoint from the global rate
93+
// limiter so that monitoring and orchestration systems can always assess
94+
// liveness and readiness without being throttled.
95+
app.MapHealthChecks("/health").DisableRateLimiting();
96+
97+
// Enforces the fixed-window rate limiting policy defined during service
98+
// registration, returning 429 Too Many Requests when the limit is exceeded.
7499
app.UseRateLimiter();
75-
app.MapControllers();
76100

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

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

0 commit comments

Comments
 (0)