背景
我想将现有的 React 应用程序集成到 ASP.NET Core Web 应用程序。目标是能够启动 ASP.NET Core Web 项目并呈现 React 应用程序,就像我通过从
npm start
文件夹运行 ClientApp
来呈现它一样。
设置
为了检查它,我使用 VS2022 新项目模板“带有 React.js 和 Redux 的 ASP.NET Core”创建了一个新的 ASP.NET Core 应用程序。该项目样板文件最多只支持 .NET 5.0,所以我立即将项目升级到 .NET 7.0,它按预期工作:显示一个带有计数器和获取数据的菜单,React 和 Redux 代码都运行良好,并在我在调试模式下启动了由 IIS Express 提供服务的 ASP.NET Core Web 应用程序。从文件夹
npm start
(由 VS 自动创建)中运行命令 ClientApp
也呈现相同的前端。
在我看来,运行ASP.NET Core项目通过运行
npm start
达到同样的效果主要是通过Startup.cs
中的这段代码完成的:
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
替换 ClientApp 内容
现在我用我自己的 React 应用程序替换了整个
ClientApp
文件夹的内容(相信这个 的指导)。为了确保 React 代码有效,我从内部运行了常用命令ClientApp
:
npm install, npm run build, npm start
一切顺利。
npm start
运行的时候,渲染到https://localhost:3000/就好了,如下图:
所以,独自一人,一切正常。
错误
现在
npm start
文件夹中的 ClientApp
可以正常工作,据说无需更改任何内容(因为我们已经在 Startup
中设置了它):
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
我希望在浏览器中看到相同的 React 应用程序渲染,就像我之前从
npm start
文件夹中运行 ClientApp
时看到的那样。
但是,我得到了这个神秘的错误:
处理请求时发生未处理的异常。
IOException:响应过早结束。
System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage 请求,布尔异步,CancellationToken cancellationToken)
HttpRequestException:发送请求时发生错误。
System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage 请求,布尔异步,CancellationToken cancellationToken)HttpRequestException: Failed to proxy the request to http://localhost:62632/,因为对代理目标的请求失败。检查代理目标服务器是否正在运行并接受对 http://localhost:62632/ 的请求。
底层异常消息是“发送请求时发生错误。”。检查 InnerException 以获取更多详细信息。
Microsoft.AspNetCore.SpaServices.Extensions.Proxy.SpaProxy.PerformProxyRequest(HttpContext 上下文,HttpClient httpClient,Task baseUriTask,CancellationToken applicationStoppingToken,bool proxy404s)
为什么要动态端口号?
从错误中可以看出,每次我运行 ASP.NET Core Web 项目时,应用程序似乎都试图向
http://localhost:[dynamic port]
发送请求。为什么会这样以及如何配置应用程序不这样做?我看不到任何可以设置的地方。
这是我的
launchSettings.json
:
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:28790",
"sslPort": 44360
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Actsoft.CAB.Manager.Core.React": {
"commandName": "IIS",
"launchBrowser": true,
"applicationUrl": "https://localhost:3000;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
这是项目元文件:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
<IsPackable>false</IsPackable>
<SpaRoot>ClientApp\</SpaRoot>
<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
<StartupObject>MyApp.Core.React.Program</StartupObject>
<PackageProjectUrl>https://localhost:44360</PackageProjectUrl>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="5.0.17" />
</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>
<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)build\**; $(SpaRoot)build-ssr\**" />
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
<RelativePath>%(DistFiles.Identity)</RelativePath>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</ResolvedFileToPublish>
</ItemGroup>
</Target>
</Project>
总结
npm start
文件夹中运行 ClientApp
时运行良好npm start
但不知何故它一直向动态 http 端口发送 http 请求并出错。如何解决这个动态端口分配似乎是关键?
我也试过在 Startup 中做这一行
spa.UseProxyToSpaDevelopmentServer("https://localhost:44360")
它也没有用。
提前感谢您的帮助!