如何在同一域名下同时托管.NET7 React SPA与.NET4.7 MVC遗留项目?
项目迁移与SPA配置问题解决
背景
我们正在进行渐进式项目迁移:从基于.NET 4.7 Framework的ASP.NET MVC遗留系统,迁移至.NET 7 Core后端+React(搭配Vite)前端架构。项目规模较大,已完成90%前端迁移、60%后端迁移。当前React并非真正SPA,而是由遗留项目每个View渲染独立React包。目标是将React改造为.NET 7托管的真正SPA,部分页面(如开发连接页、管理页)仍留在遗留项目中,要求:
- React页面路径:
XXXXX/pro/pageA - 遗留页面路径:
XXXXX/pageB(XXXXX为同一地址,如localhost)
当前问题
- .NET 7项目无法启动Vite服务
- 单独启动Vite时提示端口80已被占用
相关配置信息
Vite配置(vite.config.js)
export default defineConfig({ plugins: [react(), tsconfigPaths()], build: { outDir: 'build', }, base: '/pro', server: { strictPort: true, port: 80, host: true } });
.NET 7 Program.cs片段
builder.Services.AddSpaStaticFiles(filesOptions => filesOptions.RootPath = "ClientApp/build"); app.UseStaticFiles(); app.UseSpaStaticFiles(); app.UseRouting(); app.Run();
.NET 7 launchSettings.json
{ "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iis": { "applicationUrl": "http://localhost/pro" }, "profiles": { "WebPro": { "commandName": "Project", "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development", "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy" } }, }
.NET 7 .csproj
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>net7.0</TargetFramework> <RootNamespace>WebPro</RootNamespace> <AssemblyName>WebPro</AssemblyName> <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked> <TypeScriptToolsVersion>Latest</TypeScriptToolsVersion> <IsPackable>true</IsPackable> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> <SpaRoot>ClientApp\</SpaRoot> <DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes> <SpaProxyServerUrl>http://localhost:80/pro</SpaProxyServerUrl> <SpaProxyLaunchCommand>npm run dev</SpaProxyLaunchCommand> <!-- Set this to true if you enable server-side prerendering --> <BuildServerSideRenderer>false</BuildServerSideRenderer> <UserSecretsId>efad71c6-743c-4b87-9de8-f26d77146f6d</UserSecretsId> </PropertyGroup> <ItemGroup> <PackageReference Include="FluentValidation.AspNetCore" Version="10.3.4" /> <PackageReference Include="Microsoft.AspNetCore.OData" Version="8.0.10" /> <PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="7.0.5" /> <PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="6.0.0" /> <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.10.8" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> <PackageReference Include="NewRelic.LogEnrichers.Serilog" Version="1.0.1" /> <PackageReference Include="Serilog" Version="2.10.0" /> <PackageReference Include="Serilog.AspNetCore" Version="4.1.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" /> <PackageReference Include="System.ServiceModel.Duplex" Version="4.10.*" /> <PackageReference Include="System.ServiceModel.Federation" Version="4.10.*" /> <PackageReference Include="System.ServiceModel.Http" Version="4.10.*" /> <PackageReference Include="System.ServiceModel.NetTcp" Version="4.10.*" /> <PackageReference Include="System.ServiceModel.Security" Version="4.10.*" /> </ItemGroup> <ItemGroup> <!-- Don't publish the SPA source files, but do show them in the project files list --> <Content Remove="$(SpaRoot)**" /> <None Remove="$(SpaRoot)**" /> <None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" /> </ItemGroup> <PropertyGroup> <RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent> </PropertyGroup> <Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') "> <!-- Ensure Node.js is installed --> <Exec Command="node --version" ContinueOnError="true"> <Output TaskParameter="ExitCode" PropertyName="ErrorCode" /> </Exec> <Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." /> <Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." /> <Exec WorkingDirectory="$(SpaRoot)" Command="npm install" /> </Target> <Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish"> <!-- As part of publishing, ensure the JS resources are freshly built in production mode --> <Exec WorkingDirectory="$(SpaRoot)" Command="npm install" /> <Exec WorkingDirectory="$(SpaRoot)" Command="npm run build" /> <!-- Include the newly-built files in the publish output --> <ItemGroup> <DistFiles Include="$(SpaRoot)dist\**" /> <ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)"> <RelativePath>wwwroot\%(RecursiveDir)%(FileName)%(Extension)</RelativePath> <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> <ExcludeFromSingleFile>true</ExcludeFromSingleFile> </ResolvedFileToPublish> </ItemGroup> </Target> </Project>
解决方案
1. 解决端口占用问题
端口80被占用大概率是遗留.NET 4.7项目或其他服务正在使用:
- 先关闭遗留项目,再尝试启动Vite;
- 或修改Vite为非80端口(如默认的5173),调整Vite配置:
同时更新server: { strictPort: true, port: 5173, host: true }.csproj中的SpaProxyServerUrl为http://localhost:5173/pro
2. 修复.NET 7启动Vite服务的问题
- 完善
launchSettings.json的WebPro配置,添加独立端口避免冲突:"profiles": { "WebPro": { "commandName": "Project", "launchBrowser": true, "applicationUrl": "http://localhost:5000", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development", "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy" } } - 补充Program.cs的SPA路由配置,确保
/pro请求转发到Vite开发服务器:app.UseRouting(); // 放置其他中间件(如授权、API路由等) app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); app.UseSpa(spa => { spa.Options.SourcePath = "ClientApp"; if (builder.Environment.IsDevelopment()) { spa.UseProxyToSpaDevelopmentServer("http://localhost:5173/pro"); } }); app.Run(); - 修正
.csproj的发布目标,匹配Vite的build输出目录:<DistFiles Include="$(SpaRoot)build\**" />
3. 实现路径分流(.NET 7与遗留项目共存)
要让/pro路径走.NET 7+SPA、其余路径走遗留项目,可通过IIS配置:
- 配置两个站点:遗留项目绑定
localhost处理非/pro请求,.NET 7项目绑定localhost/pro处理/pro开头请求; - 或使用IIS URL重写规则,将
/pro/*请求转发到.NET 7项目,其余请求转发到遗留项目。
内容的提问来源于stack exchange,提问作者Nico_tvn
相关产品推荐
相关产品推荐

