using Eis.Infrastructure.Authentication; using Eis.Infrastructure.Administration; using Eis.Infrastructure.Candidate; using Eis.Infrastructure.Caching; using Eis.Application.Public; using Eis.Infrastructure; using Eis.Infrastructure.Data; using Eis.Infrastructure.Migration; using Eis.Infrastructure.Security; using Eis.Web.Configuration; using Eis.Web.Authentication; using Eis.Web.Administration; using Eis.Web.Candidate; using Eis.Web.Frontend; using Eis.Web.Public; var applicationRoot = ApplicationPaths.FindApplicationRoot(); EnvironmentFile.Load(applicationRoot); var builder = WebApplication.CreateBuilder(args); builder.WebHost.ConfigureKestrel(options => options.AddServerHeader = false); builder.Services.AddProblemDetails(); builder.Services.AddSingleton(); var authenticationOptions = AuthenticationOptions.FromEnvironment( builder.Environment.IsProduction(), builder.Configuration.GetValue("AuthenticationMigration:NativeEnabled")); var candidateMigrationOptions = CandidateMigrationOptions.FromEnvironment( builder.Configuration.GetValue("CandidateMigration:NativeEnabled"), authenticationOptions.NativeEnabled, authenticationOptions.SharesLegacySessions); var adminMigrationOptions = AdminMigrationOptions.FromEnvironment( builder.Configuration.GetValue("AdminMigration:NativeReadsEnabled"), authenticationOptions.NativeEnabled, authenticationOptions.SharesLegacySessions, builder.Configuration.GetValue("AdminMigration:NativeOrganizationWritesEnabled"), builder.Configuration.GetValue("AdminMigration:NativeAccountBatchesEnabled"), builder.Configuration.GetValue("AdminMigration:NativeConfigurationEnabled"), builder.Configuration.GetValue("AdminMigration:NativeNoticeManagementEnabled"), builder.Configuration.GetValue("AdminMigration:NativeCentersEnabled"), builder.Configuration.GetValue("AdminMigration:NativeOperationalReadsEnabled"), builder.Configuration.GetValue("AdminMigration:NativeCandidateManagementEnabled"), builder.Configuration.GetValue("AdminMigration:NativeRegistrationPaymentWritesEnabled"), builder.Configuration.GetValue("AdminMigration:NativeWorkflowOperationsEnabled"), builder.Configuration.GetValue("AdminMigration:NativeExamManagementEnabled"), builder.Configuration.GetValue("AdminMigration:NativeArrangementsEnabled"), builder.Configuration.GetValue("AdminMigration:NativeResultsEnabled"), builder.Configuration.GetValue("AdminMigration:NativeAdmissionsEnabled")); builder.Services.AddEisInfrastructure( DatabaseOptions.FromEnvironment(applicationRoot, builder.Environment.IsProduction()), DocumentVerificationOptions.FromEnvironment(builder.Environment.IsProduction()), authenticationOptions, candidateMigrationOptions, adminMigrationOptions); var app = builder.Build(); await app.Services.InitializeEisDatabaseAsync(); app.Services.EnsureNativeAuthenticationReady(authenticationOptions); app.UseExceptionHandler(); app.Use(async (context, next) => { context.Response.Headers.XContentTypeOptions = "nosniff"; context.Response.Headers.XFrameOptions = "DENY"; context.Response.Headers["Referrer-Policy"] = "same-origin"; await next(); }); app.MapGet("/health/live", () => Results.Json(new { status = "healthy", service = "Eis.Web", framework = ".NET 10" })); app.MapGet("/health/migration", (IApplicationCache cache) => { return Results.Json(new { status = "healthy", legacyApiAvailable = false, legacyApiRemoved = true, cache = new { status = cache.Status, redisEnabled = cache.Enabled, localFallback = true, namespaces = new[] { "public", "results" } }, authentication = new { nativeEnabled = authenticationOptions.NativeEnabled, stateBackend = authenticationOptions.UsesRedis ? "redis" : "memory", sharesLegacySessions = authenticationOptions.SharesLegacySessions }, candidate = new { nativeEnabled = candidateMigrationOptions.NativeEnabled, nativeRoutes = candidateMigrationOptions.NativeEnabled ? new[] { "GET dashboard", "GET notices", "GET/PUT profile", "GET exams", "GET/POST registrations", "GET results", "POST result appeals", "GET admit cards", "GET admissions", "PUT admission preferences" } : [] }, administration = new { nativeReadsEnabled = adminMigrationOptions.NativeReadsEnabled, nativeOrganizationWritesEnabled = adminMigrationOptions.NativeOrganizationWritesEnabled, nativeAccountBatchesEnabled = adminMigrationOptions.NativeAccountBatchesEnabled, nativeConfigurationEnabled = adminMigrationOptions.NativeConfigurationEnabled, nativeNoticeManagementEnabled = adminMigrationOptions.NativeNoticeManagementEnabled, nativeCentersEnabled = adminMigrationOptions.NativeCentersEnabled, nativeOperationalReadsEnabled = adminMigrationOptions.NativeOperationalReadsEnabled, nativeCandidateManagementEnabled = adminMigrationOptions.NativeCandidateManagementEnabled, nativeRegistrationPaymentWritesEnabled = adminMigrationOptions.NativeRegistrationPaymentWritesEnabled, nativeWorkflowOperationsEnabled = adminMigrationOptions.NativeWorkflowOperationsEnabled, nativeExamManagementEnabled = adminMigrationOptions.NativeExamManagementEnabled, nativeArrangementsEnabled = adminMigrationOptions.NativeArrangementsEnabled, nativeResultsEnabled = adminMigrationOptions.NativeResultsEnabled, nativeAdmissionsEnabled = adminMigrationOptions.NativeAdmissionsEnabled, nativeRoutes = (adminMigrationOptions.NativeReadsEnabled ? new[] { "GET context", "GET dashboard", "GET schools", "GET school-organization", "GET admins", "GET exams" } : []) .Concat(adminMigrationOptions.NativeOrganizationWritesEnabled ? new[] { "POST/PATCH schools", "POST/PATCH classes", "POST/PATCH admins", "POST admin password reset", "PUT self-registration setting" } : []) .Concat(adminMigrationOptions.NativeAccountBatchesEnabled ? new[] { "GET/POST/PATCH candidate-account-batches" } : []) .Concat(adminMigrationOptions.NativeConfigurationEnabled ? new[] { "GET/POST number-rules", "GET/PUT workflows" } : []) .Concat(adminMigrationOptions.NativeNoticeManagementEnabled ? new[] { "GET/POST/PATCH notices", "PATCH system publications" } : []) .Concat(adminMigrationOptions.NativeCentersEnabled ? new[] { "GET/POST/PATCH centers", "PATCH center-change-requests" } : []) .Concat(adminMigrationOptions.NativeOperationalReadsEnabled ? new[] { "GET candidates", "GET registrations", "GET payments" } : []) .Concat(adminMigrationOptions.NativeCandidateManagementEnabled ? new[] { "POST candidate-accounts/archive", "POST candidate reset-password", "PATCH candidates" } : []) .Concat(adminMigrationOptions.NativeRegistrationPaymentWritesEnabled ? new[] { "PATCH registrations", "PATCH payments" } : []) .Concat(adminMigrationOptions.NativeWorkflowOperationsEnabled ? new[] { "GET workflow-instances", "PATCH workflow transfer/supervise" } : []) .Concat(adminMigrationOptions.NativeExamManagementEnabled ? new[] { "POST/PATCH exams", "POST exam archive" } : []) .Concat(adminMigrationOptions.NativeArrangementsEnabled ? new[] { "GET admission-arrangements", "POST arrangement preview/apply", "GET admission exports" } : []) .Concat(adminMigrationOptions.NativeResultsEnabled ? new[] { "GET/POST results", "POST result bulk", "POST/PATCH feature scores", "PATCH score appeals", "GET result Excel export" } : []) .Concat(adminMigrationOptions.NativeAdmissionsEnabled ? new[] { "GET admissions/indicator qualifications", "PUT qualification single/bulk", "POST/PATCH/reset admission-school accounts", "PUT admission settings", "POST/PATCH admission plans", "POST admission match/finalize/supplementary", "PATCH admission reporting/withdrawals", "GET/POST admin Excel", "GET/PUT admission notice template", "GET/POST admission reporting Excel", "GET admission placement Excel" } : []) .ToArray() }, features = MigrationFeatureCatalog.Current(authenticationOptions.NativeEnabled, candidateMigrationOptions.NativeEnabled) }, statusCode: StatusCodes.Status200OK); }); app.MapNativePublicEndpoints(); app.MapNativeAuthenticationEndpoints(authenticationOptions); app.MapNativeCandidateEndpoints(candidateMigrationOptions); app.MapNativeAdminReadEndpoints(adminMigrationOptions); string[] methods = [ HttpMethods.Get, HttpMethods.Head, HttpMethods.Post, HttpMethods.Put, HttpMethods.Patch, HttpMethods.Delete, HttpMethods.Options ]; app.MapMethods("/api/{**path}", methods, (HttpContext context) => { context.Response.Headers.CacheControl = "no-store"; context.Response.Headers["X-EIS-Implementation"] = "aspnet-core"; return Results.Json( new { ok = false, message = "API 接口不存在" }, statusCode: StatusCodes.Status404NotFound); }); app.MapFrontendAssets(); app.Run(); public partial class Program;