《Pro ASP.NET MVC 3 Framework》學習筆記之二十【URL和Routing】


自定義路由系統

通過前面的學習,我們能夠感受到路由系統的靈活性和可配置性,如果這些不能滿足我們的需求,我們可以自定義行為,下面會介紹如何自定義路由。

創建一個對RouteBase類的自定義實現

如果我們不喜歡標准Route對象匹配URL的方式,或者想實現一些特別的東西。我們可以從RouteBase派生一個類來替代。派生出來的類可以讓我們自己控制URL的匹配,參數的提取,以及Outgoing URL的創建。派生的類需要實現下面兩個方法:

1.GetRouteData(HttpContextBase httpContext):實現傳入的URL的匹配機制。
   在每一個RouteTable.Routes進入的時候,MVC框架會輪流調用該方法直到其中的一次調用返回非空值。

2.GetVirtualPath(RequestContext requestContext, RouteValueDictionary values):實現創建傳出的URL機制。
   在每一個RouteTable.Routes進入的時候,MVC框架會輪流調用該方法直到其中的一次調用返回非空值。

下面用一個例子來說明,假設現在我們要遷移一個程序到MVC,但是一些用戶已經存了程序鏈接書簽或者在腳本里面硬編碼了。我們仍然需要支持原來的URL,我們能夠通過常規的路由系統來處理這種情況,這里用這個例子來說明自定義路由。

創建一個LegacyController,代碼如下:

View Code
        public ActionResult GetLegacyURL(string legacyURL)
{
return View((object)legacyURL);
}

在這個簡單的Controller里面,GetLegacyURL action方法會獲取一個參數並將這個參數傳遞給View。如果我們真的的要實現這個Controller,需要使用這個方法來檢索請求的文件,但是這里為了簡便,只是在View里面顯示請求的URL。注意:我們這里對View里面參數進行了Object的類型轉換。原因是View()方法本身有一個string參數的重載,如果這里我們不轉換,View會把string參數當成某一個視圖的名字去尋找,顯然這里我們不是要跳轉到某一個View,而是在默認的View上顯示出來就行。如圖所示:

轉成object后,會認為是model而使用默認的View呈現。接着添加視圖GetLegacyURL.cshtml,代碼如下:

View Code
@model string
@{
ViewBag.Title = "GetLegacyURL";
}

<h2>GetLegacyURL</h2>
The URL requested was:@Model

上面我們已經實現了從RouteBase派生,下面接着創建一個類LegacyRoute,如下所示:

View Code
namespace UrlsAndRoutes.Infrastructure
{
public class LegacyRoute : RouteBase
{
private string[] urls;
public LegacyRoute(params string[] targetUrls)
{
urls = targetUrls;
}


public override RouteData GetRouteData(HttpContextBase httpContext)
{
RouteData result = null;
string requestedURL = httpContext.Request.AppRelativeCurrentExecutionFilePath;
if (urls.Contains(requestedURL, StringComparer.OrdinalIgnoreCase))
{
result = new RouteData(this, new MvcRouteHandler());
result.Values.Add("controller", "Legacy");
result.Values.Add("action", "GetlegacyURL");
result.Values.Add("legacyURL", requestedURL);
}
return result;
}

public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
VirtualPathData result = null;
if (values.ContainsKey("legacyURL") && urls.Contains((string)values["legacyURL"], StringComparer.OrdinalIgnoreCase))
{
result = new VirtualPathData(this, new UrlHelper(requestContext).Content((string)values["legacyURL"]).Substring(1));
}
return result;
}
}
}

該類的構造器需要傳入一個字符串數組作為參數,該參數呈現這個路由類支持的個別的URL。在GetRouteData方法里面定義的部分就是路由系統調用來檢查是否能夠處理傳入的傳入的URL。如果不能處理請求,返回null,並且路由系統會移動到到下一個路由重復該過程。如果能夠處理請求,就需要返回包含了controller和action變量以及任何其他的想要傳遞給action方法的RouteData類的實例。

當我們創建RouteData對象時需要傳入要處理的值的handler,這里我使用的是MvcRouteHandler類如:result=new RouteData(this,new MvcRouteHandler());
對絕大多數MVC應用程序,這個就是我們需要的類,因為它聯接着路由系統與一個MVC程序的controller/action model。當然,我們也可以實現一個替代MvcRouteHandler的類,也就是后面會介紹的創建自定義的Route Handler.

在上面的routing實現里,我們將會路由任何傳給構造器的請求的URL。當獲取這樣一個URL時,我們添加controller和action的硬編碼值到RouteValues對象,我們也會傳遞請求的URL作為legacyURL屬性,注意這里的屬性的名字必須和action方法的參數名匹配,從而保證了我們創建的值能夠通過參數傳遞給action方法。最后一步就是注冊從RouteBase派生的新的路由。如:routes.Add(new LegacyRoute("~/article/Windows_3.1_Overview.html","~/old/.NET_1.0_Class_Library"));我們創建了一個LegacyRoute類的實例,並傳入了我們要路由的URL,然后使用Add方法添加到RouteCollection里面。當我們請求傳入的URL時,就會被路由到我們定義的Controller,如下圖所示:

創建Outgoing URL

為了支持創建Outgoing URL,我們需要實現GetVirtualPath方法。再一次說明,如果我們不能處理某個請求,我們通過返回null值來讓路由系統知道,否則就返回VirtualPathData類的實例。

代碼如下:

View Code
        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
VirtualPathData result = null;
if (values.ContainsKey("legacyURL") && urls.Contains((string)values["legacyURL"], StringComparer.OrdinalIgnoreCase))
{
result = new VirtualPathData(this, new UrlHelper(requestContext).Content((string)values["legacyURL"]).Substring(1));
}
return result;
}

我們在傳遞segment變量或其他詳細的值時通常使用了匿名類型,但是在這里,路由系統將這些轉換成了RouteValueDictionary對象。所以我們像這樣添加一個鏈接在View里面,

如下所示:

View Code
@Html.ActionLink("Click me", "GetLegacyURL", new { legacyURL =  
"~/articles/Windows_3.1_Overview.html" })

創建的具有legacyURL屬性的匿名類型被轉換成了RouteValueDictionary對象,並且包含了一個同名的key。

在本例里面,如果有一個key名為legacyURL並且它的值是我們傳入LegacyRoute類的構造器里面的URL中的一個,我們決定能處理傳出的URL請求。

創建自定義路由處理程序(Route Handler)

前面我們提到過,在我們的路由里面會依賴MvcRouteHandler類,因為它聯系着路由系統跟MVC框架。我們可以通過實現IRouteHandler接口來自定義Route Handle1r,如下所示:

View Code
namespace UrlsAndRoutes.Infrastructure
{
public class CustomRouteHandler : IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return new CustomHttpHandler();
}
}

public class CustomHttpHandler : IHttpHandler
{

public bool IsReusable
{
get { return false; }
}

public void ProcessRequest(HttpContext context)
{
context.Response.Write("Hello");
}
}
}

IRouteHandler接口的目的就是提供一種方式來創建對IHttpHandler接口的實現,IHttpHandler接口是負責處理請求的,在這些接口的MVC實現中,controller會被找到,action方法會被調用,view會被呈現。結果會被寫到Response里面。實例里面的實現非常簡單,僅僅是寫了一個"Hello"到客戶端。

下面是注冊我們自己定義的路由:
routes.Add(new Route("SayHello", new CustomRouteHandler()));這時運行程序,輸入:http://localhost:57400/SayHello,頁面會顯示"Hello".


好了,今天的筆記做到這里,后面的筆記是關於Areas和一些有關URL架構的最佳實踐。
晚安!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM