Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.Net Core - IApplicationBuilder.Map, SPA and static files

Tags:

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.

like image 464
kotpal Avatar asked Feb 07 '19 20:02

kotpal


People also ask

Can .NET Core HTTP pipeline be configured to server static files?

ASP.NET Core application cannot serve static files by default. We must include Microsoft. AspNetCore. StaticFiles middleware in the request pipeline.

What are static files in ASP.NET Core?

Static files, such as HTML, CSS, images, and JavaScript, are assets an ASP.NET Core app serves directly to clients by default.

How do I serve a static file in NET Core?

To serve static files from an ASP.NET Core app, you must configure static files middleware. With static files middleware configured, an ASP.NET Core app will serve all files located in a certain folder (typically /wwwroot).

What is the default directory for static files in ASP.NET Core?

Static files are stored within the project's web root directory. The default directory is {content root}/wwwroot , but it can be changed with the xref:Microsoft. AspNetCore. Hosting.


1 Answers

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.

like image 76
Joseph atkinson Avatar answered Oct 14 '22 08:10

Joseph atkinson