Asp.net 核心和 Angular 在生产中:没有提供 Spa

Asp.net core and Angular in production: Spa is not being served

我的 Web 应用程序是从 dotnet 核心 3.0 Angular 模板构建的。我想将第一个版本部署到生产环境中,但我正在努力提供 Angular 应用程序。我正在使用 Kestrel 作为网络服务器(它是一个内部网应用程序)。

我已经使用 dotnet publish -c Release -o ../app-dist 发布了构建 Asp.net 应用程序的应用程序,它触发了 ng 构建客户端的生产版本。生成的文件夹结构包括一个 app-dist/wwwroot 文件夹,其中包含一些资产,如网站图标,并且它有一个 app-dist/ClientApp/dist/app 文件夹,其中包含 index.html 以及编译的 jscss 资产.如果我在 app-dist 中通过 运行ning dotnet app.dll 启动应用程序,Kestrel 会启动但无法为客户端应用程序提供服务。我可以从 wwwroot 访问次要资产以及用于用户身份验证的 Razor 页面。

在我的 docker 部署中,尝试访问 https://host/https://host/index.html(以及 http 等效项)时出现以下错误:

System.InvalidOperationException: The SPA default page middleware could not return the default page '/index.html' because it was not found, and no other middleware handled the request. Your application is running in Production mode, so make sure it has been published, or that you have built your SPA manually. Alternatively you may wish to switch to the Development environment.

当我在我的 macOS 开发系统上 运行 app-dist 中的相同命令时,我得到相同的错误(在第一次设置 export ASPNETCORE_ENVIRONMENT=production 之后)。

在我的 Startup.cs 中,我有以下内容:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(); 
...

}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseStaticFiles();
    if (!env.IsDevelopment())
    {
        app.UseSpaStaticFiles();
    }

...

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller}/{action=Index}/{id?}");
        endpoints.MapRazorPages();
    });
    app.UseSpa(spa =>
    {
        spa.Options.SourcePath = "ClientApp";
        if (env.IsDevelopment())
        {
            spa.UseAngularCliServer(npmScript: "start");
        }
    });
}

在我的 csproj 中:

<PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
    <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
    <TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
    <IsPackable>false</IsPackable>
    <SpaRoot>ClientApp\</SpaRoot>
    <DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
    <BuildServerSideRenderer>false</BuildServerSideRenderer>
</PropertyGroup>

...

<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
    <Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
    <Exec WorkingDirectory="$(SpaRoot)" Command="npm run build -- --prod" />
    <Exec WorkingDirectory="$(SpaRoot)" Command="npm run build:ssr -- --prod" Condition=" '$(BuildServerSideRenderer)' == 'true' " />
    <ItemGroup>
        <DistFiles Include="$(SpaRoot)dist\**; $(SpaRoot)dist-server\**" />
        <DistFiles Include="$(SpaRoot)node_modules\**" Condition="'$(BuildServerSideRenderer)' == 'true'" />
        <ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
                <RelativePath>%(DistFiles.Identity)</RelativePath>
                <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
                <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
        </ResolvedFileToPublish>
    </ItemGroup>
</Target>

我试过将 Angular index.html 和编译后的文件复制到 wwwrootClientApp 文件夹,但都没有效果。我也尝试设置 spa.Options.SourcePath = "ClientApp/dist/app";什么似乎配置不正确,或者我接下来应该调查什么?

文件位置错误。我将文件移动到 ClientApp\dist\,这是中间件正在寻找的位置。奇怪的配置。

如果您想在生产环境中更改服务应用程序的目录,您可以按以下方式在 ConfigureServices 中进行:

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    // In production, the Angular files will be served from this directory
    services.AddSpaStaticFiles(configuration =>
    {
        configuration.RootPath = "ClientApp/dist";
    });
}

放弃 configuration.RootPath 应更改为您希望的路径。

在我的例子中,这是因为 Angular Api root

中的尾部斜线

而不是

http://localhost:81

我有

http://localhost:81/

去掉斜杠就可以了。 我已经回答了这个here