Files
EIS-dotnet/src/Eis.Web/Program.cs
T
biss e3c04dad8a 本轮迁移已完成,生产运行链路现已切换为纯 ASP.NET Core 10。
主要完成:
补齐招生学校计划、投档审核、报到、扫码、补录等原生接口。
新增 SQLite/MySQL 空库初始化及默认审批流、号码规则。
删除 Node 兼容代理,未知 API 直接返回原生 404。
Docker、Compose、Gitea CI 全部切换到 Eis.Web.dll。
CKEditor 已固化到 Web 发布资源,不再依赖 node_modules。
新增纯 .NET 冒烟脚本:[smoke-dotnet-native.ps1 (line 1)](C:/Users/BI/Documents/EIS-dotnet/scripts/smoke-dotnet-native.ps1:1)。
迁移状态已更新:[MIGRATION.md (line 14)](C:/Users/BI/Documents/EIS-dotnet/MIGRATION.md:14)。
容器入口见 [Dockerfile (line 31)](C:/Users/BI/Documents/EIS-dotnet/Dockerfile:31)。
2026-07-23 15:14:42 +08:00

219 lines
10 KiB
C#

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<IPublicSiteConfiguration, PublicSiteConfiguration>();
var authenticationOptions = AuthenticationOptions.FromEnvironment(
builder.Environment.IsProduction(),
builder.Configuration.GetValue<bool>("AuthenticationMigration:NativeEnabled"));
var candidateMigrationOptions = CandidateMigrationOptions.FromEnvironment(
builder.Configuration.GetValue<bool>("CandidateMigration:NativeEnabled"),
authenticationOptions.NativeEnabled,
authenticationOptions.SharesLegacySessions);
var adminMigrationOptions = AdminMigrationOptions.FromEnvironment(
builder.Configuration.GetValue<bool>("AdminMigration:NativeReadsEnabled"),
authenticationOptions.NativeEnabled,
authenticationOptions.SharesLegacySessions,
builder.Configuration.GetValue<bool>("AdminMigration:NativeOrganizationWritesEnabled"),
builder.Configuration.GetValue<bool>("AdminMigration:NativeAccountBatchesEnabled"),
builder.Configuration.GetValue<bool>("AdminMigration:NativeConfigurationEnabled"),
builder.Configuration.GetValue<bool>("AdminMigration:NativeNoticeManagementEnabled"),
builder.Configuration.GetValue<bool>("AdminMigration:NativeCentersEnabled"),
builder.Configuration.GetValue<bool>("AdminMigration:NativeOperationalReadsEnabled"),
builder.Configuration.GetValue<bool>("AdminMigration:NativeCandidateManagementEnabled"),
builder.Configuration.GetValue<bool>("AdminMigration:NativeRegistrationPaymentWritesEnabled"),
builder.Configuration.GetValue<bool>("AdminMigration:NativeWorkflowOperationsEnabled"),
builder.Configuration.GetValue<bool>("AdminMigration:NativeExamManagementEnabled"),
builder.Configuration.GetValue<bool>("AdminMigration:NativeArrangementsEnabled"),
builder.Configuration.GetValue<bool>("AdminMigration:NativeResultsEnabled"),
builder.Configuration.GetValue<bool>("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;