ASP轉換PHP,[轉載]ASP.NET MVC URL重寫與優化(進階篇)-繼承RouteBase玩轉URL

 2023-12-06 阅读 23 评论 0

摘要:引言--   在初級篇中,我們介紹了如何利用基于ASP.NET MVC的Web程序中的Global文件來簡單的重寫路由。也介紹了它本身的局限性-依賴于路由信息中的鍵值對:   如果鍵值對中沒有的值,我們無法將其利用湊出我們想要的URL表達式。   初級篇傳送門:使用Global路

引言--

  在初級篇中,我們介紹了如何利用基于ASP.NET MVC的Web程序中的Global文件來簡單的重寫路由。也介紹了它本身的局限性-依賴于路由信息中的鍵值對:

  如果鍵值對中沒有的值,我們無法將其利用湊出我們想要的URL表達式。

  初級篇傳送門:使用Global路由表定制URL

?

  在進階篇中,我們將介紹ASP.NET 路由相關類的基類-抽象類RouteBase,并演示如何通過繼承它,讓URL重寫和優化變成Free Style。

?

一,老板的需求

  假設我們是手機銷售網站的一名程序猿(承接初級篇),經過第一次的URL重寫之后,我們的手機分類頁面的URL的改變:

http://www.xxx.com/category/showcategory?categoryid=0001&view=list&orderby=price&page=1
=>

http://www.xxx.com/category/0001

  現在老板又提出了新的需求,URL的語義化,從而更好的反應網站的結構:

http://www.xxx.com/ca-categoryname

  比如Nokia是一個分類,那么對應URL為 /ca-nokia,如果是iPhone分類,URL則對應 /ca-iphone。ca前綴的意思是分類category。

  對于這個需求簡單的配置Global文件是無法做到的。ASP轉換PHP?首先我們來介紹一下ASP.NET 路由的所有類的基類RouteBase。


二,RouteBase類簡介與運行機制

?

  1. RouteBase類位于System.Web.Routing命名空間,結構如下:

    public abstract class RouteBase{protected RouteBase();public abstract RouteData GetRouteData(HttpContextBase httpContext);public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);}
  • GetRouteData:根據Http請求信息返回一個對象-包含路由定義的值(如果該路由與當前請求匹配)或 null(如果該路由與請求不匹配)。
  • GetVirtualPath:檢查路由值是否與某個規則匹配,返回一個對象(包含生成的 URL 和有關路由的信息)或 null(如果路由與 values 不匹配)。 
  • RouteBase:初始化該類供繼承的類實例使用。此構造函數只能由繼承的類調用。

?

  看完以上定義,可能大家會暈忽忽。ASP.NET MVC4開發指南、我們來弄一個簡單的例子說明這幾個方法是如何運作的。

  首先我們新建一個類庫JohnConnor.Routing,并且繼承抽象類RouteBase:(補充:需要添加引用System.Web)

?

復制代碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;//需要添加引用,請使用3.0以上版本
using System.Web.Routing; using JohnConnor.Models;

namespace JohnConnor.Routing {public class CategoryUrlProvider:RouteBase{public override RouteData GetRouteData(System.Web.HttpContextBase httpContext){return null;//斷點1}public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values){return null;//斷點2}} }
復制代碼

?

  這樣CategoryUrlProvider類就包含了用來處理路由映射的方法。

  首先我們需要在Web程序中添加JohnConnor.Routing類庫的引用,然后我們把CategoryUrlProvider類注冊到Global文件的路由表中。

    public static void RegisterRoutes(RouteCollection routes){
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");routes.Add(
new JohnConnor.Routing.CategoryUrlProvider());//分類規則
routes.MapRoute("Home", "", new { controller = "Home", action = "Index"});//主頁
}

  這里相當于添加了一條新的路由規則。重新生成一下Web程序在CategoryUrlProvider中打好斷點,F5啟動。

?

  2.?GetRouteData()方法

  這時候相當與你在瀏覽器輸入了http//localhost:1234/<假設本地端口號是1234>,此時程序需要判斷這個URL匹配的是哪個路由值。iis url重寫,

  自上而下的匹配,首先會嘗試匹配我們新增的分類路由規則,此時會命中GetRouteData()方法中的斷點。

  因為我們返回了null,意味著該請求與我們新增的分類路由規則不匹配,那程序將在路由表中繼續自上而下的進行匹配。

  直到在主頁這一條規則中與其URL表達式匹配,獲取了對應的路由值-調用HomeController.Index()方法。


  如果你把GetRouteData()方法修改一下:

復制代碼
public override RouteData GetRouteData(System.Web.HttpContextBase httpContext){var data = new RouteData(this, new MvcRouteHandler());data.Values.Add("controller", "Home");data.Values.Add("action", "Index");return data;}
復制代碼

  你就會發現,無論你在http//localhost:1234/后面輸入任何相對URL,都會被定向到HomeController.Index()方法。

  因為返回的是路由值而不是null,表示已經找到匹配項,就不會再往下匹配了。<這條規則覆蓋了后面所有的規則>

  當然,請不要這樣寫。servlet返回json給前端?

  由此可以推斷出GetRouteData()方法在路由映射中擔任的角色:處理請求中的URL,返回相應的路由值,不處理或不匹配則返回null。

?

  3.?VirtualPathData()方法?

  如果你在Razor頁面有這樣一段通過指定路由值來獲取URL的代碼

<a href="@Url.Action("Index", "Home")">首頁</a>

?

  當視圖引擎渲染頁面到這句代碼時,HomeController.Index()方法會被解析為一個RouteValueDictionary類型的不分大小寫的鍵值對<假設鍵值對對象為values>:

values["controller"]="Home";
values["action"]="Index"

  這個鍵值對表示了一個路由值。

  同樣是在路由表中自上而下的匹配這個路由值,嘗試第一條分類規則時,就會命中VirtualPathData()方法中的斷點。

  我們返回一個null,表示不匹配,則程序進行下一個規則的匹配。

  直到找到主頁規則的路由值與之匹配時,構造出相應的相對URL"",并返回該URL。

  顯示為:

<a href="http://localhost:1234/">首頁</a>

?

  如果我們也改寫一下VirtualPathData()方法:

  

 public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values){return  new VirtualPathData(this, "This-is-a-Test-URL");}

  結果是你通過上述方法構造的URL不論請求來自哪里,全部都會顯示成http://localhost:1234/This-is-a-Test-URL

  因為我們返回的是一個相對路徑,而不是null,表示已經找到匹配項,則匹配不會往下繼續。ASP.NET。<同上這條規則覆蓋了后面所有的規則>

  再一次提示,請不要這樣寫。

  由此可看出,VirtualPathData()在路由映射中的活:處理請求與路由鍵值對,生成相應URL,不處理或不匹配則返回null。

?

  4.方法重寫的規則

  在上文中,我一再的用紅色字體提示,請不要這樣寫。因為每一個URL的重寫類,建議僅僅處理盡可能少的路由映射

  比如CategoryUrlProvider僅處理CategoryController.Show(string categoeyid)這一個Action方法的映射。凡是不是這個方法相關的映射,都返回null。js替換url參數、

  繼續去匹配別的規則。

?

三,開始動手把~

  為了最快的說明問題,我們簡化了網站的內容。以下內容有助于理解后面的程序,如果時間充裕,還是自己構建一個網站來嘗試以下。

  首先我們在JohnConnor.Routing類庫中創建Category.cs來保存分類模型,并把所有的分類顯示的保存在List<Category>中,

復制代碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;namespace JohnConnor.Models
{//分類模型public class Category{public string CategoeyID { get; set; }public string CategoeyName { get; set; }}public static class CategoryManager{//這里只顯示創建了三個分類作為示例,實際中AllCategories可以從數據源讀取。public static readonly List<Category> AllCategories = new List<Category>{new Category(){ CategoeyID="001", CategoeyName="Nokia"},new Category(){ CategoeyID="002", CategoeyName="iPhone"},new Category(){ CategoeyID="003", CategoeyName="Anycall"}};}
}
復制代碼

  假設我們網站的CategoryController是這樣的。

復制代碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using JohnConnor.Models;
namespace JohnConnor.Web.Controllers
{public class CategoryController : Controller{public ActionResult ShowCategory(string id){var category = CategoryManager.AllCategories.Find(c => c.CategoeyID == id);return View(category);}}
}
復制代碼

  首先我們建議,VirtualPathData()GetRouteData()方法是成雙成對出現的。一旦你制定了一條路由規則,比如分類規則/ca-categoryname,那么:

  • GetRouteData()必須處理與這條規則匹配的每一條URL,返回相同的路由值放棄與之不匹配的URL,返回null,讓匹配繼續
  • VirtualPathData()必須處理與這條規則匹配的每一次路由請求返回相同的URL;放棄與之不匹配的請求,返回null,讓匹配繼續。

  !!!兩者相輔相成的完成了路由值和URL的相互映射,漏掉一個,就不能構成一個完成的路由規則。直接結果是出現404或生成URL地址錯誤。

  GetRouteData()的代碼:

復制代碼
 public override RouteData GetRouteData(System.Web.HttpContextBase httpContext){var virtualPath = httpContext.Request.AppRelativeCurrentExecutionFilePath + httpContext.Request.PathInfo;//獲取相對路徑

       virtualPath = virtualPath.Substring(2).Trim('/');//此時URL會是~/ca-categoryname,截取后面的ca-categoryname
if (!virtualPath.StartsWith("ca-"))//判斷是否是我們需要處理的URL,不是則返回null,匹配將會繼續進行。return null;var categoryname = virtualPath.Split('-').Last();//截取ca-前綴后的分類名稱
//嘗試根據分類名稱獲取相應分類,忽略大小寫var category = CategoryManager.AllCategories.Find(c => c.CategoeyName.Equals(categoryname,StringComparison.OrdinalIgnoreCase));if (category == null)//如果分類是null,可能不是我們要處理的URL,返回null,讓匹配繼續進行return null;//至此可以肯定是我們要處理的URL了var data = new RouteData(this, new MvcRouteHandler());//聲明一個RouteData,添加相應的路由值data.Values.Add("controller", "Category");data.Values.Add("action", "ShowCategory");data.Values.Add("id", category.CategoeyID);return data;//返回這個路由值將調用CategoryController.ShowCategory(category.CategoeyID)方法。匹配終止}
復制代碼

  VirtualPathData()的代碼

復制代碼
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values){//判斷請求是否來源于CategoryController.Showcategory(string id),不是則返回null,讓匹配繼續var categoryId = values["id"] as string;if (categoryId == null)//路由信息中缺少參數id,不是我們要處理的請求,返回nullreturn null;//請求不是CategoryController發起的,不是我們要處理的請求,返回nullif (!values.ContainsKey("controller") || !values["controller"].ToString().Equals("category",StringComparison.OrdinalIgnoreCase))return null;//請求不是CategoryController.Showcategory(string id)發起的,不是我們要處理的請求,返回nullif (!values.ContainsKey("action") || !values["action"].ToString().Equals("showcategory", StringComparison.OrdinalIgnoreCase))return null;//至此,我們可以確定請求是CategoryController.Showcategory(string id)發起的,生成相應的URL并返回var category = CategoryManager.AllCategories.Find(c => c.CategoeyID == categoryId);if (category == null)throw new ArgumentNullException("category");//找不到分類拋出異常var path = "ca-" + category.CategoeyName.Trim();//生成URLreturn new VirtualPathData(this, path.ToLowerInvariant());}
復制代碼

  至此,我們就把這條路由規則的映射處理完整了。如果你掌握了上述技術,任何的URL重寫和優化需求,我相信你都能Hold住。

  如果我們的主頁頁面是這樣<Razor視圖引擎>

View Code

?

  三個分類連接會得到這樣的結果

<a href="/ca-nokia">Nokia</a>
<a href="/ca-iphone">iPhone</a>
<a href="/ca-anycall">Anycall</a>

  點擊每一個連接都會先進入我們的處理程序,生成相應的路由值-調用CategoryController.Showcategory(string id)方法根據id顯示相應的分類頁面。

原文地址:http://www.cnblogs.com/John-Connor/archive/2012/05/03/2478821.html

轉載于:https://www.cnblogs.com/iack/p/3535232.html

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/5/192813.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息