using Elternbeirat.Web.Components; using Elternbeirat.Web.Features.Events; using Elternbeirat.Web.Services; using Microsoft.AspNetCore.HttpOverrides; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddRazorComponents(); // Content is read once at startup and cached -> singletons. builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); var app = builder.Build(); // NPM terminates TLS and is the only way to reach the container (no port // mapping in production). Without UseForwardedHeaders the app sees every request // as HTTP and with the proxy IP instead of the client IP. // KnownNetworks/KnownProxies are deliberately empty because only NPM reaches // the container. app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto, KnownIPNetworks = { }, KnownProxies = { } }); // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error", createScopeForErrors: true); // No UseHsts() and no UseHttpsRedirection(): NPM sets HSTS and terminates // TLS. Both here would create a redirect loop behind the proxy. } app.UseStatusCodePagesWithReExecute("/not-found", createScopeForStatusCodePages: true); app.UseAntiforgery(); app.MapStaticAssets(); app.MapRazorComponents(); // Subscribable calendar feed of all events. A minimal API endpoint rather than // a Razor page because it returns text/calendar, not HTML. app.MapGet("/termine.ics", (EventService events) => Results.Text(IcsCalendar.Build(events.All), "text/calendar; charset=utf-8")); app.Run();