ASP.NET 路由實現頁面靜態化
頁面靜態化最大的好處是利於SEO,即使是偽靜態,搜尋引擎也會覺得這是一個較為友好的Url。Url的友好也取決於其命名,為一篇描述古代文學的頁面起名用ancient-literature.html當然比隨便起的名字例如aa.html之流要友好。頁面靜態化並不代表你一定要用字尾名為.html或.htm的連結來顯示你的頁面,你完全可以不用任何字尾名(就像MVC一樣),只要Url結構良好。
實現靜態化的三個目標:
1. 實現頁面靜態化,頁面中的連結都用.html來表示,但每個.html實際都映射了一個.aspx頁面。
例如:當用戶請求index.html頁面時,實際請求的是Default.aspx頁面,index.html的物理路徑在網站中並不存在。
2. 實現請求.aspx頁面時自動跳轉到對應的靜態對映頁面。
例如:當用戶請求Default.aspx頁面,自動跳重定向到index.html頁面
3. 自定義404頁面的實現
當請求的路徑既不在對映表中,也不在網站的虛擬路徑中時,它將自動跳轉到我預先設定好的404頁面。
實現以上要點,需要用到ASP.NET Url Routing、HttpHandler和HttpModule技術。
這是一個小系列的文章,這一篇文章將詳細解釋並實現第1點。
一、專案建立
1. 建立一個ASP.NET Web Application專案
2. 建立web.config檔案
ASP.NET Membership在這裡使用不到,所以生成的web.config配置沒有用處,刪掉它並重新建立一個新的web.config檔案
<?xml version="1.0"?> <configuration> <system.web> <compilation debug="true" targetFramework="4.0" /> </system.web> </configuration>
3. 將網站新增到IIS6或IIS7中
預設的ASP.NET Web Application已經為我們提供了不少頁面,我就在下面的例子中將它們靜態化吧。
二、頁面靜態化實現
1. 新增Routing引用
由於這裡需要用到ASP.NET的路由對映(從.NET 3.5開始誕生),所以需要在專案中新增System.Web.Routing引用。
2. 新增WebHandler和WebModule資料夾
這兩個資料夾分別用於存放IHttpHandler和IHttpModule。
3. 將所有.aspx字尾的超連結更改為.html
Site.Master檔案:
<asp:Menu ID="NavigationMenu" runat="server" CssClass="menu" EnableViewState="false" IncludeStyleBlock="false" Orientation="Horizontal"> <Items> <asp:MenuItem NavigateUrl="~/Index.html" Text="Home"/> <asp:MenuItem NavigateUrl="~/About.html" Text="About"/> </Items> </asp:Menu>
Account資料夾ChangePassword.aspx檔案:
<asp:ChangePassword ID="ChangeUserPassword" runat="server" CancelDestinationPageUrl="~/" EnableViewState="false" RenderOuterTable="false" SuccessPageUrl="ChangePasswordSuccess.html">
當然現在這三個靜態連結都訪問不到,因為它們的實體地址不存在。
下面我們要做的就是:
1) 請求Index.html時實際請求的是Default.aspx
2) 請求About.html時實際請求的是About.aspx
3) 請求Account/Login.html時實際請求的是Account/Login.aspx
4. 新增自定義的IRouteHandler實現
using System.Web; using System.Web.Compilation; using System.Web.Routing; using System.Web.UI; namespace Routing_Static_Page_Demo.WebHandler { public class CustomRouteHandler : IRouteHandler { /// <summary> /// 虛擬路徑 /// </summary> public string VirtualPath { get; private set; } public CustomRouteHandler(string virtualPath) { this.VirtualPath = virtualPath; } /// <summary> /// 返回實際請求頁 /// </summary> public IHttpHandler GetHttpHandler(RequestContext requestContext) { var page = BuildManager.CreateInstanceFromVirtualPath(VirtualPath, typeof(Page)) as IHttpHandler; return page; } } }
5. 在Global.asax檔案中註冊路由
先來個簡單的實現:
using System; using System.IO; using System.Web.Routing; using Routing_Static_Page_Demo.WebHandler; namespace Routing_Static_Page_Demo { public class Global : System.Web.{ void Application_Start(object sender, EventArgs e) { RegisterRoutes(); } /// <summary> /// 註冊路由 /// </summary> private void RegisterRoutes() { //將Index.html請求對映為Default.aspx RouteTable.Routes.Add("Default", new Route("Index.html", new CustomRouteHandler("~/Default.aspx"))); // 將About.html請求對映為About.aspx RouteTable.Routes.Add("About", new Route("About.html", new CustomRouteHandler("~/About.aspx"))); // 將Account/Login.html請求對映為/Account/Login.aspx RouteTable.Routes.Add("Login", new Route("Account/Login.html", new CustomRouteHandler("~/Account/Login.aspx"))); } } }
在VS中直接執行站點(VS自帶的WebDev伺服器),點選這些連結都能夠正常訪問。
三. 在IIS 7下設定站點
下面的設定很重要,因為上面在VS自帶的web伺服器中雖然跑通了,但IIS 7下是執行不通過的(IIS 6下的設定很簡單,本文的線上Demo是執行在IIS 6下的)
1. 初次在IIS 7下執行該網站,會出現下面的錯誤。
這是因為IIS對該Web站點目錄沒有讀寫許可權。
在IIS下:右鍵站點 > Edit Permissions > Security > Edit > Add > 輸入IIS_IUSRS > Check Names > OK。
選擇完畢後,為IIS_IUSRS使用者新增Full Control許可權。
border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="SNAGHTML2f152df[4]" border="0" alt="SNAGHTML2f152df[4]" src="http://www.jileiba.com/wp-content/uploads/2012/03/SNAGHTML2f152df4_thumb.png" width="381" height="460" />
2. 新增完該設定後,再執行一次網站,可能會出現下面的錯誤。
按照上面的步驟新增IUSR使用者,為IUSR使用者分配Read許可權即可。
再次執行網站,能夠正常訪問頁面了。
3. 配置web.config
網站雖然能執行,但是點選Home或About連結時會出現404錯誤。
i. 首先確保在安裝IIS時你已經勾選了HTTP Reirection
如果沒有安裝這個功能,按照如下設定再配置一遍IIS
Control Panel –> Progams –> Turn off windows features –> World wide web Services –> Common HTTP Features –> HTTP Redirection
ii. 修改web.config檔案,在webserver中註冊RoutingHandler和RoutingModule
<?xml version="1.0" encoding="UTF-8"?> <configuration> <system.web> <compilation debug="true" targetFramework="4.0" /> </system.web> <system.webServer> <modules runAllManagedModulesForAllRequests="true"> <remove name="UrlRoutingModule"/> <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> </modules> <handlers> <add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd" type="System.Web.HttpForbiddenHandler, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/> </handlers> </system.webServer> </configuration>
注意: 如果你採用的是ASP.NET 3.5 Routing或使用IIS 6,web.config配置會不一樣。
iii. 確保web站點的應用程式池選擇的是整合模式,因為ASP.NET 4.0 Routing並不支援經典模式
OK,似乎所有的該配置的地方都配置了,那麼再去點選Index.html或About.html連結試試吧。
如果現在去訪問Login.html頁面,還是會得到一個401.3的錯誤,更改Account目錄下的web.config檔案:
<?xml version="1.0"?> <configuration> <location path="Register.aspx"> <system.web> <authorization> <allow users="*"/> </authorization> </system.web> </location> <system.web> <!--<authorization> <deny users="?"/> </authorization>--> </system.web> </configuration>
如果你不需要這個web.config檔案,直接刪掉也可以。
四. 更改RegisterRoutes方法
上面提供的註冊路由的方式屬於硬編碼,需要為每一個.aspx頁面指定對映路由。Account目錄下還有一些.aspx檔案,如果增加別的目錄也存放.aspx頁面,為了讓每個頁面都靜態化,RegisterRoutes方法將會是產生很多重複程式碼。
using System; using System.IO; using System.Web.Routing; using Routing_Static_Page_Demo.WebHandler; namespace Routing_Static_Page_Demo { public class Global : System.Web.HttpApplication { void Application_Start(object sender, EventArgs e) { RegisterRoutes(); } /// <summary> /// 註冊路由 /// </summary> private void RegisterRoutes() { //將Index.html請求對映為Default.aspx RouteTable.Routes.Add("Default", new Route("Index.html", new CustomRouteHandler("~/Default.aspx"))); // 將About.html請求對映為About.aspx RouteTable.Routes.Add("About", new Route("About.html", new CustomRouteHandler("~/About.aspx"))); // 遍歷頁面存放目錄,為每個.aspx頁面新增路由對映 foreach (string mapPth in _pageMapPath) { string path = Server.MapPath(mapPth); var directoryInfo = new DirectoryInfo(path); foreach (FileInfo f in directoryInfo.GetFiles()) { string fileName = f.Name; if (fileName.EndsWith(".aspx")) { string routeName = fileName.Substring(0, fileName.Length - 5); string url = string.Concat(mapPth.Substring(2), routeName, ".html"); RouteTable.Routes.Add(routeName, new Route(url, new CustomRouteHandler(string.Concat(mapPth, fileName)))); } } } } // 頁面存放目錄 private readonly string[] _pageMapPath = {@"~/Account/"}; } }
以上程式碼就能實現為每個.aspx頁面註冊路由實現靜態化。