.NET5升级.NET8合并Startup与Program后Angular请求404
ASP.NET Core Angular升级.NET 8后API返回404问题排查
背景
为统一项目基础设施、复用通用代码(如日志配置),我将多个项目统一为相同.NET版本,其中2个基于Angular模板、2个基于Blazor模板,该方案可行。
随后将ASP.NET Core Angular应用从.NET 5升级至.NET 8,合并了Startup.cs与Program.cs,并参照.NET 8 Blazor应用配置添加了Serilog。应用可正常启动,但客户端Angular请求控制器API时返回HTTP 404错误。
相关代码
更新后的Program.cs
var builder = WebApplication.CreateBuilder(args); var databaseConfig = builder.Configuration.GetSection("Database").Get<DatabaseConfig>(); builder.Services.AddControllers(options => { options.Filters.Add(new SessionIdFilter()); }).AddJsonOptions(opts => opts.JsonSerializerOptions.PropertyNamingPolicy = null); // 生产环境下,Angular文件将从此目录提供 builder.Services.AddSpaStaticFiles(configuration => { configuration.RootPath = "ClientApp/dist"; }); builder.Services.AddSingleton(databaseConfig); builder.Services.AddDbContext<NumberDataContext>(options => { options.UseSqlServer(databaseConfig.ConnectionString); }); builder.Services.AddSession(options => { options.Cookie.Name = "SID"; options.IdleTimeout = TimeSpan.FromDays(30); }); builder.Services.Configure<CookiePolicyOptions>(options => { options.CheckConsentNeeded = _ => false; }); builder.Services.AddMvc(setup => { }).AddFluentValidation(); builder.Services.AddTransient<IValidator<UpdateEndedModel>, UpdateEndedModelValidator>(); builder.Services.AddScoped<ICheckService, CheckService>(); builder.Services.AddScoped<IGameService, GameService>(); builder.Services.AddScoped<ITutorialService, TutorialService>(); var logger = new LoggerConfiguration() .ReadFrom.Configuration(builder.Configuration) .Enrich.FromLogContext() .CreateLogger(); builder.Logging.ClearProviders(); builder.Logging.AddSerilog(logger); builder.Host.UseSerilog(logger); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); app.UseHsts(); } app.UseSession(); app.UseHttpsRedirection(); app.UseStaticFiles(); if (!app.Environment.IsDevelopment()) { app.UseSpaStaticFiles(); } app.UseRouting(); app.UseSpa(spa => { spa.Options.SourcePath = "ClientApp"; if (app.Environment.IsDevelopment()) { spa.UseAngularCliServer(npmScript: "start"); } }); app.MapControllers(); app.Run();
合并时移除的原代码
public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
问题原因
核心问题是中间件执行顺序错误:在.NET 6+的最小API模型中,UseSpa()中间件会捕获所有未匹配的请求并转发至SPA应用。当前代码中UseSpa()放在MapControllers()之前,导致控制器路由还未被匹配就被SPA中间件拦截,最终返回404。
解决方案
调整中间件顺序,将MapControllers()移至UseSpa()之前,确保路由先匹配控制器API:
app.UseRouting(); // 优先映射控制器路由,避免被SPA中间件拦截 app.MapControllers(); app.UseSpa(spa => { spa.Options.SourcePath = "ClientApp"; if (app.Environment.IsDevelopment()) { spa.UseAngularCliServer(npmScript: "start"); } });
额外检查项
- 确认控制器类上已添加
[ApiController]和[Route]属性,路由配置正确 - 开发环境下检查Angular的
proxy.conf.json,确保API请求被正确转发至后端 - 验证
builder.Services.AddControllers()和app.MapControllers()均已正确配置,无遗漏
内容的提问来源于stack exchange,提问作者user571203
相关产品推荐
相关产品推荐

