Serve Angular spa pathed off the root
Asked Answered
W

3

11

I'm looking to upgrade an existing asp.net 4.5 mvc site which has two angular applications to an asp.netcore 2 mvc site with potentially two spa's. using Aspnet Javascriptservices with the new angular cli template.

Ideally i want to host two spa's one at http://mysite/member and the other at http://mysite/admin

I've started with just one members and i initially used <base href="/members/" /> in the index.html (but then swapped to use the baseHref" property in the.angular-cli.json (giving the same results)) which half works. Locally when debugging the app it serves pages and navigates as expected but in the console i can see zone.js errors.

enter image description here

If i open a new tab and paste in

http://localhost:50930/**members**/sockjs-node/info?t=1518084503138

then i get what looks like a correct response

{"websocket":true,"origins":["*:*"],"cookie_needed":false,"entropy":2082738399}

If i deploy this to Azure app service (production) then navigating to

https://mysite.azurewebsites.net/members then the spa doesn't load at all and it seems that the bundled js has the index.html which is loading it inside. enter image description here

Has anyone managed to use the angular spa template as an application served off the route of an MVC site? I created a ticket on the repo but i suspect its beyond the scope of the project https://github.com/aspnet/JavaScriptServices/issues/1518

Also created a repo to demonstrate what i am trying to achieve https://github.com/tbertenshaw/MultiSpa

Wood answered 8/2, 2018 at 11:54 Comment(7)
I'm not sure if it is helpful or not but I hosted my similar react js front end app on IIS on a sub domain. For that I needed to add Urlrewrite to the IIS to make it work. I'm not sure if it's is the case but are you using urlrewrite on azure?Sturgill
Have you actually watched what you receive in your main, polyfills and other bundles in network tab? I might guess all of them contain your index.html contentFakir
@Fakir yes although on disk they all contain their expected minimised uglified js. Just somehow are serving their parent html pageWood
@Wood Thats because your web server is configured wrongFakir
Ok any ideas what's wrong? The repo should show my config.Wood
@Wood I'm not an aspnet specialist, you should probably search for aspnet web server configuration and official angular documentation angular.io/guide/deployment#server-configurationFakir
Have you tried to use --deployUrl along with the --base-href? We host all JS on CDN and that's what we use. There's not much information about it, but here is the article shekhargulati.com/2017/07/06/…Transilluminate
S
1

You have to configure the webserver to always return the index.html page of your angular pwa.

Default, the server returns an error 404, because for /members there is no file present. But you want angular to handle the routes and therefore you have to always serve the index.html instead of an 404 error page.

This documentation explains this further explicitly for the aspnet JavaScriptServices: https://github.com/aspnet/JavaScriptServices/tree/dev/src/Microsoft.AspNetCore.SpaServices#routing-helper-mapspafallbackroute

Sandhi answered 16/2, 2018 at 14:22 Comment(2)
confused by that, is it suggesting to create a view which contains the same code as the index.html? My example app does serve the index.html, its just that the resources(js, css) referenced on it seem to be returned without their contents, and with the calling index.html's html inside them.Wood
i don't think this would work because even if it served the index.html, the base path would be wrong and it wouldn't find the JS.Scientistic
S
0

I have used this before in my apps. In a later version I added caching to make it faster, but it always works regardless of where it's deployed. It makes moving files between servers or even just folders very easy, especially when we move between dev, test, and prod servers.

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;

namespace Management.Middleware
{
    public class AngularDefaultRouteMiddleware
    {
        private readonly RequestDelegate _next;

        public AngularDefaultRouteMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task Invoke(HttpContext context)
        {
            if (context.Request.Path == "/")
            {
                await context.Response.WriteAsync(await GetAngularSpa(context.Request.PathBase));
            }
            else
            {
                await _next(context);
                if (context.Response.StatusCode == 404 && !context.Response.HasStarted)
                {
                    await context.Response.WriteAsync(await GetAngularSpa(context.Request.PathBase));
                }
            }
        }

        private async Task<string> GetAngularSpa(string pathBase)
        {
            string html = await System.IO.File.ReadAllTextAsync($"{Environment.CurrentDirectory}\\wwwroot\\index.html");
            return html.Replace("<base href='/'>", $"<base href='{pathBase}'>");
        }
    }

    public static class AngularDefaultRouteMiddlewareExtensions
    {
        public static IApplicationBuilder UseAngularDefaultRoute(this IApplicationBuilder app)
        {
            return app.UseMiddleware<AngularDefaultRouteMiddleware>();
        }
    }
}

Then you can just call this middleware from Startup.cs with app.UseAngularDefaultRoute();

Scientistic answered 16/2, 2018 at 16:25 Comment(2)
Is this used without the javascriptservices middleware then?Wood
I'm not sure if you could use it with serverside rendering, but I don'tScientistic
S
0

Tim, did you ever get this working? Im currently trying to get an Aurelia app hosted from a sub-path within a .NET Core MVC app. I am almost there, the main difficulty has been in creating an MVC and Webpack config that works in both production and development.

My sample project is based off the new 2.1 style Angular SPA template which uses the 'UseAngularCliServer' or 'UseProxyToSpaDevelopmentServer' middleware when in dev mode and serves the bundled files from the 'dist' dir when in production mode.

UPDATE: I have published a working repo for this scenario, no sockjs-node errors, also works with HMR, please see the thread here: https://github.com/aspnet/JavaScriptServices/issues/1518

It works in both Development and Production modes.

Schexnayder answered 30/10, 2018 at 13:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.