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.
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.
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();
}
});
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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With