7

I'm working on a mixed routing Angular 2 and ASP.NET Core 2 (razor) project. How would you jump out of angular routing and get razor pages? I tried catching all unknown route with angular routing and reloading the unknown route but if there is a route ASP.NET and angular doesn't recognize it goes into a loop. The Configure method of the Startup class contains this.

public void Configure(IApplicationBuilder app)
{
    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "Index",
            defaults: new { controller = "controller", action = "Index" },
            template: "{controller}");

        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");

        routes.MapRoute(
            name: "Login",
            defaults: new { controller = "Sessions", action = "New" },
            template: "Login");
    });

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

Some examples:

  • Mvc route Mysite.com/documents/view/
  • Angular route Mysite.com/PendingTransactions
NightOwl888
  • 55,572
  • 24
  • 139
  • 212
Ben Weidberg
  • 89
  • 1
  • 4
  • 8
    If you down vote a question have the decency to point out why. – Ben Weidberg Feb 14 '18 at 17:46
  • Do you have the angular app and the mvc app sharing some common routing. ie mysite.com/app/angular and mysite.com/app/mvc? Please give some examples of the routes in your app and the configuration you have for MVC and Angular for those routes. – Zzz Feb 14 '18 at 18:42
  • Just noticed that you are using ASP.Net Core MVC. I have solved this issue in ASP.Net MVC (NOT Core) with angular 5. Let me know if you would like for me to answer this question with what worked for me, but you will have to apply it to Core on your own. – Zzz Feb 14 '18 at 20:02
  • I would like you (Zzz) answer the question for asp.net mvc and I'll try to port it to core. – Ben Weidberg Feb 14 '18 at 20:09
  • Did my answer help? – Zzz Feb 14 '18 at 22:23
  • Your `Login` route is an unreachable execution path. You need to put it above (or just below) the `Index` route. See [Why map special routes first before common routes in asp.net mvc?](https://stackoverflow.com/a/35674633). – NightOwl888 Feb 15 '18 at 11:55
  • Yes Zzz your answer definitely gives me a start but didn't get a chance to implement it yet. Thanks – Ben Weidberg Feb 15 '18 at 15:51

1 Answers1

1

Solution works for MVC 4.

NOTE: You should place your default route after all your other routes, but before your catch all route.

Exclude Angular app from MVC routing (You will notice something funny with the true/false evaluation, this is because the app routing is handled by MVC unless we are in the /app angular application. You can see the opposite implantation here):

routes.MapRouteLowercase(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
                constraints: new
                {
                    serverRoute = new ServerRouteConstraint(url =>
                    {
                        var isAngularApp = false;
                        if (url.PathAndQuery.StartsWith("/app",
                            StringComparison.InvariantCultureIgnoreCase))
                        {
                            isAngularApp = true;
                        }               
                        return !isAngularApp;
                    })
                }
            );

The ServerRouteConstraint class:

 public class ServerRouteConstraint : IRouteConstraint
    {
        private readonly Func<Uri, bool> _predicate;

        public ServerRouteConstraint(Func<Uri, bool> predicate)
        {
            this._predicate = predicate;
        }

        public bool Match(HttpContextBase httpContext, Route route, string parameterName,
            RouteValueDictionary values, RouteDirection routeDirection)
        {
            return this._predicate(httpContext.Request.Url);
        }
    }

This is a catch-all for when no other routes matched. Let the Angular router take care of it

    routes.MapRouteLowercase(
        name: "angular",
        url: "{*url}",
        defaults: new { controller = "App", action = "Index" } // The view that bootstraps Angular 5
    );
Zzz
  • 2,927
  • 5
  • 36
  • 58