Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ This project uses famous football stadiums (A-Z) that hosted FIFA World Cup matc

### Changed

- 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)
- 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)
- 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)
- 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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,21 @@ IWebHostEnvironment environment
}

/// <summary>
/// Adds a default CORS policy that allows any origin, method, and header.
/// Adds a default CORS policy that allows any origin, method, and header,
/// restricted to the Development environment.
/// <br />
/// <see href="https://learn.microsoft.com/en-us/aspnet/core/security/cors"/>
/// </summary>
/// <remarks>
/// The permissive wildcard policy (AllowAnyOrigin, AllowAnyMethod, AllowAnyHeader)
/// is intentional for local development, where Swagger UI and local frontends
/// need unrestricted cross-origin access. No CORS policy is registered in
/// Production or other environments, where the API is assumed to be consumed
/// server-to-server or to sit behind a reverse proxy on the same origin, making
/// CORS irrelevant. If a production frontend on a different domain is ever added,
/// replace this with a restrictive named policy that enumerates specific allowed
/// origins instead of using a wildcard.
/// </remarks>
/// <param name="services">The IServiceCollection instance.</param>
/// <param name="environment">The web host environment.</param>
/// <returns>The IServiceCollection for method chaining.</returns>
Expand Down
51 changes: 46 additions & 5 deletions src/Dotnet.Samples.AspNetCore.WebApi/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@

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

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

/* Controllers -------------------------------------------------------------- */
/* Infrastructure ----------------------------------------------------------- */

builder.Services.AddHealthChecks();
builder.Services.AddControllers();
builder.Services.AddValidators();
builder.Services.AddCorsDefaultPolicy(builder.Environment);
builder.Services.AddFixedWindowRateLimiter(builder.Configuration);

Expand All @@ -35,7 +37,12 @@
builder.Services.AddSwaggerConfiguration(builder.Configuration);
}

/* Services ----------------------------------------------------------------- */
/* Controllers -------------------------------------------------------------- */

builder.Services.AddControllers();
builder.Services.AddValidators();

/* Services (Business Logic) ------------------------------------------------ */

builder.Services.RegisterPlayerService();
builder.Services.AddMemoryCache();
Expand All @@ -53,6 +60,7 @@

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

Expand All @@ -64,21 +72,54 @@

/* -----------------------------------------------------------------------------
* Middlewares
* Defines the order in which middleware components process each HTTP request.
* https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware
* https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware#middleware-order
* -------------------------------------------------------------------------- */

// Replaces the default ASP.NET Core request logging with Serilog's structured
// logging, emitting one log entry per request with timing, status code, and
// other contextual properties.
app.UseSerilogRequestLogging();

// Custom middleware that catches unhandled exceptions and returns a consistent
// RFC 7807 Problem Details response instead of exposing a raw stack trace.
app.UseExceptionHandling();

// Redirects all plain HTTP requests to HTTPS, enforcing transport security.
app.UseHttpsRedirection();

// Intentionally registered before UseRateLimiter so that health check probes
// always succeed regardless of rate-limiting thresholds, allowing monitoring
// and orchestration systems to assess liveness and readiness without being
// throttled.
app.MapHealthChecks("/health");

// Enforces the fixed-window rate limiting policy defined during service
// registration, returning 429 Too Many Requests when the limit is exceeded.
app.UseRateLimiter();
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
app.MapControllers();

if (app.Environment.IsDevelopment())
{
// Only active in Development, where AddCorsDefaultPolicy registers a
// permissive wildcard policy for Swagger UI and local frontends. No policy
// exists in Production — the API is assumed to be consumed server-to-server
// or behind a reverse proxy on the same origin, where CORS is not needed.
// Must precede MapControllers so CORS headers are applied before any
// endpoint executes, consistent with the standard middleware pipeline order.
app.UseCors();

// Generates the OpenAPI JSON document consumed by Swagger UI.
app.UseSwagger();

// Serves the interactive Swagger UI at /swagger, allowing manual
// exploration and testing of the API endpoints during development.
app.UseSwaggerUI();
}

// Routes incoming HTTP requests to the matching controller actions. Must come
// after all middleware that needs to run before endpoint execution (CORS, rate
// limiting, etc.).
app.MapControllers();

await app.RunAsync();
Loading