Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET 5 + Angular 2 routing (template page not REloading)

Angular 2 beta uses html5 routing by default. However, when you go to a component and the route changes (eg http://localhost:5000/aboutus) and you reload/refresh the page, nothing is loaded.

The issue has been raised in this post also. Most of the answers say that if we are going to pursue HTML5 routing in angular 2, then this issue of routing should be taken care of in server-side. More discussion here.

I am not sure how to handle this issue using the asp.net server environment.

Any angular 2 devs out there who also uses asp.net and encounters this issue?

PS. I'm using ASP.NET 5. My Angular 2 routes are using MVC routes.

like image 920
raberana Avatar asked Jan 06 '16 08:01

raberana


3 Answers

The problem you're seeing has to do with the difference between Angular routing on the client and MVC server-side routing. You are actually getting a 404 Page Not Found error because the server does not have a Controller and Action for that route. I suspect you are not handling errors which is why it appears as if nothing happens.

When you reload http://localhost:5000/aboutus or if you were to try to link to that URL directly from a shortcut or by typing it into the address bar (deep linking), it sends a request to the server. ASP.NET MVC will try to resolve that route and in your case it will try to load the aboutusController and run the Index action. Of course, that's not what you want, because your aboutus route is an Angular component.

What you should do is create a way for the ASP.NET MVC router to pass URLs that should be resolved by Angular back to the client.

In your Startup.cs file, in the Configure() method, add an "spa-fallback" route to the existing routes:

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

    // when the user types in a link handled by client side routing to the address bar 
    // or refreshes the page, that triggers the server routing. The server should pass 
    // that onto the client, so Angular can handle the route
    routes.MapRoute(
        name: "spa-fallback",
        template: "{*url}",
        defaults: new { controller = "Home", action = "Index" }
    );
});

By creating a catch-all route that points to the Controller and View that ultimately loads your Angular app, this will allow URLs that the server does not handle to be passed onto the client for proper routing.

like image 163
Brad Rem Avatar answered Nov 16 '22 07:11

Brad Rem


In your Startup.cs add this to the Configure method. This must be before other app statements.

app.Use(async (context, next) => {
    await next();

    if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value)) {
        context.Request.Path = "/index.html"; // Put your Angular root page here 
        await next();
    }
});
like image 22
Jaanus Avatar answered Nov 16 '22 08:11

Jaanus


My favorite solution is to add the following code to Global.asax.cs which very smoothly and reliably takes care of the issue:

     private const string RootUrl = "~/Home/Index";
     // You can replace "~Home/Index" with whatever holds your app selector (<my-app></my-app>)
     // such as RootUrl="index.html" or any controller action or browsable route

     protected void Application_BeginRequest(Object sender, EventArgs e)
        {
            // Gets incoming request path
            var path = Request.Url.AbsolutePath;

            // To allow access to api via url during testing (if you're using api controllers) - you may want to remove this in production unless you wish to grant direct access to api calls from client...
            var isApi = path.StartsWith("/api", StringComparison.InvariantCultureIgnoreCase);
            // To allow access to my .net MVCController for login
            var isAccount = path.StartsWith("/account", StringComparison.InvariantCultureIgnoreCase);
            if (isApi || isAccount)
            {
                return;
            }

            // Redirects to the RootUrl you specified above if the server can't find anything else
            if (!System.IO.File.Exists(Context.Server.MapPath(path)))
                Context.RewritePath(RootUrl);
        }
like image 6
Methodician Avatar answered Nov 16 '22 09:11

Methodician