Make Angular routes work inside ASP.NET Core 2.0 app


I have an ASP.NET Core 2.0 app and I have Angular 5 app. Those are developed separately (1st in VS2017, 2nd in VS Code). So I set up CD/CI in VSTS and Angular app gets injected into /angularapp/ folder of ASP.NET Core app during the build.

In order to make angular app work when user opens <a href="http://domain/angularapp" rel="nofollow">http://domain/angularapp</a> I set up URL rewrite rule in IIS (so when it hits /angularapp it gets rewritten to /angularapp/index.html).

But what about deeper links in Angular app? If I try to open /angularapp/feature I get the 404 error from ASP.NET Core 2.0. Can I workaround this?


<a href="https://stackoverflow.com/users/8081009/janne-harju" rel="nofollow">Janne-Harju</a> is right. The solution is here - <a href="https://code.msdn.microsoft.com/How-to-fix-the-routing-225ac90f" rel="nofollow">https://code.msdn.microsoft.com/How-to-fix-the-routing-225ac90f</a>. But in order to make it work make sure you have this:

app.UseDefaultFiles(new DefaultFilesOptions { DefaultFileNames = new List<string> { "index.html" }});


If you're looking for a solution whereby your api is on the same general route e.g. "/api/". And everything else should be routed back to the SPA, then this should work well for you.

app.UseWhen(x => !x.Request.Path.Value.StartsWith("/api"), builder => { builder.Use(async (context, next) => { await next(); if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value)) { context.Request.Path = "/index.html"; await next(); } }) .UseDefaultFiles(new DefaultFilesOptions {DefaultFileNames = new List<string> {"index.html"}}) .UseStaticFiles() .UseMvc(); }); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); });


I'm not sure about .net core 2.0 but this works for me with .net core 1.1 <a href="https://github.com/JanneHarju/MultiSourcePlayList/blob/076c6e4108cbae3bb5128e7f176ed35a61593922/Startup.cs#L169" rel="nofollow">https://github.com/JanneHarju/MultiSourcePlayList/blob/076c6e4108cbae3bb5128e7f176ed35a61593922/Startup.cs#L169</a>

app.Use(async (context, next) => { await next(); if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value) && !context.Request.Path.Value.StartsWith("/api/")) { context.Request.Path = "/index.html"; await next(); } });

In my repo there is also that else if part for angular routes but I think there is no more use for it anymore (or maybe ever wasn't).


The answers given here will partially work but also route requests to index.html if your controllers return a 404 (not found). I am using the following code:

app.Use(async (context, next) => { await next(); if (!Path.HasExtension(context.Request.Path.Value) && !context.Request.Path.Value.StartsWith("/api/")) { context.Request.Path = "/index.html"; await next(); } }); app.UseDefaultFiles(new DefaultFilesOptions { DefaultFileNames = new List<string> { "index.html" }});

This will route all request to index.html, except the ones with extension and api route. Be careful that the api bit is hard-coded and will stop working if you change your resource paths.


  • Exception is undefined when app is on remote machine
  • IIS 6.0 DirectoryEntry ScriptMaps property and set .Net version
  • Use .htaccess to hide variables
  • Memory usage if upload big file in one request in IIS
  • Node.js installation troubles
  • Trying to Graph a Simple Square in pyOpenGL
  • IIS application pool recycling and “shutdown time limit” role in overlapping
  • XML request in PHP NuSoap - “HTTP/1.1 400 Bad Request”
  • Error when building the website
  • Parser Error Message: The file '/Site.master' does not exist
  • How to return a deferred promise and create a model with Ember.Deferred?
  • Changing the publicly exposed endpoint URL for a WCF web service without changing the site bindings
  • Elmah not logging 404 (missing files / images)
  • How to get database credentials into a c# application without committing it to source code?
  • Get the computer user name in a web application
  • Add Windows Feature from C#
  • ZipList with Scalaz
  • Implement JwtBearer Authentication in NSwag SwaggerUi
  • Elasticsearch script query involving root and nested values
  • ASP.NET MVC 2 Preview 2 - display directory list rather than home/index
  • Does it make sense to call System.gc() and Thread.sleep() when working on Bitmaps?
  • Abort upload large uploads after reading headers
  • azure media services - The request body is too large and exceeds the maximum permissible limit
  • Bad request using file_get_contents for PUT request in PHP
  • Change Inet root folder for iis 7
  • java.lang.NoClassDefFoundError: com.parse.Parse$Configuration$Builder on below Lollipop versions
  • What is Eclipse's Declaration View used for?
  • Excel - Autoshape get it's name from cell (value)
  • How to redirect a user to a different server and include HTTP basic authentication credentials?
  • Check if a string to interpolate provides expected placeholders
  • Can I make an Android app that runs a web view in Chrome 39?
  • RestKit - RKRequestDelegate does not exist
  • Traverse Array and Display in markup
  • Hits per day in Google Big Query
  • how does django model after text[] in postgresql [duplicate]
  • FormattedException instead of throw new Exception(string.Format(…)) in .NET
  • LevelDB C iterator
  • Linking SubReports Without LinkChild/LinkMaster
  • XCode 8, some methods disappeared ? ex: layoutAttributesClass() -> AnyClass
  • How to get NHibernate ISession to cache entity not retrieved by primary key