5

I want to use Asp.Net Core 2.2 to host my Angular app - as well as serve API requests (on /api).

So in Startup.cs, Configure, I set the following:

        app.Map("/home", config =>
        {
            config.UseSpa(spa =>
            {
            ...
            });
         });

However, the problem is that runtime.js, polyfills.js etc are all not found because they are being referenced as http://localhost:port/filename.ext

I tried to use

    config.UseSpaStaticFiles(new StaticFileOptions { RequestPath = "/runtime.js" });

But to no avail.

What is the secret sauce to serve Angular SPA under a different route in ASP.Net Core?

Edit: Answering @Michael - I was looking into this to ultimately host multiple apps, but I figured it may not be worth the trouble. I want to be able to do 'ng serve' when I am developing the apps and run under Asp.Net Core when I deploy. If one thing works, the other thing is getting broken. So decided to table it for now.

kotpal
  • 437
  • 8
  • 11
  • I'm not sure how your base path looks like. But it seems to be a question about how to serve statics, and quite similar to this [question](https://stackoverflow.com/questions/53833968/how-to-host-angular-application-with-kestrel/53844723#53844723). Hope it helps. – itminus Feb 08 '19 at 05:16
  • @kotpal Did you ever figure this out? – Michael Feb 26 '19 at 02:16

1 Answers1

4

I'm going to talk to the csproj configurations, package.json npm configurations, and naturally your Startup.cs code.

The .csproj file

at the bottom of your csproj file, you will find a set of npm commands that are run when the application is published.

    <!--...-->
    <PropertyGroup>
        <SpaRoot>ClientApp\</SpaRoot>
    </PropertyGroup>
    <!--...-->
    <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' " />
    <!--...-->

If you wanted to have two applications deployed, you will need to double up on all those deploy instructions.

    <!--...-->
    <PropertyGroup> 
        <!--...-->
        <SpaRoot>ClientApp\</SpaRoot>
        <SpaRoot2>ClientApp2\</SpaRoot2>
        <!--...-->
    </PropertyGroup>
    <!--...-->
    <Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
    <!--...-->
    <Exec WorkingDirectory="$(SpaRoot2)" Command="npm install" />
    <!--...-->

configuring the package.json

While under development, you will likely want nodejs to host the application. In this scenario, our server isn't hosting our client app.

You going to need to set the servepath to match the subdirectory you want the client application to run out of.

   // ...
   "start": "ng serve --servePath /app/ --baseHref /app/",
   // ...

At this point, don't forget to update the baseHref for the build. otherwise when the scripts in csproj call build, it won't be pointing to the correct basehref.

"build": "ng build --baseHref /app/",

Startup.cs configurations

Remember how I said while in development the server don't host the client? I would suggest running one at a time while developing. The important thing is that you update the package.json servePath so that your testing the url pathing and how everything will link together.

if (env.IsDevelopment())
{
    app.UseSpaStaticFiles();
    app.UseSpa(spa =>
    {
        spa.Options.SourcePath = "ClientApp";
        // this is calling the start found in package.json
        spa.UseAngularCliServer(npmScript: "start");
    });
}
else // Production -- in the next section, 

Finally, we have how we want it to behave in production.

// how you had it, we will create a map 
// for each angular client we want to host. 
app.Map(new PathString("/app"), client =>
{
    // Each map gets its own physical path
    // for it to map the static files to. 
    StaticFileOptions clientAppDist = new StaticFileOptions()
    {
        FileProvider = new PhysicalFileProvider(
                Path.Combine(
                    Directory.GetCurrentDirectory(),
                    @"ClientApp\dist"
                )
            )
    };

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

    // Each map will call its own UseSpa where
    // we give its own sourcepath
    client.UseSpa(spa =>
    {
        spa.Options.SourcePath = "ClientApp";
        spa.Options.DefaultPageStaticFileOptions = clientAppDist;
    });
});

you can test the production setup by commenting out the development code and running npm run build in your respective clientapp folders before running the C# code. Just ensure the dist folder generated is not checked into your git repo.

Hopefully, you now have a better understand of how it works in a developing environment, creating the build instructions, and how it will run on a production environment.

Joseph atkinson
  • 139
  • 1
  • 7