Angular 2的HTML5 pushState在ASP.NET Core上的解决思路

Angular 2的HTML5 pushState在ASP.NET Core上的解决思路

正如Angular 2在Routing & Navigation中所提及的那样,Angular 2是推荐使用HTML5 pushState的URL style的。

localhost:3002/crisis-center/

而不是Angular 1中所使用的“hash URL sytle“

localhost:3002/src/#/crisis-center/

这种URL Style带来的问题是,直接输入的URL会直接访问对应Server资源,换言之,要支持这种URL Style,Server端必须增加额外的Routing才行。本文简单介绍一下在ASP.NET Core上的三种解决思路。

  • 解决思路一,使用NotFound的MiddleWare
    MSDN 有一篇Article介绍了如何实现自己的MiddleWare来实现自定义404 Page,当然,该Article主要Focus在如何智能纠错。我们这里只关注如何使用类似的方法来达到所需要的效果。

MiddleWare的实现代码:

    public class NotFoundMiddleware
    {
        private readonly RequestDelegate _next;

        public NotFoundMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task Invoke(HttpContext httpContext)
        {
            string path = httpContext.Request.Path;

            await _next(httpContext);

            if (httpContext.Response.StatusCode == 404 && 
                (path.StartsWith("/allowpath1") 
                || path.StartsWith("/allowpath2"))
            {
                string indexPath = "wwwroot/index.html";
                // Redirect is another way
                //httpContext.Response.Redirect(indexPath, permanent: true);
                httpContext.Response.Clear();
                httpContext.Response.StatusCode = 200; // HttpStatusCode.OK;
                httpContext.Response.ContentType = "text/html";

                await httpContext.Response.WriteAsync(File.ReadAllText(indexPath));
            }
        }
    }

    // Extension method used to add the middleware to the HTTP request pipeline.
    public static class NotFoundMiddlewareExtensions
    {
        public static IApplicationBuilder UseNotFoundMiddleware(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware();
        }
    }

然后再Startup Class中使用该MiddleWare:

app.UseNotFoundMiddleware();
  • 解决思路二,使用Routing
    使用Routing是另外一种解决问题的思路,即把所有默认的request发送给默认的Controller。这里,要求启用标准的MVC。
    实现一个HomeController类:
    public class HomeController : Controller
    {
        // GET: //
        public IActionResult Index()
        {
            return View();
        }
    }

创建Index.cshtml,必须放置在Views\Home或者Views\Shared文件夹中,文件内容即index.html内容。
然后再Startup 类中指定default routing:

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc(); 
            //services.AddMvcCore()
            //    .AddJsonFormatters();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            loggerFactory.AddConsole();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseDefaultFiles();
            app.UseStaticFiles();
            app.UseMvc(routes =>
            {
                routes.MapRoute("AngularDeepLinkingRoute", "{*url}",
                    new { controller = "Home", action = "Index" });
            });
        }

值得注意的是,必须在project.json中把Views文件夹加入publishOptions的include部分:

  "publishOptions": {
    "include": [
      "wwwroot",
      "Views",
      "web.config",
    ],
    "exclude": [
      "node_modules",
      "bower_components"
    ]
  },
  • 解决思路三,直接修改Request的Path
    这个思路更加简单暴力,也更为高效,因为之前的思路要么是访问失败(404的StatusCode)后的Redirect,要么是路由失败后的Default实现,这个思路直接在Request入口就改写了Request的Path
public void Configure(IApplicationBuilder app)
{
    app.UseIISPlatformHandler();

         var angularRoutes = new[] {
                "/allowpath1",
                "/allowpath2",
        };

    app.Use(async (context, next) =>
    {
        if (context.Request.Path.HasValue &&
            null !=
            angularRoutes.FirstOrDefault(
            (ar) => context.Request.Path.Value.StartsWith(ar, StringComparison.OrdinalIgnoreCase)))
        {
            context.Request.Path = new PathString("/");
        }

        await next();
    });

    app.UseDefaultFiles();
    app.UseStaticFiles();
}

是为之记。
Alva Chien
2016.8.24

你可能感兴趣的:(Windows,Programming,Web,Programming,asp.net,html5,angular2,routing,pushState)