C# 在请求管道的分支中为SPA提供服务时,我的SPA文件给出了404个错误。如何使我的SPA可以使用静态文件?

C# 在请求管道的分支中为SPA提供服务时,我的SPA文件给出了404个错误。如何使我的SPA可以使用静态文件?,c#,asp.net-core,single-page-application,C#,Asp.net Core,Single Page Application,首先,在我的项目根目录中有一个名为ClientApp的文件夹,其中包含一个文件夹build,它是前端构建的输出所在 然后,在Startup.cs中,我在ConfigureServices中有以下内容: public void ConfigureServices(IServiceCollection services) { ... services.AddSpaStaticFiles(configuration => { configuration.Root

首先,在我的项目根目录中有一个名为
ClientApp
的文件夹,其中包含一个文件夹
build
,它是前端构建的输出所在

然后,在
Startup.cs
中,我在
ConfigureServices
中有以下内容:

public void ConfigureServices(IServiceCollection services)
{
    ...

    services.AddSpaStaticFiles(configuration => {
        configuration.RootPath = "ClientApp/build";
    });
}
下面,我的
Configure
方法如下所示:

 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
 {
     if (env.IsDevelopment()) {
         app.UseDeveloperExceptionPage();
     } else {
         app.UseExceptionHandler("/Error");
         app.UseHsts();
     }

     app.UseHttpsRedirection();
     app.UseStaticFiles();
     app.UseSpaStaticFiles();
     app.UseAuthentication();

     app.UseMvcWithDefaultRoute();

     app.Map("/dashboard", dashboard => {
         dashboard.Use(async (context, next) => {
             if (context.User.Identity.IsAuthenticated) {
                 await next();
                 return;
             }

             context.Response.Redirect("/Account/Login");
         });

         dashboard.UseSpa(spa => {
             spa.Options.SourcePath = "ClientApp";

             if (env.IsDevelopment()) {
                 spa.UseProxyToSpaDevelopmentServer("http://localhost:3000");
            }
        });
    });
}
如果我删除
.Map(…)
并在
app
iaapplicationbuilder实例中为spa提供服务,那么它就会工作

提前谢谢你的帮助,这已经困扰了我好几天了

编辑 我最终想要的设置如下
/dashboard
将服务于SPA应用程序,任何访问该路由的人都必须经过身份验证。但是,诸如
/Account/Login
之类的路由不属于SPA


通过将
UseSpa
移动到
Map
之外,任何未由Mvc或
wwwroot
中的静态文件处理的路由都将呈现SPA,但当访问例如
/about
时,我想显示一个404,而不是呈现404的SPA。

对于
app.Map
,它将根据路径
https://localhost:44378/dashboard/
。这意味着只有
https://localhost:44378/dashboard/
将进入
Spa
中间件

对于
dashboard.UseSpa
,它将使用
https://localhost:44378/styles.bundle.css
哪个将不匹配
https://localhost:44378/dashboard/

        app.UseSpa(spa =>
        {
            // To learn more about options for serving an Angular SPA from ASP.NET Core,
            // see https://go.microsoft.com/fwlink/?linkid=864501

            spa.Options.SourcePath = "ClientApp";

            if (env.IsDevelopment())
            {
                spa.UseAngularCliServer(npmScript: "start");
            }
        });
        app.Map("/dashboard", dashboard =>
        {
            dashboard.Use(async (context, next) =>
            {
                if (context.User.Identity.IsAuthenticated)
                {
                    await next();
                    return;
                }
                context.Response.Redirect("/Account/Login");
            });
        });
如果您不想将SPA中的请求基本路径更改为
https://localhost:44378/dashboard/
,您可以尝试将
UseSpa
移动到
app.Map(“/dashboard”
)之外

        app.UseSpa(spa =>
        {
            // To learn more about options for serving an Angular SPA from ASP.NET Core,
            // see https://go.microsoft.com/fwlink/?linkid=864501

            spa.Options.SourcePath = "ClientApp";

            if (env.IsDevelopment())
            {
                spa.UseAngularCliServer(npmScript: "start");
            }
        });
        app.Map("/dashboard", dashboard =>
        {
            dashboard.Use(async (context, next) =>
            {
                if (context.User.Identity.IsAuthenticated)
                {
                    await next();
                    return;
                }
                context.Response.Redirect("/Account/Login");
            });
        });
更新

要更改SPA静态文件请求URL,您可以尝试更改
package.json
,如下所示:

"start": "ng serve --base-href=/dashboard/ --serve-path=/ --live-reload-client=https://localhost:port/frontend/sockjs-node/",
开发过程中的另一个选项是在
Startup

        app.Map("/dashboard", frontendApp =>
        {
            frontendApp.UseSpa(spa =>
            {
                // To learn more about options for serving an Angular SPA from ASP.NET Core,
                // see https://go.microsoft.com/fwlink/?linkid=864501

                spa.Options.SourcePath = "ClientApp";

                if (env.IsDevelopment())
                {
                    spa.UseAngularCliServer(npmScript: "start --  --base-href=/frontend/ --serve-path=/ --live-reload-client=https://localhost:44302/frontend/sockjs-node/");
                }
            });
        });    

没错,在Edward进行了一些澄清和帮助之后,我发现了这个问题。正如Edward指出的,由于对
UseSpa
的调用是在请求管道的一个分支内完成的,所以在
ClientApp/build
上服务的静态资产不会被使用,因为这些资产的请求以
/static/而不是
/dashboard
。这意味着请求管道不知道它们

我发现的修复实际上更多的是在客户端构建上,而不是在服务器上,因为我无法正确地让服务器知道静态资产。修复需要在
package.json
中设置
homepage
属性。唯一的缺点是,在运行
npm start
sinc时,这不起作用e构建实际上不是输出到文件系统,而是在web服务器的内存中

在服务器上,我确实必须将
app.UseSpaStaticFiles()
移动到
Map
调用中,才能使其正常工作


再次感谢Edward帮助我更好地理解
Map
的工作原理。

UseSpa
移动到
app之外。Map
将使SPA可用于除任何MVC路由之外的所有路径。但这不是我想要的,因为“默认”响应不应该是面向客户端的应用程序(即使显示404)在我看来。但是,您的解释确实澄清了SpaServices如何运行的一些问题,因此感谢您。对于angular文件的身份验证和授权,如何使用?spa
中的哪些敏感信息?一般来说,静态文件是公共访问。它与访问静态文件无关。我的意思是,如果我把
UseSpa
Map
中拿出来,然后在Mvc系统不处理的任何路线上都可以访问spa。因此
/dashboard
会去spa,但是
/about
也会去,即使我的站点中不存在该页面。我会编辑帖子以澄清我的想法。是的,这会有工作正常,但我的SPA是使用create react app的react应用程序,而不是使用Angular cli的Angular应用程序。为了使Angular服务器和实时重新加载在开发中正常工作,请包括
app.useSpa(s=>s.Options.SourcePath=null;if(env.IsDevelopment())s.UseProxyToSpaDevelopmentServer(“http://localhost:4200)