ASP.NET Core multiple angular app

2020-05-24 04:54发布

问题:

I have an ASP.NET Core 2.1 and I need to setup workspace for multiple Angular applications with following routing:

http://someurl.com/main -> first app
http://someurl.com/admin -> second app

I use angular-cli.json with following settings:

"apps": [
{
  "root": "src",
  "outDir": "dist",
  "assets": [
    "assets"
  ],
  "index": "index.html",
  "main": "main.ts",
  "polyfills": "polyfills.ts",
  "test": "test.ts",
  "tsconfig": "tsconfig.app.json",
  "testTsconfig": "tsconfig.spec.json",
  "prefix": "app",
  "styles": [
    "styles.css",
    "../node_modules/bootstrap/dist/css/bootstrap.min.css"
  ],
  "scripts": [],
  "environmentSource": "environments/environment.ts",
  "environments": {
    "dev": "environments/environment.ts",
    "prod": "environments/environment.prod.ts"
  }
},
{
  "root": "src2",
  "outDir": "dist2",
  "assets": [
    "assets"
  ],
  "index": "index.html",
  "main": "main.ts",
  "polyfills": "polyfills.ts",
  "test": "test.ts",
  "tsconfig": "tsconfig.app.json",
  "testTsconfig": "tsconfig.spec.json",
  "prefix": "app",
  "styles": [
    "styles.css",
    "../node_modules/bootstrap/dist/css/bootstrap.min.css"
  ],
  "scripts": [],
  "environmentSource": "environments/environment.ts",
  "environments": {
    "dev": "environments/environment.ts",
    "prod": "environments/environment.prod.ts"
  }
}

]

I've been trying to setup mapping in Startup.cs like below:

app.Map("/main", l => 
        {
            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("/admin", l =>
        {
            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";
                spa.UseSpaPrerendering(options =>
                {
                    options.BootModulePath = $"{spa.Options.SourcePath}/dist2/main.bundle.js";
                    options.BootModuleBuilder = env.IsDevelopment()
                        ? new AngularCliBuilder(npmScript: "build2")
                        : null;
                });

                if (env.IsDevelopment())
                {
                    spa.UseAngularCliServer(npmScript: "start2");
                }
            });
        });

With following scripts in project.json:

"scripts": {
"ng": "ng",
"start": "ng serve --extract-css --base-href=/main/ --serve-path=/main/",
"start2": "ng serve --app=1 --extract-css --base-href=/admin/ --serve-path=/admin/ ",
"build": "ng build --extract-css",
"build2": "ng build --app=1 --extract-css"

}

When I launch solution main app work's well but when I tried go to admin I have failed with error:

Error: Cannot match any routes. URL Segment: 'admin' Error: Cannot match any routes.

Please tell what I've missed and did wrong to achieve my goal Thanks for any advice !

回答1:

You are registering the Single Page Application (SPA) on the app not the mapped path:

app.Map("/admin", l =>
{
    app.UseSpa(spa =>

Change app to l to fix the issue:

app.Map("/admin", l =>
{
    l.UseSpa(spa =>


回答2:

After dealing with such scenario in real time finally got the working solution.

Source code: https://github.com/alpitg/.NetCoreSpa

Important steps : 1. In Startup.cs file under Configure() use following code,

  // for each angular client we want to host use Map function
            app.Map(new PathString("/clientapp1"), client =>
            {
                string clientApp1Path = env.IsDevelopment() ? "ClientApp1" : @"ClientApp1/dist";

                // Each map gets its own physical path for it to map the static files to. 
                StaticFileOptions clientApp1Dist = new StaticFileOptions()
                {
                    FileProvider = new PhysicalFileProvider(
                            Path.Combine(Directory.GetCurrentDirectory(), clientApp1Path)
                        )
                };

                // Each map its own static files otherwise it will only ever serve index.html no matter the filename 
                client.UseSpaStaticFiles(clientApp1Dist);

                client.UseSpa(spa =>
                {
                    spa.Options.StartupTimeout = new TimeSpan(0, 5, 0);
                    spa.Options.SourcePath = "ClientApp1";

                    if (env.IsDevelopment())
                    {
                        // it will use package.json & will search for start command to run
                        spa.UseAngularCliServer(npmScript: "start");
                    }
                    else
                    {
                        spa.Options.DefaultPageStaticFileOptions = clientApp1Dist;
                    }
                });
            });
  1. package.json file changes,

        "start": "ng serve --servePath / --baseHref /newui/",
        "build": "ng build --baseHref /newui/",
        "build:ssr": "npm run build --baseHref /newui/ -- --app=ssr --output-hashing=media",
    

These are the primary changes i have shared here. Fore more detail please use the source code and compare your changes.

NOTE: Tested with .net core 2.2 & angular 7

For more detail please refer my blog: https://wayeasier.home.blog/2019/07/21/hosting-two-angular-app-behind-net-core-web-application/



回答3:

@sven.to's answer works, I am just pasting here the full snippet for clarity:

        app.Map("/foo", l => l.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");
            }
        }));

This adds the /foo prefix and now https://localhost:44383/foo/main.js will show you main.js while https://localhost:44383/main.js will give you 404 Not Found.