可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
With RC1 of ASP.NET Core 1.0's MVC 6 you can map routes from within your Startup.Configure
function when invoking app.UseMvc
. I have mapped a "spa-fallback" route that will ensure that the HomeController
and Index
view are the defaults like so:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { // ... omitted for brevity app.UseExceptionHandler("/Home/Error"); app.UseStatusCodePagesWithRedirects("/Home/Error/{0}"); app.UseMvc(routes => { routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}"); routes.MapRoute("spa-fallback", "{*anything}", new { controller = "Home", action = "Index" }); routes.MapWebApiRoute("defaultApi", "api/{controller}/{id?}"); }); }
I desire the fallback so that my Angular2 app's routes will not result in an HTTP Status Code of 404, Not Found. But I also need to correctly handle when a user does inadvertently attempt to navigate to a page view that doesn't exist. You might notice that I have also called app.UseStatusCodePagesWithRedirects("/Home/Error/{0}");
.
The call to redirect to my error page with the status code and the "spa-fallback" route seem mutually exclusive -- meaning it appears that I can only have one or the other (but sadly not both). Does anyone know how I could manage to have the best of both worlds?
回答1:
It took me some time to figure out how to do this without serving my index using MVC and to still receive 404s for missing files. Here's my http pipeline:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { app.UseDefaultFiles(); app.UseStaticFiles(); app.UseMvc( routes => { routes.MapRoute( name: "api", template: "api/{controller}/{action}/{id?}"); // ## commented out since I don't want to use MVC to serve my index. // routes.MapRoute( // name:"spa-fallback", // template: "{*anything}", // defaults: new { controller = "Home", action = "Index" }); }); // ## this serves my index.html from the wwwroot folder when // ## a route not containing a file extension is not handled by MVC. // ## If the route contains a ".", a 404 will be returned instead. app.MapWhen(context => context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value), branch => { branch.Use((context, next) => { context.Request.Path = new PathString("/index.html"); Console.WriteLine("Path changed to:" + context.Request.Path.Value); return next();}); branch.UseStaticFiles(); }); }
回答2:
I came up with two possible workarounds/solutions.
ASP.NET Core 1.0, RC1
With Angular2 specifically, we can simply swap out the LocationStrategy
. For example in my wwwroot/app/boot.ts
I have the following:
import {provide} from "angular2/core"; import {bootstrap} from "angular2/platform/browser"; import {LocationStrategy, HashLocationStrategy, ROUTER_PROVIDERS} from "angular2/router"; import {HTTP_PROVIDERS} from "angular2/http"; import {AppComponent} from "./app.component" bootstrap(AppComponent, [ ROUTER_PROVIDERS, HTTP_PROVIDERS, provide(LocationStrategy, { useClass: HashLocationStrategy }) ]);
Note that I am utilizing the provide
function to override the standard LocationStrategy
with the HashLocationStrategy
. This adds the #
in the URL and prevents MVC from incorrectly throwing 404's, but also correctly handles responding with 404's when the user manually types in a URL that doesn't exist.
ASP.NET Core 1.0, RC2
Simply use Microsoft.AspNet.NodeServices
. Within this library there are both AngularServices
and ReactServices
which allow for the mapping of SPA routes specifically, via the MapSpaFallbackRoute
function. I state that we need to wait for RC2 with the understanding that the current implementations are not fully functioning as desired.
回答3:
Try this:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { app.UseExceptionHandler("/Home/Error"); app.UseStatusCodePagesWithRedirects("/Home/Error/{0}"); app.UseMvc(routes => { routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}"); routes.MapWebApiRoute("defaultApi", "api/{controller}/{id?}"); }); app.Run(async context => { context.Response.Redirect("/Home/Index"); await Task.CompletedTask; }); }
app.Run() will catch all requests that doesn't match any of the routes defined earlier. This way you can get your custom spa fallback and use app.UseStatusCodePagesWithRedirects() at the same time.