简体   繁体   中英

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

My web application was scaffolded from the dotnet core 3.0 Angular template. I want to deploy the first version into production but I am struggling to have the Angular app served. I am using Kestrel as the webserver (it's an intranet application).

I have published the application with dotnet publish -c Release -o../app-dist which build the Asp.net application and it triggered ng to build a production release of the client. The resulting folder structure includes a app-dist/wwwroot folder which has some assets like favicon and it has a app-dist/ClientApp/dist/app folder with the index.html and the compiled js and css assets. If I start the application by running dotnet app.dll in app-dist , Kestrel starts but it fails to serve the client application. I can access the minor assets from wwwroot as well as the Razor pages that are used for user authentication.

In my docker deployment, I get the following error when trying to access https://host/ or https://host/index.html (as well as http equivalents):

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.

When I run the same command in app-dist on my macOS development system I get the same error (after first setting export ASPNETCORE_ENVIRONMENT=production ).

In my Startup.cs I have the following:

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");
        }
    });
}

In my 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>

I have tried copying the Angular index.html and compiled files to the wwwroot as well as the ClientApp folder, but neither made a difference. I also tried setting spa.Options.SourcePath = "ClientApp/dist/app"; . What seems incorrectly configured, or what should I investigate next?

If you want to change the directory of the served app in production you can do it in ConfigureServices following way:

// 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";
    });
}

Aborve the configuration.RootPath should be changed to your wished path.

The location of the files was wrong. I moved the files to ClientApp\dist\ and that was the location that the middleware was looking for. Strange configuration.

In my case this was because of a trailing slash in the Angular Api root

Instead of

http://localhost:81

i had

http://localhost:81/

Remove the slash and you will be fine. I have answered this here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM