using YD_TrainingCompetition_Api.Competition; using YD_TrainingCompetition_Api.Hubs; using YD_TrainingCompetition_Api.Options; using YD_TrainingCompetition_Api.Protocols; using YD_TrainingCompetition_Api.Serial; using YD_TrainingCompetition_Api.Services; var builder = WebApplication.CreateBuilder(args); var listenUrls = builder.Configuration["ASPNETCORE_URLS"] ?? builder.Configuration["urls"] ?? "http://*:9996"; builder.WebHost.UseUrls(listenUrls); builder.Services.Configure(builder.Configuration.GetSection(ScoringOptions.SectionName)); builder.Services.Configure(builder.Configuration.GetSection(Serial24GOptions.SectionName)); builder.Services.Configure(builder.Configuration.GetSection(RosterOptions.SectionName)); builder.Services.Configure(builder.Configuration.GetSection(HikvisionOptions.SectionName)); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); builder.Services.AddSignalR(); builder.Services.AddCors(options => { options.AddDefaultPolicy(policy => { policy.AllowAnyHeader() .AllowAnyMethod() .SetIsOriginAllowed(_ => true) .AllowCredentials(); }); }); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddHostedService(); builder.Services.AddHostedService(); builder.Services.AddHostedService(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } // 提供打包后内置的前端静态资源(桌面端通过 http 加载,避免 file:// 下 fetch/绝对路径失效)。 // 使用可执行文件同级的 wwwroot 绝对路径,避免内容根/工作目录差异导致静态资源 404。 var webRootPath = Path.Combine(AppContext.BaseDirectory, "wwwroot"); var hasBundledFrontend = Directory.Exists(webRootPath); Microsoft.Extensions.FileProviders.PhysicalFileProvider? frontendFileProvider = null; if (hasBundledFrontend) { frontendFileProvider = new Microsoft.Extensions.FileProviders.PhysicalFileProvider(webRootPath); app.UseDefaultFiles(new DefaultFilesOptions { FileProvider = frontendFileProvider }); app.UseStaticFiles(new StaticFileOptions { FileProvider = frontendFileProvider }); } app.UseRouting(); app.UseCors(); app.MapControllers(); app.MapHub("/hubs/scoring"); // 单页应用兜底:非 API/Hub 路由回退到 index.html(仅当存在内置前端时生效)。 if (hasBundledFrontend && frontendFileProvider is not null) { app.MapFallbackToFile("index.html", new StaticFileOptions { FileProvider = frontendFileProvider }); } app.Run();