拥有一个网站意味着需要投入时间和精力在互联网上推广,确保搜索引擎索引所有页面,并通过博客或讨论板获得曝光。然后,当有了新的想法,真的需要重新组织网站——改变一些文件夹名称,移动一些页面等。那么,那些曾经引以为豪的第三方链接会发生什么?想要失去它们吗?
在.NET Framework 3.5 SP1的到来,有了一个优雅的解决这个问题的方法——ASP.NET路由。最初,它是ASP.NET MVC Preview 2的一部分,现在它已经成为框架的一部分。
这个想法是向网站添加特殊的“路由”,其单一目标是处理对不再存在于网站上的页面的请求。在其最简单的形式中,处理可以在一个ASPX页面中完成,该页面负责正确处理请求。
下面是一个示例:
附加的项目包含了所需要的所有部分:
让看看Global.asax:
void Application_Start(object sender, EventArgs e) {
// 运行在应用程序启动时
RegisterMyRoutes(System.Web.Routing.RouteTable.Routes);
}
private void RegisterMyRoutes(System.Web.Routing.RouteCollection routes) {
// 引用IRouteHandler实现
// (示例由Chris Cavanagh创建)
// 参见 http://chriscavanagh.wordpress.com/2008/03/11/aspnet-routing-goodbye-url-rewriting/
var startPageRouteHandler = new WebFormRouteHandler("~/default.aspx");
// 排除.axd以处理Web服务和AJAX,而不需要检查所有路由
// 参见 http://msdn.microsoft.com/en-us/library/
// system.web.routing.stoproutinghandler.aspx
routes.Add(new System.Web.Routing.Route("{resource}.axd/{*pathInfo}", new System.Web.Routing.StopRoutingHandler()));
routes.Add(new System.Web.Routing.Route("{service}.asmx/{*path}", new System.Web.Routing.StopRoutingHandler()));
// 映射:
// 提取文件夹名称和页面名称作为HttpContext.Items中的项
routes.Add(new System.Web.Routing.Route("{folderName}/", startPageRouteHandler));
routes.Add(new System.Web.Routing.Route("{folderName}/{pageName}", startPageRouteHandler));
}
在这里,定义了一个单一的路由处理器——default.aspx,以及路由规则。
规则#1:
routes.Add(new System.Web.Routing.Route("{folderName}/", startPageRouteHandler));
表明所有结构为"http://mysite.com/something"的URL请求将由default.aspx页面处理,如果网站上没有实际的"something"。例如,如果网站上有RealPage.aspx页面,那么对http://mysite.com/RealPage.aspx的请求将由该页面处理。
但是,如果客户端请求RealPage2.aspx,那么该请求将由default.aspx页面根据规则#1处理。请注意,客户端不会被重定向到default.aspx,它将只是Web服务器在响应请求时运行default.aspx中的代码。对于客户端来说,响应将来自RealPage2.aspx。
可以添加尽可能多的路由,例如规则#2:
routes.Add(new System.Web.Routing.Route("{folderName}/{pageName}", startPageRouteHandler));
表明所有结构为"http://mysite.com/somefolder/somethingelse"的URL请求将由default.aspx页面处理,如果网站上没有实际的"somefolder/somethingelse"。
default.aspx的代码背后展示了如何提取请求的这些部分。如所见,它们将被放置在HttpContext.Items集合中。
lblFolder.Text = Context.Items["folderName"] as string;
lblPage.Text = Context.Items["pageName"] as string;
在现实生活中的应用:
这里有一个实际使用这种技术的网站——Digitsy Global Store。除了处理过时的URL,ASP.NET路由还被用来处理网站上的多种语言,实时切换CultureInfo:
protected void Page_PreInit(object sender, EventArgs e) {
CultureInfo lang = new CultureInfo(getCurrentLanguage());
Thread.CurrentThread.CurrentCulture = lang;
Thread.CurrentThread.CurrentUICulture = lang;
}
private static string getCurrentLanguage() {
string lang = HttpContext.Current.Items["language"] as string;
switch (lang) {
case "france":
return "fr-FR";
case "canada":
return "en-CA";
case "germany":
return "de-DE";
case "japan":
return "ja-JP";
case "uk":
return "en-GB";
case "russia":
return "ru-RU";
default:
return "en-US";
}
}
如所见,默认语言是英语,美国:"en-US"。在内部链接中,网站使用结构http://{sitename}/{language}/…其他东西…
所以,如果尝试http://digitsy.com/us/,将得到美国版本,尝试http://digitsy.com/japan/将带去日本版本,如果尝试http://digitsy.com/whatever/——不会得到404错误,将再次得到美国版本。
ASP.NET路由使网站的重构变得非常容易。文件夹结构"{language}/{index}/category/{categoryID}"最近被替换为"{language}/{index}/shopping/{categoryID}"。网站上不应该再有"category"文件夹。但由于两个路由都指向同一个处理页面,两个文件夹"category"和"shopping"都返回有效响应。
尝试http://digitsy.com/us/Electronics/shopping/541966将使用规则:
routes.Add(new System.Web.Routing.Route("{language}/{index}/shopping/{categoryID}", categoryRouteHandler));
而尝试http://digitsy.com/us/Electronics/category/541966将使用:
routes.Add(new System.Web.Routing.Route("{language}/{index}/category/{categoryID}", categoryRouteHandler));
两者都将解析到同一个路由处理页面。