What is the purpose of the following code which is automatically loaded to the Startup class with this project:
routes.MapSpaFallbackRoute(
name: "spa-fallback",
defaults: new { controller = "Home", action = "Index" });
This results in a 200 being thrown when a non-existent API endpoint is hit instead of a 404.
It's for when you want to handle the 404 within your front-end application (and as noted below, let all Routes go through so your front-end can handle them)
@MarkPieszak My use case - which I assume is very common - is to want to handle bad angular routes in the front-end (by either sending to a "404" routes or just loading a "home" route), but throw 404s on bad API calls (that is, requests whose URL follows a certain pattern eg. "/api").
Can you give me a recommendation?
You want to use a mapWhen looking for something that starts with /api, use this below and you'll be all set:
```c#
// this part you already have
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
// here you can see we make sure it doesn't start with /api, if it does, it'll 404 within .NET if it can't be found
app.MapWhen(x => !x.Request.Path.Value.StartsWith("/api"), builder =>
{
builder.UseMvc(routes =>
{
routes.MapSpaFallbackRoute(
name: "spa-fallback",
defaults: new { controller = "Home", action = "Index" });
});
});
```
Hope that helps!
Thanks @MarkPieszak for the answer. If this becomes a common request, we could add a further excludePrefix option onto MapSpaFallbackRoute so you can set it to api.
Also:
It's for when you want to handle the 404 within your front-end application.
That's not the whole story. It's mostly just so that all URLs that might be handled by your front-end application cause the front-end application to be returned. For example, a request for the URL /counter (in the default template) should cause the front-end application to be loaded, which will then display a suitable UI. If you didn't have MapSpaFallbackRoute then the server would just return a 404 for /counter since there's no matching MVC controller.
@MarkPieszak Perfect. Your solution works as desired.
Fantastic responsiveness as usual.
If you didn't have MapSpaFallbackRoute then the server would just return a 404 for /counter since there's no matching MVC controller.
So umm yeah, this is REALLY an important point that I hope does not get lost :)
Meaning. I can send someone a url like this:
http://helloworlddata.azurewebsites.net/counter
..and it works even though there is really no /counter page. It exists only as an Angular route :)
That's not the whole story. It's mostly just so that all URLs that might be handled by your front-end application cause the front-end application to be returned. For example, a request for the URL /counter (in the default template) should cause the front-end application to be loaded, which will then display a suitable UI. If you didn't have MapSpaFallbackRoute then the server would just return a 404 for /counter since there's no matching MVC controller.
Yes apologies I should of mentioned that! @SteveSandersonMS
For anyone who wants to use ASP.NET Razor Pages that came out with .NET Core 2.0 I never could get map fallback route to work so I pivoted and went a different direction which implements @MarkPieszak 's solution of only routing all requests to the SPA when the route doesn't start with API.
```csharp
public void ConfigureServices(IServiceCollection services) =>
services
.AddMvc()
.AddRazorPagesOptions(options =>
{
options.Conventions.AddPageRoute("/Index", "{url:regex(^(?!api).$)}");
});
````
@buvinghausen That works well. Just be aware that every request that doesn't match a static file will get routed to your SPA - even requests with file extensions. MapSpaFallbackRoute does not match requests that look like filenames - that is, have an extension at the end.
Edit: I just realize you do account for periods in the request - but I'll leave my comment here just in case it helps others. Thanks!
Edit2: Just opened an issue with https://github.com/aspnet/JavaScriptServices with a suggestion: https://github.com/aspnet/JavaScriptServices/issues/1354
app.UseMvc(routes =>
{
routes.MapSpaFallbackRoute(
name: "spa-fallback-admin",
defaults: new { area="Admin", controller = "Home", action = "Index" });
});
is this the correct way to using controller from some areas?
Most helpful comment
You want to use a mapWhen looking for something that starts with
/api, use this below and you'll be all set:```c#
// this part you already have
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
```
Hope that helps!