Is there a way to make a catch all route serve a static file?
Looking at this http://blog.nbellocam.me/2016/03/21/routing-angular-2-asp.net-core/
I basically want something like this:
app.UseMvc(routes =>
{
routes.MapRoute("default", "{controller}/{action=Index}");
routes.MapRoute("spa", "{*url}"); // This should serve SPA index.html
});
So any route that doesn't match an MVC controller will serve up wwwroot/index.html
I had to make some additions to @DavidG answer. Here is what I ended up with
Startup.cs
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute("default", "{controller}/{action}");
routes.MapRoute("Spa", "{*url}", defaults: new { controller = "Home", action = "Spa" });
});
HomeController.cs
public class HomeController : Controller
{
public IActionResult Spa()
{
return File("~/index.html", "text/html");
}
}
ASP.NET Core catch all routes for Web API and MVC are configured differently
With Web API ( if you're using prefix "api" for all server-side controllers eg. Route("api/[controller"]
):
app.Use(async (context, next) =>
{
await next();
var path = context.Request.Path.Value;
if (!path.StartsWith("/api") && !Path.HasExtension(path))
{
context.Request.Path = "/index.html";
await next();
}
});
app.UseStaticFiles();
app.UseDefaultFiles();
app.UseMvc();
With MVC ( dotnet add package Microsoft.AspNetCore.SpaServices -Version xyz
):
app.UseStaticFiles();
app.UseDefaultFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}");
routes.MapSpaFallbackRoute("spa", new { controller = "Home", action = "Index" });
});
If you're already in the routing stage, you've gone past the point where static files are served in the pipeline. Your startup will look something like this:
app.UseStaticFiles();
...
app.UseMvc(...);
The order here is important. So your app will look for static files first, which makes sense from a performance standpoint - no need to run through MVC pipeline if you just want to throw out a static file.
You can create a catch-all controller action that will return the content of the file instead. For example (stealing the code in your comment):
public IActionResult Spa()
{
return File("~/index.html", "text/html");
}
In case you don't want manually specify which routes are for api:
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseMvc() // suggestion: you can move all the SPA requests to for example /app/<endpoints_for_the_Spa> and let the mvc return 404 in case <endpoints_for_the_Spa> is not recognized by the backend. This way SPA will not receive index.html
// at this point the request did not hit the api nor any of the files
// return index instead of 404 and let the SPA to take care of displaying the "not found" message
app.Use(async (context, next) => {
context.Request.Path = "/index.html";
await next();
});
app.UseStaticFiles(); // this will return index.html
What I'm using that works well is Microsoft.AspNetCore.Builder.SpaRouteExtensions.MapSpaFallbackRoute
:
app.UseMvc(routes =>
{
// Default route for SPA components, excluding paths which appear to be static files (have an extension)
routes.MapSpaFallbackRoute(
"spaFallback",
new { controller = "Home", action = "Index" });
});
HomeController.Index
has the equivalent of your index.html
. You can probably route to a static page also.
A bit off topic, but if you also have an API in the same project under an api
folder you can set a default 404 response for any API routes that don't match:
routes.MapRoute(
"apiDefault",
"api/{*url}",
new { controller = "Home", action = "ApiNotFound" });
You would end up with the following behavior:
/controller
=> No extension, so serve SPA default page from HomeController.Index
and let SPA handle routing /file.txt
=> Extension detected, serve static file /api/controller
=> proper API response (use attribute routing or set up another map for the API controllers) /api/non-existent-route
=> 404 NotFound()
returned from HomeController.ApiNotFound
In many cases you'll want an API in a separate project, but this is a viable alternative.
In order to serve index.html
from wwwroot
folder the following directives should be added (.Net Core 2).
This allows to serve static files:
app.UseStaticFiles();
This allows to get default files, eg index.html
:
app.UseDefaultFiles();
In ASP.NET Core 3.1, I've used the following:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseCors();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseDefaultFiles();
app.UseStaticFiles();
}
[HttpGet("{anything}")]
public IActionResult GetSPA()
{
return File("~/index.html", "text/html");
}
In .NET Core 6, add app.MapFallbackToFile("index.html");
in your Program.cs
file.
Here is example code from the ASP.NET Core with React project template:
app.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
app.MapFallbackToFile("index.html");
app.Run();
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.