asp.net core中托管SPA应用

假定一个场景,我们需要一个前后端分离的应用,服务端API使用ASP.NET Core开发,前端有两套,一个是用于所有用户的客户端,另一个是给管理员使用的管理后台,使用asp.net core的hosting作为后端+前端的web服务器。应为默认情况下没有开启hosting的spa功能。针对这个,我们可能首先想到的是自定义一个中间件进行处理,当请求特定path,以及静态资源是,加载对应文件夹下的spa应用文件。其实微软早就为我们准备好了这个中间件。这个中间件在:Microsoft.AspNetCore.SpaServices.Extensions 包中。

dotnet new 命令创建项目时,模板就已经内置了 angular和react的spa 模板。新建完成后,可以看到startup启动类中,多出来了两个东西:

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddSpaStaticFiles(configuration =>
            {
                configuration.RootPath = "ClientApp/dist";
            });
    ...
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // app.UseEndpoints ...

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

直接运行,就可以启动应用程序,就可以看到spa应用程序已经正常工作了。

默认的例子,只hosting 了一个spa应用,回到最初的问题,如果有两个或者多个需要处理呢。这就需要多次配置。

我们来做下多spa的配置。

为了整齐可读性高,我们使用IApplicationBuilder扩展的方式来配置多个SPA应用

新建SpaAPP01的扩展

/// <summary>
/// SpaAPP01
/// </summary>
/// <returns></returns>
public static IApplicationBuilder UseSpaAPP01(this IApplicationBuilder app, IConfiguration configuration)
{
     // sourcePathPath 是spa应用程序build后的文件目录
     var sourcePathPath =  configuration["Spa:SpaAPP01:RootPath"];
     // routeString 是路由模板,这里需要在spa应用打包时,所有引用的静态资源的地址前缀
     // 比如  './spa001/statics/index.js'  可以参见html <base href=''> 的作用
     var routeString =  configuration["Spa:SpaAPP01:RouteTemplate"];
     var fileOtp = new StaticFileOptions
     {
         FileProvider = new PhysicalFileProvider(sourcePathPath)
     };
     app.Map(routeString, appBuilder =>
     {
          appBuilder.UseSpaStaticFiles(fileOtp);
          appBuilder.UseSpa(options =>
          {
               options.Options.DefaultPageStaticFileOptions=fileOtp;
           });
      });
   return app;
}

/// <summary>
/// SpaAPP02
/// </summary>
/// <returns></returns>
public static IApplicationBuilder UseSpaAPP02(this IApplicationBuilder app, IConfiguration configuration)
{
     // sourcePathPath 是spa应用程序build后的文件目录
     var sourcePathPath =  configuration["Spa:SpaAPP02:RootPath"];
     // routeString 是路由模板,这里需要在spa应用打包时,所有引用的静态资源的地址前缀
     // 比如  './spa001/statics/index.js'  可以参见html <base href=''> 的作用
     var routeString =  configuration["Spa:SpaAPP02:RouteTemplate"];
     var fileOtp = new StaticFileOptions
     {
         FileProvider = new PhysicalFileProvider(sourcePathPath)
     };
     app.Map(routeString, appBuilder =>
     {
          appBuilder.UseSpaStaticFiles(fileOtp);
          appBuilder.UseSpa(options =>
          {
               options.Options.DefaultPageStaticFileOptions=fileOtp;
           });
      });
   return app;
}

appsettign.json

{
"Spa": {
    "SpaAPP01": {
      "RootPath":"E:\\spa001",
      "RouteTemplate":"/spa-demo1"
    },
    "SpaAPP02":{
      "RootPath":"E:\\spa002",
      "RouteTemplate":"/spa-demo2"
    }
  },
}

startup

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddSpaStaticFiles();
    ...
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // app.UseEndpoints ...
    app.UseSpaAPP01(configuration);
    app.UseSpaAPP02(configuration); 
}

最后在E:\\spa001E:\\spa002中放置build后的spa应用。启动asp.net core 应用程序,访问appsetting中设置好的对应RouteTemplate,就会打开对应的spa应用程序。spa中请求接口的路径也只需要使用接口的相对路径即可。spa引用的静态资源也会被加载。

注意:当静态资源不存在时,会默认指向index.html。 如果发现某些非html 静态文件,返回成了html格式,那就是引入路径缺少了appsetting中配置的RouteTemplate前缀。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容